Python · 4111 bytes Raw Blame History
1 """Tests for typed verification observations on policy timelines and traces."""
2
3 from __future__ import annotations
4
5 from loader.runtime.completion_trace import (
6 CompletionTraceEntry,
7 completion_trace_from_workflow_timeline,
8 )
9 from loader.runtime.verification_observations import (
10 VerificationObservation,
11 VerificationObservationStatus,
12 normalize_verification_observations,
13 )
14 from loader.runtime.workflow_policy import (
15 WorkflowTimelineEntry,
16 WorkflowTimelineEntryKind,
17 )
18
19
20 def test_normalize_verification_observations_round_trips_entries() -> None:
21 entries = normalize_verification_observations(
22 [
23 {
24 "status": "PASSED",
25 "summary": "verification passed for `uv run pytest -q`",
26 "command": "uv run pytest -q",
27 "kind": "test",
28 "exit_code": 0,
29 "detail": "219 passed",
30 "attempt_id": "verification-attempt-3",
31 "attempt_number": 3,
32 "supersedes_attempt_id": "verification-attempt-2",
33 }
34 ]
35 )
36
37 assert entries == [
38 VerificationObservation(
39 status=VerificationObservationStatus.PASSED.value,
40 summary="verification passed for `uv run pytest -q`",
41 command="uv run pytest -q",
42 kind="test",
43 exit_code=0,
44 detail="219 passed",
45 attempt_id="verification-attempt-3",
46 attempt_number=3,
47 supersedes_attempt_id="verification-attempt-2",
48 )
49 ]
50
51
52 def test_workflow_timeline_entry_derives_evidence_summary_from_verification_observations() -> None:
53 entry = WorkflowTimelineEntry.accountability(
54 kind=WorkflowTimelineEntryKind.VERIFY_SKIP,
55 mode="execute",
56 reason_code="verification_not_required",
57 summary="verification skipped because the turn made no mutating changes",
58 verification_observations=[
59 VerificationObservation(
60 status=VerificationObservationStatus.SKIPPED.value,
61 summary="verification was skipped because no mutating work required checks",
62 )
63 ],
64 )
65
66 assert entry.evidence_summary == [
67 "verification was skipped because no mutating work required checks"
68 ]
69
70
71 def test_completion_trace_projection_preserves_verification_observations() -> None:
72 timeline = [
73 WorkflowTimelineEntry.accountability(
74 kind=WorkflowTimelineEntryKind.COMPLETION_COMPLETE,
75 mode="execute",
76 reason_code="verification_passed",
77 summary="completion: accepted the response after verification evidence passed",
78 policy_stage="definition_of_done",
79 policy_outcome="complete",
80 verification_observations=[
81 VerificationObservation(
82 status=VerificationObservationStatus.PASSED.value,
83 summary="verification passed for `uv run pytest -q`",
84 command="uv run pytest -q",
85 kind="test",
86 exit_code=0,
87 detail="219 passed",
88 )
89 ],
90 )
91 ]
92
93 trace = completion_trace_from_workflow_timeline(
94 timeline,
95 last_decision_code="verification_passed",
96 )
97
98 assert trace == [
99 CompletionTraceEntry(
100 stage="definition_of_done",
101 outcome="complete",
102 decision_code="verification_passed",
103 decision_summary="accepted the response after verification evidence passed",
104 evidence_summary=["verification passed for `uv run pytest -q`"],
105 verification_observations=[
106 VerificationObservation(
107 status=VerificationObservationStatus.PASSED.value,
108 summary="verification passed for `uv run pytest -q`",
109 command="uv run pytest -q",
110 kind="test",
111 exit_code=0,
112 detail="219 passed",
113 )
114 ],
115 )
116 ]