feat(issue-5): shadow watcher that logs would-complete and cannot write

policy.decide is a pure function so the phase-0 scenario fixtures can be fed to
it verbatim. Those seven decisions survived three-reviewer scrutiny, so they are
the contract rather than a fresh set of rules, and the test asserts against
expected_policy.decision directly.

Order inside the policy matters. Transport doubt and staleness invalidate the
evidence itself, so they are answered before anything is inferred from it; a
blocked agent is waiting for a human and can never be completed; attribution
including the execution anchor comes before quiescence, because idle is not
evidence of finishing when a session is reused; and a report must be finalized,
never merely paused, since a debounce is a candidate filter and not an authority.

The shadow runner is never handed the engine, so it has no route to a write.
That is the structural half of P2A-03. The measured half hashes every file under
the registry directory around a full run and asserts it is unchanged, which is a
stronger claim than checking a status field.

Adds the five scenarios P2A-04 requires: a raced double dispatch, a reused
attempt with no anchor, a mid-write report, an unknown status, and a pane
restarted mid-flight. They pass phase 0's own fixture validator, which is what
keeps them honest. The phase-0 test that pinned exactly seven scenarios now
requires the seven to still exist rather than forbidding growth.

Also pins the two phase 1 handoffs as dormant: nothing here spawns a daemon, so
preexec_fn stays unreachable, and nothing calls a frozen shell helper.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UrDNJkHmm18uu7n7JwV5Qd
This commit is contained in:
GodopuandClaude Opus 5 committed 2026-09-06 18:56:35 +09:00
1 parent b49af56c3c
commit 964abc6965
10 files changed
+639 -1

No files matched your search

