tenseleyflow/loader / bc68deb

Browse files

Emit pending verification observations

Authored by espadonne
SHA
bc68deb6de7183684ed7fc98afda5a7030419382
Parents
3e1343f
Tree
2a1aa0b

3 changed files

StatusFile+-
M src/loader/runtime/finalization.py 47 0
M src/loader/runtime/verification_observations.py 1 0
M tests/test_finalization.py 10 0
src/loader/runtime/finalization.pymodified
@@ -220,6 +220,21 @@ class TurnFinalizer:
220220
             emit=emit,
221221
             summary=summary,
222222
         )
223
+        if dod.verification_commands:
224
+            append_verification_timeline_entry(
225
+                self.context,
226
+                summary,
227
+                reason_code="verification_pending",
228
+                reason_summary=(
229
+                    "verification is pending for the active command set"
230
+                ),
231
+                evidence_summary=[
232
+                    f"verification command pending: {command}"
233
+                    for command in dod.verification_commands[:2]
234
+                ],
235
+                evidence_provenance=_pending_verification_provenance(dod),
236
+                verification_observations=_pending_verification_observations(dod),
237
+            )
223238
         verification_passed = await self.verify_definition_of_done(
224239
             dod=dod,
225240
             emit=emit,
@@ -705,6 +720,38 @@ def _missing_verification_provenance() -> list[EvidenceProvenance]:
705720
     ]
706721
 
707722
 
723
+def _pending_verification_observations(
724
+    dod: DefinitionOfDone,
725
+) -> list[VerificationObservation]:
726
+    observations: list[VerificationObservation] = []
727
+    for command in dod.verification_commands:
728
+        observations.append(
729
+            VerificationObservation(
730
+                status=VerificationObservationStatus.PENDING.value,
731
+                summary=f"verification pending for `{command}`",
732
+                command=command,
733
+            )
734
+        )
735
+    return observations
736
+
737
+
738
+def _pending_verification_provenance(
739
+    dod: DefinitionOfDone,
740
+) -> list[EvidenceProvenance]:
741
+    provenance: list[EvidenceProvenance] = []
742
+    for command in dod.verification_commands:
743
+        provenance.append(
744
+            EvidenceProvenance(
745
+                category="verification",
746
+                source="dod.verification_commands",
747
+                summary=f"verification command pending: {command}",
748
+                status=EvidenceProvenanceStatus.MISSING.value,
749
+                subject=command,
750
+            )
751
+        )
752
+    return provenance
753
+
754
+
708755
 def _verification_detail(evidence: VerificationEvidence) -> str | None:
709756
     for candidate in (evidence.stdout, evidence.stderr, evidence.output):
710757
         text = str(candidate).strip()
src/loader/runtime/verification_observations.pymodified
@@ -10,6 +10,7 @@ from typing import Any
1010
 class VerificationObservationStatus(StrEnum):
1111
     """How one verification observation resolved at runtime."""
1212
 
13
+    PENDING = "pending"
1314
     PASSED = "passed"
1415
     FAILED = "failed"
1516
     SKIPPED = "skipped"
tests/test_finalization.pymodified
@@ -339,6 +339,16 @@ async def test_turn_finalizer_records_passed_verification_observation(
339339
     assert result.verification_observations[0].command == "uv run pytest -q"
340340
     assert result.verification_observations[0].detail == "219 passed"
341341
     assert summary.verification_status == "passed"
342
+    assert [entry.reason_code for entry in session.workflow_timeline[-2:]] == [
343
+        "verification_pending",
344
+        "verification_command_passed",
345
+    ]
346
+    assert [item.status for item in session.workflow_timeline[-2].verification_observations] == [
347
+        VerificationObservationStatus.PENDING.value
348
+    ]
349
+    assert session.workflow_timeline[-2].verification_observations[0].command == (
350
+        "uv run pytest -q"
351
+    )
342352
     assert session.workflow_timeline[-1].kind == "verify_observation"
343353
     assert session.workflow_timeline[-1].reason_code == "verification_command_passed"
344354
     assert [item.status for item in session.workflow_timeline[-1].verification_observations] == [