160 lines
4.9 KiB
Python
160 lines
4.9 KiB
Python
from datetime import datetime, timezone
|
|
|
|
import pytest
|
|
|
|
from core.competences.verdicts import (
|
|
CompetenceVerdictError,
|
|
iter_competence_verdicts,
|
|
store_competence_verdict,
|
|
)
|
|
|
|
|
|
VERDICT_ID = "123e4567-e89b-42d3-a456-426614174000"
|
|
|
|
|
|
def _payload(**overrides):
|
|
payload = {
|
|
"verdict_id": VERDICT_ID,
|
|
"verdict_kind": "valid",
|
|
"verdict_by": "human:dom",
|
|
"context_signature": {
|
|
"machine_id": "DESKTOP-58D5CAC_windows",
|
|
"screen_state_initial": "before_hash",
|
|
"screen_state_after_action": "after_hash",
|
|
},
|
|
"evidence": {
|
|
"screenshot_before": "evidence/before.png",
|
|
"screenshot_after": "evidence/after.png",
|
|
"wait_state_matched_evidence": {
|
|
"window_title": "Executer",
|
|
"process_name": "explorer.exe",
|
|
},
|
|
},
|
|
"workflow_id": "preview_competence_key_win_r_wait_explorer_exe",
|
|
"step_results": [
|
|
{
|
|
"step_id": "step_1_key_combo",
|
|
"action_type": "keyboard_shortcut",
|
|
"status": "success",
|
|
}
|
|
],
|
|
"comments": "Supervised replay ok",
|
|
}
|
|
payload.update(overrides)
|
|
return payload
|
|
|
|
|
|
def test_store_competence_verdict_appends_jsonl(tmp_path):
|
|
log_path = tmp_path / "verdicts.jsonl"
|
|
|
|
record = store_competence_verdict(
|
|
"key_win_r_wait_explorer_exe",
|
|
_payload(),
|
|
log_path=log_path,
|
|
now=datetime(2026, 5, 29, 16, 30, tzinfo=timezone.utc),
|
|
)
|
|
|
|
assert record["schema_version"] == "lea_competence_verdict.v1"
|
|
assert record["competence_id"] == "key_win_r_wait_explorer_exe"
|
|
assert record["verdict_kind"] == "valid"
|
|
assert record["write_back_enabled"] is False
|
|
assert record["yaml_write"] is False
|
|
assert record["duplicate"] is False
|
|
assert record["workflow_id"] == "preview_competence_key_win_r_wait_explorer_exe"
|
|
assert record["step_results"] == [
|
|
{
|
|
"step_id": "step_1_key_combo",
|
|
"action_type": "keyboard_shortcut",
|
|
"status": "success",
|
|
}
|
|
]
|
|
assert record["context_signature"]["machine_id"] == "DESKTOP-58D5CAC_windows"
|
|
|
|
records = iter_competence_verdicts(log_path=log_path)
|
|
assert len(records) == 1
|
|
assert records[0]["verdict_id"] == VERDICT_ID
|
|
|
|
|
|
def test_store_competence_verdict_is_idempotent(tmp_path):
|
|
log_path = tmp_path / "verdicts.jsonl"
|
|
|
|
first = store_competence_verdict(
|
|
"key_win_r_wait_explorer_exe",
|
|
_payload(),
|
|
log_path=log_path,
|
|
)
|
|
second = store_competence_verdict(
|
|
"key_win_r_wait_explorer_exe",
|
|
_payload(comments="second click"),
|
|
log_path=log_path,
|
|
)
|
|
|
|
assert first["duplicate"] is False
|
|
assert second["duplicate"] is True
|
|
assert len(log_path.read_text(encoding="utf-8").splitlines()) == 1
|
|
assert second["comments"] == "Supervised replay ok"
|
|
|
|
|
|
def test_store_competence_verdict_rejects_same_id_for_other_competence(tmp_path):
|
|
log_path = tmp_path / "verdicts.jsonl"
|
|
|
|
store_competence_verdict(
|
|
"key_win_r_wait_explorer_exe",
|
|
_payload(),
|
|
log_path=log_path,
|
|
)
|
|
|
|
with pytest.raises(CompetenceVerdictError, match="deja utilise"):
|
|
store_competence_verdict(
|
|
"key_ctrl_s_wait_notepad_exe",
|
|
_payload(),
|
|
log_path=log_path,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("kind", ["valid", "invalid", "inconclusive"])
|
|
def test_store_competence_verdict_accepts_three_kinds(tmp_path, kind):
|
|
record = store_competence_verdict(
|
|
"key_win_r_wait_explorer_exe",
|
|
_payload(
|
|
verdict_id={
|
|
"valid": "123e4567-e89b-42d3-a456-426614174000",
|
|
"invalid": "123e4567-e89b-42d3-a456-426614174001",
|
|
"inconclusive": "123e4567-e89b-42d3-a456-426614174002",
|
|
}[kind],
|
|
verdict_kind=kind,
|
|
),
|
|
log_path=tmp_path / "verdicts.jsonl",
|
|
)
|
|
|
|
assert record["verdict_kind"] == kind
|
|
|
|
|
|
def test_store_competence_verdict_requires_context_machine(tmp_path):
|
|
with pytest.raises(CompetenceVerdictError, match="machine_id"):
|
|
store_competence_verdict(
|
|
"key_win_r_wait_explorer_exe",
|
|
_payload(context_signature={}),
|
|
log_path=tmp_path / "verdicts.jsonl",
|
|
)
|
|
|
|
|
|
def test_store_competence_verdict_rejects_yaml_write_attempt(tmp_path):
|
|
record = store_competence_verdict(
|
|
"key_win_r_wait_explorer_exe",
|
|
_payload(write_back_enabled=True, yaml_write=True),
|
|
log_path=tmp_path / "verdicts.jsonl",
|
|
)
|
|
|
|
assert record["write_back_enabled"] is False
|
|
assert record["yaml_write"] is False
|
|
|
|
|
|
def test_store_competence_verdict_requires_step_results_list(tmp_path):
|
|
with pytest.raises(CompetenceVerdictError, match="step_results"):
|
|
store_competence_verdict(
|
|
"key_win_r_wait_explorer_exe",
|
|
_payload(step_results={"step_id": "not_a_list"}),
|
|
log_path=tmp_path / "verdicts.jsonl",
|
|
)
|