+61
View File
@@ -0,0 +1,61 @@
{
"schema_version": "1.0.0",
"scenario_id": "attempt_reuse",
"backend": "backend_agnostic",
"provenance": "simulated",
"description": "The same session was reused for a new attempt whose execution was never observed. Idle here is leftover quiescence from the prior attempt.",
"dispatch_context": {
"job_id": "test-job-attempt-reuse-01",
"attempt_id": 2,
"agent_session_uuid": "7d5700d0-bab1-4f65-9665-6b887396a9a6",
"pane_process_generation": "w2X:p1:1234:2026-09-06T00:00:00Z",
"dispatch_ack": true,
"execution_anchor_observed": false
},
"timeline": [
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 0,
"source_kind": "event",
"source_provenance": "simulated",
"payload": {
"event": "started",
"job_id": "test-job-finalized-01"
}
},
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 5000,
"source_kind": "filesystem",
"source_provenance": "simulated",
"payload": {
"report_manifest": {
"report_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"attempt_id": 1,
"finalized": true
}
}
},
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 6000,
"source_kind": "herdr",
"source_provenance": "simulated",
"payload": {
"agent_status": "idle",
"interactive_ready": true
}
}
],
"filesystem": {
"report_path": ".mam/jobs/test-job-finalized-01/report-final.md",
"exists": true,
"manifest_committed": true,
"hash_verified": true
},
"expected_policy": {
"decision": "hold",
"reason": "no execution anchor observed for the current attempt",
"policy_version": "2.0.0"
}
}
+30
View File
@@ -43,6 +43,36 @@
"provenance": "simulated",
"expected_decision": "reject_stale",
"description": "Pane process restarted with new PID/start time; stale attempt rejected."
},
"race_double_dispatch": {
"file": "race_double_dispatch.json",
"provenance": "simulated",
"expected_decision": "reject_stale",
"description": "Two dispatches raced; the observed signal carries the previous process generation. The stale attempt must not decide anything."
},
"attempt_reuse": {
"file": "attempt_reuse.json",
"provenance": "simulated",
"expected_decision": "hold",
"description": "The same session was reused for a new attempt whose execution was never observed. Idle here is leftover quiescence from the prior attempt."
},
"partial_report": {
"file": "partial_report.json",
"provenance": "simulated",
"expected_decision": "hold",
"description": "A report is mid-write: bytes on disk but no atomic rename and no commit manifest."
},
"unknown_status": {
"file": "unknown_status.json",
"provenance": "simulated",
"expected_decision": "hold",
"description": "Native status is unknown. An unreadable state is not a quiescent one."
},
"restart_midflight": {
"file": "restart_midflight.json",
"provenance": "simulated",
"expected_decision": "reject_stale",
"description": "The pane was restarted mid-flight, so the idle signal comes from a different pane than the one dispatched to."
}
}
}
+59
View File
@@ -0,0 +1,59 @@
{
"schema_version": "1.0.0",
"scenario_id": "partial_report",
"backend": "backend_agnostic",
"provenance": "simulated",
"description": "A report is mid-write: bytes on disk but no atomic rename and no commit manifest.",
"dispatch_context": {
"job_id": "test-job-partial-report-01",
"attempt_id": 1,
"agent_session_uuid": "7d5700d0-bab1-4f65-9665-6b887396a9a6",
"pane_process_generation": "w2X:p1:1234:2026-09-06T00:00:00Z",
"dispatch_ack": true,
"execution_anchor_observed": true
},
"timeline": [
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 0,
"source_kind": "event",
"source_provenance": "simulated",
"payload": {
"event": "started",
"job_id": "test-job-finalized-01"
}
},
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 5000,
"source_kind": "filesystem",
"source_provenance": "simulated",
"payload": {
"report_manifest": null,
"bytes": 512,
"phase": "writing"
}
},
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 6000,
"source_kind": "herdr",
"source_provenance": "simulated",
"payload": {
"agent_status": "idle",
"interactive_ready": true
}
}
],
"filesystem": {
"report_path": ".mam/jobs/test-job-finalized-01/report-final.md",
"exists": true,
"manifest_committed": false,
"hash_verified": false
},
"expected_policy": {
"decision": "hold",
"reason": "report is still being written; no finalization manifest",
"policy_version": "2.0.0"
}
}
@@ -0,0 +1,62 @@
{
"schema_version": "1.0.0",
"scenario_id": "race_double_dispatch",
"backend": "backend_agnostic",
"provenance": "simulated",
"description": "Two dispatches raced; the observed signal carries the previous process generation. The stale attempt must not decide anything.",
"dispatch_context": {
"job_id": "test-job-race-01",
"attempt_id": 2,
"agent_session_uuid": "7d5700d0-bab1-4f65-9665-6b887396a9a6",
"pane_process_generation": "w2X:p1:1234:2026-09-06T00:00:00Z",
"dispatch_ack": true,
"execution_anchor_observed": true
},
"timeline": [
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 0,
"source_kind": "event",
"source_provenance": "simulated",
"payload": {
"event": "started",
"job_id": "test-job-finalized-01"
}
},
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 5000,
"source_kind": "filesystem",
"source_provenance": "simulated",
"payload": {
"report_manifest": {
"report_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"attempt_id": 1,
"finalized": true
}
}
},
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 6000,
"source_kind": "herdr",
"source_provenance": "simulated",
"payload": {
"agent_status": "idle",
"interactive_ready": true,
"pane_process_generation": "w2X:p9:9999:2026-09-06T00:00:00Z"
}
}
],
"filesystem": {
"report_path": ".mam/jobs/test-job-finalized-01/report-final.md",
"exists": true,
"manifest_committed": true,
"hash_verified": true
},
"expected_policy": {
"decision": "reject_stale",
"reason": "signal belongs to a superseded process generation",
"policy_version": "2.0.0"
}
}
+61
View File
@@ -0,0 +1,61 @@
{
"schema_version": "1.0.0",
"scenario_id": "restart_midflight",
"backend": "backend_agnostic",
"provenance": "simulated",
"description": "The pane was restarted mid-flight, so the idle signal comes from a different pane than the one dispatched to.",
"dispatch_context": {
"job_id": "test-job-restart-midflight-01",
"attempt_id": 1,
"agent_session_uuid": "7d5700d0-bab1-4f65-9665-6b887396a9a6",
"pane_process_generation": "w2X:p1:1234:2026-09-06T00:00:00Z",
"dispatch_ack": true,
"execution_anchor_observed": true
},
"timeline": [
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 0,
"source_kind": "event",
"source_provenance": "simulated",
"payload": {
"event": "started",
"job_id": "test-job-finalized-01"
}
},
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 5000,
"source_kind": "filesystem",
"source_provenance": "simulated",
"payload": {
"report_manifest": {
"report_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"attempt_id": 1,
"finalized": true
}
}
},
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 6000,
"source_kind": "herdr",
"source_provenance": "simulated",
"payload": {
"agent_status": "idle",
"pane_id": "w2X:p7"
}
}
],
"filesystem": {
"report_path": ".mam/jobs/test-job-finalized-01/report-final.md",
"exists": true,
"manifest_committed": true,
"hash_verified": true
},
"expected_policy": {
"decision": "reject_stale",
"reason": "signal belongs to a different pane",
"policy_version": "2.0.0"
}
}
+61
View File
@@ -0,0 +1,61 @@
{
"schema_version": "1.0.0",
"scenario_id": "unknown_status",
"backend": "backend_agnostic",
"provenance": "simulated",
"description": "Native status is unknown. An unreadable state is not a quiescent one.",
"dispatch_context": {
"job_id": "test-job-unknown-01",
"attempt_id": 1,
"agent_session_uuid": "7d5700d0-bab1-4f65-9665-6b887396a9a6",
"pane_process_generation": "w2X:p1:1234:2026-09-06T00:00:00Z",
"dispatch_ack": true,
"execution_anchor_observed": true
},
"timeline": [
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 0,
"source_kind": "event",
"source_provenance": "simulated",
"payload": {
"event": "started",
"job_id": "test-job-finalized-01"
}
},
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 5000,
"source_kind": "filesystem",
"source_provenance": "simulated",
"payload": {
"report_manifest": {
"report_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"attempt_id": 1,
"finalized": true
}
}
},
{
"collector_clock_id": "CLOCK_MONOTONIC",
"relative_ms": 6000,
"source_kind": "herdr",
"source_provenance": "simulated",
"payload": {
"agent_status": "unknown",
"interactive_ready": false
}
}
],
"filesystem": {
"report_path": ".mam/jobs/test-job-finalized-01/report-final.md",
"exists": true,
"manifest_committed": true,
"hash_verified": true
},
"expected_policy": {
"decision": "hold",
"reason": "agent status is unknown; fail closed",
"policy_version": "2.0.0"
}
}