@@ -529,6 +529,53 @@ def _persist_session_with_pending_verification(temp_dir: Path) -> str: |
| 529 | 529 | return snapshot.session_id |
| 530 | 530 | |
| 531 | 531 | |
| 532 | +def _persist_session_with_stale_verification(temp_dir: Path) -> str: |
| 533 | + snapshot = SessionSnapshot( |
| 534 | + session_id="20260406T160700Z-stale1234", |
| 535 | + created_at="2026-04-06T16:07:00Z", |
| 536 | + updated_at="2026-04-06T16:07:30Z", |
| 537 | + messages=[ |
| 538 | + Message(role=Role.USER, content="Keep working on the runtime"), |
| 539 | + Message(role=Role.ASSISTANT, content="Fresh verification is required again."), |
| 540 | + ], |
| 541 | + current_task="Keep working on the runtime", |
| 542 | + runtime_owner_type="RuntimeHandle", |
| 543 | + runtime_owner_path="runtime-handle", |
| 544 | + workflow_mode="execute", |
| 545 | + permission_mode="workspace-write", |
| 546 | + prompt_format="native", |
| 547 | + prompt_sections=["Runtime Config", "Workflow Context", "Mode Guidance"], |
| 548 | + workflow_timeline=[ |
| 549 | + WorkflowTimelineEntry( |
| 550 | + timestamp="2026-04-06T16:07:30Z", |
| 551 | + kind="verify_observation", |
| 552 | + mode="execute", |
| 553 | + reason_code="verification_stale", |
| 554 | + summary="verify: previous verification became stale after new mutating work", |
| 555 | + decision_kind="forced", |
| 556 | + policy_stage="verification", |
| 557 | + policy_outcome="stale", |
| 558 | + verification_observations=[ |
| 559 | + VerificationObservation( |
| 560 | + status="stale", |
| 561 | + summary=( |
| 562 | + "verification became stale for `uv run pytest -q` " |
| 563 | + "after new mutating work" |
| 564 | + ), |
| 565 | + command="uv run pytest -q", |
| 566 | + kind="runtime", |
| 567 | + detail="write changed src/loader/runtime/finalization.py", |
| 568 | + ) |
| 569 | + ], |
| 570 | + prompt_format="native", |
| 571 | + prompt_sections=["Runtime Config", "Workflow Context", "Mode Guidance"], |
| 572 | + ) |
| 573 | + ], |
| 574 | + ) |
| 575 | + SessionStore(temp_dir).save(snapshot) |
| 576 | + return snapshot.session_id |
| 577 | + |
| 578 | + |
| 532 | 579 | @pytest.mark.asyncio |
| 533 | 580 | async def test_collect_doctor_report_passes_for_healthy_workspace(temp_dir: Path) -> None: |
| 534 | 581 | _write_python_workspace(temp_dir) |
@@ -842,6 +889,30 @@ def test_collect_status_snapshot_surfaces_pending_verification( |
| 842 | 889 | ] |
| 843 | 890 | |
| 844 | 891 | |
| 892 | +def test_collect_status_snapshot_surfaces_stale_verification( |
| 893 | + temp_dir: Path, |
| 894 | +) -> None: |
| 895 | + _write_python_workspace(temp_dir) |
| 896 | + _ensure_loader_dirs(temp_dir) |
| 897 | + _persist_session_with_stale_verification(temp_dir) |
| 898 | + |
| 899 | + snapshot = collect_status_snapshot(temp_dir) |
| 900 | + |
| 901 | + assert snapshot.latest_policy_summary is not None |
| 902 | + assert "verification_stale" in snapshot.latest_policy_summary |
| 903 | + assert "policy-outcome=stale" in snapshot.latest_policy_summary |
| 904 | + assert snapshot.latest_policy_observed_verification == [ |
| 905 | + "verification became stale for `uv run pytest -q` after new mutating work [write changed src/loader/runtime/finalization.py]" |
| 906 | + ] |
| 907 | + assert [item.status for item in snapshot.recent_verification] == ["stale"] |
| 908 | + assert [item.command for item in snapshot.recent_verification] == [ |
| 909 | + "uv run pytest -q" |
| 910 | + ] |
| 911 | + assert [item.detail for item in snapshot.recent_verification] == [ |
| 912 | + "write changed src/loader/runtime/finalization.py" |
| 913 | + ] |
| 914 | + |
| 915 | + |
| 845 | 916 | def test_collect_prompt_diff_uses_persisted_prompt_history(temp_dir: Path) -> None: |
| 846 | 917 | _write_python_workspace(temp_dir) |
| 847 | 918 | _ensure_loader_dirs(temp_dir) |
@@ -1000,6 +1071,29 @@ def test_workflow_command_renders_policy_accountability_context( |
| 1000 | 1071 | assert "handoff" not in policy_result.output |
| 1001 | 1072 | |
| 1002 | 1073 | |
| 1074 | +def test_workflow_command_renders_stale_verification_context( |
| 1075 | + temp_dir: Path, |
| 1076 | + monkeypatch: pytest.MonkeyPatch, |
| 1077 | +) -> None: |
| 1078 | + _write_python_workspace(temp_dir) |
| 1079 | + _ensure_loader_dirs(temp_dir) |
| 1080 | + session_id = _persist_session_with_stale_verification(temp_dir) |
| 1081 | + runner = CliRunner() |
| 1082 | + |
| 1083 | + monkeypatch.chdir(temp_dir) |
| 1084 | + |
| 1085 | + result = runner.invoke(cli_main_module.workflow_cli, ["show"]) |
| 1086 | + |
| 1087 | + assert result.exit_code == 0 |
| 1088 | + assert session_id in result.output |
| 1089 | + assert "Verify stale:" in result.output |
| 1090 | + assert "verification_stale" in result.output |
| 1091 | + assert "policy-outcome=stale" in result.output |
| 1092 | + assert "Observed Verification" in result.output |
| 1093 | + assert "uv run pytest -q" in result.output |
| 1094 | + assert "new mutating work" in result.output |
| 1095 | + |
| 1096 | + |
| 1003 | 1097 | def test_collect_workflow_timeline_can_focus_on_policy_accountability( |
| 1004 | 1098 | temp_dir: Path, |
| 1005 | 1099 | ) -> None: |