Emit pending verification observations
- SHA
bc68deb6de7183684ed7fc98afda5a7030419382- Parents
-
3e1343f - Tree
2a1aa0b
bc68deb
bc68deb6de7183684ed7fc98afda5a70304193823e1343f
2a1aa0b| Status | File | + | - |
|---|---|---|---|
| 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: | ||
| 220 | 220 | emit=emit, |
| 221 | 221 | summary=summary, |
| 222 | 222 | ) |
| 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 | + ) | |
| 223 | 238 | verification_passed = await self.verify_definition_of_done( |
| 224 | 239 | dod=dod, |
| 225 | 240 | emit=emit, |
@@ -705,6 +720,38 @@ def _missing_verification_provenance() -> list[EvidenceProvenance]: | ||
| 705 | 720 | ] |
| 706 | 721 | |
| 707 | 722 | |
| 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 | + | |
| 708 | 755 | def _verification_detail(evidence: VerificationEvidence) -> str | None: |
| 709 | 756 | for candidate in (evidence.stdout, evidence.stderr, evidence.output): |
| 710 | 757 | text = str(candidate).strip() |
src/loader/runtime/verification_observations.pymodified@@ -10,6 +10,7 @@ from typing import Any | ||
| 10 | 10 | class VerificationObservationStatus(StrEnum): |
| 11 | 11 | """How one verification observation resolved at runtime.""" |
| 12 | 12 | |
| 13 | + PENDING = "pending" | |
| 13 | 14 | PASSED = "passed" |
| 14 | 15 | FAILED = "failed" |
| 15 | 16 | SKIPPED = "skipped" |
tests/test_finalization.pymodified@@ -339,6 +339,16 @@ async def test_turn_finalizer_records_passed_verification_observation( | ||
| 339 | 339 | assert result.verification_observations[0].command == "uv run pytest -q" |
| 340 | 340 | assert result.verification_observations[0].detail == "219 passed" |
| 341 | 341 | 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 | + ) | |
| 342 | 352 | assert session.workflow_timeline[-1].kind == "verify_observation" |
| 343 | 353 | assert session.workflow_timeline[-1].reason_code == "verification_command_passed" |
| 344 | 354 | assert [item.status for item in session.workflow_timeline[-1].verification_observations] == [ |