Three scenarios join the contract set, so the fifteen vectors now cover an unproven side effect, an undecidable attribution, and an agent whose state goes unreadable in the window between finalization and notification. All fifteen match their expected decision. The side-effect case needed a decision about layering. Authoritative enforcement belongs in manifest verification, which has the job record and therefore knows what was declared; the policy honours an explicit negative from the collector so the case is expressible as a vector. Absence is not read as proof there, because the manifest check is the layer that fails closed on missing evidence. The operations note records why the agent declares and the reader re-derives, the three gates and why the backend allowlist can only be narrowed, the notification transaction, and the rollback. It also records a deviation from my own plan. §D2 asked for reviewer sign-off before promoting an attempt id into the record, since that changes a contract phase 1 froze. Measurement during implementation showed the change was not needed: the attempt guard already lives in the evidence layer, where attempt identity actually is, so auto-completion passes the engine a status precondition instead. The schema is untouched, the frozen contract holds, and a characterization test fails the moment a record starts carrying an attempt id, which is when to revisit it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrDNJkHmm18uu7n7JwV5Qd
97 lines
4.2 KiB
JSON
97 lines
4.2 KiB
JSON
{
|
|
"schema_version": "1.0.0",
|
|
"description": "Multi-channel Watcher composite timeline scenario manifest",
|
|
"scenarios": {
|
|
"initial_idle": {
|
|
"file": "initial_idle.json",
|
|
"provenance": "simulated",
|
|
"expected_decision": "hold",
|
|
"description": "Dispatch record exists and native status is idle, but no execution anchor observed since dispatch_ack. Inferred completion must be held."
|
|
},
|
|
"tool_running": {
|
|
"file": "tool_running.json",
|
|
"provenance": "simulated",
|
|
"expected_decision": "hold",
|
|
"description": "Native status working or interactive_ready with active background tool execution. Inferred completion must be held."
|
|
},
|
|
"report_pause_15s": {
|
|
"file": "report_pause_15s.json",
|
|
"provenance": "simulated",
|
|
"expected_decision": "hold",
|
|
"description": "Partial report written and stable for >= 15s debounce, but lacks atomic finalization manifest. Completion must be held."
|
|
},
|
|
"finalized_candidate": {
|
|
"file": "finalized_candidate.json",
|
|
"provenance": "simulated",
|
|
"expected_decision": "candidate_approved",
|
|
"description": "Execution anchor verified, native status idle/done, atomic rename complete with valid SHA-256 commit manifest. Inferred candidate approved for CAS."
|
|
},
|
|
"blocked_permission": {
|
|
"file": "blocked_permission.json",
|
|
"provenance": "simulated",
|
|
"expected_decision": "hold_blocked",
|
|
"description": "Native status blocked on interactive permission prompt. Completion forbidden."
|
|
},
|
|
"transport_disconnected": {
|
|
"file": "transport_disconnected.json",
|
|
"provenance": "simulated",
|
|
"expected_decision": "hold_reconnect",
|
|
"description": "Herdr socket connection failure or freshness gap. Cached evidence invalidated; must reconnect and resnapshot."
|
|
},
|
|
"restarted_generation": {
|
|
"file": "restarted_generation.json",
|
|
"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."
|
|
},
|
|
"side_effect_unproven": {
|
|
"file": "side_effect_unproven.json",
|
|
"provenance": "simulated",
|
|
"expected_decision": "hold",
|
|
"description": "The job declared an external side effect but the manifest carries no evidence for it. Partial evidence is no evidence."
|
|
},
|
|
"no_verdict_fail_closed": {
|
|
"file": "no_verdict_fail_closed.json",
|
|
"provenance": "simulated",
|
|
"expected_decision": "hold",
|
|
"description": "The collector could not establish the agent session, so attribution cannot be completed. An undecidable case must hold."
|
|
},
|
|
"notification_crash_window": {
|
|
"file": "notification_crash_window.json",
|
|
"provenance": "simulated",
|
|
"expected_decision": "hold",
|
|
"description": "The agent's state became unreadable between finalization and notification. Unknown is not quiescent."
|
|
}
|
|
}
|
|
}
|