diff --git a/.agents/pm/features/pm-rust-crash-harness.toon b/.agents/pm/features/pm-rust-crash-harness.toon index fa5fc9a..8a048df 100644 --- a/.agents/pm/features/pm-rust-crash-harness.toon +++ b/.agents/pm/features/pm-rust-crash-harness.toon @@ -6,10 +6,11 @@ status: open priority: 2 tags[3]: conformance,crash-consistency,harness created_at: "2026-10-21T21:59:35.474Z" -updated_at: "2026-10-24T21:48:10.764Z" +updated_at: "2026-10-25T07:26:31.736Z" author: codex-agent acceptance_criteria: Every declared crash boundary preserves acknowledged writes; failures retain minimized synthetic reproductions and never rewrite original history.; Typed SDK and CLI with bounded TOON/JSON receipts and actionable refusals; documented example; public tracker read-copy validation with measured counts; exact-head CI release-check passes. -comments[15]{created_at,author,text}: +unblock_note: Native cross-operation recovery is integrated from main and both live permanent replays pass with zero pending journals and successful return operations. +comments[40]{created_at,author,text}: "2026-10-21T21:59:37.843Z",codex-agent,"Overlap recheck: published CLI 2026.10.21 matches the locked oracle. Native tests cover normal command differentials and manually reconstructed durable journals; they do not run a reusable live kill/restart corpus. pm-ops assurance reports measurements; pm-vcs writer publication is backend-specific. This feature adds cross-implementation crash evidence beyond lock/parity work. Reconciliation PR 103 closures and performance PR 102 items are excluded. TypeScript-only SDK/command; synthetic failures; targeted local checks; full gate in CI." "2026-10-21T22:16:09.535Z",codex-agent,"Implemented the typed TypeScript SDK and standalone just crash CLI. Declared boundaries are all observed rename/fsync task-local ordinals: event-loop write calls were rejected as unstable storage boundaries after real tracing. Two mutation families run on disposable non-git clones; same-family restart checks exact durable bytes and raw per-runtime restart receipts, with explicit shared cross-runtime acknowledgement projections. Synthetic probing measured 20 real kills, 20 preserved acknowledged writes/history prefixes, two successful baseline byte/acknowledgement comparisons and two early native lock-initialization restart refusals. Those refusals are retained as minimal one-item synthetic cases; no original stream is repaired. Full runtime crash conformance is not claimed. Adding independent replay/no-git regressions and public-copy measurements before CI." "2026-10-21T22:19:48.804Z",codex-agent,"Read-only public-copy validation: public main c0154dbd7cd8071ac52b891be13f956f7a0f21fd, 74 items and 154 authoritative files in a non-git copy with read-only permissions. Measured 20 injected kills, 20 acknowledged-write preservations, 20 exact retained-history prefixes, two cross-runtime baseline byte/acknowledgement matches, 18 successful restart state/receipt checks, two independently reproduced native incomplete-lock restart refusals. Source fingerprint unchanged. Retained evidence is synthetic only. Follow-up pm-rust-crash-lock-restart covers the safe recovery policy, outside this harness change. Behavioral controls disabling history-prefix checking, exact inventory comparison and injected-kill admission each fail their targeted regression with exit 1 and pass after exact byte restoration." @@ -25,7 +26,32 @@ comments[15]{created_at,author,text}: "2026-10-22T16:41:17.977Z",codex-agent,"Self-review of the whole PR confirms the only overstatements were the retained-case guide and public replay docstring; README, CLI help, manifest validation and the single-boundary selection type do not claim that every replay selects one case. Original histories, stored commands and implementation behavior remain untouched. Releasing the implementation claim with status retained in_progress. Final exact-head unchanged just release-check CI receipts and counts will be recorded in PR https://github.com/unbraind/pm-rust/pull/104; pending CI is not approval. The original stacked-PR instruction still requires merging this completed update and main into PR 105 after PR 104 has passed and been pushed. No review replies/resolutions, PR merge or release." "2026-10-22T16:47:29.332Z",codex-agent,"Additional self-review caught an LF-only assumption in the new guide regression. The matcher now accepts both LF and CRLF and exercises both spellings using the real guide contents. Reverting only the optional carriage-return matcher makes the CRLF assertion fail; restoring it passes both guidance tests 2/2. Strict TypeScript and ESLint pass. No documentation, runtime function, input fixture or gate threshold changed in this follow-up. Superseded pending CI at 84ddc56 is not used as approval; the corrected final head needs fresh full release CI." "2026-10-24T21:48:10.764Z",codex-agent,"Returned to open in the 2026-10-24 sweep: Open PR https://github.com/unbraind/pm-rust/pull/104 carries the reusable kill-corpus harness; merged PR 105 fixes lock recovery but is not complete harness delivery. Review and full harness acceptance remain pending, with no active agent established." -files[5]: + "2026-10-25T02:26:08.451Z",codex-agent,"Orchestrator correction: restored this item and its history exactly from main before writing. Main records remain untouched. Branch-only intended evidence is now re-recorded through the pinned CLI as new events, not copied or spliced. The prior archive-based resolution was rejected and is superseded by this linear main-chain extension. Runtime implementation and previously completed crash acceptance remain unchanged; adding a PR-wide byte-prefix regression and fresh health/CI evidence." + "2026-10-25T02:26:24.823Z",codex-agent,"Historical branch evidence from 2026-10-23T06:38:11.820Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Orchestrator review follow-up on PR 104: remote f555a42 was current; merged main c46ad00 and preserved both benchmark and crash recipes in two overlap resolutions. Reusing this item, without redoing completed refusal/doc fixes. Will capture runtime journals, add cross-operation restart plus a return-to-original-operation probe, inject published history-open failures, compare recovered runtime outcomes, disclose clock semantics, keep replay unconditional, preserve measured failure when synthetic reduction refuses, and record reproducible source/toolchain/control artifacts. Native cross-operation repair remains a separate blocking defect unless safely implemented. No review replies or mentions." + "2026-10-25T02:26:26.192Z",codex-agent,"Historical branch evidence from 2026-10-23T06:44:41.257Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Confirmed blocking cross-operation journal defect with real update rename-1 kill: restart comment exits 0 while journal persists, returning to update exits 2. Created pm-rust-cross-operation-journal as priority-0 blocking Issue linked to PR 104; no Rust recovery fix is folded into this TypeScript harness change. History-path openat injection also proves published item/history divergence with exit-0 restart. Historical 20-boundary receipts remain immutable and are no longer described as complete crash evidence." + "2026-10-25T02:26:27.405Z",codex-agent,"Historical branch evidence from 2026-10-23T06:52:47.487Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Targeted validation now confirms update cross-operation replay and reduction-refusal CLI behavior, with clock disclosure assertions. Permanent manifests replace conditional replay coverage. Runtime snapshots retain canonical transaction JSON plus raw runtime frames; unpublished temporary files remain observed but are not misclassified as committed journals. Shared recovery comparisons fail on byte, receipt projection, state or pending-journal mismatches, and unpaired cuts are not counted. Next commit pins the code source for the reproducible control recorder; complete regressions and gate evidence remain pending." + "2026-10-25T02:26:28.388Z",codex-agent,"Historical branch evidence from 2026-10-23T07:03:34.150Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Review follow-up: exact behavioral controls independently failed when runtime snapshots, different-operation restart, history-open interruption, recovery comparison, clock disclosure or secondary-refusal preservation was reverted; each passed after exact restoration. Source commit 5bdcd8e records the production implementation. Expanded public read-copy validation and permanent independent replays are in progress. PR 104 is draft because priority-zero pm-rust-cross-operation-journal remains unresolved; this is storage recovery testing of our own processes in scratch trackers." + "2026-10-25T02:26:29.435Z",codex-agent,"Historical branch evidence from 2026-10-23T07:09:28.604Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Public-copy validation exposed nondeterministic published cache renames: libuv can place the second rename on another worker, making an observed per-thread ordinal unreachable on replay. Published rename tracing now selects only the probe item path; a separate history-open cut still interrupts after item publication. Derived cache publication is explicitly outside the corpus. A real two-publication process regression covers path scoping. The recorder checkpoints completed controls, uses a bounded 60-second public-copy process deadline and refreshes controls whose source changed." + "2026-10-25T02:26:30.387Z",codex-agent,"Historical branch evidence from 2026-10-24T23:22:18.387Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Resuming PR 104 in its existing worktree. Preserving unpublished commits and unfinished review fixes before merging current main. The prior 18-test receipt is historical: expanded cross-operation, journal, history-open, clock and reduction controls require fresh local and exact-head CI evidence. Full native release-check will run in CI under host contention. Acceptance will be evaluated against measured results; no merge or release." + "2026-10-25T02:26:31.421Z",codex-agent,"Historical branch evidence from 2026-10-24T23:23:08.977Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Main integration preserves newer native lock recovery, cross-operation journal recovery, bounded reads, adapter ABI, npm/Bun release workflows and changelog behavior alongside the expanded harness. Shared history prefixes were verified byte-identical and longer streams retained unchanged. Independently created cross-operation reports used one id; main owns the implemented task and its untouched history, while the original report and raw history are preserved byte-for-byte under docs/controls/crash-review/original-journal-report.{toon,jsonl}. No history records were rewritten. Recovery controls will now require the integrated fixes to succeed; published history-open failures remain measured, not hidden." + "2026-10-25T02:26:32.403Z",codex-agent,"Historical branch evidence from 2026-10-24T23:25:45.396Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: After the merge, both permanent native cross-operation replays pass with zero pending journals and successful return operations. Their real child argument logs enforce the different-operation restart; first-fsync fixtures from main are retained. Corrected unfinished destination-path rename filtering after a real strace probe proved it observes no rename. Published children now use UV_THREADPOOL_SIZE=1 and retain all observed rename/fsync cuts plus history-open cuts; a real two-publication regression and independent environment revert enforce reproducibility. Compiler and ESLint pass. Local tracker health is blocked only by shared extension version skew, so isolated clone-local health and CI will supply authoritative gate evidence." + "2026-10-25T02:26:33.390Z",codex-agent,"Historical branch evidence from 2026-10-24T23:28:19.587Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Fresh behavioral revert proof: node scripts/crash-review-proof.mts independently disables single-worker scheduling, runtime snapshot capture, different-operation restart, history-open admission, paired recovery comparison, clock disclosure and secondary-refusal preservation. All seven negative runs exit 1 from their targeted regression, all seven exact restorations exit 0, with original source bytes verified after each. Patches and source hashes are retained under docs/controls/crash-review. Native runtime recovery remains inherited unchanged from main. The published divergence follow-up is pm-rust-published-history-open." + "2026-10-25T02:26:34.419Z",codex-agent,"Historical branch evidence from 2026-10-24T23:31:06.778Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Review findings PRRT_kwDOTwgMRs6vW0BC, PRRT_kwDOTwgMRs6vW0BM and PRRT_kwDOTwgMRs6vW0BU are valid. Replay/source options now use presence checks; default output includes baseline parity and actionable case/recovery failure details; completed reference and killed workspaces are removed during the run. Added real CLI and live-process scratch-budget regressions, with independent behavioral controls in the recorder. Fresh public-copy evidence measures 26 kills, 26 acknowledged-write preservations, 26 history-prefix preservations, 24 successful local recovery cases, two published history-open divergences, four cross-runtime outcome mismatches and four minimized synthetic reproductions. Source fingerprint is unchanged. Harness correctness and package gates are distinct from runtime recovery conformance." + "2026-10-25T02:26:35.351Z",codex-agent,"Historical branch evidence from 2026-10-24T23:35:01.614Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Preservation audit confirms all 85 main history streams remain byte-identical prefixes; both independently created original defect artifacts are byte-identical to their saved branch snapshots. Targeted native cross_operation_journal tests pass 9/9 and isolated-HOME check-only strict health passes. The evidence recorder emits applicable control patches without trailing whitespace and retains exact source/toolchain hashes. Final full harness and linked commands will run after all negative-control source bytes are restored." + "2026-10-25T02:26:36.235Z",codex-agent,"Historical branch evidence from 2026-10-24T23:45:23.540Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Linked execution passed commands 1, 2, 3 and 5: 22/22 harness tests, 4/4 typed refusal regressions, 2/2 replay guidance regressions and 9/9 native journal tests. The expanded combined suite hit the runner default 120-second outer budget after its first file passed 22/22; no assertion failed. Retrying only that combined command with --timeout 300. Per-test process deadlines, CI aggregate timeout, coverage thresholds and scope are unchanged. Result tracking remains disabled by project policy; evidence is recorded in comments." + "2026-10-25T02:26:37.176Z",codex-agent,"Historical branch evidence from 2026-10-24T23:49:09.238Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Final local acceptance: all five linked commands pass, totaling 71 test executions including repeated subsets (22 + 4 + 2 + 34 + 9). The complete Linux crash suite passes 34/34, zero failed/canceled/skipped, in 166 seconds under the 300-second outer runner budget. The old 120-second outer-budget interruption remains explicit; individual test/process deadlines and all native release/coverage gates are unchanged. Strict erasable TypeScript, ESLint, native build, targeted Clippy, fmt, isolated strict health and changelog generation/check pass. All 11 behavioral controls plus receipt-schema control fail when independently reverted and pass after exact byte restoration. The final receipt pins source commit 881f550 and all recorded source bytes match that commit. Full exact-head npm and Bun native release-check CI is the remaining readiness gate; its URL and measured counts will be recorded in PR 104." + "2026-10-25T02:26:38.189Z",codex-agent,"Historical branch evidence from 2026-10-24T23:51:13.307Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Source candidate acc8ca5 is pushed with a clean worktree. No automatic synchronize CI run appeared, so the existing full CI workflow was explicitly dispatched at the feature branch. A final receipt commit records the independent follow-up test; implementation, tests and hashed source remain byte-identical to 881f550. The final pushed receipt head still requires its own full native npm/Bun matrix before readiness. Exact run URL and pass counts are linked from https://github.com/unbraind/pm-rust/pull/104; pending, canceled or superseded runs are not approval. Claim remains released and item in progress." + "2026-10-25T02:26:39.331Z",codex-agent,"Historical branch evidence from 2026-10-24T23:52:57.403Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Merged the new tracker-only main sweep e9b88ab. The installed driver generated a re-anchored union for this divergent stream; that generated output was discarded before commit. Original canonical branch history is restored unchanged, and main status-sweep item/history bytes are preserved exactly under docs/controls/crash-review/main-status-sweep-harness.{toon,jsonl}. All other newer main statuses are retained. Implementation, tests and receipt source hashes are unchanged. Current source remains locally validated; superseded queued CI was canceled. Regenerating changelog inside this merge and requiring a fresh full matrix on the integrated head." + "2026-10-25T02:26:41.000Z",codex-agent,"Historical branch evidence from 2026-10-25T00:07:31.755Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Final format audit found duplicate default TOON keys when multiple failures were emitted. Strict parsing with the locked published dependency rejects that output. Extracted a typed formatter with bounded failures and recovery_failures tables, preserved case/parity details and secondary-refusal remedies, and added strict decode coverage over the measured 26-case public receipt plus the real standalone CLI. A dedicated behavioral revert restores repeated root failure keys and must fail strict decoding. JSON behavior is unchanged. Superseded CI was canceled; fresh formatter/control/full-suite evidence and exact-head CI are required before readiness." + "2026-10-25T02:26:42.044Z",codex-agent,"Historical branch evidence from 2026-10-25T00:14:05.953Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Final corrected local acceptance passes all five linked commands: 22 + 4 + 2 + 35 + 9 = 72 test executions including repeated subsets, zero failures or skips. The complete 35-test Linux suite passes in 131 seconds under its 300-second outer runner budget. Strict TypeScript and ESLint pass. The default CLI and the measured multi-failure receipt both decode with the locked strict TOON parser. Reverting only strict failure-table formatting restores duplicate keys and fails the new regression; restoring exact source bytes passes. All 12 behavior controls plus the receipt-schema control fail independently and pass restored. Refreshed public-copy validation at main e9b88ab measures 85 items, 176 files, 26 kills, 26 acknowledged-write preservations, 26 history-prefix preservations, 24 successful local recoveries, two published divergences, four paired mismatches and four synthetic reproductions; source unchanged. Source commit 3b0b53b and every recorded source hash match exactly. Old CI runs are superseded; final pushed-head counts will be linked from PR 104." + "2026-10-25T02:26:43.266Z",codex-agent,"Historical branch evidence from 2026-10-25T00:36:02.940Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: CI run 40145918742 exposed a Windows-only clock-launcher failure: Node --import rejects raw drive-letter paths with ERR_UNSUPPORTED_ESM_URL_SCHEME. Windows ordinary native tests passed before the Node clock assertion; the aggregate stopped before coverage. Linux ordinary tests passed 648/648 and macOS 635/635, zero failed or ignored, but that superseded run is not final approval. The process adapter now exports a file-URL preload specifier used by both the published adapter and the real clock test. The test asserts the portable URL contract before launching the child; reverting to a raw path fails on Linux too. Clock semantics, platform skips, Rust source and all gate thresholds remain unchanged. Recording the new independent revert control, refreshing source provenance and rerunning the linked full harness before fresh exact-head CI." + "2026-10-25T02:26:44.833Z",codex-agent,"Historical branch evidence from 2026-10-25T00:41:09.756Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Portable-clock correction validated: all six linked commands pass (22 + 4 + 2 + 35 + 9 + 1 = 73 test executions including repeated subsets), zero failed/canceled/skipped. Full Linux suite passes 35/35 in 87 seconds; strict TypeScript and ESLint pass. The clock preload now uses a file URL in both actual launcher sites; independent raw-path reversion fails the portable URL assertion and exact restoration passes the real child clock checks. All 13 behavioral controls plus receipt-schema control fail independently and pass restored. Fresh source provenance pins 5f6664f; public-copy measurements remain 85 items, 176 files, 26 kills, all 26 acknowledged writes/history prefixes preserved, two published divergences, four paired mismatches, four synthetic reproductions and source unchanged. Prior Windows CI clock failure and all superseded runs remain historical, not approval. Fresh exact pushed-head full npm/Bun CI and counts are required and will be linked from PR 104." + "2026-10-25T02:32:00.645Z",codex-agent,"Append-only correction complete: main item/history restored exactly, then 19 branch-only evidence comments and intended files/docs/tests/unblock rationale were re-recorded through the pinned CLI. Main records remain a byte-identical prefix. All existing main history streams pass the prefix audit; the branch-only oracle item was preserved unchanged. Added scripts/crash-history-prefix.mts to the release gate; it checks every changed history path, rejects replaced or deleted main bytes, and permits new item streams. New real-Git/PM fixture tests pass 2/2, including a plain tracker without a Git executable. Behavioral revert proof: disabling only the byte-prefix rejection yields exit 1 from the intended missing-exception assertion; exact source restoration passes 2/2. TypeScript and ESLint pass. A stale clone-only receipt from the rejected merge was quarantined outside active metadata, without repair/force/re-anchor; isolated-HOME pinned health passes with exit 0, ok true and no failing checks. Completed runtime crash/revert evidence is retained; only new prefix/health validation is rerun locally, with full exact-head CI still required." + "2026-10-25T02:35:59.401Z",codex-agent,"Final pre-push audit: all 86 history streams present on main are byte-identical prefixes of their branch files; one branch-only oracle stream is unchanged. Main harness history has 37 original records, all preserved before the new PM events. The targeted linked prefix regression passes 2/2 with no failures, skips or empty runs. Default strict pinned health passes in isolated HOME; no active clone receipt remains. The optional full history audit reports existing mismatches for pm-rust-bj7a and pm-rust-unih; both item/history pairs are byte-for-byte identical to main and were left untouched. No main records or hash anchors were repaired. Completed runtime evidence is retained; the final pushed correction requires a fresh full CI matrix before promotion." + "2026-10-25T07:10:31.684Z",codex-agent,"Round-2 review reopened oracle correctness: replace seed-prefix/final-return checks with an exact transaction-owned PRE/POST oracle, and pair recovery cuts by observed journal commit phase instead of syscall ordinal. Add independent data-loss mutation and phase-equivalence controls, keep main history byte prefixes, and require fresh full release CI. Prior receipts remain historical and are superseded for these claims." + "2026-10-25T07:22:44.290Z",codex-agent,"Oracle correction and independent revert proofs: exactState compares the complete canonical inventory, all item bytes, every full history stream and pending journals against the phase-selected clean reference after restart and after return. PRE/POST selection is made from successful native journal publication or published item publication in the interrupted trace, including resumed calls; final returns now perform an actual priority change. Restoring seed-history-prefix-only acceptance fails the real-state mutation regressions and the live exit-zero item-deletion/event-truncation regressions (exit 1); restoring exact equality passes (exit 0). Restoring same-syscall/same-ordinal pairing fails phase parity (exit 1); restoring phase matching passes (exit 0). Applicable patches and both tables are in docs/controls/crash-oracle and docs/CRASH_ORACLE_2026_10_25.json. Core mutation table: four mutations times six real acknowledged states plus one live restart and one live return each, 32 killed and zero survived. Fresh public copy: 85 items, 176 files, 26 kills, 24 exact restart/return successes, two published history-open divergences, two minimized fixtures, unchanged source. Phase parity: 20 same-phase pairs, 10 pass, 10 differences all explained by those two independently failing published cases; no ordinal-alias false failures. All 26 seed acknowledgements/history prefixes remain preserved. Default pinned strict health passes; optional full audit retains the two main-identical bj7a/unih mismatches, untouched. Running the full linked harness and fresh CI next." + "2026-10-25T07:26:30.802Z",codex-agent,"Linked full harness validation passed: pm test --run --match test-concurrency=1 --progress --json ran node --test --test-concurrency=1 scripts/crash-*.test.mts, 50/50 passing with zero failures, skips or cancellations in 171 seconds. Strict TypeScript and ESLint pass. Removed the unused legacy permissive recoveredState helper so the active and unit-tested recovery path has one exact oracle; its replacement history-state regression also passes independently. Both live rename-1 cases now pass under different phases and are explicitly excluded from same-phase pairing. All 86 main streams remain raw byte prefixes; changed-history release gate passes. Default isolated pinned strict health passes; full audit remains blocked only on the two unchanged main items already recorded. Fresh full npm/Bun native release CI is still required on the pushed head." +files[13]: - path: scripts/crash-cli.mts scope: project note: Compact TOON and JSON command @@ -34,18 +60,107 @@ files[5]: note: Typed reusable crash corpus SDK - path: scripts/crash-harness.test.mts scope: project + - path: scripts/crash-history-prefix.mts + scope: project + note: Read-only exact main-history prefix gate for every changed stream + - path: scripts/crash-history-prefix.test.mts + scope: project + note: "Real Git and PM fixtures, replacement/deletion rejection, and no-Git refusal" + - path: scripts/crash-oracle-proof.mts + scope: project + - path: scripts/crash-oracle.mts + scope: project + - path: scripts/crash-oracle.test.mts + scope: project + - path: scripts/crash-output.mts + scope: project + note: Strict bounded TOON formatter with unique tabular failure keys - path: scripts/crash-process.mts scope: project note: Real bounded syscall kill adapters + - path: scripts/crash-review-proof.mts + scope: project + note: Reproducible control patches and public-copy receipt + - path: scripts/crash-review.test.mts + scope: project + note: Permanent native and published replays plus CLI and scratch-budget regressions - path: scripts/crash-storage.mts scope: project note: Byte inventories and immutable history checks -tests[3]{command,scope,provenance{author,created_at,source_kind,source_ref}}: - node --test scripts/crash-harness.test.mts,project,codex-agent,"2026-10-21T22:17:14.334Z",local_mutation,feat/crash-consistency-harness - "node --test --test-name-pattern=\"oracle metadata|malformed source settings|malformed mutation acknowledgements\" scripts/crash-harness.test.mts",project,codex-agent,"2026-10-22T10:42:11.763Z",local_mutation,feat/crash-consistency-harness - "node --test --test-name-pattern=\"replay guidance\" scripts/crash-harness.test.mts",project,codex-agent,"2026-10-22T16:40:13.066Z",local_mutation,feat/crash-consistency-harness -docs[3]{path,scope,note}: - docs/CRASH_HARNESS.md,project,SDK CLI replay and no-git examples - docs/CRASH_PUBLIC_COPY_2026_10_22.json,project,Measured public tracker copy receipt - docs/CRASH_REVERT_PROOF_2026_10_22.json,project,Independent behavioral negative controls +tests[8]: + - command: node --test scripts/crash-harness.test.mts + scope: project + provenance: + author: codex-agent + created_at: "2026-10-21T22:17:14.334Z" + source_kind: local_mutation + source_ref: feat/crash-consistency-harness + - command: "node --test --test-name-pattern=\"oracle metadata|malformed source settings|malformed mutation acknowledgements\" scripts/crash-harness.test.mts" + scope: project + provenance: + author: codex-agent + created_at: "2026-10-22T10:42:11.763Z" + source_kind: local_mutation + source_ref: feat/crash-consistency-harness + - command: "node --test --test-name-pattern=\"replay guidance\" scripts/crash-harness.test.mts" + scope: project + provenance: + author: codex-agent + created_at: "2026-10-22T16:40:13.066Z" + source_kind: local_mutation + source_ref: feat/crash-consistency-harness + - command: node --test --test-concurrency=1 scripts/crash-*.test.mts + scope: project + timeout_seconds: 300 + provenance: + author: codex-agent + created_at: "2026-10-25T02:26:23.596Z" + source_kind: local_mutation + source_ref: feat/crash-consistency-harness + - command: cargo +1.90.0 test --locked --lib cross_operation_journal -j 2 + scope: project + provenance: + author: codex-agent + created_at: "2026-10-25T02:26:23.596Z" + source_kind: local_mutation + source_ref: feat/crash-consistency-harness + - command: "node --test --test-name-pattern=\"clock disclosure\" scripts/crash-review.test.mts" + scope: project + provenance: + author: codex-agent + created_at: "2026-10-25T02:26:23.596Z" + source_kind: local_mutation + source_ref: feat/crash-consistency-harness + - command: node --test scripts/crash-history-prefix.test.mts + scope: project + provenance: + author: codex-agent + created_at: "2026-10-25T02:31:58.455Z" + source_kind: local_mutation + source_ref: feat/crash-consistency-harness + - command: node --test scripts/crash-oracle.test.mts + scope: project + provenance: + author: codex-agent + created_at: "2026-10-25T07:19:03.496Z" + source_kind: local_mutation + source_ref: feat/crash-consistency-harness +docs[6]: + - path: docs/CRASH_HARNESS.md + scope: project + note: SDK CLI replay and no-git examples + - path: docs/CRASH_ORACLE_2026_10_25.json + scope: project + - path: docs/CRASH_PUBLIC_COPY_2026_10_22.json + scope: project + note: Measured public tracker copy receipt + - path: docs/CRASH_REVERT_PROOF_2026_10_22.json + scope: project + note: Independent behavioral negative controls + - path: docs/CRASH_REVIEW_2026_10_23.json + scope: project + note: Versioned public-copy measurements and independent behavioral control patches + - path: README.md + scope: project + note: History prefix gate and its Git requirement body: "" diff --git a/.agents/pm/history/pm-rust-crash-harness.jsonl b/.agents/pm/history/pm-rust-crash-harness.jsonl index 64e5d6e..f5fe250 100644 --- a/.agents/pm/history/pm-rust-crash-harness.jsonl +++ b/.agents/pm/history/pm-rust-crash-harness.jsonl @@ -35,3 +35,51 @@ {"hash_algorithm":"sha256","ts":"2026-10-22T16:47:30.014Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T16:47:30.014Z"}],"before_hash":"83037d46c61d87ab8453636cfd3c88e01469e44d6f148b25675d89b1b1b86f73","after_hash":"b2b4f9ac3d7daac208fb57e1b7e3e022fa734cf1d99add9d55b62bcc2f26ed06","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"9626a8e574048e48725d5dd6ca08c1e5d75995ad91a8d9983608af28786bc13c"} {"hash_algorithm":"sha256","ts":"2026-10-24T21:48:10.651Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"45d20434178787c3d9448609","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-24T21:48:10.651Z"},{"op":"replace","path":"/metadata/status","value":"open"}],"before_hash":"b2b4f9ac3d7daac208fb57e1b7e3e022fa734cf1d99add9d55b62bcc2f26ed06","after_hash":"e3dd26e6f6bb390b29bfb9e1c3eb68d0d8b7153d8952a698d001a23f957e78da","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"8414298d289dbd1d1e6e3ca34610add3f104ca3e75515f9280f1e8a944b2e2d3"} {"hash_algorithm":"sha256","ts":"2026-10-24T21:48:10.764Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"45d20434178787c3d9448609","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/14","value":{"created_at":"2026-10-24T21:48:10.764Z","author":"codex-agent","text":"Returned to open in the 2026-10-24 sweep: Open PR https://github.com/unbraind/pm-rust/pull/104 carries the reusable kill-corpus harness; merged PR 105 fixes lock recovery but is not complete harness delivery. Review and full harness acceptance remain pending, with no active agent established."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-24T21:48:10.764Z"}],"before_hash":"e3dd26e6f6bb390b29bfb9e1c3eb68d0d8b7153d8952a698d001a23f957e78da","after_hash":"58ed6bc34e44cd03df7fdf32e1060b9c9774e131f0d42a9784a22d1463bde37f","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"5b416384fc52bfc7a715ba1e184299b46581ffe7ea39d56cac67f19305fdc287"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:05.585Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:05.585Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"58ed6bc34e44cd03df7fdf32e1060b9c9774e131f0d42a9784a22d1463bde37f","after_hash":"a84ce52d85e1603228002a36342527e3a9942764ddfb8637201ee7312a8509ad","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"7acc8fe129f242c1956996c250ba51e9c876d8bb9a6533fbc8490c1b1a0e3723"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:06.722Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:06.722Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"a84ce52d85e1603228002a36342527e3a9942764ddfb8637201ee7312a8509ad","after_hash":"84ebdc12e0b3079930566e8a1904f401e1fe7705be70c57acfdcda45b8fe2602","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"bfa4afa5417b90f58f5e4799be53b1ab503ec6b55b94fe097e22fedfc82d0982"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:08.451Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/15","value":{"created_at":"2026-10-25T02:26:08.451Z","author":"codex-agent","text":"Orchestrator correction: restored this item and its history exactly from main before writing. Main records remain untouched. Branch-only intended evidence is now re-recorded through the pinned CLI as new events, not copied or spliced. The prior archive-based resolution was rejected and is superseded by this linear main-chain extension. Runtime implementation and previously completed crash acceptance remain unchanged; adding a PR-wide byte-prefix regression and fresh health/CI evidence."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:08.451Z"}],"before_hash":"84ebdc12e0b3079930566e8a1904f401e1fe7705be70c57acfdcda45b8fe2602","after_hash":"371db59512975a23ebeac39e5631c9b9f3630917711af26a06aded3fc665bd32","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"5d01dbbe3d2fc7ba98fc65e51e09bb3214323caa208e58f95695fe6e6793595d"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:10.380Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:10.380Z"},{"op":"add","path":"/metadata/unblock_note","value":"Native cross-operation recovery is integrated from main and both live permanent replays pass with zero pending journals and successful return operations."}],"before_hash":"371db59512975a23ebeac39e5631c9b9f3630917711af26a06aded3fc665bd32","after_hash":"cdb56a9a29653ab01df0effd45a2eb5f6c9573cc0e4b7f12f57edc348c3067b8","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"9d3544a53f02d0041ebe5d6680572da3a0460fb2b7356168f7723ffc7e8b0981"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:14.699Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/4/note","value":"Real bounded syscall kill adapters"},{"op":"replace","path":"/metadata/files/4/path","value":"scripts/crash-process.mts"},{"op":"replace","path":"/metadata/files/3/note","value":"Strict bounded TOON formatter with unique tabular failure keys"},{"op":"replace","path":"/metadata/files/3/path","value":"scripts/crash-output.mts"},{"op":"add","path":"/metadata/files/5","value":{"path":"scripts/crash-storage.mts","scope":"project","note":"Byte inventories and immutable history checks"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:14.699Z"}],"before_hash":"cdb56a9a29653ab01df0effd45a2eb5f6c9573cc0e4b7f12f57edc348c3067b8","after_hash":"8fa90f8b988f48c301977993673cb4368e8db8b48521759ecfaef671afe19d99","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"5c27cd02a0ce8b959792058c0d74fdd238031c87c09acc9a9b7f3637b6ffa862"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:16.783Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/5/note","value":"Reproducible control patches and public-copy receipt"},{"op":"replace","path":"/metadata/files/5/path","value":"scripts/crash-review-proof.mts"},{"op":"add","path":"/metadata/files/6","value":{"path":"scripts/crash-storage.mts","scope":"project","note":"Byte inventories and immutable history checks"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:16.783Z"}],"before_hash":"8fa90f8b988f48c301977993673cb4368e8db8b48521759ecfaef671afe19d99","after_hash":"e92a5ae7c212cbb6b9d7ed57a08e77d71f10f004c5cac3e1dda2fc76290d3830","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"a4230d806a74c233666b3c0ec71d039afc6ae3a6a88dc0f4d457bac42eb0db29"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:17.702Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/6/note","value":"Permanent native and published replays plus CLI and scratch-budget regressions"},{"op":"replace","path":"/metadata/files/6/path","value":"scripts/crash-review.test.mts"},{"op":"add","path":"/metadata/files/7","value":{"path":"scripts/crash-storage.mts","scope":"project","note":"Byte inventories and immutable history checks"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:17.702Z"}],"before_hash":"e92a5ae7c212cbb6b9d7ed57a08e77d71f10f004c5cac3e1dda2fc76290d3830","after_hash":"ee624c91e973a12ae211821fb4fe1f9681be029cf2d975f2eea3340979aba1f7","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"fd681f7e11ea84229e5fbe4596d08b871b13379aae49e6289a12d6f36cd83633"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:22.724Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"add","path":"/metadata/docs/3","value":{"path":"docs/CRASH_REVIEW_2026_10_23.json","scope":"project","note":"Versioned public-copy measurements and independent behavioral control patches"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:22.724Z"}],"before_hash":"ee624c91e973a12ae211821fb4fe1f9681be029cf2d975f2eea3340979aba1f7","after_hash":"bc46297ceb31abdc30901f9c77e780cf7e523034094161edcf5fb5ae06a8a41f","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"a9969e54c18443e26cc389b2101ccecf91340f39120a62d1fb27b61860e90caf"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:23.647Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/3","value":{"command":"node --test --test-concurrency=1 scripts/crash-*.test.mts","scope":"project","timeout_seconds":300,"provenance":{"author":"codex-agent","created_at":"2026-10-25T02:26:23.596Z","source_kind":"local_mutation","source_ref":"feat/crash-consistency-harness"}}},{"op":"add","path":"/metadata/tests/4","value":{"command":"cargo +1.90.0 test --locked --lib cross_operation_journal -j 2","scope":"project","provenance":{"author":"codex-agent","created_at":"2026-10-25T02:26:23.596Z","source_kind":"local_mutation","source_ref":"feat/crash-consistency-harness"}}},{"op":"add","path":"/metadata/tests/5","value":{"command":"node --test --test-name-pattern=\"clock disclosure\" scripts/crash-review.test.mts","scope":"project","provenance":{"author":"codex-agent","created_at":"2026-10-25T02:26:23.596Z","source_kind":"local_mutation","source_ref":"feat/crash-consistency-harness"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:23.647Z"}],"before_hash":"bc46297ceb31abdc30901f9c77e780cf7e523034094161edcf5fb5ae06a8a41f","after_hash":"f2a9d341e17ee55cc9617e0dc60a3213770509b1d9bc772fc10965e9c0da8955","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"509b71693e82065636a26b755e50f82c097cc6d3345f0771e1511dbb56686ffa"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:24.824Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/16","value":{"created_at":"2026-10-25T02:26:24.823Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-23T06:38:11.820Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Orchestrator review follow-up on PR 104: remote f555a42 was current; merged main c46ad00 and preserved both benchmark and crash recipes in two overlap resolutions. Reusing this item, without redoing completed refusal/doc fixes. Will capture runtime journals, add cross-operation restart plus a return-to-original-operation probe, inject published history-open failures, compare recovered runtime outcomes, disclose clock semantics, keep replay unconditional, preserve measured failure when synthetic reduction refuses, and record reproducible source/toolchain/control artifacts. Native cross-operation repair remains a separate blocking defect unless safely implemented. No review replies or mentions."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:24.824Z"}],"before_hash":"f2a9d341e17ee55cc9617e0dc60a3213770509b1d9bc772fc10965e9c0da8955","after_hash":"554ca0a264497f941cf1c2c8cc17b057ab6980917f8cf5469a5ef3bc7d586645","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e94f9466daaf7429d6679e9097cd023d63272850c328c44ef9d508fac77e2669"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:26.192Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/17","value":{"created_at":"2026-10-25T02:26:26.192Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-23T06:44:41.257Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Confirmed blocking cross-operation journal defect with real update rename-1 kill: restart comment exits 0 while journal persists, returning to update exits 2. Created pm-rust-cross-operation-journal as priority-0 blocking Issue linked to PR 104; no Rust recovery fix is folded into this TypeScript harness change. History-path openat injection also proves published item/history divergence with exit-0 restart. Historical 20-boundary receipts remain immutable and are no longer described as complete crash evidence."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:26.192Z"}],"before_hash":"554ca0a264497f941cf1c2c8cc17b057ab6980917f8cf5469a5ef3bc7d586645","after_hash":"830f9c4bfe3ad773709ad81e5e81170cd136e3310c9814b7468a16efdfe454d2","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"b3448900be6bee0f56ea7f72d9b5269e57a12a6831f3f745017427120ad684d9"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:27.405Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/18","value":{"created_at":"2026-10-25T02:26:27.405Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-23T06:52:47.487Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Targeted validation now confirms update cross-operation replay and reduction-refusal CLI behavior, with clock disclosure assertions. Permanent manifests replace conditional replay coverage. Runtime snapshots retain canonical transaction JSON plus raw runtime frames; unpublished temporary files remain observed but are not misclassified as committed journals. Shared recovery comparisons fail on byte, receipt projection, state or pending-journal mismatches, and unpaired cuts are not counted. Next commit pins the code source for the reproducible control recorder; complete regressions and gate evidence remain pending."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:27.405Z"}],"before_hash":"830f9c4bfe3ad773709ad81e5e81170cd136e3310c9814b7468a16efdfe454d2","after_hash":"653e0a75c394d695f07868d4dd6489c210b5f73f96719c76d6ecb4bd6bc39000","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"135990389cf3042ead1b8fd2ca460f6e38105b2a3a291608a9aa18438a65b86b"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:28.388Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/19","value":{"created_at":"2026-10-25T02:26:28.388Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-23T07:03:34.150Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Review follow-up: exact behavioral controls independently failed when runtime snapshots, different-operation restart, history-open interruption, recovery comparison, clock disclosure or secondary-refusal preservation was reverted; each passed after exact restoration. Source commit 5bdcd8e records the production implementation. Expanded public read-copy validation and permanent independent replays are in progress. PR 104 is draft because priority-zero pm-rust-cross-operation-journal remains unresolved; this is storage recovery testing of our own processes in scratch trackers."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:28.388Z"}],"before_hash":"653e0a75c394d695f07868d4dd6489c210b5f73f96719c76d6ecb4bd6bc39000","after_hash":"07559256c08f317ece976458ad644cd4ba2f7015b8e015e31e95db2ae16c21d9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"7a27fef80a7f006f7d27d7ecf72f8357d6d8c989d74999ad904cac6d74abd4c7"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:29.436Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/20","value":{"created_at":"2026-10-25T02:26:29.435Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-23T07:09:28.604Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Public-copy validation exposed nondeterministic published cache renames: libuv can place the second rename on another worker, making an observed per-thread ordinal unreachable on replay. Published rename tracing now selects only the probe item path; a separate history-open cut still interrupts after item publication. Derived cache publication is explicitly outside the corpus. A real two-publication process regression covers path scoping. The recorder checkpoints completed controls, uses a bounded 60-second public-copy process deadline and refreshes controls whose source changed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:29.436Z"}],"before_hash":"07559256c08f317ece976458ad644cd4ba2f7015b8e015e31e95db2ae16c21d9","after_hash":"376714a2f20e950258d6e6e7242e86d4f447bfa66406199882f7785139df74e7","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"c70450b454892ae22b5eaebf85172e0ec3d79c8e4dc99694211dda81a3faf6d3"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:30.387Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/21","value":{"created_at":"2026-10-25T02:26:30.387Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-24T23:22:18.387Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Resuming PR 104 in its existing worktree. Preserving unpublished commits and unfinished review fixes before merging current main. The prior 18-test receipt is historical: expanded cross-operation, journal, history-open, clock and reduction controls require fresh local and exact-head CI evidence. Full native release-check will run in CI under host contention. Acceptance will be evaluated against measured results; no merge or release."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:30.387Z"}],"before_hash":"376714a2f20e950258d6e6e7242e86d4f447bfa66406199882f7785139df74e7","after_hash":"8d9958daa4d6a6e75350569572ac10d319be2057e24d3e1b1f0039b05b175c3e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"7c573e728c5e8e093f55216c2375e12c388385534af6be21fc3d9664b4c9c340"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:31.421Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/22","value":{"created_at":"2026-10-25T02:26:31.421Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-24T23:23:08.977Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Main integration preserves newer native lock recovery, cross-operation journal recovery, bounded reads, adapter ABI, npm/Bun release workflows and changelog behavior alongside the expanded harness. Shared history prefixes were verified byte-identical and longer streams retained unchanged. Independently created cross-operation reports used one id; main owns the implemented task and its untouched history, while the original report and raw history are preserved byte-for-byte under docs/controls/crash-review/original-journal-report.{toon,jsonl}. No history records were rewritten. Recovery controls will now require the integrated fixes to succeed; published history-open failures remain measured, not hidden."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:31.421Z"}],"before_hash":"8d9958daa4d6a6e75350569572ac10d319be2057e24d3e1b1f0039b05b175c3e","after_hash":"9dd0c749f7764af6ede5611580b0fc75ac7f1a5793928394dbea2240d91ce646","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"365b2eab549b568130a58b4f06a26e492ef645a691f04c8bca29836c97274b73"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:32.405Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/23","value":{"created_at":"2026-10-25T02:26:32.403Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-24T23:25:45.396Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: After the merge, both permanent native cross-operation replays pass with zero pending journals and successful return operations. Their real child argument logs enforce the different-operation restart; first-fsync fixtures from main are retained. Corrected unfinished destination-path rename filtering after a real strace probe proved it observes no rename. Published children now use UV_THREADPOOL_SIZE=1 and retain all observed rename/fsync cuts plus history-open cuts; a real two-publication regression and independent environment revert enforce reproducibility. Compiler and ESLint pass. Local tracker health is blocked only by shared extension version skew, so isolated clone-local health and CI will supply authoritative gate evidence."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:32.405Z"}],"before_hash":"9dd0c749f7764af6ede5611580b0fc75ac7f1a5793928394dbea2240d91ce646","after_hash":"c3079393a79f6336d15d05902af172c95c481740f947ad9da7eb247828d6ea21","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"7dcfcab58f580a00d073363669db0f366325d421cb3a4fcba3a779c5ba24265f"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:33.391Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/24","value":{"created_at":"2026-10-25T02:26:33.390Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-24T23:28:19.587Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Fresh behavioral revert proof: node scripts/crash-review-proof.mts independently disables single-worker scheduling, runtime snapshot capture, different-operation restart, history-open admission, paired recovery comparison, clock disclosure and secondary-refusal preservation. All seven negative runs exit 1 from their targeted regression, all seven exact restorations exit 0, with original source bytes verified after each. Patches and source hashes are retained under docs/controls/crash-review. Native runtime recovery remains inherited unchanged from main. The published divergence follow-up is pm-rust-published-history-open."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:33.391Z"}],"before_hash":"c3079393a79f6336d15d05902af172c95c481740f947ad9da7eb247828d6ea21","after_hash":"032a184a7dd715ab821fb52e98897af14aeb0b52ab415f3a4c31006d78609aa8","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e0645bfbe4c0af9eb9d3bcfb9a9427a46b8f6011ee1b415b8ddcda3827809571"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:34.419Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/25","value":{"created_at":"2026-10-25T02:26:34.419Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-24T23:31:06.778Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Review findings PRRT_kwDOTwgMRs6vW0BC, PRRT_kwDOTwgMRs6vW0BM and PRRT_kwDOTwgMRs6vW0BU are valid. Replay/source options now use presence checks; default output includes baseline parity and actionable case/recovery failure details; completed reference and killed workspaces are removed during the run. Added real CLI and live-process scratch-budget regressions, with independent behavioral controls in the recorder. Fresh public-copy evidence measures 26 kills, 26 acknowledged-write preservations, 26 history-prefix preservations, 24 successful local recovery cases, two published history-open divergences, four cross-runtime outcome mismatches and four minimized synthetic reproductions. Source fingerprint is unchanged. Harness correctness and package gates are distinct from runtime recovery conformance."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:34.419Z"}],"before_hash":"032a184a7dd715ab821fb52e98897af14aeb0b52ab415f3a4c31006d78609aa8","after_hash":"027f702309638b8173be37844c1cb8ff18f7ab0b33fc944fb5e8e310079ad861","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"3b81725519ca6c7b1852a98cb0d45a1349d66c03a37b006b83226172b111f6fd"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:35.351Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/26","value":{"created_at":"2026-10-25T02:26:35.351Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-24T23:35:01.614Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Preservation audit confirms all 85 main history streams remain byte-identical prefixes; both independently created original defect artifacts are byte-identical to their saved branch snapshots. Targeted native cross_operation_journal tests pass 9/9 and isolated-HOME check-only strict health passes. The evidence recorder emits applicable control patches without trailing whitespace and retains exact source/toolchain hashes. Final full harness and linked commands will run after all negative-control source bytes are restored."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:35.351Z"}],"before_hash":"027f702309638b8173be37844c1cb8ff18f7ab0b33fc944fb5e8e310079ad861","after_hash":"2a0fa4d1acd0d40cc5680510044412fe55f06fffde048d63e08b42f0b981f4c2","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"93512f8771869ca5df10894d17f38f37bc8f8ba39f5d9c0043e005de61e39dc3"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:36.236Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/27","value":{"created_at":"2026-10-25T02:26:36.235Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-24T23:45:23.540Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Linked execution passed commands 1, 2, 3 and 5: 22/22 harness tests, 4/4 typed refusal regressions, 2/2 replay guidance regressions and 9/9 native journal tests. The expanded combined suite hit the runner default 120-second outer budget after its first file passed 22/22; no assertion failed. Retrying only that combined command with --timeout 300. Per-test process deadlines, CI aggregate timeout, coverage thresholds and scope are unchanged. Result tracking remains disabled by project policy; evidence is recorded in comments."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:36.236Z"}],"before_hash":"2a0fa4d1acd0d40cc5680510044412fe55f06fffde048d63e08b42f0b981f4c2","after_hash":"bcc6a6aa9add1e35a2a6dd58007d29162d74b8590c7612ea79fffd61c6c0bd92","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"5c770822d53901202a06996c24f727a0d9357c1fb30860a810cacf9579784518"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:37.176Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/28","value":{"created_at":"2026-10-25T02:26:37.176Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-24T23:49:09.238Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Final local acceptance: all five linked commands pass, totaling 71 test executions including repeated subsets (22 + 4 + 2 + 34 + 9). The complete Linux crash suite passes 34/34, zero failed/canceled/skipped, in 166 seconds under the 300-second outer runner budget. The old 120-second outer-budget interruption remains explicit; individual test/process deadlines and all native release/coverage gates are unchanged. Strict erasable TypeScript, ESLint, native build, targeted Clippy, fmt, isolated strict health and changelog generation/check pass. All 11 behavioral controls plus receipt-schema control fail when independently reverted and pass after exact byte restoration. The final receipt pins source commit 881f550 and all recorded source bytes match that commit. Full exact-head npm and Bun native release-check CI is the remaining readiness gate; its URL and measured counts will be recorded in PR 104."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:37.176Z"}],"before_hash":"bcc6a6aa9add1e35a2a6dd58007d29162d74b8590c7612ea79fffd61c6c0bd92","after_hash":"595904d6defc892f90ddc8280aa6e5ccc9a03f4ab138005f8b709782904be743","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"c13dfa0f26d3e8b72904bec31abcf59ab5556c112daea6730440cef914fc893b"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:38.189Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/29","value":{"created_at":"2026-10-25T02:26:38.189Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-24T23:51:13.307Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Source candidate acc8ca5 is pushed with a clean worktree. No automatic synchronize CI run appeared, so the existing full CI workflow was explicitly dispatched at the feature branch. A final receipt commit records the independent follow-up test; implementation, tests and hashed source remain byte-identical to 881f550. The final pushed receipt head still requires its own full native npm/Bun matrix before readiness. Exact run URL and pass counts are linked from https://github.com/unbraind/pm-rust/pull/104; pending, canceled or superseded runs are not approval. Claim remains released and item in progress."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:38.189Z"}],"before_hash":"595904d6defc892f90ddc8280aa6e5ccc9a03f4ab138005f8b709782904be743","after_hash":"9607e8411748e93c1181cfa625172e7bbf4a62794b98b1a495a06535283c2993","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a5881e8d17cf90983df1cde53785774a644b9d92046aa0de4b9a364a01d384c2"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:39.333Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/30","value":{"created_at":"2026-10-25T02:26:39.331Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-24T23:52:57.403Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Merged the new tracker-only main sweep e9b88ab. The installed driver generated a re-anchored union for this divergent stream; that generated output was discarded before commit. Original canonical branch history is restored unchanged, and main status-sweep item/history bytes are preserved exactly under docs/controls/crash-review/main-status-sweep-harness.{toon,jsonl}. All other newer main statuses are retained. Implementation, tests and receipt source hashes are unchanged. Current source remains locally validated; superseded queued CI was canceled. Regenerating changelog inside this merge and requiring a fresh full matrix on the integrated head."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:39.333Z"}],"before_hash":"9607e8411748e93c1181cfa625172e7bbf4a62794b98b1a495a06535283c2993","after_hash":"74dcf523a7f903a639228806e4a77627d5c7ed56f7476164e1c624138798bd5e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"efb61f87e14329307b7202faf9daa2ec59581779af26feba7f0e602f5dafefe3"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:41.001Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/31","value":{"created_at":"2026-10-25T02:26:41.000Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-25T00:07:31.755Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Final format audit found duplicate default TOON keys when multiple failures were emitted. Strict parsing with the locked published dependency rejects that output. Extracted a typed formatter with bounded failures and recovery_failures tables, preserved case/parity details and secondary-refusal remedies, and added strict decode coverage over the measured 26-case public receipt plus the real standalone CLI. A dedicated behavioral revert restores repeated root failure keys and must fail strict decoding. JSON behavior is unchanged. Superseded CI was canceled; fresh formatter/control/full-suite evidence and exact-head CI are required before readiness."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:41.001Z"}],"before_hash":"74dcf523a7f903a639228806e4a77627d5c7ed56f7476164e1c624138798bd5e","after_hash":"eac29d2d793a2b22abcc930d54fbdaea638589dba0be99d9a824306d481060d9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d9bf1449b53cf452f40db4e8e1c83ba3a913ed5d7ae4f0eee3c44b48ea92b963"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:42.044Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/32","value":{"created_at":"2026-10-25T02:26:42.044Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-25T00:14:05.953Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Final corrected local acceptance passes all five linked commands: 22 + 4 + 2 + 35 + 9 = 72 test executions including repeated subsets, zero failures or skips. The complete 35-test Linux suite passes in 131 seconds under its 300-second outer runner budget. Strict TypeScript and ESLint pass. The default CLI and the measured multi-failure receipt both decode with the locked strict TOON parser. Reverting only strict failure-table formatting restores duplicate keys and fails the new regression; restoring exact source bytes passes. All 12 behavior controls plus the receipt-schema control fail independently and pass restored. Refreshed public-copy validation at main e9b88ab measures 85 items, 176 files, 26 kills, 26 acknowledged-write preservations, 26 history-prefix preservations, 24 successful local recoveries, two published divergences, four paired mismatches and four synthetic reproductions; source unchanged. Source commit 3b0b53b and every recorded source hash match exactly. Old CI runs are superseded; final pushed-head counts will be linked from PR 104."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:42.044Z"}],"before_hash":"eac29d2d793a2b22abcc930d54fbdaea638589dba0be99d9a824306d481060d9","after_hash":"cbb654883bd715a16279f44821850175be6d98aa0e1198f6421709c4b70d31e1","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"44a78847309d285c1a3d168cedf8732cc19e9f8bccd82a3a32acb9dbf709f923"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:43.267Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/33","value":{"created_at":"2026-10-25T02:26:43.266Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-25T00:36:02.940Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: CI run 40145918742 exposed a Windows-only clock-launcher failure: Node --import rejects raw drive-letter paths with ERR_UNSUPPORTED_ESM_URL_SCHEME. Windows ordinary native tests passed before the Node clock assertion; the aggregate stopped before coverage. Linux ordinary tests passed 648/648 and macOS 635/635, zero failed or ignored, but that superseded run is not final approval. The process adapter now exports a file-URL preload specifier used by both the published adapter and the real clock test. The test asserts the portable URL contract before launching the child; reverting to a raw path fails on Linux too. Clock semantics, platform skips, Rust source and all gate thresholds remain unchanged. Recording the new independent revert control, refreshing source provenance and rerunning the linked full harness before fresh exact-head CI."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:43.267Z"}],"before_hash":"cbb654883bd715a16279f44821850175be6d98aa0e1198f6421709c4b70d31e1","after_hash":"fa998ecf2fb1631c26e712a3a042a92d6a634c2189572726e7dd0b23c5ee9894","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"fa746bc0836a9c4148a5f349b6dde8895f65c963bd42a04e10f84c9bbcc77ae9"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:26:44.835Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/34","value":{"created_at":"2026-10-25T02:26:44.833Z","author":"codex-agent","text":"Historical branch evidence from 2026-10-25T00:41:09.756Z, re-recorded after main-chain restoration; later corrections supersede earlier approaches: Portable-clock correction validated: all six linked commands pass (22 + 4 + 2 + 35 + 9 + 1 = 73 test executions including repeated subsets), zero failed/canceled/skipped. Full Linux suite passes 35/35 in 87 seconds; strict TypeScript and ESLint pass. The clock preload now uses a file URL in both actual launcher sites; independent raw-path reversion fails the portable URL assertion and exact restoration passes the real child clock checks. All 13 behavioral controls plus receipt-schema control fail independently and pass restored. Fresh source provenance pins 5f6664f; public-copy measurements remain 85 items, 176 files, 26 kills, all 26 acknowledged writes/history prefixes preserved, two published divergences, four paired mismatches, four synthetic reproductions and source unchanged. Prior Windows CI clock failure and all superseded runs remain historical, not approval. Fresh exact pushed-head full npm/Bun CI and counts are required and will be linked from PR 104."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:26:44.835Z"}],"before_hash":"fa998ecf2fb1631c26e712a3a042a92d6a634c2189572726e7dd0b23c5ee9894","after_hash":"793b7c580b1a53e4a580faff273000af255d6b640d7c206cbdbd04cc1971287d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"c7369061c52a700e4cb9dc46db84c77b45a131f8e44e46e5924a5ffd2de75a3d"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:31:52.377Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/7/note","value":"Permanent native and published replays plus CLI and scratch-budget regressions"},{"op":"replace","path":"/metadata/files/7/path","value":"scripts/crash-review.test.mts"},{"op":"replace","path":"/metadata/files/6/note","value":"Reproducible control patches and public-copy receipt"},{"op":"replace","path":"/metadata/files/6/path","value":"scripts/crash-review-proof.mts"},{"op":"replace","path":"/metadata/files/5/note","value":"Real bounded syscall kill adapters"},{"op":"replace","path":"/metadata/files/5/path","value":"scripts/crash-process.mts"},{"op":"replace","path":"/metadata/files/4/note","value":"Strict bounded TOON formatter with unique tabular failure keys"},{"op":"replace","path":"/metadata/files/4/path","value":"scripts/crash-output.mts"},{"op":"replace","path":"/metadata/files/3/note","value":"Read-only exact main-history prefix gate for every changed stream"},{"op":"replace","path":"/metadata/files/3/path","value":"scripts/crash-history-prefix.mts"},{"op":"add","path":"/metadata/files/8","value":{"path":"scripts/crash-storage.mts","scope":"project","note":"Byte inventories and immutable history checks"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:31:52.377Z"}],"before_hash":"793b7c580b1a53e4a580faff273000af255d6b640d7c206cbdbd04cc1971287d","after_hash":"9a8d0b5ed6e0aacb0ada7faf5a1c1b3a64e89c1d70d1416dedee538a3623df24","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"f585f97f99f6dbc0eed642d258cb247e623c52b12402aaad45640d255102cc80"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:31:54.464Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/8/note","value":"Permanent native and published replays plus CLI and scratch-budget regressions"},{"op":"replace","path":"/metadata/files/8/path","value":"scripts/crash-review.test.mts"},{"op":"replace","path":"/metadata/files/7/note","value":"Reproducible control patches and public-copy receipt"},{"op":"replace","path":"/metadata/files/7/path","value":"scripts/crash-review-proof.mts"},{"op":"replace","path":"/metadata/files/6/note","value":"Real bounded syscall kill adapters"},{"op":"replace","path":"/metadata/files/6/path","value":"scripts/crash-process.mts"},{"op":"replace","path":"/metadata/files/5/note","value":"Strict bounded TOON formatter with unique tabular failure keys"},{"op":"replace","path":"/metadata/files/5/path","value":"scripts/crash-output.mts"},{"op":"replace","path":"/metadata/files/4/note","value":"Real Git and PM fixtures, replacement/deletion rejection, and no-Git refusal"},{"op":"replace","path":"/metadata/files/4/path","value":"scripts/crash-history-prefix.test.mts"},{"op":"add","path":"/metadata/files/9","value":{"path":"scripts/crash-storage.mts","scope":"project","note":"Byte inventories and immutable history checks"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:31:54.464Z"}],"before_hash":"9a8d0b5ed6e0aacb0ada7faf5a1c1b3a64e89c1d70d1416dedee538a3623df24","after_hash":"6f86c92b7e86be6592a966bb12f5608df2dc8ac9adc22ec432dbe66faea3e42e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"70f1c47f2b86cb426ee4e1665c1beb5f734182e4807962863e52c57029bbd0ea"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:31:56.637Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"add","path":"/metadata/docs/4","value":{"path":"README.md","scope":"project","note":"History prefix gate and its Git requirement"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:31:56.637Z"}],"before_hash":"6f86c92b7e86be6592a966bb12f5608df2dc8ac9adc22ec432dbe66faea3e42e","after_hash":"199266289673d34d50d6fad32942e51af464c45a87905421303c7824b8b297f0","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"539ac65fb6d7b49be5f3662d864eef5e96ec4ce9ab7746f05768a0783efdb758"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:31:58.579Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/6","value":{"command":"node --test scripts/crash-history-prefix.test.mts","scope":"project","provenance":{"author":"codex-agent","created_at":"2026-10-25T02:31:58.455Z","source_kind":"local_mutation","source_ref":"feat/crash-consistency-harness"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:31:58.579Z"}],"before_hash":"199266289673d34d50d6fad32942e51af464c45a87905421303c7824b8b297f0","after_hash":"1f47198de91be3b0867f35cf84833bcd64b7aa2cdb7c7e4d177cc822e9ed9753","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"f1f9ddbbf0a27eac03042d58c9ead238aaec145112b540bf98bd46a2f002405d"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:32:00.646Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/35","value":{"created_at":"2026-10-25T02:32:00.645Z","author":"codex-agent","text":"Append-only correction complete: main item/history restored exactly, then 19 branch-only evidence comments and intended files/docs/tests/unblock rationale were re-recorded through the pinned CLI. Main records remain a byte-identical prefix. All existing main history streams pass the prefix audit; the branch-only oracle item was preserved unchanged. Added scripts/crash-history-prefix.mts to the release gate; it checks every changed history path, rejects replaced or deleted main bytes, and permits new item streams. New real-Git/PM fixture tests pass 2/2, including a plain tracker without a Git executable. Behavioral revert proof: disabling only the byte-prefix rejection yields exit 1 from the intended missing-exception assertion; exact source restoration passes 2/2. TypeScript and ESLint pass. A stale clone-only receipt from the rejected merge was quarantined outside active metadata, without repair/force/re-anchor; isolated-HOME pinned health passes with exit 0, ok true and no failing checks. Completed runtime crash/revert evidence is retained; only new prefix/health validation is rerun locally, with full exact-head CI still required."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:32:00.646Z"}],"before_hash":"1f47198de91be3b0867f35cf84833bcd64b7aa2cdb7c7e4d177cc822e9ed9753","after_hash":"7f4e36bf4f28284fc6a8e25c904c73f2f66b85f22529ab45ff741474fe26fd9c","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"0682fb8ecbd2b0572a21e35c62a22713372e5155d9aac180b04d01d8da477c75"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:35:59.401Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/36","value":{"created_at":"2026-10-25T02:35:59.401Z","author":"codex-agent","text":"Final pre-push audit: all 86 history streams present on main are byte-identical prefixes of their branch files; one branch-only oracle stream is unchanged. Main harness history has 37 original records, all preserved before the new PM events. The targeted linked prefix regression passes 2/2 with no failures, skips or empty runs. Default strict pinned health passes in isolated HOME; no active clone receipt remains. The optional full history audit reports existing mismatches for pm-rust-bj7a and pm-rust-unih; both item/history pairs are byte-for-byte identical to main and were left untouched. No main records or hash anchors were repaired. Completed runtime evidence is retained; the final pushed correction requires a fresh full CI matrix before promotion."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:35:59.401Z"}],"before_hash":"7f4e36bf4f28284fc6a8e25c904c73f2f66b85f22529ab45ff741474fe26fd9c","after_hash":"cf76e3d80deb0d5f974de35e7bf30eea10eaee6ac36dd45a37098b0d981a4740","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"134e7354e58ffccfcf5e4e77fcfc0815b03b0ff16bea8fd1e68bd0c9aec6974e"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:36:01.145Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:36:01.145Z"},{"op":"replace","path":"/metadata/status","value":"open"}],"before_hash":"cf76e3d80deb0d5f974de35e7bf30eea10eaee6ac36dd45a37098b0d981a4740","after_hash":"f4f4af9e67e9606d3e4e7e8218570ea905f2e6a2ba365c12fc13ad541bf6cab5","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"695c03832142f1f3356b2ef545aab6802648738952ddbd040f9b81870c3d9b21"} +{"hash_algorithm":"sha256","ts":"2026-10-25T02:36:01.308Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T02:36:01.308Z"}],"before_hash":"f4f4af9e67e9606d3e4e7e8218570ea905f2e6a2ba365c12fc13ad541bf6cab5","after_hash":"a5554608db333f5253533cd3306d58a465d69405cd33518e8fae92a4cf037fa6","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"f3c5f72170dd4efcfbf50b9c9675fbe34452f6ccd4bbb9d9aa5f967224ae3e98"} +{"hash_algorithm":"sha256","ts":"2026-10-25T07:10:30.008Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T07:10:30.008Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"a5554608db333f5253533cd3306d58a465d69405cd33518e8fae92a4cf037fa6","after_hash":"6f4f2bb30b450c1e0cb85825d197f725034bae464dd5c2f17e5ced7cf29806ab","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"deb8d6d2e99cc6e9f323ab0c40ab9413408714d36430b9047264dd3d4d9eda91"} +{"hash_algorithm":"sha256","ts":"2026-10-25T07:10:30.958Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T07:10:30.958Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"6f4f2bb30b450c1e0cb85825d197f725034bae464dd5c2f17e5ced7cf29806ab","after_hash":"cef8baa4d88a79ef13779cfa30795526a82995e4c10b0205a1e5938d0eddcf51","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"148079b563e28ef287321d905a9a2ec50912ba43a485930456d30b72b66047e5"} +{"hash_algorithm":"sha256","ts":"2026-10-25T07:10:31.684Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/37","value":{"created_at":"2026-10-25T07:10:31.684Z","author":"codex-agent","text":"Round-2 review reopened oracle correctness: replace seed-prefix/final-return checks with an exact transaction-owned PRE/POST oracle, and pair recovery cuts by observed journal commit phase instead of syscall ordinal. Add independent data-loss mutation and phase-equivalence controls, keep main history byte prefixes, and require fresh full release CI. Prior receipts remain historical and are superseded for these claims."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T07:10:31.684Z"}],"before_hash":"cef8baa4d88a79ef13779cfa30795526a82995e4c10b0205a1e5938d0eddcf51","after_hash":"ec6fcaaa12a31101f48d790cf8b7d1ff35a0d36512c07cff49518c78aa9656af","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a5d43bb491936a61f5ce9e84ad44e74eac3e14206ecbf920012dc32c7606dcc6"} +{"hash_algorithm":"sha256","ts":"2026-10-25T07:19:02.509Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/4/note","value":"Versioned public-copy measurements and independent behavioral control patches"},{"op":"replace","path":"/metadata/docs/4/path","value":"docs/CRASH_REVIEW_2026_10_23.json"},{"op":"replace","path":"/metadata/docs/3/note","value":"Independent behavioral negative controls"},{"op":"replace","path":"/metadata/docs/3/path","value":"docs/CRASH_REVERT_PROOF_2026_10_22.json"},{"op":"replace","path":"/metadata/docs/2/note","value":"Measured public tracker copy receipt"},{"op":"replace","path":"/metadata/docs/2/path","value":"docs/CRASH_PUBLIC_COPY_2026_10_22.json"},{"op":"remove","path":"/metadata/docs/1/note"},{"op":"replace","path":"/metadata/docs/1/path","value":"docs/CRASH_ORACLE_2026_10_25.json"},{"op":"add","path":"/metadata/docs/5","value":{"path":"README.md","scope":"project","note":"History prefix gate and its Git requirement"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T07:19:02.509Z"}],"before_hash":"ec6fcaaa12a31101f48d790cf8b7d1ff35a0d36512c07cff49518c78aa9656af","after_hash":"2400329ead449314ecb67317d5603641e0079ce4a2f5d34edaa3713c2a736afc","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"4c08abd567e737e21305c5f2c2b458eb60fc42a43af9d0c668ddc66b6f4548a1"} +{"hash_algorithm":"sha256","ts":"2026-10-25T07:19:03.553Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/7","value":{"command":"node --test scripts/crash-oracle.test.mts","scope":"project","provenance":{"author":"codex-agent","created_at":"2026-10-25T07:19:03.496Z","source_kind":"local_mutation","source_ref":"feat/crash-consistency-harness"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T07:19:03.553Z"}],"before_hash":"2400329ead449314ecb67317d5603641e0079ce4a2f5d34edaa3713c2a736afc","after_hash":"f9558ec85286ad92735b263eab813c36fa8e5e3b94b3be2e7869c30b5ef8252b","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"abf8e26afb557eb9b086a42edf6136d85eec54b946e5fb02cd5dbb1a681be5ef"} +{"hash_algorithm":"sha256","ts":"2026-10-25T07:19:41.350Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/9/note","value":"Permanent native and published replays plus CLI and scratch-budget regressions"},{"op":"replace","path":"/metadata/files/9/path","value":"scripts/crash-review.test.mts"},{"op":"replace","path":"/metadata/files/8/note","value":"Reproducible control patches and public-copy receipt"},{"op":"replace","path":"/metadata/files/8/path","value":"scripts/crash-review-proof.mts"},{"op":"replace","path":"/metadata/files/7/note","value":"Real bounded syscall kill adapters"},{"op":"replace","path":"/metadata/files/7/path","value":"scripts/crash-process.mts"},{"op":"replace","path":"/metadata/files/6/note","value":"Strict bounded TOON formatter with unique tabular failure keys"},{"op":"replace","path":"/metadata/files/6/path","value":"scripts/crash-output.mts"},{"op":"remove","path":"/metadata/files/5/note"},{"op":"replace","path":"/metadata/files/5/path","value":"scripts/crash-oracle.mts"},{"op":"add","path":"/metadata/files/10","value":{"path":"scripts/crash-storage.mts","scope":"project","note":"Byte inventories and immutable history checks"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T07:19:41.350Z"}],"before_hash":"f9558ec85286ad92735b263eab813c36fa8e5e3b94b3be2e7869c30b5ef8252b","after_hash":"8741c11458efbc55191c2df32c1956c7952401975ff998d91213b353de31b221","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"eec525a8a3511cbc2888490b5e88c40fc7d57dbab3dadb91de1920133b84659b"} +{"hash_algorithm":"sha256","ts":"2026-10-25T07:19:42.197Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/10/note","value":"Permanent native and published replays plus CLI and scratch-budget regressions"},{"op":"replace","path":"/metadata/files/10/path","value":"scripts/crash-review.test.mts"},{"op":"replace","path":"/metadata/files/9/note","value":"Reproducible control patches and public-copy receipt"},{"op":"replace","path":"/metadata/files/9/path","value":"scripts/crash-review-proof.mts"},{"op":"replace","path":"/metadata/files/8/note","value":"Real bounded syscall kill adapters"},{"op":"replace","path":"/metadata/files/8/path","value":"scripts/crash-process.mts"},{"op":"replace","path":"/metadata/files/7/note","value":"Strict bounded TOON formatter with unique tabular failure keys"},{"op":"replace","path":"/metadata/files/7/path","value":"scripts/crash-output.mts"},{"op":"remove","path":"/metadata/files/6/note"},{"op":"replace","path":"/metadata/files/6/path","value":"scripts/crash-oracle.test.mts"},{"op":"add","path":"/metadata/files/11","value":{"path":"scripts/crash-storage.mts","scope":"project","note":"Byte inventories and immutable history checks"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T07:19:42.197Z"}],"before_hash":"8741c11458efbc55191c2df32c1956c7952401975ff998d91213b353de31b221","after_hash":"a3042173e5242a77fa93baf07e217735885fccc42bfa2fc19e4402d5e5a525cd","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"403fb5d73898a80fc6fdba2cd7b8f0625048d178540e3256c7d2f1b239bb80fc"} +{"hash_algorithm":"sha256","ts":"2026-10-25T07:19:42.999Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/11/note","value":"Permanent native and published replays plus CLI and scratch-budget regressions"},{"op":"replace","path":"/metadata/files/11/path","value":"scripts/crash-review.test.mts"},{"op":"replace","path":"/metadata/files/10/note","value":"Reproducible control patches and public-copy receipt"},{"op":"replace","path":"/metadata/files/10/path","value":"scripts/crash-review-proof.mts"},{"op":"replace","path":"/metadata/files/9/note","value":"Real bounded syscall kill adapters"},{"op":"replace","path":"/metadata/files/9/path","value":"scripts/crash-process.mts"},{"op":"replace","path":"/metadata/files/8/note","value":"Strict bounded TOON formatter with unique tabular failure keys"},{"op":"replace","path":"/metadata/files/8/path","value":"scripts/crash-output.mts"},{"op":"remove","path":"/metadata/files/7/note"},{"op":"replace","path":"/metadata/files/7/path","value":"scripts/crash-oracle.test.mts"},{"op":"replace","path":"/metadata/files/6/path","value":"scripts/crash-oracle.mts"},{"op":"replace","path":"/metadata/files/5/path","value":"scripts/crash-oracle-proof.mts"},{"op":"add","path":"/metadata/files/12","value":{"path":"scripts/crash-storage.mts","scope":"project","note":"Byte inventories and immutable history checks"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T07:19:42.999Z"}],"before_hash":"a3042173e5242a77fa93baf07e217735885fccc42bfa2fc19e4402d5e5a525cd","after_hash":"721ee287d84c8f8d9bc26ed082d271a6f800436e02fb4888f2fed11d265bbcd7","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"0da3240ed20a30c5668b45e4760937a099ea1f4e7a408d6922c6f48eeabd1c9d"} +{"hash_algorithm":"sha256","ts":"2026-10-25T07:22:44.291Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/38","value":{"created_at":"2026-10-25T07:22:44.290Z","author":"codex-agent","text":"Oracle correction and independent revert proofs: exactState compares the complete canonical inventory, all item bytes, every full history stream and pending journals against the phase-selected clean reference after restart and after return. PRE/POST selection is made from successful native journal publication or published item publication in the interrupted trace, including resumed calls; final returns now perform an actual priority change. Restoring seed-history-prefix-only acceptance fails the real-state mutation regressions and the live exit-zero item-deletion/event-truncation regressions (exit 1); restoring exact equality passes (exit 0). Restoring same-syscall/same-ordinal pairing fails phase parity (exit 1); restoring phase matching passes (exit 0). Applicable patches and both tables are in docs/controls/crash-oracle and docs/CRASH_ORACLE_2026_10_25.json. Core mutation table: four mutations times six real acknowledged states plus one live restart and one live return each, 32 killed and zero survived. Fresh public copy: 85 items, 176 files, 26 kills, 24 exact restart/return successes, two published history-open divergences, two minimized fixtures, unchanged source. Phase parity: 20 same-phase pairs, 10 pass, 10 differences all explained by those two independently failing published cases; no ordinal-alias false failures. All 26 seed acknowledgements/history prefixes remain preserved. Default pinned strict health passes; optional full audit retains the two main-identical bj7a/unih mismatches, untouched. Running the full linked harness and fresh CI next."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T07:22:44.291Z"}],"before_hash":"721ee287d84c8f8d9bc26ed082d271a6f800436e02fb4888f2fed11d265bbcd7","after_hash":"2aa2ae25391c92e6972c609cd591eafd907c70b56f4568221e1c164679d5e741","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"91a0f46b8a9791f1263d382313091abe5e53004b0cf8d9ad2eae951f88ad904c"} +{"hash_algorithm":"sha256","ts":"2026-10-25T07:26:30.802Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/39","value":{"created_at":"2026-10-25T07:26:30.802Z","author":"codex-agent","text":"Linked full harness validation passed: pm test --run --match test-concurrency=1 --progress --json ran node --test --test-concurrency=1 scripts/crash-*.test.mts, 50/50 passing with zero failures, skips or cancellations in 171 seconds. Strict TypeScript and ESLint pass. Removed the unused legacy permissive recoveredState helper so the active and unit-tested recovery path has one exact oracle; its replacement history-state regression also passes independently. Both live rename-1 cases now pass under different phases and are explicitly excluded from same-phase pairing. All 86 main streams remain raw byte prefixes; changed-history release gate passes. Default isolated pinned strict health passes; full audit remains blocked only on the two unchanged main items already recorded. Fresh full npm/Bun native release CI is still required on the pushed head."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T07:26:30.802Z"}],"before_hash":"2aa2ae25391c92e6972c609cd591eafd907c70b56f4568221e1c164679d5e741","after_hash":"f10a26b3442a4ffcb0db2a82aad6e3fd7186f7614cc3a315b34aada42ae9ba2c","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"9a13a561a77b7fa0e17526e3b69c039cd73e56adcca5d7416596e36e7698fca5"} +{"hash_algorithm":"sha256","ts":"2026-10-25T07:26:31.686Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T07:26:31.686Z"},{"op":"replace","path":"/metadata/status","value":"open"}],"before_hash":"f10a26b3442a4ffcb0db2a82aad6e3fd7186f7614cc3a315b34aada42ae9ba2c","after_hash":"5e9146b0b5f0e370196b3716239d54d735521e106d12397dd0c96bc392ac0880","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"097065b6e50b7d4154b1cff10e5b4c96be4035fd5b595b99f9f35450f175689b"} +{"hash_algorithm":"sha256","ts":"2026-10-25T07:26:31.736Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T07:26:31.736Z"}],"before_hash":"5e9146b0b5f0e370196b3716239d54d735521e106d12397dd0c96bc392ac0880","after_hash":"6ef5ef405c20c1425c98b71b3f4ddbca5e6071bfd6e95150a3f838d22d5d44af","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"02ca8af2353173f1fd1a85bda2846d67f6a938c1a39ba7f45ebd5e6e73a1cfd5"} diff --git a/.agents/pm/history/pm-rust-published-history-open.jsonl b/.agents/pm/history/pm-rust-published-history-open.jsonl new file mode 100644 index 0000000..48d5f50 --- /dev/null +++ b/.agents/pm/history/pm-rust-published-history-open.jsonl @@ -0,0 +1,6 @@ +{"hash_algorithm":"sha256","ts":"2026-10-24T23:28:02.986Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-rust-published-history-open"},{"op":"add","path":"/metadata/title","value":"Measure and track published oracle history-open crash divergence"},{"op":"add","path":"/metadata/description","value":"The locked published pm-cli 2026.10.21 can publish an item before appending its history. A history-path openat SIGKILL followed by a different mutation exits zero but leaves item/history bytes outside both complete reference states. The crash harness detects and retains this synthetic failure. Investigate current published behavior separately without changing the locked parity oracle or repairing original streams."},{"op":"add","path":"/metadata/type","value":"Task"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":["crash-consistency","follow-up","oracle"]},{"op":"add","path":"/metadata/created_at","value":"2026-10-24T23:28:02.986Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-10-24T23:28:02.986Z"},{"op":"add","path":"/metadata/author","value":"codex-agent"},{"op":"add","path":"/metadata/acceptance_criteria","value":"Replay both mutation families on versioned disposable non-git trackers; distinguish acknowledged-prefix preservation from interrupted-write atomicity; retain independent behavioral revert evidence for any future runtime fix; no original history rewrites."}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"5bd5cab903f58aca89826b7008b58eb5528326ca08f1afafb58a1f93d7385c86","item_hash_version":3,"message":"","context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"21c2337c5128c4fe2f96351c4f2a7bce1632f92e413dd7f9cf0c60d131d6974f"} +{"hash_algorithm":"sha256","ts":"2026-10-24T23:28:07.872Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-24T23:28:07.872Z"},{"op":"add","path":"/metadata/files","value":[{"path":"tests/fixtures/crash-review/published-history.json","scope":"project"}]}],"before_hash":"5bd5cab903f58aca89826b7008b58eb5528326ca08f1afafb58a1f93d7385c86","after_hash":"5c0c2d9a608bd947ccdc6f6e5302fdd8f1f963416444e4d91024c58396f1d8e5","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"e7873d331e7b173d211791ed3e5709a3ab2eaf4b99f79efd526f38464110bd53"} +{"hash_algorithm":"sha256","ts":"2026-10-24T23:28:12.293Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-24T23:28:12.293Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/CRASH_HARNESS.md","scope":"project"}]}],"before_hash":"5c0c2d9a608bd947ccdc6f6e5302fdd8f1f963416444e4d91024c58396f1d8e5","after_hash":"4b0175c99e102967036b078900d6ec0df006e42e50c2b3e96a0db5de5fabc6a8","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"e88f7095ab71128c4a4a1a493a67770f17d8bf9bf69fb3723bdd0a4f865af74c"} +{"hash_algorithm":"sha256","ts":"2026-10-24T23:35:50.997Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-24T23:35:50.997Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node --test --test-name-pattern=\"published history-open\" scripts/crash-review.test.mts","scope":"project","provenance":{"author":"codex-agent","created_at":"2026-10-24T23:35:50.919Z","source_kind":"local_mutation","source_ref":"feat/crash-consistency-harness"}}]}],"before_hash":"4b0175c99e102967036b078900d6ec0df006e42e50c2b3e96a0db5de5fabc6a8","after_hash":"26a421e83cf1920e65cc2e892debdb388c378de27aadf616940616b540cd0cb1","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"525b8dad060f9bce3ed5da3445d77e5d0f98e1726f9537164af1fb2d425cea72"} +{"hash_algorithm":"sha256","ts":"2026-10-24T23:49:15.458Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-24T23:49:15.458Z"},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-10-24T23:49:15.454Z","author":"codex-agent","text":"The complete 34-test Linux harness passes while explicitly detecting both version-pinned published history-open divergences. Public-copy measurements preserve all 26 acknowledged writes and history prefixes, but two interrupted writes diverge after exit-zero restart. Four differing paired outcomes and four synthetic reproductions are recorded in docs/CRASH_REVIEW_2026_10_23.json. This follow-up stays open; no runtime repair or oracle pin change is included."}]}],"before_hash":"26a421e83cf1920e65cc2e892debdb388c378de27aadf616940616b540cd0cb1","after_hash":"16053d3de859d45ee6e185db7ad2bd1be30a0c85781a206e3c6a945a7b1f20e0","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"310e6cec4ea857064e5ba1c99fe121d2e6fe23a6c2cf52a1fd38c99d7d85a4c1"} +{"hash_algorithm":"sha256","ts":"2026-10-24T23:51:09.155Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b901d62468c1f8f5717845ea","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-10-24T23:51:09.155Z","author":"codex-agent","text":"Its pinned-PM linked command also passes independently: one real published history-open replay regression, zero failed/canceled/skipped, preserving the expected durable_divergence finding. The runtime follow-up remains open."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-24T23:51:09.155Z"}],"before_hash":"16053d3de859d45ee6e185db7ad2bd1be30a0c85781a206e3c6a945a7b1f20e0","after_hash":"8b155ccff26107d7729668874c3b83705a40b5c778ec1751babb2a8d1aad3796","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"98ae775ed032b8d7f01dd856a1c6dc2333a7fc5399552d1371f7adaaad344a91"} diff --git a/.agents/pm/tasks/pm-rust-published-history-open.toon b/.agents/pm/tasks/pm-rust-published-history-open.toon new file mode 100644 index 0000000..97f5ff4 --- /dev/null +++ b/.agents/pm/tasks/pm-rust-published-history-open.toon @@ -0,0 +1,21 @@ +id: pm-rust-published-history-open +title: Measure and track published oracle history-open crash divergence +description: The locked published pm-cli 2026.10.21 can publish an item before appending its history. A history-path openat SIGKILL followed by a different mutation exits zero but leaves item/history bytes outside both complete reference states. The crash harness detects and retains this synthetic failure. Investigate current published behavior separately without changing the locked parity oracle or repairing original streams. +type: Task +status: open +priority: 2 +tags[3]: crash-consistency,follow-up,oracle +created_at: "2026-10-24T23:28:02.986Z" +updated_at: "2026-10-24T23:51:09.155Z" +author: codex-agent +acceptance_criteria: Replay both mutation families on versioned disposable non-git trackers; distinguish acknowledged-prefix preservation from interrupted-write atomicity; retain independent behavioral revert evidence for any future runtime fix; no original history rewrites. +comments[2]{created_at,author,text}: + "2026-10-24T23:49:15.454Z",codex-agent,"The complete 34-test Linux harness passes while explicitly detecting both version-pinned published history-open divergences. Public-copy measurements preserve all 26 acknowledged writes and history prefixes, but two interrupted writes diverge after exit-zero restart. Four differing paired outcomes and four synthetic reproductions are recorded in docs/CRASH_REVIEW_2026_10_23.json. This follow-up stays open; no runtime repair or oracle pin change is included." + "2026-10-24T23:51:09.155Z",codex-agent,"Its pinned-PM linked command also passes independently: one real published history-open replay regression, zero failed/canceled/skipped, preserving the expected durable_divergence finding. The runtime follow-up remains open." +files[1]{path,scope}: + tests/fixtures/crash-review/published-history.json,project +tests[1]{command,scope,provenance{author,created_at,source_kind,source_ref}}: + "node --test --test-name-pattern=\"published history-open\" scripts/crash-review.test.mts",project,codex-agent,"2026-10-24T23:35:50.919Z",local_mutation,feat/crash-consistency-harness +docs[1]{path,scope}: + docs/CRASH_HARNESS.md,project +body: "" diff --git a/README.md b/README.md index 70e150e..7e3892f 100644 --- a/README.md +++ b/README.md @@ -92,8 +92,8 @@ The TypeScript SDK in [`scripts/crash-harness.mts`](scripts/crash-harness.mts) and `just crash` compare real native processes with the locked pm-cli 2026.10.21 oracle. On Linux, strace injects SIGKILL at every declared per-task `rename` and `fsync` entry ordinal observed in uninterrupted update/comment reference runs. -Each case starts after an acknowledged synthetic create, restarts through the -same operation family, and checks exact item/history bytes, immutable history +Each case starts after an acknowledged synthetic create, restarts through a +different operation and returns to the original one, and checks exact item/history bytes, immutable history prefixes and recovery receipts. These commands work in plain directories without a Git executable. The source tracker is read only; all mutations use disposable non-git clones. @@ -318,3 +318,12 @@ with `cargo build --locked --example native_adapter`, then pass an explicitly authorized tracker directory as its argument and one `AdapterRequest` on stdin. Replace its `exchange` implementation with the existing authorized transport when embedding against a remote backend. The example grants only get and list. + +The expanded crash corpus includes history-path `openat` cuts and native runtime +journals. Historical same-operation receipts do not establish complete recovery +conformance; the locked published oracle still has measured history-open failures. + +The repository check `node scripts/crash-history-prefix.mts` requires Git and +compares every changed history stream with `origin/main` as exact bytes. Main +history must remain a prefix; new item streams are permitted. Tracker commands +and `just crash` continue to work in plain directories without Git. diff --git a/docs/CRASH_HARNESS.md b/docs/CRASH_HARNESS.md index ee59d4d..be3f83e 100644 --- a/docs/CRASH_HARNESS.md +++ b/docs/CRASH_HARNESS.md @@ -31,29 +31,40 @@ console.log(receipt.ok, receipt.killed, receipt.parity); // the whitelisted scenario/implementation/syscall/ordinal, never stored commands. // Exception: kind: 'baseline_parity' replays the scenario across both implementations // and all their observed boundaries, rather than selecting a single case. +// A recovery_parity manifest likewise replays its complete paired scenario. // replayCrashFailure(options, '.crash-failures/failure-example/case.json'); ``` Each fixture has one synthetic Task and its acknowledged create history. Update changes its description; comment appends a synthetic comment. Restart -re-enters update with the acknowledged priority, or comment with a distinct -sentinel. Both uninterrupted alternatives (before/committed) run that identical -restart command. No history hash, patch, receipt or existing stream is normalized -or repaired. Item and history bytes must match one complete reference state; +uses a different operation: update is followed by a comment sentinel; comment +is followed by a description update. It then returns to the original operation +to detect a stranded journal that a successful different operation concealed. Both uninterrupted alternatives (PRE/POST) run that identical +restart command and the same final return. The final update changes priority to 2 +so it produces an acknowledged event rather than a no-op. No history hash, patch, receipt or existing stream is normalized +or repaired. The observed transaction phase selects exactly one reference; all canonical +item bytes and complete history files must match it after restart and return; each implementation's raw restart receipt must match its corresponding reference. The cross-runtime acknowledgement projection is explicitly update `id/status` or comment `id/comments`, because native mutation commands emit full legacy JSON while the published CLI emits flat mutation or collection receipts. Durable item/history comparisons remain exact bytes. -The declared boundaries are all observed task-local entry ordinals of `rename` -and `fsync` for each runtime/scenario, up to the configured maximum. A zero +The declared boundaries are all observed task-local entry ordinals of +`rename` and `fsync`, up to the configured maximum. Child processes set +`UV_THREADPOOL_SIZE=1` so successive published publications use one libuv worker +and their observed ordinals remain reproducible. Cache renames remain in scope; +this configuration does not certify other worker-pool sizes. An additional +`openat` ordinal 1 cut is traced with strace `-P` scoped to the item history +stream, including published execution after item publication but before history +append. strace ordinals count per thread; libuv worker assignment does not make +a rename cut equivalent to a history-open cut. A zero syscall count is reported, and a missing requested boundary or truncated matrix refuses. A kill is counted only when the trace shows an interrupted selected syscall and a fatal SIGKILL. strace kills remaining tracees on controller death; commands also have time and output bounds. The corpus does not cover every syscall, torn kernel writes, filesystem/power failures, network backends or -cross-runtime journal recovery. Socket/event-loop `write` calls are excluded: +cross-runtime replay of another implementation's journal format. Socket/event-loop `write` calls are excluded: they do not provide stable storage boundaries in Node's worker scheduler. Public tracker validation takes a stable regular-file copy of a publicly @@ -66,8 +77,17 @@ just crash --native target/debug/pm-rust --artifacts .crash-failures \ --replay .crash-failures/failure-example/case.json --json ``` -Root caches (`runtime`, `locks`, `transactions`, `checkpoints`, `search`) are -excluded from the authoritative copy. Nested names remain authoritative. Regular +Root caches (`locks`, `transactions`, `checkpoints`, `search`) are +excluded from the authoritative copy. The complete `runtime/` tree is captured, +including native `runtime/transactions/` recovery intent. The exact state oracle +excludes only the derived `runtime/context-usage.jsonl` access log, +`runtime/metadata-cache-delta.json` metadata cache and private +atomic-write staging names (`.*.tmp`), in addition to the root caches above. +Other runtime files, all config/schema files, all items, every complete history +stream and canonical pending journals remain in the exact inventory. Pending +transaction bytes are retained at kill, after restart and after returning to the +original operation. Staging garbage is outside this canonical-state contract; +this is a process-crash test, not a power-loss durability certificate. Any pending journal fails the case. Nested names remain authoritative. Regular config/schema files, items and history streams are copied byte-for-byte; symlinks and special files refuse. Output inside the input tracker refuses, including symlink aliases. Source fingerprints are checked again after execution. No raw @@ -86,12 +106,93 @@ authoritative files. All 20 real kills preserve acknowledged item bytes and history prefixes, both baseline byte/acknowledgement comparisons pass, and 18 restart state/receipt comparisons pass. Two native first-fsync lock-initialization kills refuse restart with exit 4; both reproduce on minimal synthetic fixtures. -The source fingerprint remains unchanged. The safe recovery policy is tracked -in `pm-rust-crash-lock-restart`. That receipt records the original failures before -the recovery fix; it remains unchanged as historical evidence. -Four [behavioral negative controls](CRASH_REVERT_PROOF_2026_10_22.json) +The source fingerprint remains unchanged. The native lock recovery fix is now integrated from main; the receipt above +remains historical. Complete cross-runtime crash conformance remains unproven. Four [behavioral negative controls](CRASH_REVERT_PROOF_2026_10_22.json) fail their regression with the production invariant disabled and pass restored. +Exact-head CI evidence is recorded in the PR. +Full-gate success tests the harness implementation and existing package contracts; +it does not turn a failed crash conformance report into runtime approval. + +## Orchestrator review correction + +The historical receipts above excluded runtime journals and used same-operation +restart. They remain immutable and do not establish cross-operation conformance. +The current corpus records pending journals and tests a different operation plus +return to the original one. Main now includes the separate `pm-rust-cross-operation-journal` fix as well +as first-fsync lock recovery. Permanent live rename-1 replays require the other +operation to drain the journal and the original operation to succeed afterward. +The locked published oracle still diverges at history-open cuts; that versioned +behavior is tracked separately by `pm-rust-published-history-open`. + +Recovered canonical bytes, shared receipt projections, states and pending +journals are paired by **transaction phase**, never syscall ordinal. Every pair +within the same phase is compared; unequal counts and different syscall classes +are allowed. A phase with cuts in only one runtime is explicitly unpaired in +`phaseCoverage`, with no cross-runtime claim. A mismatch fails the report. + +The phase labels come from the interrupted process trace, before recovery: + +| Phase | Evidence | Required recovery | +| --- | --- | --- | +| `before-commit` | No successful commit publication | Exact PRE | +| `after-commit` | Native journal hard-link publication, or published canonical item rename | Exact POST | +| `during-cleanup` | Successful history write after publication | Exact POST | + +The path-filtered history-open cut independently identifies the append/write +open that follows publication; read opens do not establish a commit. Successful +`link`/`rename` results, including resumed strace calls, establish publication; +failed calls and cache renames do not. This policy describes the pinned update +and comment implementations, not arbitrary future transaction protocols. + +Recovery is triggered by a different acknowledged operation, so comparisons use +clean `restart(PRE)` or `restart(POST)` references. Final returns use the matching +clean `return(restart(...))` reference. Thus neither the restart event nor a +field changed by the final operation can disappear behind a seed-history prefix. +The same `exactState` function checks both; exact filenames, file counts, and +bytes determine equality, without parsing, sorting, or repairing history. +Synthetic failures retain expected restart/return and actual returned states. + +`node --test scripts/crash-oracle.test.mts` runs real plain-directory tracker +fixtures plus Linux child-process mutations. It kills item deletion, final-event +truncation, field removal and history reordering at recovery and return. Phase +regressions accept equivalent cuts with different ordinals and exclude identical +ordinals from different phases. `node scripts/crash-oracle-proof.mts` records +independent seed-prefix and ordinal-pairing behavioral reverts, a mutation table, +a phase-equivalence table, and a fresh public-copy report in +[the phase-oracle receipt](CRASH_ORACLE_2026_10_25.json). Earlier receipts remain +historical and their old ordinal mismatches are superseded by this measurement. + +The metadata constructor and Date.now() are both frozen at CRASH_CLOCK. This also +freezes published lock TTL ages, Date.now-based wait budgets and stale-gate age +calculations (which may be negative against real file timestamps). performance.now() +and the harness's external process deadline remain real. The clock policy is +included in every report. No elapsed-time, stale-gate or TTL parity is certified. + +Permanent independent update/comment rename manifests and a published history-open +manifest live in `tests/fixtures/crash-review/`. Their tests always run on Linux; +they never depend on the full corpus finding another failure. Fixing first-fsync +recovery therefore cannot silently remove replay coverage. The locked oracle is +2026.10.21. Reported empty-lock recovery in 2026.10.22 is outside that pin; the +first-fsync item must not imply current published-release parity without a +separate versioned measurement. Dependency pins are unchanged. + +A synthetic reduction refusal is secondary evidence. It is attached to the +already measured failure; the CLI retains exit 1, the original cases and the +unchanged-source result, rather than replacing them with a setup refusal exit 2. + +Reproduce review evidence with `node scripts/crash-review-proof.mts` after the +recorded source commit is checked out, the locked oracle/tools installed and the +native executable rebuilt. This Git-dependent evidence recorder explicitly +refuses a missing repository; `just crash` still requires no Git. The new receipt +`docs/CRASH_REVIEW_2026_10_23.json` records the code commit, public tracker commit, +source hashes, exact toolchain versions, build/reproduction commands and exact +negative-control patches under `docs/controls/crash-review/`. Each patch is +applied independently, must fail its regression, and is restored byte-for-byte +before the passing control. Original receipts are not rewritten. + +## Integrated native recovery + The recovery fix permits an unexpired empty publication gate to be reclaimed only while holding its kernel lease and after confirming the lock's original process is dead on the same Linux host/namespace. The lock payload is already complete at @@ -112,9 +213,8 @@ just crash --native target/debug/pm-rust --artifacts .crash-failures \ The fixtures contain only the whitelisted selection and minimal synthetic settings. The locked oracle creates their acknowledged seed, and each real injected kill must restart successfully with exact reference item/history bytes -and the corresponding raw restart receipt. The full Linux regression now requires -every measured boundary to pass; expected native restart failures are no longer -allowed. Separate ownership JSON refusal comparisons on the shared gate path +and the corresponding raw restart receipt. The permanent native first-fsync regressions require successful recovery. +The expanded corpus separately reports published history-open divergences. Separate ownership JSON refusal comparisons on the shared gate path retain the oracle's complete error receipt and authoritative bytes. The no-git contention contract runs 50 simultaneous writers, three comments each, and verifies all 150 comments and the history chain. @@ -127,14 +227,3 @@ per-process timeout was used for this local run; the SDK default remains 15000 m The [rebuild-based revert proof](CRASH_RESTART_REVERT_PROOF_2026_10_22.json) replaces only the recovery function with its original implementation: both permanent replays fail with restart exit 4, then both pass after restoration. - -Pre-existing native comment lock-conflict diagnostic differences are tracked in -`pm-rust-comment-lock-receipt`: admission and bytes agree, but detail, guidance and -the refusal surface label differ. This corpus uses each runtime's own raw restart -reference and the declared shared acknowledgement projection; it does not certify -every CLI diagnostic surface. - -Exact-head recovery CI evidence, including all platform test and coverage counts, -is recorded in [PR #105](https://github.com/unbraind/pm-rust/pull/105). -Full-gate success tests the harness implementation and existing package contracts; -it does not establish power-loss durability or coverage of unmeasured syscalls. diff --git a/docs/CRASH_ORACLE_2026_10_25.json b/docs/CRASH_ORACLE_2026_10_25.json new file mode 100644 index 0000000..0f7f4f0 --- /dev/null +++ b/docs/CRASH_ORACLE_2026_10_25.json @@ -0,0 +1,1131 @@ +{ + "schema": "pm-rust/crash-oracle-v1", + "publicTrackerCommit": "e9b88ab368d5854ec541bbd41ed4e2f5dc0ee84a", + "sourceFiles": { + "scripts/crash-oracle.mts": "5f1f9dfde89ef38adc2c8191dfb86b06dc52a191b0db1b1aab89179979fe5a86", + "scripts/crash-oracle.test.mts": "f2e6ad48789bb121d518eaa22958326d6a79c9cdfcce970b5a4eb9905de6a20f", + "scripts/crash-harness.mts": "ff93ee020e2edf403057acaee00a49dd454e21384e98f207727dab9000725c7b", + "scripts/crash-process.mts": "0f728090b13d421d17cc68e8bcaea925fdd3eb5269ef648ef917bd33b4c34ffb" + }, + "definition": "Exact canonical tracker inventory and bytes, including every complete history and pending journal; phase chooses the clean PRE or POST plus the acknowledged restart and return operations.", + "phases": [ + "before-commit", + "after-commit", + "during-cleanup" + ], + "mutations": [ + { + "mutation": "delete-item", + "realStateChecks": 6, + "realStateKilled": 6, + "liveRestartKilled": 1, + "liveReturnKilled": 1, + "survived": 0 + }, + { + "mutation": "truncate-event", + "realStateChecks": 6, + "realStateKilled": 6, + "liveRestartKilled": 1, + "liveReturnKilled": 1, + "survived": 0 + }, + { + "mutation": "drop-field", + "realStateChecks": 6, + "realStateKilled": 6, + "liveRestartKilled": 1, + "liveReturnKilled": 1, + "survived": 0 + }, + { + "mutation": "reorder-history", + "realStateChecks": 6, + "realStateKilled": 6, + "liveRestartKilled": 1, + "liveReturnKilled": 1, + "survived": 0 + } + ], + "equivalence": [ + { + "phase": "before-commit", + "nativeCut": "fsync/1", + "publishedCut": "rename/1", + "pass": true + }, + { + "phase": "after-commit", + "nativeCut": "rename/1", + "publishedCut": "openat/9", + "pass": true + }, + { + "phase": "after-commit", + "nativeCut": "rename/1", + "publishedCut": "rename/2", + "pass": true + }, + { + "phase": "during-cleanup", + "nativeCut": "fsync/6", + "publishedCut": "rename/12", + "pass": true + } + ], + "equivalenceNote": "Synthetic phase-key regression; live measured pairs and unpaired phase counts are in publicCopy.", + "proofs": [ + { + "name": "exact-state", + "file": "scripts/crash-oracle.mts", + "sourceSha256": "5f1f9dfde89ef38adc2c8191dfb86b06dc52a191b0db1b1aab89179979fe5a86", + "patch": "docs/controls/crash-oracle/exact-state.patch", + "patchSha256": "a4043a50e4f65538576276cf81a7cb69dfccbca7c624d2aca2d13203d8742636", + "command": [ + "node", + "--test", + "--test-name-pattern=exact state oracle kills all|live exact oracle kills return (delete-item|truncate-event)", + "scripts/crash-oracle.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "phase-pairing", + "file": "scripts/crash-oracle.mts", + "sourceSha256": "5f1f9dfde89ef38adc2c8191dfb86b06dc52a191b0db1b1aab89179979fe5a86", + "patch": "docs/controls/crash-oracle/phase-pairing.patch", + "patchSha256": "3114a78eca501512cf30db807dd6e8dee41a5bfd144c0486d17a162d633d8123", + "command": [ + "node", + "--test", + "--test-name-pattern=phase parity", + "scripts/crash-oracle.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + } + ], + "publicCopy": { + "schema": "pm-rust/crash-v1", + "ok": false, + "oracleVersion": "2026.10.21", + "nativeSha256": "cfd5598c3c957ca0cb7ed47636ba6662d0727ba5dfd5a2cddf12beff701a6e0c", + "sourceFiles": 176, + "sourceItems": 85, + "sourceSha256": "a1ed87dcbf95d4bf7c48348bceb91b7710b0db7b8071461b48828ac5cc49011e", + "sourceUnchanged": true, + "acknowledgedComparisons": 2, + "killed": 26, + "boundaries": [ + { + "scenario": "update", + "implementation": "native", + "syscall": "rename", + "count": 1 + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "count": 8 + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "openat", + "count": 1 + }, + { + "scenario": "update", + "implementation": "published", + "syscall": "rename", + "count": 2 + }, + { + "scenario": "update", + "implementation": "published", + "syscall": "fsync", + "count": 0 + }, + { + "scenario": "update", + "implementation": "published", + "syscall": "openat", + "count": 1 + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "rename", + "count": 1 + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "count": 8 + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "openat", + "count": 1 + }, + { + "scenario": "comment", + "implementation": "published", + "syscall": "rename", + "count": 2 + }, + { + "scenario": "comment", + "implementation": "published", + "syscall": "fsync", + "count": 0 + }, + { + "scenario": "comment", + "implementation": "published", + "syscall": "openat", + "count": 1 + } + ], + "cases": [ + { + "scenario": "update", + "implementation": "native", + "syscall": "rename", + "boundary": 1, + "phase": "after-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 1, + "phase": "before-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "before", + "durableSha256": "bbfa1f48b522b71d7232fc1cbf4ea8d65e0a4a7acc05bfc8265e9c41832a3859", + "receiptSha256": "f0c3e717500261f6cee7d8b0e19bfd9a5da3594e4745baa54c576341ddce2e47", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 2, + "phase": "before-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "before", + "durableSha256": "bbfa1f48b522b71d7232fc1cbf4ea8d65e0a4a7acc05bfc8265e9c41832a3859", + "receiptSha256": "f0c3e717500261f6cee7d8b0e19bfd9a5da3594e4745baa54c576341ddce2e47", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 3, + "phase": "after-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 4, + "phase": "after-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 5, + "phase": "after-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 6, + "phase": "during-cleanup", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 7, + "phase": "during-cleanup", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 8, + "phase": "during-cleanup", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "openat", + "boundary": 1, + "phase": "after-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "published", + "syscall": "rename", + "boundary": 1, + "phase": "before-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "before", + "durableSha256": "bbfa1f48b522b71d7232fc1cbf4ea8d65e0a4a7acc05bfc8265e9c41832a3859", + "receiptSha256": "4079f1dc3ff9abce9c03bcbea8ca4a6e8f5589c1b9e3d460e085f0f833fb72af", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "published", + "syscall": "rename", + "boundary": 2, + "phase": "during-cleanup", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "4079f1dc3ff9abce9c03bcbea8ca4a6e8f5589c1b9e3d460e085f0f833fb72af", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "published", + "syscall": "openat", + "boundary": 1, + "phase": "after-commit", + "restartExact": false, + "returnExact": false, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "diverged", + "durableSha256": "2b2fcad3b3dfdbf4c91eb54a50eeff5c0a98c200c9a0d56bdbc0522324ab7cdd", + "receiptSha256": "4079f1dc3ff9abce9c03bcbea8ca4a6e8f5589c1b9e3d460e085f0f833fb72af", + "receiptMatches": false, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": false, + "failure": { + "code": "durable_divergence", + "remedy": "Replay the retained synthetic case and inspect its lock, journal, bytes and receipt; preserve all original history. Runtime repairs need separate implementation work." + } + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "rename", + "boundary": 1, + "phase": "after-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 1, + "phase": "before-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "before", + "durableSha256": "6612f75d37328944dec0e55af965c79e9c503dd0c999dd7f46e5f60951771e02", + "receiptSha256": "453857b3b6d80eca9ab7cceda848c5f592c3da596e7d93bb16b478386148781c", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 2, + "phase": "before-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "before", + "durableSha256": "6612f75d37328944dec0e55af965c79e9c503dd0c999dd7f46e5f60951771e02", + "receiptSha256": "453857b3b6d80eca9ab7cceda848c5f592c3da596e7d93bb16b478386148781c", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 3, + "phase": "after-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 4, + "phase": "after-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 5, + "phase": "after-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 6, + "phase": "during-cleanup", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 7, + "phase": "during-cleanup", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 8, + "phase": "during-cleanup", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "openat", + "boundary": 1, + "phase": "after-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "published", + "syscall": "rename", + "boundary": 1, + "phase": "before-commit", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "before", + "durableSha256": "6612f75d37328944dec0e55af965c79e9c503dd0c999dd7f46e5f60951771e02", + "receiptSha256": "7d05462db0414128a712202ce356260d614b8684ef9df6026a5ec8da275347c5", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "published", + "syscall": "rename", + "boundary": 2, + "phase": "during-cleanup", + "restartExact": true, + "returnExact": true, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "7d05462db0414128a712202ce356260d614b8684ef9df6026a5ec8da275347c5", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "published", + "syscall": "openat", + "boundary": 1, + "phase": "after-commit", + "restartExact": false, + "returnExact": false, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "diverged", + "durableSha256": "cef5854a65ccc484905fe47fad5002b06d0a322178f0fc7f998fd724ee62dc90", + "receiptSha256": "7d05462db0414128a712202ce356260d614b8684ef9df6026a5ec8da275347c5", + "receiptMatches": false, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": false, + "failure": { + "code": "durable_divergence", + "remedy": "Replay the retained synthetic case and inspect its lock, journal, bytes and receipt; preserve all original history. Runtime repairs need separate implementation work." + } + } + ], + "failuresRetained": 2, + "parity": [ + { + "scenario": "update", + "bytes": true, + "acknowledgement": true + }, + { + "scenario": "comment", + "bytes": true, + "acknowledgement": true + } + ], + "recoveryParity": [ + { + "scenario": "update", + "syscall": "rename", + "boundary": 1, + "phase": "after-commit", + "publishedSyscall": "openat", + "publishedBoundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + }, + { + "scenario": "update", + "syscall": "fsync", + "boundary": 1, + "phase": "before-commit", + "publishedSyscall": "rename", + "publishedBoundary": 1, + "bytes": true, + "receipt": true, + "state": true, + "journals": true, + "ok": true + }, + { + "scenario": "update", + "syscall": "fsync", + "boundary": 2, + "phase": "before-commit", + "publishedSyscall": "rename", + "publishedBoundary": 1, + "bytes": true, + "receipt": true, + "state": true, + "journals": true, + "ok": true + }, + { + "scenario": "update", + "syscall": "fsync", + "boundary": 3, + "phase": "after-commit", + "publishedSyscall": "openat", + "publishedBoundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + }, + { + "scenario": "update", + "syscall": "fsync", + "boundary": 4, + "phase": "after-commit", + "publishedSyscall": "openat", + "publishedBoundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + }, + { + "scenario": "update", + "syscall": "fsync", + "boundary": 5, + "phase": "after-commit", + "publishedSyscall": "openat", + "publishedBoundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + }, + { + "scenario": "update", + "syscall": "fsync", + "boundary": 6, + "phase": "during-cleanup", + "publishedSyscall": "rename", + "publishedBoundary": 2, + "bytes": true, + "receipt": true, + "state": true, + "journals": true, + "ok": true + }, + { + "scenario": "update", + "syscall": "fsync", + "boundary": 7, + "phase": "during-cleanup", + "publishedSyscall": "rename", + "publishedBoundary": 2, + "bytes": true, + "receipt": true, + "state": true, + "journals": true, + "ok": true + }, + { + "scenario": "update", + "syscall": "fsync", + "boundary": 8, + "phase": "during-cleanup", + "publishedSyscall": "rename", + "publishedBoundary": 2, + "bytes": true, + "receipt": true, + "state": true, + "journals": true, + "ok": true + }, + { + "scenario": "update", + "syscall": "openat", + "boundary": 1, + "phase": "after-commit", + "publishedSyscall": "openat", + "publishedBoundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + }, + { + "scenario": "comment", + "syscall": "rename", + "boundary": 1, + "phase": "after-commit", + "publishedSyscall": "openat", + "publishedBoundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + }, + { + "scenario": "comment", + "syscall": "fsync", + "boundary": 1, + "phase": "before-commit", + "publishedSyscall": "rename", + "publishedBoundary": 1, + "bytes": true, + "receipt": true, + "state": true, + "journals": true, + "ok": true + }, + { + "scenario": "comment", + "syscall": "fsync", + "boundary": 2, + "phase": "before-commit", + "publishedSyscall": "rename", + "publishedBoundary": 1, + "bytes": true, + "receipt": true, + "state": true, + "journals": true, + "ok": true + }, + { + "scenario": "comment", + "syscall": "fsync", + "boundary": 3, + "phase": "after-commit", + "publishedSyscall": "openat", + "publishedBoundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + }, + { + "scenario": "comment", + "syscall": "fsync", + "boundary": 4, + "phase": "after-commit", + "publishedSyscall": "openat", + "publishedBoundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + }, + { + "scenario": "comment", + "syscall": "fsync", + "boundary": 5, + "phase": "after-commit", + "publishedSyscall": "openat", + "publishedBoundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + }, + { + "scenario": "comment", + "syscall": "fsync", + "boundary": 6, + "phase": "during-cleanup", + "publishedSyscall": "rename", + "publishedBoundary": 2, + "bytes": true, + "receipt": true, + "state": true, + "journals": true, + "ok": true + }, + { + "scenario": "comment", + "syscall": "fsync", + "boundary": 7, + "phase": "during-cleanup", + "publishedSyscall": "rename", + "publishedBoundary": 2, + "bytes": true, + "receipt": true, + "state": true, + "journals": true, + "ok": true + }, + { + "scenario": "comment", + "syscall": "fsync", + "boundary": 8, + "phase": "during-cleanup", + "publishedSyscall": "rename", + "publishedBoundary": 2, + "bytes": true, + "receipt": true, + "state": true, + "journals": true, + "ok": true + }, + { + "scenario": "comment", + "syscall": "openat", + "boundary": 1, + "phase": "after-commit", + "publishedSyscall": "openat", + "publishedBoundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + } + ], + "phaseCoverage": [ + { + "scenario": "update", + "phase": "before-commit", + "native": 2, + "published": 1, + "paired": true + }, + { + "scenario": "update", + "phase": "after-commit", + "native": 5, + "published": 1, + "paired": true + }, + { + "scenario": "update", + "phase": "during-cleanup", + "native": 3, + "published": 1, + "paired": true + }, + { + "scenario": "comment", + "phase": "before-commit", + "native": 2, + "published": 1, + "paired": true + }, + { + "scenario": "comment", + "phase": "after-commit", + "native": 5, + "published": 1, + "paired": true + }, + { + "scenario": "comment", + "phase": "during-cleanup", + "native": 3, + "published": 1, + "paired": true + } + ], + "clock": { + "metadata": "2026-10-21T12:00:00.000Z", + "dateNow": "fixed", + "performanceNow": "real", + "limitation": "Published Date.now lock TTL/wait ages are frozen; only the real external timeout bounds those waits. This corpus does not certify elapsed-time or stale-gate parity." + }, + "reduction": { + "status": "completed" + } + } +} diff --git a/docs/CRASH_REVIEW_2026_10_23.json b/docs/CRASH_REVIEW_2026_10_23.json new file mode 100644 index 0000000..1dadfb0 --- /dev/null +++ b/docs/CRASH_REVIEW_2026_10_23.json @@ -0,0 +1,972 @@ +{ + "schema": "pm-rust/crash-review-v1", + "provenance": { + "sourceRepository": "https://github.com/unbraind/pm-rust", + "sourceCommit": "5f6664f78a6701f552142d9aee286515e71322bb", + "publicTrackerCommit": "e9b88ab368d5854ec541bbd41ed4e2f5dc0ee84a", + "sourceFiles": { + "Cargo.lock": "5499fc4eb8fed36d2488701cfba02b6879f78040846851dfc4a63ac4295d07ee", + "Cargo.toml": "af19a32a77cb4d8bb43da470ad22ba42ad0ba7556810895cc516b92d22b1489a", + "README.md": "eb05260080bed91dabc78fd1034f461e80d04055254842f9d6fc372eb80f3079", + "docs/CRASH_HARNESS.md": "0c0d722269837de6ca3645c2eb5efce05be3575ab0b845af69240ec6937ec98d", + "justfile": "ee100f7692b55a21230a3d45e220d08d000cdcd0977bdd16e7cb13042ae042b4", + "rust-toolchain.toml": "d04f655906d1d680c28e0e4ba55bdbe8aad931766b1f9f392a6acbbf69d8a2fd", + "scripts/crash-cli.mts": "ad93e4ef39b31fb7d6617aa0b520365b678601d9c1ffc9eeb7e39ab203dda47f", + "scripts/crash-clock.mts": "aa001dd0b3ce57c073875bbc94589ac83e655b78ea4a72eac992fc9b91df21fb", + "scripts/crash-harness.mts": "7e30d3efebbe7166cb819f84ba60c13d5dde7600769ba3fab0af2608d83d3818", + "scripts/crash-harness.test.mts": "a2f029321f8dcc4e8411f1aaed6f71741373edd78590df8efb3e41d0e288db10", + "scripts/crash-output.mts": "b1670e73ec7c0d5f030d59b82ef35ab66ccec61b890dd0f03f14a9673a4c02f8", + "scripts/crash-process.mts": "ada6b8c40d69a8de0dcb7ff6f4abda25483b3834df29755e095cb722a0360bc2", + "scripts/crash-review-proof.mts": "fccee36b291b190fe935c4d9e5b1fd79df58cca5ec0cb932ae280c1eb3d4fbac", + "scripts/crash-review.test.mts": "e2686f58d3e25c4408a05c5779e9c8630f818fcc79e7f0b05b4dc6140cabde11", + "scripts/crash-storage.mts": "2f3abe68f859b2854a72d691febce4f63e10d150df3f5ef75905f55a502c1874", + "src/assurance.rs": "a598e33f3b402caf35d02223bd0447b58baec56a644c79526bdd1533817ec0a5", + "src/collation.rs": "f177e71a4f8cd3cbad1b80ca8ce16b3ae810bb8c33ed23b2b9834b9917f053ba", + "src/collections.rs": "453eedcea7789161571e4dc2f3680b83c7254e42cc6e2480ef3b7fe0ed7fa613", + "src/error.rs": "e0a2f21948e45d8fd6b66ea5b18f38037ba99d82d4be05e2106046a10afc1b98", + "src/history.rs": "a8612988d2624359be8c782e8fffe1fb8e7287706fe89b0dadd4d61b8e4dffa6", + "src/identity_probes.rs": "cee177bc04c3126f9b73a3874ac27a457afd611b59900da2ca52aa637eb2c871", + "src/item.rs": "d27b92a03d7c910e06fe32981d882d66c2fbc2dadf8cf83a1070b8c2e3e252de", + "src/json_output.rs": "65b6e577e526127a4865c1d4d51c9d540072067dec634b8e39b7a7ee8dc3b301", + "src/lib.rs": "457e189c57775c959982849e08c7de79a7ff29c2e6fcc55f3d40712c9ba05503", + "src/list.rs": "5ca7624bc04da29a566023e1668c387a0ea41faeeb178ed29ae736cfda0332a0", + "src/list_intent.rs": "5d7d522abc1f1d8711f725da6e6babd5045a25022400753e3733bef68f35c060", + "src/list_registry.rs": "892356a955c4af267dce744cf97a0b8ce3832a4b046e8d318fc14a2d262e3e38", + "src/lock_owner.rs": "3e00484810a87d9a2abc57356538f784a6169a2fbb9a1440b8489ff07b5dac3a", + "src/main.rs": "1126fba0179cabef49077f464f84bf854c7f7a324fdd6e3c44c6186e8b080da2", + "src/mutation.rs": "d1db4a148a6de8b8163bc397d97a1c81172d03a0deb061a04e2bbbebd7c03f3d", + "src/native_adapter.rs": "2854ee1303ba71a273ef4223745e351384d5a30ab855d484f9758cd018497112", + "src/orientation.rs": "4b6816fafa8de8781cb2b0980fd6d55236fb0f00515595aec8226555993360bc", + "src/orientation_context.rs": "a1dbbe5be05bf40955d85b3ef0b63ac00139c9cb39c0a042f59511d3c394de8c", + "src/orientation_context/sections.rs": "05f94b2702709f40121b4c91f873036ca2be4424c2a819949668c3049f5851be", + "src/orientation_deps.rs": "b04339646b6c1539c9ac8a25d7c8faacbd8d64143fc09481196653149952998b", + "src/orientation_deps/budget_recovery.rs": "d20a4ec88d4459e86e9aaf958c25133ef753ff8ec6cc28bdec224a08ce12e084", + "src/orientation_deps/packet.rs": "083ad9ded12ea4d2d34c7f19dc0b2f8defc0dd4a46cd3912d0f20d59386eb86f", + "src/ownership.rs": "2e3c61956ce07f21711fd4ea8e2082257ebfaa7c48cb7666ebdd8173e04ae2e9", + "src/pagination.rs": "15453428c7561a9aa2e0a55d1395488ac3afd877e0014a4e781103968a0d4830", + "src/read_output.rs": "3fa86acf83462ecf49074c5983d9c8be44925736e28fccd70cc6a3db4387a23a", + "src/read_projection.rs": "04b1c32d48c99e45456763cd75c7ca7d521b196795510687dd9e77f15278cda7", + "src/read_session.rs": "6f8d4154d2c831ac723ae69db451a7280dc6af100e19438683814e2ac356b4f2", + "src/search.rs": "1f4743bf37664b26c8444c0b2afb1274f601d507586f3585123b4c7669df2591", + "src/selection.rs": "12fbf274173e1f560df1521730ce8ee6f7379242ac2d1448609c3e9a78250613", + "src/strict_json.rs": "dbcc6d16a815cacb8de4f179c312daa3ffc24b3bee81ada25d0fbd71e3a9ba06", + "src/toon_output.rs": "e9f4cc52860a74be15c452dfdb7ca721be6669a4bd999a1e7a559938928ce936", + "src/workspace.rs": "a124604816ef06536d4464da0815de9594443906b5591600b8bfaf77ac3c9d0b", + "tests/fixtures/crash-review/comment.json": "631cdda01e43bc2dfc01a1b221eacce5cec1ea885da237f3839eeee2969ef938", + "tests/fixtures/crash-review/fixture/.agents/pm/settings.json": "7f1dbf9fa110788173530da16b8878e6e4eceea861ec07ed2d354a753bdfefc7", + "tests/fixtures/crash-review/published-history.json": "e70c85f90419badb75ebaab99a148238a7fad22e8fb2fff4842c28eacc355c15", + "tests/fixtures/crash-review/update.json": "9b964df999f38c908a36fcac9f5ad2f38f67ded6fe31c7c1b7de52c7cc0f64c7", + "tests/harness/eslint.config.mjs": "8ac6b9a397d6963e65d20d7a7747d775e245674a26624abb9985c42f18ca25b7", + "tests/harness/package-lock.json": "d1a9db8d1c705fc6e1f9d1d3f2336b5c38c5eef1e9845055aac8996db3757af8", + "tests/harness/package.json": "82df86fe3c452b529ebab9620c2cb9b6811abe4bf2515f6fc3200de0c67ad043", + "tests/harness/tsconfig.json": "5c855edab9a8766f222b77d49cedb53b420a624d26ba39fe1158bf85c9badc5a" + }, + "toolchain": { + "node": "v24.19.0", + "rustc": "rustc 1.90.0 (1159e78c4 2025-09-14)", + "nightly": "rustc 1.99.0-nightly (7608eb7b0 2026-08-05)", + "cargo": "cargo 1.90.0 (840b83a10 2025-07-30)", + "strace": "strace -- version 6.8" + }, + "reproduction": [ + "git checkout ", + "just oracle-install", + "npm ci --prefix tests/harness --ignore-scripts", + "cargo +1.90.0 build --locked --bin pm-rust", + "node scripts/crash-review-proof.mts" + ], + "oracleLockSha256": "4dab8fa9ce75881f978f5bae767e99190c5a9f43edf230d9b22a347012b0d0b9", + "harnessLockSha256": "d1a9db8d1c705fc6e1f9d1d3f2336b5c38c5eef1e9845055aac8996db3757af8" + }, + "controls": [ + { + "name": "stable-write-boundary", + "file": "scripts/crash-process.mts", + "sourceSha256": "ada6b8c40d69a8de0dcb7ff6f4abda25483b3834df29755e095cb722a0360bc2", + "patch": "docs/controls/crash-review/stable-write-boundary.patch", + "patchSha256": "a1577ed429565c295eee2ed682b8361729c81148fb98b1cfe6ed8af04fc2dac0", + "command": [ + "node", + "--test", + "--test-name-pattern=single-worker published boundary", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "empty-replay-dispatch", + "file": "scripts/crash-cli.mts", + "sourceSha256": "ad93e4ef39b31fb7d6617aa0b520365b678601d9c1ffc9eeb7e39ab203dda47f", + "patch": "docs/controls/crash-review/empty-replay-dispatch.patch", + "patchSha256": "d263747867e8d62a803b90034cf5c0ba09b6c09acdbde341da1fce7a5cc40a25", + "command": [ + "node", + "--test", + "--test-name-pattern=empty replay options", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "empty-replay-exclusion", + "file": "scripts/crash-cli.mts", + "sourceSha256": "ad93e4ef39b31fb7d6617aa0b520365b678601d9c1ffc9eeb7e39ab203dda47f", + "patch": "docs/controls/crash-review/empty-replay-exclusion.patch", + "patchSha256": "5a1c816559f83ea2aec310eb613ba16a12340390f4766a2496aa3ab562ef4740", + "command": [ + "node", + "--test", + "--test-name-pattern=empty replay options", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "default-failure-details", + "file": "scripts/crash-output.mts", + "sourceSha256": "b1670e73ec7c0d5f030d59b82ef35ab66ccec61b890dd0f03f14a9673a4c02f8", + "patch": "docs/controls/crash-review/default-failure-details.patch", + "patchSha256": "544b75a7f73ddc13fea4e72b93defa3a87401c50c06e67def945b3efa53a277f", + "command": [ + "node", + "--test", + "--test-name-pattern=default crash output|TOON output", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "strict-toon-failures", + "file": "scripts/crash-output.mts", + "sourceSha256": "b1670e73ec7c0d5f030d59b82ef35ab66ccec61b890dd0f03f14a9673a4c02f8", + "patch": "docs/controls/crash-review/strict-toon-failures.patch", + "patchSha256": "8799597eb8288afd8b22d792f62ac7f95ed61eddab869fa313140b471a7e4402", + "command": [ + "node", + "--test", + "--test-name-pattern=TOON output", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "workspace-cleanup", + "file": "scripts/crash-harness.mts", + "sourceSha256": "7e30d3efebbe7166cb819f84ba60c13d5dde7600769ba3fab0af2608d83d3818", + "patch": "docs/controls/crash-review/workspace-cleanup.patch", + "patchSha256": "0b864c36bad3a651818b3ef633477921f4a92a4e55b0bdcee1982153a8a366c7", + "command": [ + "node", + "--test", + "--test-name-pattern=completed case workspaces", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "portable-clock-import", + "file": "scripts/crash-process.mts", + "sourceSha256": "ada6b8c40d69a8de0dcb7ff6f4abda25483b3834df29755e095cb722a0360bc2", + "patch": "docs/controls/crash-review/portable-clock-import.patch", + "patchSha256": "94fc1ce01846a5ef47cb25ed906a34cc1db66202f3142dce8dc8e005f41cde39", + "command": [ + "node", + "--test", + "--test-name-pattern=clock disclosure", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "runtime-snapshot", + "file": "scripts/crash-storage.mts", + "sourceSha256": "2f3abe68f859b2854a72d691febce4f63e10d150df3f5ef75905f55a502c1874", + "patch": "docs/controls/crash-review/runtime-snapshot.patch", + "patchSha256": "9bdfef5c685a78abb9f22c30302e0d10141d6cb2d08ac4076bcf607d9af7c7e4", + "command": [ + "node", + "--test", + "--test-name-pattern=runtime transaction", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "cross-operation", + "file": "scripts/crash-harness.mts", + "sourceSha256": "7e30d3efebbe7166cb819f84ba60c13d5dde7600769ba3fab0af2608d83d3818", + "patch": "docs/controls/crash-review/cross-operation.patch", + "patchSha256": "83b4835cc20db43f1e844ed6e7b9620495bcd9efe4602b9803971b7a4dc31488", + "command": [ + "node", + "--test", + "--test-name-pattern=independent (update|comment) cross-operation", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "published-injection", + "file": "scripts/crash-harness.mts", + "sourceSha256": "7e30d3efebbe7166cb819f84ba60c13d5dde7600769ba3fab0af2608d83d3818", + "patch": "docs/controls/crash-review/published-injection.patch", + "patchSha256": "28604d495e4277c087922501b7f1b87161449e0649240b863127ad34cb624061", + "command": [ + "node", + "--test", + "--test-name-pattern=published history-open", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "recovery-comparison", + "file": "scripts/crash-harness.mts", + "sourceSha256": "7e30d3efebbe7166cb819f84ba60c13d5dde7600769ba3fab0af2608d83d3818", + "patch": "docs/controls/crash-review/recovery-comparison.patch", + "patchSha256": "68256b7e8a5f17613b0c1865bb19dff327227408dd5dcaffaddb50bb35260edc", + "command": [ + "node", + "--test", + "--test-name-pattern=cross-runtime recovery comparison", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "clock-disclosure", + "file": "scripts/crash-harness.mts", + "sourceSha256": "7e30d3efebbe7166cb819f84ba60c13d5dde7600769ba3fab0af2608d83d3818", + "patch": "docs/controls/crash-review/clock-disclosure.patch", + "patchSha256": "4205021c8eaffd617b4c0ef04b75b45f244e72ad6dd4504d9ab9c33f38477a3e", + "command": [ + "node", + "--test", + "--test-name-pattern=clock disclosure", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + }, + { + "name": "reduction-refusal", + "file": "scripts/crash-harness.mts", + "sourceSha256": "7e30d3efebbe7166cb819f84ba60c13d5dde7600769ba3fab0af2608d83d3818", + "patch": "docs/controls/crash-review/reduction-refusal.patch", + "patchSha256": "4a2743e87fb53312fe5e4028d57a2cdf42a41d765fb63d49352611790ec4c3dd", + "command": [ + "node", + "--test", + "--test-name-pattern=synthetic reduction refusal", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + } + ], + "publicCopy": { + "schema": "pm-rust/crash-v1", + "ok": false, + "oracleVersion": "2026.10.21", + "nativeSha256": "cfd5598c3c957ca0cb7ed47636ba6662d0727ba5dfd5a2cddf12beff701a6e0c", + "sourceFiles": 176, + "sourceItems": 85, + "sourceSha256": "a1ed87dcbf95d4bf7c48348bceb91b7710b0db7b8071461b48828ac5cc49011e", + "sourceUnchanged": true, + "acknowledgedComparisons": 2, + "killed": 26, + "boundaries": [ + { + "scenario": "update", + "implementation": "native", + "syscall": "rename", + "count": 1 + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "count": 8 + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "openat", + "count": 1 + }, + { + "scenario": "update", + "implementation": "published", + "syscall": "rename", + "count": 2 + }, + { + "scenario": "update", + "implementation": "published", + "syscall": "fsync", + "count": 0 + }, + { + "scenario": "update", + "implementation": "published", + "syscall": "openat", + "count": 1 + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "rename", + "count": 1 + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "count": 8 + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "openat", + "count": 1 + }, + { + "scenario": "comment", + "implementation": "published", + "syscall": "rename", + "count": 2 + }, + { + "scenario": "comment", + "implementation": "published", + "syscall": "fsync", + "count": 0 + }, + { + "scenario": "comment", + "implementation": "published", + "syscall": "openat", + "count": 1 + } + ], + "cases": [ + { + "scenario": "update", + "implementation": "native", + "syscall": "rename", + "boundary": 1, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 1, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "before", + "durableSha256": "bbfa1f48b522b71d7232fc1cbf4ea8d65e0a4a7acc05bfc8265e9c41832a3859", + "receiptSha256": "f0c3e717500261f6cee7d8b0e19bfd9a5da3594e4745baa54c576341ddce2e47", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 2, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "before", + "durableSha256": "bbfa1f48b522b71d7232fc1cbf4ea8d65e0a4a7acc05bfc8265e9c41832a3859", + "receiptSha256": "f0c3e717500261f6cee7d8b0e19bfd9a5da3594e4745baa54c576341ddce2e47", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 3, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 4, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 5, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 6, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 7, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "fsync", + "boundary": 8, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "native", + "syscall": "openat", + "boundary": 1, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "5285740632550d3c7bbf2d7c1d646e5bcc2058584918f8be8b23859097ecd705", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "published", + "syscall": "rename", + "boundary": 1, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "before", + "durableSha256": "bbfa1f48b522b71d7232fc1cbf4ea8d65e0a4a7acc05bfc8265e9c41832a3859", + "receiptSha256": "4079f1dc3ff9abce9c03bcbea8ca4a6e8f5589c1b9e3d460e085f0f833fb72af", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "published", + "syscall": "rename", + "boundary": 2, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "55d919ebc98001f13fa61559649010d78c62282f3a4f6d61b9a7b8ee440e2418", + "receiptSha256": "4079f1dc3ff9abce9c03bcbea8ca4a6e8f5589c1b9e3d460e085f0f833fb72af", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "update", + "implementation": "published", + "syscall": "openat", + "boundary": 1, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "diverged", + "durableSha256": "2b2fcad3b3dfdbf4c91eb54a50eeff5c0a98c200c9a0d56bdbc0522324ab7cdd", + "receiptSha256": "4079f1dc3ff9abce9c03bcbea8ca4a6e8f5589c1b9e3d460e085f0f833fb72af", + "receiptMatches": false, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": false, + "failure": { + "code": "durable_divergence", + "remedy": "Replay the retained synthetic case and inspect its lock, journal, bytes and receipt; preserve all original history. Runtime repairs need separate implementation work." + } + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "rename", + "boundary": 1, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 1, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "before", + "durableSha256": "6612f75d37328944dec0e55af965c79e9c503dd0c999dd7f46e5f60951771e02", + "receiptSha256": "453857b3b6d80eca9ab7cceda848c5f592c3da596e7d93bb16b478386148781c", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 2, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "before", + "durableSha256": "6612f75d37328944dec0e55af965c79e9c503dd0c999dd7f46e5f60951771e02", + "receiptSha256": "453857b3b6d80eca9ab7cceda848c5f592c3da596e7d93bb16b478386148781c", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 3, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 4, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 5, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 6, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 7, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "fsync", + "boundary": 8, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "native", + "syscall": "openat", + "boundary": 1, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "10a5b9ea5359aeb73f74225860d23aeb73a4b3347603bedabfad7cc1176b6299", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 1, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "published", + "syscall": "rename", + "boundary": 1, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "before", + "durableSha256": "6612f75d37328944dec0e55af965c79e9c503dd0c999dd7f46e5f60951771e02", + "receiptSha256": "7d05462db0414128a712202ce356260d614b8684ef9df6026a5ec8da275347c5", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "published", + "syscall": "rename", + "boundary": 2, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "committed", + "durableSha256": "c78269b633bd06e0a2526106a0ff9bc7bf038aa7b22226b223452d0598bfd251", + "receiptSha256": "7d05462db0414128a712202ce356260d614b8684ef9df6026a5ec8da275347c5", + "receiptMatches": true, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": true + }, + { + "scenario": "comment", + "implementation": "published", + "syscall": "openat", + "boundary": 1, + "killed": true, + "acknowledged": true, + "historyPreserved": true, + "restartStatus": 0, + "state": "diverged", + "durableSha256": "cef5854a65ccc484905fe47fad5002b06d0a322178f0fc7f998fd724ee62dc90", + "receiptSha256": "7d05462db0414128a712202ce356260d614b8684ef9df6026a5ec8da275347c5", + "receiptMatches": false, + "returnStatus": 0, + "journalsAtKill": 0, + "journalsAfterRestart": 0, + "journalsAfterReturn": 0, + "journalSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ok": false, + "failure": { + "code": "durable_divergence", + "remedy": "Replay the retained synthetic case and inspect its lock, journal, bytes and receipt; preserve all original history. Runtime repairs need separate implementation work." + } + } + ], + "failuresRetained": 4, + "parity": [ + { + "scenario": "update", + "bytes": true, + "acknowledgement": true + }, + { + "scenario": "comment", + "bytes": true, + "acknowledgement": true + } + ], + "recoveryParity": [ + { + "scenario": "update", + "syscall": "rename", + "boundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + }, + { + "scenario": "update", + "syscall": "openat", + "boundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + }, + { + "scenario": "comment", + "syscall": "rename", + "boundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + }, + { + "scenario": "comment", + "syscall": "openat", + "boundary": 1, + "bytes": false, + "receipt": true, + "state": false, + "journals": true, + "ok": false + } + ], + "clock": { + "metadata": "2026-10-21T12:00:00.000Z", + "dateNow": "fixed", + "performanceNow": "real", + "limitation": "Published Date.now lock TTL/wait ages are frozen; only the real external timeout bounds those waits. This corpus does not certify elapsed-time or stale-gate parity." + }, + "reduction": { + "status": "completed" + } + }, + "artifactControl": { + "name": "legacy-receipt-format", + "file": "docs/CRASH_REVIEW_2026_10_23.json", + "patch": "docs/controls/crash-review/legacy-receipt-format.patch", + "patchSha256": "25d80269537b93113f61981a28b912084eb303cb7b0c7a97ad21df032e758128", + "command": [ + "node", + "--test", + "--test-name-pattern=review receipt", + "scripts/crash-review.test.mts" + ], + "negativeExit": 1, + "restoredExit": 0 + } +} diff --git a/docs/controls/crash-oracle/exact-state.patch b/docs/controls/crash-oracle/exact-state.patch new file mode 100644 index 0000000..f0fe9ba --- /dev/null +++ b/docs/controls/crash-oracle/exact-state.patch @@ -0,0 +1,16 @@ +diff --git a/scripts/crash-oracle.mts b/scripts/crash-oracle.mts +index b810035..3bf6156 100644 +--- a/scripts/crash-oracle.mts ++++ b/scripts/crash-oracle.mts +@@ -13,7 +13,10 @@ export function transactionState(files: Snapshot): Snapshot { + } + /** One exact state oracle for clean returns, restart operations and final returns. No prefix acceptance. */ + export function exactState(expected: Snapshot, actual: Snapshot): boolean { +- return sameBytes(transactionState(expected), transactionState(actual)); ++ return [...expected].filter(([name]) => name.startsWith('history/')).every(([name, bytes]) => { ++ const seed = Buffer.from(bytes.toString().split('\n')[0] + '\n'); ++ return actual.get(name)?.subarray(0, seed.length).equals(seed); ++ }); + } + /** Join strace's per-task resumed lines before inspecting successful commit events. */ + function completedCalls(trace: string): string[] { diff --git a/docs/controls/crash-oracle/phase-pairing.patch b/docs/controls/crash-oracle/phase-pairing.patch new file mode 100644 index 0000000..4708360 --- /dev/null +++ b/docs/controls/crash-oracle/phase-pairing.patch @@ -0,0 +1,11 @@ +diff --git a/scripts/crash-oracle.mts b/scripts/crash-oracle.mts +index b810035..cde219b 100644 +--- a/scripts/crash-oracle.mts ++++ b/scripts/crash-oracle.mts +@@ -53,5 +53,5 @@ export function transactionPhase(trace: string, implementation: 'native' | 'publ + /** Phase-aware pairing covers every observed cut, including unequal per-runtime cut counts. */ + export function phasePairs(cuts: readonly T[]): [T, T][] { + return cuts.filter(cut => cut.implementation === 'native').flatMap(native => +- cuts.filter(published => published.implementation === 'published' && published.phase === native.phase).map(published => [native, published] as [T, T])); ++ cuts.filter(published => published.implementation === 'published' && published.syscall === native.syscall && published.boundary === native.boundary).map(published => [native, published] as [T, T])); + } diff --git a/docs/controls/crash-review/clock-disclosure.patch b/docs/controls/crash-review/clock-disclosure.patch new file mode 100644 index 0000000..fe9b1b5 --- /dev/null +++ b/docs/controls/crash-review/clock-disclosure.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/crash-harness.mts b/scripts/crash-harness.mts +index 8379d2b..95ca882 100644 +--- a/scripts/crash-harness.mts ++++ b/scripts/crash-harness.mts +@@ -81,7 +81,7 @@ export interface CrashReport { + } + + /** The metadata clock also freezes Date.now-based elapsed time; external process deadlines remain real. */ +-export const CLOCK_POLICY = { metadata: CRASH_CLOCK, dateNow: 'fixed', performanceNow: 'real', ++export const CLOCK_POLICY = { metadata: CRASH_CLOCK, dateNow: 'real', performanceNow: 'real', + limitation: 'Published Date.now lock TTL/wait ages are frozen; only the real external timeout bounds those waits. This corpus does not certify elapsed-time or stale-gate parity.' } as const; + + /** A paired recovery comparison never treats an unpaired syscall as cross-runtime evidence. */ diff --git a/docs/controls/crash-review/cross-operation.patch b/docs/controls/crash-review/cross-operation.patch new file mode 100644 index 0000000..93d25a9 --- /dev/null +++ b/docs/controls/crash-review/cross-operation.patch @@ -0,0 +1,15 @@ +diff --git a/scripts/crash-harness.mts b/scripts/crash-harness.mts +index 8379d2b..8092ef3 100644 +--- a/scripts/crash-harness.mts ++++ b/scripts/crash-harness.mts +@@ -257,8 +257,8 @@ function run(options: CrashOptions, root: string, timeout: number, maximum: numb + for (const scenario of scenarios) { + const mutation = scenario === 'update' ? ['update', id, '--description', 'Interrupted synthetic write'] : ['comment', id, 'Interrupted synthetic comment']; + // A different operation must observe/recover every pending journal before it writes. +- const restart = scenario === 'update' ? ['comment', id, 'Restart synthetic sentinel', ...common] : +- ['update', id, '--description', 'Restart synthetic description', ...common]; ++ const restart = scenario === 'update' ? ['update', id, '--priority', '1', ...common] : ++ ['comment', id, 'Restart synthetic sentinel', ...common]; + const returnCommand = scenario === 'update' ? ['update', id, '--priority', '1', ...common] : + ['comment', id, 'Return synthetic sentinel', ...common]; + const baselines = new Map(); diff --git a/docs/controls/crash-review/default-failure-details.patch b/docs/controls/crash-review/default-failure-details.patch new file mode 100644 index 0000000..77654f4 --- /dev/null +++ b/docs/controls/crash-review/default-failure-details.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/crash-output.mts b/scripts/crash-output.mts +index ab16fb5..e0c4148 100644 +--- a/scripts/crash-output.mts ++++ b/scripts/crash-output.mts +@@ -2,7 +2,7 @@ import type { CrashReport } from './crash-harness.mts'; + + /** Format bounded crash evidence as strict TOON with unique keys and tabular failures. */ + export function formatCrashToon(report: CrashReport): string { +- const failures = report.cases.filter(row => row.failure); ++ const failures = report.cases.filter(() => false); + const recoveryFailures = report.recoveryParity.filter(row => !row.ok); + const lines = [ + `schema: ${JSON.stringify(report.schema)}`, diff --git a/docs/controls/crash-review/empty-replay-dispatch.patch b/docs/controls/crash-review/empty-replay-dispatch.patch new file mode 100644 index 0000000..4cae824 --- /dev/null +++ b/docs/controls/crash-review/empty-replay-dispatch.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/crash-cli.mts b/scripts/crash-cli.mts +index 3c16720..78f515c 100644 +--- a/scripts/crash-cli.mts ++++ b/scripts/crash-cli.mts +@@ -21,7 +21,7 @@ function main(): void { + const options = { native: values.native, artifacts: values.artifacts, oracle: values.oracle, + source: values.source, strace: values.strace, maxBoundaries: values['max-boundaries'] === undefined ? undefined : Number(values['max-boundaries']), + timeoutMs: values.timeout === undefined ? undefined : Number(values.timeout) }; +- const report = values.replay !== undefined ? replayCrashFailure(options, values.replay) : runCrashCorpus(options); ++ const report = values.replay ? replayCrashFailure(options, values.replay) : runCrashCorpus(options); + if (json) console.log(JSON.stringify(values.full ? report : { ...report, + cases: report.cases.map(row => ({ scenario: row.scenario, implementation: row.implementation, + syscall: row.syscall, boundary: row.boundary, state: row.state, acknowledged: row.acknowledged, diff --git a/docs/controls/crash-review/empty-replay-exclusion.patch b/docs/controls/crash-review/empty-replay-exclusion.patch new file mode 100644 index 0000000..f5285cd --- /dev/null +++ b/docs/controls/crash-review/empty-replay-exclusion.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/crash-cli.mts b/scripts/crash-cli.mts +index 3c16720..6eb9445 100644 +--- a/scripts/crash-cli.mts ++++ b/scripts/crash-cli.mts +@@ -17,7 +17,7 @@ function main(): void { + return; + } + if (!values.native || !values.artifacts) throw new CrashRefusal('invalid_options', 'Supply --native and --artifacts; use --help for the full command.'); +- if (values.source !== undefined && values.replay !== undefined) throw new CrashRefusal('invalid_options', 'Supply only one of --source and --replay.'); ++ if (values.source && values.replay) throw new CrashRefusal('invalid_options', 'Supply only one of --source and --replay.'); + const options = { native: values.native, artifacts: values.artifacts, oracle: values.oracle, + source: values.source, strace: values.strace, maxBoundaries: values['max-boundaries'] === undefined ? undefined : Number(values['max-boundaries']), + timeoutMs: values.timeout === undefined ? undefined : Number(values.timeout) }; diff --git a/docs/controls/crash-review/legacy-receipt-format.patch b/docs/controls/crash-review/legacy-receipt-format.patch new file mode 100644 index 0000000..460fcd9 --- /dev/null +++ b/docs/controls/crash-review/legacy-receipt-format.patch @@ -0,0 +1,11 @@ +diff --git a/docs/CRASH_REVIEW_2026_10_23.json b/docs/CRASH_REVIEW_2026_10_23.json +index 98c85b7..b9fdf4c 100644 +--- a/docs/CRASH_REVIEW_2026_10_23.json ++++ b/docs/CRASH_REVIEW_2026_10_23.json +@@ -1,5 +1,5 @@ + { +- "schema": "pm-rust/crash-review-v1", ++ "schema": "legacy-receipt", + "provenance": { + "sourceRepository": "https://github.com/unbraind/pm-rust", + "sourceCommit": "5f6664f78a6701f552142d9aee286515e71322bb", diff --git a/docs/controls/crash-review/main-status-sweep-harness.jsonl b/docs/controls/crash-review/main-status-sweep-harness.jsonl new file mode 100644 index 0000000..64e5d6e --- /dev/null +++ b/docs/controls/crash-review/main-status-sweep-harness.jsonl @@ -0,0 +1,37 @@ +{"hash_algorithm":"sha256","ts":"2026-10-21T21:59:35.474Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-rust-crash-harness"},{"op":"add","path":"/metadata/title","value":"Compare native and published crash recovery with a reusable kill corpus"},{"op":"add","path":"/metadata/description","value":"Reusable TypeScript process-kill/restart differential SDK and command against the locked published oracle; compare acknowledged durable bytes, append-only histories and restart receipts on disposable plain-directory trackers."},{"op":"add","path":"/metadata/type","value":"Feature"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":["conformance","crash-consistency","harness"]},{"op":"add","path":"/metadata/created_at","value":"2026-10-21T21:59:35.474Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-10-21T21:59:35.474Z"},{"op":"add","path":"/metadata/author","value":"codex-agent"},{"op":"add","path":"/metadata/acceptance_criteria","value":"Every declared crash boundary preserves acknowledged writes; failures retain minimized synthetic reproductions and never rewrite original history.; Typed SDK and CLI with bounded TOON/JSON receipts and actionable refusals; documented example; public tracker read-copy validation with measured counts; exact-head CI release-check passes."}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"8e1f670ca81a6d238930adc15d6761f4546e07ee126e5484a8b18e542a059d7c","item_hash_version":3,"message":"","context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d6f8184c3613afda85e48f00b3df55e86e31fee5bf9ecec84f077733513c35fd"} +{"hash_algorithm":"sha256","ts":"2026-10-21T21:59:36.236Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T21:59:36.236Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"8e1f670ca81a6d238930adc15d6761f4546e07ee126e5484a8b18e542a059d7c","after_hash":"905ff535be5ae00a6a409c771aa71a435bdd2ad2f8a47f23bf5abf6dddb90041","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"ccd03b5fdcd44ca9e20712780731e32a83ffbadf48f36a06387cf18772e0a09d"} +{"hash_algorithm":"sha256","ts":"2026-10-21T21:59:37.044Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T21:59:37.044Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"905ff535be5ae00a6a409c771aa71a435bdd2ad2f8a47f23bf5abf6dddb90041","after_hash":"9361a97ad6df97b84a3c1e96a4dd147f4e34b53dbc8580eadb00e912826d76f5","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"b45b9fa7f8fed31eca02004b2ce337b560e38d496ccc43bd4acd8df517c43b6e"} +{"hash_algorithm":"sha256","ts":"2026-10-21T21:59:37.844Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T21:59:37.844Z"},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-10-21T21:59:37.843Z","author":"codex-agent","text":"Overlap recheck: published CLI 2026.10.21 matches the locked oracle. Native tests cover normal command differentials and manually reconstructed durable journals; they do not run a reusable live kill/restart corpus. pm-ops assurance reports measurements; pm-vcs writer publication is backend-specific. This feature adds cross-implementation crash evidence beyond lock/parity work. Reconciliation PR 103 closures and performance PR 102 items are excluded. TypeScript-only SDK/command; synthetic failures; targeted local checks; full gate in CI."}]}],"before_hash":"9361a97ad6df97b84a3c1e96a4dd147f4e34b53dbc8580eadb00e912826d76f5","after_hash":"83c7380e2346d35bed7a78863a172cac06bc9865791b45c0d63340850d5f6427","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"4b87244775a4ce1c87aacc04a2d52081c31de8a0d807a7896164b79afcebbb65"} +{"hash_algorithm":"sha256","ts":"2026-10-21T22:16:09.536Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-10-21T22:16:09.535Z","author":"codex-agent","text":"Implemented the typed TypeScript SDK and standalone just crash CLI. Declared boundaries are all observed rename/fsync task-local ordinals: event-loop write calls were rejected as unstable storage boundaries after real tracing. Two mutation families run on disposable non-git clones; same-family restart checks exact durable bytes and raw per-runtime restart receipts, with explicit shared cross-runtime acknowledgement projections. Synthetic probing measured 20 real kills, 20 preserved acknowledged writes/history prefixes, two successful baseline byte/acknowledgement comparisons and two early native lock-initialization restart refusals. Those refusals are retained as minimal one-item synthetic cases; no original stream is repaired. Full runtime crash conformance is not claimed. Adding independent replay/no-git regressions and public-copy measurements before CI."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T22:16:09.536Z"}],"before_hash":"83c7380e2346d35bed7a78863a172cac06bc9865791b45c0d63340850d5f6427","after_hash":"9985e10419614c48372edb655c34bc7e87e772d84e8709598ed527c77cddc851","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"4069d780939f74450abcf502a20d86d81dea60cc14d9d766cfec84909b32452d"} +{"hash_algorithm":"sha256","ts":"2026-10-21T22:17:03.402Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T22:17:03.402Z"},{"op":"add","path":"/metadata/files","value":[{"path":"scripts/crash-harness.mts","scope":"project","note":"Typed reusable crash corpus SDK"}]}],"before_hash":"9985e10419614c48372edb655c34bc7e87e772d84e8709598ed527c77cddc851","after_hash":"1ce3be396867355b33bbaf3c0f94c2aa76f6eb8fe495eee39ef03704bc470293","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"d177be839eefcb4e12bedc31390d656072f74ebfa6eb7cb51be3bf037124dcb8"} +{"hash_algorithm":"sha256","ts":"2026-10-21T22:17:05.759Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"add","path":"/metadata/files/1","value":{"path":"scripts/crash-process.mts","scope":"project","note":"Real bounded syscall kill adapters"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T22:17:05.759Z"}],"before_hash":"1ce3be396867355b33bbaf3c0f94c2aa76f6eb8fe495eee39ef03704bc470293","after_hash":"407c104b16e6db0770c6a20485de2d16c6f420edc944d559522dc6df99156bad","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"5c22cd75dc8280ea7db25cd574e8555ba7212238d42995509051cd80657de0cf"} +{"hash_algorithm":"sha256","ts":"2026-10-21T22:17:08.697Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"add","path":"/metadata/files/2","value":{"path":"scripts/crash-storage.mts","scope":"project","note":"Byte inventories and immutable history checks"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T22:17:08.697Z"}],"before_hash":"407c104b16e6db0770c6a20485de2d16c6f420edc944d559522dc6df99156bad","after_hash":"5e38e746ecf02f68ca87ba61402641f06f85f8cb29b645c1a94e9f2af2b8b7df","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"9c72b2afa6a1c621850ad51bccdaceac29abe38eee7fa7fbe2278b71a5fce63b"} +{"hash_algorithm":"sha256","ts":"2026-10-21T22:17:10.875Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/2/note","value":"Real bounded syscall kill adapters"},{"op":"replace","path":"/metadata/files/2/path","value":"scripts/crash-process.mts"},{"op":"replace","path":"/metadata/files/1/note","value":"Typed reusable crash corpus SDK"},{"op":"replace","path":"/metadata/files/1/path","value":"scripts/crash-harness.mts"},{"op":"replace","path":"/metadata/files/0/note","value":"Compact TOON and JSON command"},{"op":"replace","path":"/metadata/files/0/path","value":"scripts/crash-cli.mts"},{"op":"add","path":"/metadata/files/3","value":{"path":"scripts/crash-storage.mts","scope":"project","note":"Byte inventories and immutable history checks"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T22:17:10.875Z"}],"before_hash":"5e38e746ecf02f68ca87ba61402641f06f85f8cb29b645c1a94e9f2af2b8b7df","after_hash":"e6b35403a79d53a397f1afbab820949be024d85d231f894368ac4d7f7a2fe2ef","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"e76e185e57b09299f7fb7d6aa3030751097e7cd1826e09f987fe0bd32b90760b"} +{"hash_algorithm":"sha256","ts":"2026-10-21T22:17:12.618Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T22:17:12.618Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/CRASH_HARNESS.md","scope":"project","note":"SDK CLI replay and no-git examples"}]}],"before_hash":"e6b35403a79d53a397f1afbab820949be024d85d231f894368ac4d7f7a2fe2ef","after_hash":"804ce1f4cf235ea88120d0e4a96eed6924bcb686d3628ded8315c4ebd8c05a06","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"f72e867f6c842b7a0329e709725ac238f10f3d68d81370be9dae953753acedcd"} +{"hash_algorithm":"sha256","ts":"2026-10-21T22:17:14.411Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T22:17:14.411Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node --test scripts/crash-harness.test.mts","scope":"project","provenance":{"author":"codex-agent","created_at":"2026-10-21T22:17:14.334Z","source_kind":"local_mutation","source_ref":"feat/crash-consistency-harness"}}]}],"before_hash":"804ce1f4cf235ea88120d0e4a96eed6924bcb686d3628ded8315c4ebd8c05a06","after_hash":"1334fc5f7bf17e9ab224d2b2df7854b64e2966c24973074a87d2ff04bc15fed7","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"4e8c9c7274cc6f890223271bfd78f494e76d82b76100768898146896e19d193d"} +{"hash_algorithm":"sha256","ts":"2026-10-21T22:19:48.805Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-10-21T22:19:48.804Z","author":"codex-agent","text":"Read-only public-copy validation: public main c0154dbd7cd8071ac52b891be13f956f7a0f21fd, 74 items and 154 authoritative files in a non-git copy with read-only permissions. Measured 20 injected kills, 20 acknowledged-write preservations, 20 exact retained-history prefixes, two cross-runtime baseline byte/acknowledgement matches, 18 successful restart state/receipt checks, two independently reproduced native incomplete-lock restart refusals. Source fingerprint unchanged. Retained evidence is synthetic only. Follow-up pm-rust-crash-lock-restart covers the safe recovery policy, outside this harness change. Behavioral controls disabling history-prefix checking, exact inventory comparison and injected-kill admission each fail their targeted regression with exit 1 and pass after exact byte restoration."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T22:19:48.805Z"}],"before_hash":"1334fc5f7bf17e9ab224d2b2df7854b64e2966c24973074a87d2ff04bc15fed7","after_hash":"f17b4115940329581053ba77eb64e955d5be02a6af2cc0f2f95acf3332efe367","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"015e0d38a7027cd8c780795a5ddcc2e545ae10e966b02b82c157cccfbcfd2b20"} +{"hash_algorithm":"sha256","ts":"2026-10-21T22:19:50.144Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"add","path":"/metadata/docs/1","value":{"path":"docs/CRASH_PUBLIC_COPY_2026_10_22.json","scope":"project","note":"Measured public tracker copy receipt"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T22:19:50.144Z"}],"before_hash":"f17b4115940329581053ba77eb64e955d5be02a6af2cc0f2f95acf3332efe367","after_hash":"7e88009806e98188eaf2929dee14f8cebf38ffa7aab7415d794374ebbf4346e4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"49cf0f718505e9a251c4567e696529df0c107ba298129e7f73da1c164062b77c"} +{"hash_algorithm":"sha256","ts":"2026-10-21T22:19:51.361Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"add","path":"/metadata/docs/2","value":{"path":"docs/CRASH_REVERT_PROOF_2026_10_22.json","scope":"project","note":"Independent behavioral negative controls"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T22:19:51.361Z"}],"before_hash":"7e88009806e98188eaf2929dee14f8cebf38ffa7aab7415d794374ebbf4346e4","after_hash":"789cecc2c663f4c1233c7459b2d7e54a80e58c4ecca14c2f92fca9e6c0dffc71","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"7a665d8cd5e872652132668953472e2b64ca662892f91913c550bbcf8d44a662"} +{"hash_algorithm":"sha256","ts":"2026-10-21T22:21:46.519Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-10-21T22:21:46.519Z","author":"codex-agent","text":"Final targeted checks: pinned PM linked runner passes 14/14 Node regressions with no skips, including real native/published kills, read-only source-output guards, a PATH with no git executable, and independent one-case replay. Strict erasable TypeScript typecheck, ESLint, Rust fmt and targeted binary Clippy pass. Four behavioral negative controls now fail independently and pass after byte restoration, including rejecting a successful restart that lost its own history. Full unchanged-threshold Rust release-check is reserved for CI; no local full release suite was run. Local health retains existing guidance/provenance/stale-item advisories and shared configuration drift; history was not repaired. CI uses its existing clone-local configuration setup. Full CI run results and exact counts will be linked in the PR."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T22:21:46.519Z"}],"before_hash":"789cecc2c663f4c1233c7459b2d7e54a80e58c4ecca14c2f92fca9e6c0dffc71","after_hash":"6b0ba0ece22d00f1e6da6dfbeb6223105db7f2ec6c2b2f5bc9240046e0e822a4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"535eda1828ac8f2bec07c85f0fd91c4f06f3238aa56400044292ff51bff2ff17"} +{"hash_algorithm":"sha256","ts":"2026-10-21T22:21:47.994Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-21T22:21:47.994Z"}],"before_hash":"6b0ba0ece22d00f1e6da6dfbeb6223105db7f2ec6c2b2f5bc9240046e0e822a4","after_hash":"c69757dfb574b5f56f1a463f92b594d8860f7e3c364e3de518fba9ac4d0376cd","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"69da1e40bab6dada4e4dfc62c2208f3dc7ecd8528e2782ffb8a43898d3a608c8"} +{"hash_algorithm":"sha256","ts":"2026-10-22T10:38:45.211Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T10:38:45.211Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"c69757dfb574b5f56f1a463f92b594d8860f7e3c364e3de518fba9ac4d0376cd","after_hash":"c0f966e39cb7fdd6aac20728214a6ddd67d044a8bb2ab9add0066c8e8d23b565","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d3e06a47e6952437bc68840af0c6500fb64c9fbaf31152e1839d36b0187af554"} +{"hash_algorithm":"sha256","ts":"2026-10-22T10:38:52.443Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/4","value":{"created_at":"2026-10-22T10:38:52.442Z","author":"codex-agent","text":"PR 104 review round: pulled remote head and merged origin/main. PRRT_kwDOTwgMRs6vBg8Y is valid: oracle metadata read/parse errors bypass oracle_version. Adding public SDK/CLI regressions for missing, unreadable, malformed, invalid-shape and wrong-version metadata. Full-diff self-review found the same parse-before-typed-refusal pattern in mutation acknowledgements: malformed successful stdout bypasses baseline_failed. Covering and correcting that instance too. Replay-manifest parsing already has its typed invalid_options catch. Latest substantive CodeRabbit review has no Outside diff range findings. No thread replies or resolutions."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T10:38:52.443Z"}],"before_hash":"c0f966e39cb7fdd6aac20728214a6ddd67d044a8bb2ab9add0066c8e8d23b565","after_hash":"b1886052dd84ed2ee9263306253ce3a0ca22a55f2e3cda2d045fd09cf32dbe47","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e3728323af834729821e57ed7ed1b320a89a6aa5cb75c02aed27b0ee6fe1bd89"} +{"hash_algorithm":"sha256","ts":"2026-10-22T10:42:07.761Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/3/note","value":"Real bounded syscall kill adapters"},{"op":"replace","path":"/metadata/files/3/path","value":"scripts/crash-process.mts"},{"op":"remove","path":"/metadata/files/2/note"},{"op":"replace","path":"/metadata/files/2/path","value":"scripts/crash-harness.test.mts"},{"op":"add","path":"/metadata/files/4","value":{"path":"scripts/crash-storage.mts","scope":"project","note":"Byte inventories and immutable history checks"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T10:42:07.761Z"}],"before_hash":"b1886052dd84ed2ee9263306253ce3a0ca22a55f2e3cda2d045fd09cf32dbe47","after_hash":"d25c395f591659d337639938d4ef64c3c9a594055938fbbd0b9e79c70b25355e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"0f2125a6861fe9eda2187301cac564918886495e8ec69f3fd718e8b634019cb8"} +{"hash_algorithm":"sha256","ts":"2026-10-22T10:42:11.946Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/1","value":{"command":"node --test --test-name-pattern=\"oracle metadata|malformed source settings|malformed mutation acknowledgements\" scripts/crash-harness.test.mts","scope":"project","provenance":{"author":"codex-agent","created_at":"2026-10-22T10:42:11.763Z","source_kind":"local_mutation","source_ref":"feat/crash-consistency-harness"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T10:42:11.946Z"}],"before_hash":"d25c395f591659d337639938d4ef64c3c9a594055938fbbd0b9e79c70b25355e","after_hash":"d063bc0d14d4bef250b067ca480d1c932a5c232709a07e2ffdccba04ddb0dacf","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"2f661b78b7f6274d27f6e3d790427c41359c6dbd0a44a14bc66a79629c9611c2"} +{"hash_algorithm":"sha256","ts":"2026-10-22T10:42:18.350Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/5","value":{"created_at":"2026-10-22T10:42:18.350Z","author":"codex-agent","text":"Full-diff validation review also found malformed source settings JSON bypassed its unsafe_source guard. Corrected all three parse-before-validation paths: oracle metadata maps to oracle_version, source settings to unsafe_source, and malformed successful mutation stdout to baseline_failed. Added ten SDK oracle metadata cases, bounded JSON/default CLI refusal checks, source immutability checks and a real published-CLI baseline with an incompatible executable. No PM SDK mocks; all fixtures are disposable non-git directories. Replay-manifest parsing already preserves invalid_options. Original histories and all gate thresholds remain unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T10:42:18.350Z"}],"before_hash":"d063bc0d14d4bef250b067ca480d1c932a5c232709a07e2ffdccba04ddb0dacf","after_hash":"eb4c898761c6a1048bd10815c69a6df7967c44e867dc32a0a6a8a4d01b25365b","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"1c415892b334b681b552dfddace61f6a521146827c0167d355d482dbf25074da"} +{"hash_algorithm":"sha256","ts":"2026-10-22T10:43:02.665Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/6","value":{"created_at":"2026-10-22T10:43:02.665Z","author":"codex-agent","text":"Independent revert proofs complete with exact source-byte restoration. Oracle metadata: replacing only its guarded read/parse with the original statement makes both SDK and CLI regressions fail (2/2, io_error); restored both pass. Source settings: reverting only its guarded parse fails 1/1 with io_error; restored passes 1/1. Mutation acknowledgement: reverting only its guarded parse fails 1/1 with io_error; restored passes 1/1 using real published init/create processes and an incompatible native executable. Exact commands: node --test --test-name-pattern=\"oracle metadata\" scripts/crash-harness.test.mts; node --test --test-name-pattern=\"malformed source settings\" scripts/crash-harness.test.mts; node --test --test-name-pattern=\"malformed mutation acknowledgements\" scripts/crash-harness.test.mts. Each negative run exits 1 from the intended assertion; each restored run exits 0."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T10:43:02.665Z"}],"before_hash":"eb4c898761c6a1048bd10815c69a6df7967c44e867dc32a0a6a8a4d01b25365b","after_hash":"1453efc166c2dd451c88c55f278fcc3584c789b0f936717ec06a9969bfbf29c6","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"9a37927d857861d644e79cbaf776447fbdbe13fb070ea2c531ce37497c601a74"} +{"hash_algorithm":"sha256","ts":"2026-10-22T10:44:51.308Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/7","value":{"created_at":"2026-10-22T10:44:51.308Z","author":"codex-agent","text":"Final local targeted validation passed: strict erasable TypeScript compiler and ESLint checks; full crash harness 18/18 with zero skips; linked new regressions 4/4. All three independent behavior reverts failed exactly their intended assertions (2+1+1), then passed restored (2+1+1). Isolated pinned-PM health passed. Starting unchanged-threshold just release-check with the existing 35-minute release CI budget as the local wall-time bound."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T10:44:51.308Z"}],"before_hash":"1453efc166c2dd451c88c55f278fcc3584c789b0f936717ec06a9969bfbf29c6","after_hash":"d0dddffcf447490a6a4966777095512ec532bd161925381b14da71b4455049d2","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"0a0ac2b420999dda1f60bd93836486213568d0d40ef80fc72a051c339ad1cb29"} +{"hash_algorithm":"sha256","ts":"2026-10-22T10:56:48.199Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/8","value":{"created_at":"2026-10-22T10:56:48.191Z","author":"codex-agent","text":"Local full release attempt is incomplete, not failed: dependency install, fmt, strict Clippy and private-item rustdoc passed; the cold Rust test build was stopped under shared-host contention (main compiler about 7 percent CPU over six minutes). No compiler or test assertion failed. Using exact-head CI for the full unchanged-threshold release gate; this PR remains the active round until that gate passes. Targeted TypeScript compiler/lint checks, full Linux crash harness 18/18, linked new controls 4/4 and all independent revert proofs already pass."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T10:56:48.199Z"}],"before_hash":"d0dddffcf447490a6a4966777095512ec532bd161925381b14da71b4455049d2","after_hash":"dcb633b6cbdb5a98bb461cc0fba7628686206fe45269f39f664c02de519a6d5a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"9dd706a1a191a07cbb4223a279c3f674ba2f2e66f5b62260cff9d10f6c1d1b61"} +{"hash_algorithm":"sha256","ts":"2026-10-22T11:23:46.735Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/9","value":{"created_at":"2026-10-22T11:23:46.735Z","author":"codex-agent","text":"Full CI release evidence at code head 5b84803625d18e3ab3b7fdb4454a49448a628bf6: Linux just release-check passed (https://github.com/unbraind/pm-rust/actions/runs/39767043319/job/119784971422). Ordinary and instrumented Rust tests each passed 578 across 22 suites, zero failed or ignored; Rust lines 14025/14025, functions 1466/1466, regions 23438/23438, branches 3296/3296, all 100 percent. TypeScript compiler, ESLint and Linux crash harness 18/18 with zero skips also passed inside the gate. Audit, changelog and strict tracker health passed; only the pre-existing allowed RUSTSEC-2024-0449 advisory remains. macOS full release gate also passed: 567 ordinary and 567 instrumented Rust tests; all four required Rust metrics 100 percent; Node harness 11 passed with 7 declared Linux-only skips. The stopped local cold-build attempt is incomplete evidence; CI supplies the full pass. Releasing the claim and retaining in_progress for orchestrator verification. Final receipt-head CI evidence will be linked from PR 104; no thread replies/resolutions, PR merge or release."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T11:23:46.735Z"}],"before_hash":"dcb633b6cbdb5a98bb461cc0fba7628686206fe45269f39f664c02de519a6d5a","after_hash":"b0bf9b9f56e5aca05aeef4f33668816860a50a6ee49d9161d15ce3642ced0e8d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"bd9dacb0b680c11b142c7f14b5075fa6bfd05ee0e2b0e132dbb21b6217b11baf"} +{"hash_algorithm":"sha256","ts":"2026-10-22T11:23:55.320Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T11:23:55.320Z"}],"before_hash":"b0bf9b9f56e5aca05aeef4f33668816860a50a6ee49d9161d15ce3642ced0e8d","after_hash":"8298587058cc3412cc1f43d31e0b68d0d8e7199675c77cee6983396f79aa6ffc","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"63ca93664b4282ba89e6e0227f9cd4c1ca98444f94de9392d1a7f8a997e08ecb"} +{"hash_algorithm":"sha256","ts":"2026-10-22T16:36:59.617Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T16:36:59.617Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"8298587058cc3412cc1f43d31e0b68d0d8e7199675c77cee6983396f79aa6ffc","after_hash":"8284b4d4cc5c1a1870c977087bdfa5f74bdb83a1016130a175f563672b52b447","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"c7a8067ff258527b6c82accb0f42ba7f0b1772ea55e1ec2b2f371fd5ff6ed189"} +{"hash_algorithm":"sha256","ts":"2026-10-22T16:37:02.495Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/10","value":{"created_at":"2026-10-22T16:37:02.495Z","author":"codex-agent","text":"New PR 104 review round: pulled remote head 328ff00, then merged origin/main a600bd8 because the branch was one commit behind. Thread PRRT_kwDOTwgMRs6vRw2E is valid: the retained-case example claims every replay selects one implementation/syscall/ordinal, but baseline_parity evidence reruns its scenario across both implementations and all observed boundaries. The public SDK replay docstring has the same overstatement. Will correct both descriptions and add a regression tied to the replay contract with a documentation revert proof. Latest CodeRabbit review has no Outside diff range findings. Existing implementation, completed review fixes and append-only histories remain intact."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T16:37:02.495Z"}],"before_hash":"8284b4d4cc5c1a1870c977087bdfa5f74bdb83a1016130a175f563672b52b447","after_hash":"52ddb438d8c9fc4bf1073c6924b003dec706ffe68d87cad1a7ce2e19635229cc","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"f37e2d464783d111bafb72b5271aeaaf831471ff4cd5d871a55f6836c1124775"} +{"hash_algorithm":"sha256","ts":"2026-10-22T16:40:13.115Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/2","value":{"command":"node --test --test-name-pattern=\"replay guidance\" scripts/crash-harness.test.mts","scope":"project","provenance":{"author":"codex-agent","created_at":"2026-10-22T16:40:13.066Z","source_kind":"local_mutation","source_ref":"feat/crash-consistency-harness"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T16:40:13.115Z"}],"before_hash":"52ddb438d8c9fc4bf1073c6924b003dec706ffe68d87cad1a7ce2e19635229cc","after_hash":"9c3a3ecafc2da4fc7ab0a7728e648b6046e9739a9fc0aeb23c8ddf4b00c6673d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"a832d6caced03f1479a3be320a105351c5b096d184fdce117f6db7127fc08f09"} +{"hash_algorithm":"sha256","ts":"2026-10-22T16:41:16.374Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/11","value":{"created_at":"2026-10-22T16:41:16.374Z","author":"codex-agent","text":"Documentation revert proof for PRRT_kwDOTwgMRs6vRw2E: node --test --test-name-pattern=\"replay guidance\" scripts/crash-harness.test.mts checks the public guide and SDK docstring. Reverting only docs/CRASH_HARNESS.md yields one intended missing-baseline_parity-exception failure and one unaffected pass. Restoring it and reverting only the replay API docstring yields the other intended failure and one unaffected pass. Both exact byte sequences restored: 2/2 pass. These are documentation-contract controls; runtime replay behavior was already correct and was not changed. The complete just crash-check passes strict erasable TypeScript, ESLint and 20/20 Linux tests with zero failed/canceled/skipped; current native build also passes. Pinned-PM linked controls pass 2/2; result storage remains disabled by project policy, so results are retained here."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T16:41:16.374Z"}],"before_hash":"9c3a3ecafc2da4fc7ab0a7728e648b6046e9739a9fc0aeb23c8ddf4b00c6673d","after_hash":"ec55fa45b7604d575e52b7c37e633d477469380c96c8d8d6644fdab7f9476c7b","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"c77b6745e4f32729ae3ddb96776d89f8de090ef5982c2e2d4975dbd9cd22fc24"} +{"hash_algorithm":"sha256","ts":"2026-10-22T16:41:17.978Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/12","value":{"created_at":"2026-10-22T16:41:17.977Z","author":"codex-agent","text":"Self-review of the whole PR confirms the only overstatements were the retained-case guide and public replay docstring; README, CLI help, manifest validation and the single-boundary selection type do not claim that every replay selects one case. Original histories, stored commands and implementation behavior remain untouched. Releasing the implementation claim with status retained in_progress. Final exact-head unchanged just release-check CI receipts and counts will be recorded in PR https://github.com/unbraind/pm-rust/pull/104; pending CI is not approval. The original stacked-PR instruction still requires merging this completed update and main into PR 105 after PR 104 has passed and been pushed. No review replies/resolutions, PR merge or release."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T16:41:17.978Z"}],"before_hash":"ec55fa45b7604d575e52b7c37e633d477469380c96c8d8d6644fdab7f9476c7b","after_hash":"b938090f790628c8f45bb60d705b0d512bbce8da2f7818fb98012ba7cfce11a2","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"160a001c32a83306f045dad2dba30cc27731d944237b5c598e653d0cec75c6ee"} +{"hash_algorithm":"sha256","ts":"2026-10-22T16:41:19.128Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T16:41:19.128Z"}],"before_hash":"b938090f790628c8f45bb60d705b0d512bbce8da2f7818fb98012ba7cfce11a2","after_hash":"8ff8538f4d29be4f79c2d1986f36336e0b6f069545556415f3873c0ee8a5a714","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"0bd5fa5bc211f652b6007ee1f090717c7ad54c4308d547771f103f283a831098"} +{"hash_algorithm":"sha256","ts":"2026-10-22T16:47:28.503Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T16:47:28.503Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"8ff8538f4d29be4f79c2d1986f36336e0b6f069545556415f3873c0ee8a5a714","after_hash":"2a1609dc8119e9de0500613ed33ebea562a1271508b4db428a12d90aa7768b55","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"f9591ac740e83d28665a9dfd2a873552ef3811b960c876a820cd7e5e2b15bdbd"} +{"hash_algorithm":"sha256","ts":"2026-10-22T16:47:29.333Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/13","value":{"created_at":"2026-10-22T16:47:29.332Z","author":"codex-agent","text":"Additional self-review caught an LF-only assumption in the new guide regression. The matcher now accepts both LF and CRLF and exercises both spellings using the real guide contents. Reverting only the optional carriage-return matcher makes the CRLF assertion fail; restoring it passes both guidance tests 2/2. Strict TypeScript and ESLint pass. No documentation, runtime function, input fixture or gate threshold changed in this follow-up. Superseded pending CI at 84ddc56 is not used as approval; the corrected final head needs fresh full release CI."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T16:47:29.333Z"}],"before_hash":"2a1609dc8119e9de0500613ed33ebea562a1271508b4db428a12d90aa7768b55","after_hash":"83037d46c61d87ab8453636cfd3c88e01469e44d6f148b25675d89b1b1b86f73","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"46a3d1ba57fa48da1ec04d0c71bc279221d3fc5c701ccfa760b569d7ab2d79ef"} +{"hash_algorithm":"sha256","ts":"2026-10-22T16:47:30.014Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_instance":"9cd644682823b57766dff4f3","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-22T16:47:30.014Z"}],"before_hash":"83037d46c61d87ab8453636cfd3c88e01469e44d6f148b25675d89b1b1b86f73","after_hash":"b2b4f9ac3d7daac208fb57e1b7e3e022fa734cf1d99add9d55b62bcc2f26ed06","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"failed","reason":"resolver_failed","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"9626a8e574048e48725d5dd6ca08c1e5d75995ad91a8d9983608af28786bc13c"} +{"hash_algorithm":"sha256","ts":"2026-10-24T21:48:10.651Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"45d20434178787c3d9448609","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-24T21:48:10.651Z"},{"op":"replace","path":"/metadata/status","value":"open"}],"before_hash":"b2b4f9ac3d7daac208fb57e1b7e3e022fa734cf1d99add9d55b62bcc2f26ed06","after_hash":"e3dd26e6f6bb390b29bfb9e1c3eb68d0d8b7153d8952a698d001a23f957e78da","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"8414298d289dbd1d1e6e3ca34610add3f104ca3e75515f9280f1e8a944b2e2d3"} +{"hash_algorithm":"sha256","ts":"2026-10-24T21:48:10.764Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"45d20434178787c3d9448609","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/14","value":{"created_at":"2026-10-24T21:48:10.764Z","author":"codex-agent","text":"Returned to open in the 2026-10-24 sweep: Open PR https://github.com/unbraind/pm-rust/pull/104 carries the reusable kill-corpus harness; merged PR 105 fixes lock recovery but is not complete harness delivery. Review and full harness acceptance remain pending, with no active agent established."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-24T21:48:10.764Z"}],"before_hash":"e3dd26e6f6bb390b29bfb9e1c3eb68d0d8b7153d8952a698d001a23f957e78da","after_hash":"58ed6bc34e44cd03df7fdf32e1060b9c9774e131f0d42a9784a22d1463bde37f","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"5b416384fc52bfc7a715ba1e184299b46581ffe7ea39d56cac67f19305fdc287"} diff --git a/docs/controls/crash-review/main-status-sweep-harness.toon b/docs/controls/crash-review/main-status-sweep-harness.toon new file mode 100644 index 0000000..fa5fc9a --- /dev/null +++ b/docs/controls/crash-review/main-status-sweep-harness.toon @@ -0,0 +1,51 @@ +id: pm-rust-crash-harness +title: Compare native and published crash recovery with a reusable kill corpus +description: "Reusable TypeScript process-kill/restart differential SDK and command against the locked published oracle; compare acknowledged durable bytes, append-only histories and restart receipts on disposable plain-directory trackers." +type: Feature +status: open +priority: 2 +tags[3]: conformance,crash-consistency,harness +created_at: "2026-10-21T21:59:35.474Z" +updated_at: "2026-10-24T21:48:10.764Z" +author: codex-agent +acceptance_criteria: Every declared crash boundary preserves acknowledged writes; failures retain minimized synthetic reproductions and never rewrite original history.; Typed SDK and CLI with bounded TOON/JSON receipts and actionable refusals; documented example; public tracker read-copy validation with measured counts; exact-head CI release-check passes. +comments[15]{created_at,author,text}: + "2026-10-21T21:59:37.843Z",codex-agent,"Overlap recheck: published CLI 2026.10.21 matches the locked oracle. Native tests cover normal command differentials and manually reconstructed durable journals; they do not run a reusable live kill/restart corpus. pm-ops assurance reports measurements; pm-vcs writer publication is backend-specific. This feature adds cross-implementation crash evidence beyond lock/parity work. Reconciliation PR 103 closures and performance PR 102 items are excluded. TypeScript-only SDK/command; synthetic failures; targeted local checks; full gate in CI." + "2026-10-21T22:16:09.535Z",codex-agent,"Implemented the typed TypeScript SDK and standalone just crash CLI. Declared boundaries are all observed rename/fsync task-local ordinals: event-loop write calls were rejected as unstable storage boundaries after real tracing. Two mutation families run on disposable non-git clones; same-family restart checks exact durable bytes and raw per-runtime restart receipts, with explicit shared cross-runtime acknowledgement projections. Synthetic probing measured 20 real kills, 20 preserved acknowledged writes/history prefixes, two successful baseline byte/acknowledgement comparisons and two early native lock-initialization restart refusals. Those refusals are retained as minimal one-item synthetic cases; no original stream is repaired. Full runtime crash conformance is not claimed. Adding independent replay/no-git regressions and public-copy measurements before CI." + "2026-10-21T22:19:48.804Z",codex-agent,"Read-only public-copy validation: public main c0154dbd7cd8071ac52b891be13f956f7a0f21fd, 74 items and 154 authoritative files in a non-git copy with read-only permissions. Measured 20 injected kills, 20 acknowledged-write preservations, 20 exact retained-history prefixes, two cross-runtime baseline byte/acknowledgement matches, 18 successful restart state/receipt checks, two independently reproduced native incomplete-lock restart refusals. Source fingerprint unchanged. Retained evidence is synthetic only. Follow-up pm-rust-crash-lock-restart covers the safe recovery policy, outside this harness change. Behavioral controls disabling history-prefix checking, exact inventory comparison and injected-kill admission each fail their targeted regression with exit 1 and pass after exact byte restoration." + "2026-10-21T22:21:46.519Z",codex-agent,"Final targeted checks: pinned PM linked runner passes 14/14 Node regressions with no skips, including real native/published kills, read-only source-output guards, a PATH with no git executable, and independent one-case replay. Strict erasable TypeScript typecheck, ESLint, Rust fmt and targeted binary Clippy pass. Four behavioral negative controls now fail independently and pass after byte restoration, including rejecting a successful restart that lost its own history. Full unchanged-threshold Rust release-check is reserved for CI; no local full release suite was run. Local health retains existing guidance/provenance/stale-item advisories and shared configuration drift; history was not repaired. CI uses its existing clone-local configuration setup. Full CI run results and exact counts will be linked in the PR." + "2026-10-22T10:38:52.442Z",codex-agent,"PR 104 review round: pulled remote head and merged origin/main. PRRT_kwDOTwgMRs6vBg8Y is valid: oracle metadata read/parse errors bypass oracle_version. Adding public SDK/CLI regressions for missing, unreadable, malformed, invalid-shape and wrong-version metadata. Full-diff self-review found the same parse-before-typed-refusal pattern in mutation acknowledgements: malformed successful stdout bypasses baseline_failed. Covering and correcting that instance too. Replay-manifest parsing already has its typed invalid_options catch. Latest substantive CodeRabbit review has no Outside diff range findings. No thread replies or resolutions." + "2026-10-22T10:42:18.350Z",codex-agent,"Full-diff validation review also found malformed source settings JSON bypassed its unsafe_source guard. Corrected all three parse-before-validation paths: oracle metadata maps to oracle_version, source settings to unsafe_source, and malformed successful mutation stdout to baseline_failed. Added ten SDK oracle metadata cases, bounded JSON/default CLI refusal checks, source immutability checks and a real published-CLI baseline with an incompatible executable. No PM SDK mocks; all fixtures are disposable non-git directories. Replay-manifest parsing already preserves invalid_options. Original histories and all gate thresholds remain unchanged." + "2026-10-22T10:43:02.665Z",codex-agent,"Independent revert proofs complete with exact source-byte restoration. Oracle metadata: replacing only its guarded read/parse with the original statement makes both SDK and CLI regressions fail (2/2, io_error); restored both pass. Source settings: reverting only its guarded parse fails 1/1 with io_error; restored passes 1/1. Mutation acknowledgement: reverting only its guarded parse fails 1/1 with io_error; restored passes 1/1 using real published init/create processes and an incompatible native executable. Exact commands: node --test --test-name-pattern=\"oracle metadata\" scripts/crash-harness.test.mts; node --test --test-name-pattern=\"malformed source settings\" scripts/crash-harness.test.mts; node --test --test-name-pattern=\"malformed mutation acknowledgements\" scripts/crash-harness.test.mts. Each negative run exits 1 from the intended assertion; each restored run exits 0." + "2026-10-22T10:44:51.308Z",codex-agent,"Final local targeted validation passed: strict erasable TypeScript compiler and ESLint checks; full crash harness 18/18 with zero skips; linked new regressions 4/4. All three independent behavior reverts failed exactly their intended assertions (2+1+1), then passed restored (2+1+1). Isolated pinned-PM health passed. Starting unchanged-threshold just release-check with the existing 35-minute release CI budget as the local wall-time bound." + "2026-10-22T10:56:48.191Z",codex-agent,"Local full release attempt is incomplete, not failed: dependency install, fmt, strict Clippy and private-item rustdoc passed; the cold Rust test build was stopped under shared-host contention (main compiler about 7 percent CPU over six minutes). No compiler or test assertion failed. Using exact-head CI for the full unchanged-threshold release gate; this PR remains the active round until that gate passes. Targeted TypeScript compiler/lint checks, full Linux crash harness 18/18, linked new controls 4/4 and all independent revert proofs already pass." + "2026-10-22T11:23:46.735Z",codex-agent,"Full CI release evidence at code head 5b84803625d18e3ab3b7fdb4454a49448a628bf6: Linux just release-check passed (https://github.com/unbraind/pm-rust/actions/runs/39767043319/job/119784971422). Ordinary and instrumented Rust tests each passed 578 across 22 suites, zero failed or ignored; Rust lines 14025/14025, functions 1466/1466, regions 23438/23438, branches 3296/3296, all 100 percent. TypeScript compiler, ESLint and Linux crash harness 18/18 with zero skips also passed inside the gate. Audit, changelog and strict tracker health passed; only the pre-existing allowed RUSTSEC-2024-0449 advisory remains. macOS full release gate also passed: 567 ordinary and 567 instrumented Rust tests; all four required Rust metrics 100 percent; Node harness 11 passed with 7 declared Linux-only skips. The stopped local cold-build attempt is incomplete evidence; CI supplies the full pass. Releasing the claim and retaining in_progress for orchestrator verification. Final receipt-head CI evidence will be linked from PR 104; no thread replies/resolutions, PR merge or release." + "2026-10-22T16:37:02.495Z",codex-agent,"New PR 104 review round: pulled remote head 328ff00, then merged origin/main a600bd8 because the branch was one commit behind. Thread PRRT_kwDOTwgMRs6vRw2E is valid: the retained-case example claims every replay selects one implementation/syscall/ordinal, but baseline_parity evidence reruns its scenario across both implementations and all observed boundaries. The public SDK replay docstring has the same overstatement. Will correct both descriptions and add a regression tied to the replay contract with a documentation revert proof. Latest CodeRabbit review has no Outside diff range findings. Existing implementation, completed review fixes and append-only histories remain intact." + "2026-10-22T16:41:16.374Z",codex-agent,"Documentation revert proof for PRRT_kwDOTwgMRs6vRw2E: node --test --test-name-pattern=\"replay guidance\" scripts/crash-harness.test.mts checks the public guide and SDK docstring. Reverting only docs/CRASH_HARNESS.md yields one intended missing-baseline_parity-exception failure and one unaffected pass. Restoring it and reverting only the replay API docstring yields the other intended failure and one unaffected pass. Both exact byte sequences restored: 2/2 pass. These are documentation-contract controls; runtime replay behavior was already correct and was not changed. The complete just crash-check passes strict erasable TypeScript, ESLint and 20/20 Linux tests with zero failed/canceled/skipped; current native build also passes. Pinned-PM linked controls pass 2/2; result storage remains disabled by project policy, so results are retained here." + "2026-10-22T16:41:17.977Z",codex-agent,"Self-review of the whole PR confirms the only overstatements were the retained-case guide and public replay docstring; README, CLI help, manifest validation and the single-boundary selection type do not claim that every replay selects one case. Original histories, stored commands and implementation behavior remain untouched. Releasing the implementation claim with status retained in_progress. Final exact-head unchanged just release-check CI receipts and counts will be recorded in PR https://github.com/unbraind/pm-rust/pull/104; pending CI is not approval. The original stacked-PR instruction still requires merging this completed update and main into PR 105 after PR 104 has passed and been pushed. No review replies/resolutions, PR merge or release." + "2026-10-22T16:47:29.332Z",codex-agent,"Additional self-review caught an LF-only assumption in the new guide regression. The matcher now accepts both LF and CRLF and exercises both spellings using the real guide contents. Reverting only the optional carriage-return matcher makes the CRLF assertion fail; restoring it passes both guidance tests 2/2. Strict TypeScript and ESLint pass. No documentation, runtime function, input fixture or gate threshold changed in this follow-up. Superseded pending CI at 84ddc56 is not used as approval; the corrected final head needs fresh full release CI." + "2026-10-24T21:48:10.764Z",codex-agent,"Returned to open in the 2026-10-24 sweep: Open PR https://github.com/unbraind/pm-rust/pull/104 carries the reusable kill-corpus harness; merged PR 105 fixes lock recovery but is not complete harness delivery. Review and full harness acceptance remain pending, with no active agent established." +files[5]: + - path: scripts/crash-cli.mts + scope: project + note: Compact TOON and JSON command + - path: scripts/crash-harness.mts + scope: project + note: Typed reusable crash corpus SDK + - path: scripts/crash-harness.test.mts + scope: project + - path: scripts/crash-process.mts + scope: project + note: Real bounded syscall kill adapters + - path: scripts/crash-storage.mts + scope: project + note: Byte inventories and immutable history checks +tests[3]{command,scope,provenance{author,created_at,source_kind,source_ref}}: + node --test scripts/crash-harness.test.mts,project,codex-agent,"2026-10-21T22:17:14.334Z",local_mutation,feat/crash-consistency-harness + "node --test --test-name-pattern=\"oracle metadata|malformed source settings|malformed mutation acknowledgements\" scripts/crash-harness.test.mts",project,codex-agent,"2026-10-22T10:42:11.763Z",local_mutation,feat/crash-consistency-harness + "node --test --test-name-pattern=\"replay guidance\" scripts/crash-harness.test.mts",project,codex-agent,"2026-10-22T16:40:13.066Z",local_mutation,feat/crash-consistency-harness +docs[3]{path,scope,note}: + docs/CRASH_HARNESS.md,project,SDK CLI replay and no-git examples + docs/CRASH_PUBLIC_COPY_2026_10_22.json,project,Measured public tracker copy receipt + docs/CRASH_REVERT_PROOF_2026_10_22.json,project,Independent behavioral negative controls +body: "" diff --git a/docs/controls/crash-review/original-journal-report.jsonl b/docs/controls/crash-review/original-journal-report.jsonl new file mode 100644 index 0000000..736d69e --- /dev/null +++ b/docs/controls/crash-review/original-journal-report.jsonl @@ -0,0 +1,7 @@ +{"hash_algorithm":"sha256","ts":"2026-10-23T06:44:33.942Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-rust-cross-operation-journal"},{"op":"add","path":"/metadata/title","value":"BLOCKING: recover pending journals before a different native mutation writes"},{"op":"add","path":"/metadata/description","value":"PR 104 orchestrator blocker, independently reproduced with the real process-kill harness. Kill native update at rename ordinal 1, then comment succeeds while runtime/transactions/update-.json remains; returning to update exits 2 RecoveryConflict. The analogous comment to update sequence is tested too. Snapshot runtime intent, recover all applicable journals before any item mutation, preserve original history, and verify cross-runtime evidence before removing this blocker. PR: https://github.com/unbraind/pm-rust/pull/104 . This is separate from first-fsync gate recovery in PR 105."},{"op":"add","path":"/metadata/type","value":"Issue"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":0},{"op":"add","path":"/metadata/tags","value":["blocking","crash-consistency","recovery"]},{"op":"add","path":"/metadata/created_at","value":"2026-10-23T06:44:33.942Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-10-23T06:44:33.942Z"},{"op":"add","path":"/metadata/author","value":"codex-agent"},{"op":"add","path":"/metadata/severity","value":"critical"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"05c2269c15c01228af75e057ed88dd52ce0e3259c2af70ea0d5034f5ed5f51bd","item_hash_version":3,"message":"","context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"8a8d7775b8edc19295ce2a27b7bbfdb43126ed6156b1908ba5e71ae2e9caf649"} +{"hash_algorithm":"sha256","ts":"2026-10-23T06:50:13.795Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-23T06:50:13.795Z"},{"op":"add","path":"/metadata/files","value":[{"path":"scripts/crash-review.test.mts","scope":"project","note":"Permanent independent cross-operation proofs"}]}],"before_hash":"05c2269c15c01228af75e057ed88dd52ce0e3259c2af70ea0d5034f5ed5f51bd","after_hash":"689cf51708e83492647daa1ca77756e86dfc31cd248befe9950516e93f0760fb","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"0e172bed7e186be64bcc3520f2793b931014d44c9a5c78521cc427cf498047d1"} +{"hash_algorithm":"sha256","ts":"2026-10-23T06:50:19.475Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-23T06:50:19.475Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/CRASH_HARNESS.md","scope":"project","note":"Review correction and PR 104 blocker"}]}],"before_hash":"689cf51708e83492647daa1ca77756e86dfc31cd248befe9950516e93f0760fb","after_hash":"5266253e97a3b67c32af35274cf28dda821659515959a61b4ad3a2f58c6142db","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"2ff07609e87ed739da2fc6a740ce88c6d15e05eb15be2de43c77da647c19d17d"} +{"hash_algorithm":"sha256","ts":"2026-10-23T06:54:18.285Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-23T06:54:18.285Z"},{"op":"add","path":"/metadata/acceptance_criteria","value":"Before any native item mutation writes, recover applicable pending journals across operation names; update to comment to update and comment to update to comment must succeed after every declared publication cut with no pending canonical journal, exact history chain and matching reference receipts. Never rewrite original history."}],"before_hash":"5266253e97a3b67c32af35274cf28dda821659515959a61b4ad3a2f58c6142db","after_hash":"f04e492fc36cddcf8a4dc102340e6982bc8101e002bd2fc723f268544afab3fb","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"c0befb23e93f99a860dc64e79b1b6a757e7573772a49f765a7280c463728972b"} +{"hash_algorithm":"sha256","ts":"2026-10-23T06:54:23.819Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"add","path":"/metadata/files/1","value":{"path":"src/mutation.rs","scope":"project","note":"Operation-specific recover_and_locate is the unresolved runtime source"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-23T06:54:23.819Z"}],"before_hash":"f04e492fc36cddcf8a4dc102340e6982bc8101e002bd2fc723f268544afab3fb","after_hash":"d58d8c53c21926e5b0a1f1de063fe37da2398772c7f1623287fb8c5d0857c064","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"2703bd2cca008e9da829434e7bc6eb2baa47482df7fc3ba11befb99695fe5f47"} +{"hash_algorithm":"sha256","ts":"2026-10-23T06:54:33.004Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-23T06:54:33.004Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node --test --test-name-pattern=independent scripts/crash-review.test.mts","scope":"project","provenance":{"author":"codex-agent","created_at":"2026-10-23T06:54:32.346Z","source_kind":"local_mutation","source_ref":"feat/crash-consistency-harness"}}]}],"before_hash":"d58d8c53c21926e5b0a1f1de063fe37da2398772c7f1623287fb8c5d0857c064","after_hash":"c5eea981c0d7afd64f2994226e2b1cbd019fe3dead528b03b0e0a308258d3832","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"fa4f5c33cd71892b433ee02e90f9ddbb65cf9a1356abc9fc85d7a07e6f0ce0b1"} +{"hash_algorithm":"sha256","ts":"2026-10-23T06:58:21.817Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7a6225902f81bc40eed1bcd8","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-23T06:58:21.817Z"},{"op":"replace","path":"/metadata/description","value":"PR 104 blocking durability defect, independently reproduced by interrupting our native process at a write boundary in a scratch tracker. Interrupt native update at rename ordinal 1, then comment succeeds while runtime/transactions/update-.json remains; returning to update exits 2 RecoveryConflict. The analogous comment to update sequence is tested too. Snapshot runtime intent, recover all applicable journals before any item mutation, preserve original history, and verify cross-runtime evidence before removing this blocker. PR: https://github.com/unbraind/pm-rust/pull/104 . Separate from first-fsync gate recovery in PR 105."}],"before_hash":"c5eea981c0d7afd64f2994226e2b1cbd019fe3dead528b03b0e0a308258d3832","after_hash":"195dc928ac329c97f48e3eb70747734a158c1c130c1fe05d1d352e070d17fb08","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"acff6d9565a560400becac92e6e674231e75323966323eed5ec94ccb6e5490c8"} diff --git a/docs/controls/crash-review/original-journal-report.toon b/docs/controls/crash-review/original-journal-report.toon new file mode 100644 index 0000000..7152462 --- /dev/null +++ b/docs/controls/crash-review/original-journal-report.toon @@ -0,0 +1,20 @@ +id: pm-rust-cross-operation-journal +title: "BLOCKING: recover pending journals before a different native mutation writes" +description: "PR 104 blocking durability defect, independently reproduced by interrupting our native process at a write boundary in a scratch tracker. Interrupt native update at rename ordinal 1, then comment succeeds while runtime/transactions/update-.json remains; returning to update exits 2 RecoveryConflict. The analogous comment to update sequence is tested too. Snapshot runtime intent, recover all applicable journals before any item mutation, preserve original history, and verify cross-runtime evidence before removing this blocker. PR: https://github.com/unbraind/pm-rust/pull/104 . Separate from first-fsync gate recovery in PR 105." +type: Issue +status: open +priority: 0 +tags[3]: blocking,crash-consistency,recovery +created_at: "2026-10-23T06:44:33.942Z" +updated_at: "2026-10-23T06:58:21.817Z" +author: codex-agent +acceptance_criteria: "Before any native item mutation writes, recover applicable pending journals across operation names; update to comment to update and comment to update to comment must succeed after every declared publication cut with no pending canonical journal, exact history chain and matching reference receipts. Never rewrite original history." +severity: critical +files[2]{path,scope,note}: + scripts/crash-review.test.mts,project,Permanent independent cross-operation proofs + src/mutation.rs,project,Operation-specific recover_and_locate is the unresolved runtime source +tests[1]{command,scope,provenance{author,created_at,source_kind,source_ref}}: + node --test --test-name-pattern=independent scripts/crash-review.test.mts,project,codex-agent,"2026-10-23T06:54:32.346Z",local_mutation,feat/crash-consistency-harness +docs[1]{path,scope,note}: + docs/CRASH_HARNESS.md,project,Review correction and PR 104 blocker +body: "" diff --git a/docs/controls/crash-review/portable-clock-import.patch b/docs/controls/crash-review/portable-clock-import.patch new file mode 100644 index 0000000..84f7c9d --- /dev/null +++ b/docs/controls/crash-review/portable-clock-import.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/crash-process.mts b/scripts/crash-process.mts +index d235670..1081e07 100644 +--- a/scripts/crash-process.mts ++++ b/scripts/crash-process.mts +@@ -5,7 +5,7 @@ import { join } from 'node:path'; + /** Observable syscall classes shared by real native and published processes. */ + export const CRASH_SYSCALLS = ['rename', 'fsync'] as const; + /** Portable Node preload specifier, including drive-letter paths and escaped filenames. */ +-export const CRASH_CLOCK_IMPORT = new URL('./crash-clock.mts', import.meta.url).href; ++export const CRASH_CLOCK_IMPORT = decodeURIComponent(new URL('./crash-clock.mts', import.meta.url).pathname); + /** One syscall's per-task entry ordinal; ordinals are not cross-runtime semantic phases. */ + export interface Boundary { syscall: typeof CRASH_SYSCALLS[number] | 'openat'; ordinal: number } + /** Complete child receipt, retained privately and reduced to hashes in public output. */ diff --git a/docs/controls/crash-review/published-injection.patch b/docs/controls/crash-review/published-injection.patch new file mode 100644 index 0000000..035d546 --- /dev/null +++ b/docs/controls/crash-review/published-injection.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/crash-harness.mts b/scripts/crash-harness.mts +index 8379d2b..7c799c3 100644 +--- a/scripts/crash-harness.mts ++++ b/scripts/crash-harness.mts +@@ -287,7 +287,7 @@ function run(options: CrashOptions, root: string, timeout: number, maximum: numb + rmSync(historyDirectory, { recursive: true, force: true }); + const counts: { syscall: Boundary['syscall']; count: number }[] = CRASH_SYSCALLS.map(syscall => ({ syscall, count: boundaryCount(receipt.trace, syscall) })); + if (boundaryCount(historyReceipt.trace, 'openat') < 1) throw new CrashRefusal('boundary_unreached', 'Enable history-path openat tracing; the post-publication history boundary must be observed.'); +- counts.push({ syscall: 'openat', count: 1 }); ++ // Disabled history-open boundary (negative control). + report.boundaries.push(...counts.map(entry => ({ scenario, implementation: label, ...entry }))); + if (counts.every(entry => entry.count === 0) || counts.some(entry => entry.count > maximum)) { + const refusal = new CrashRefusal('boundary_unreached', 'Allow ptrace/syscall tracing and set maxBoundaries high enough for every measured per-task rename/fsync ordinal (maximum 64).'); diff --git a/docs/controls/crash-review/recovery-comparison.patch b/docs/controls/crash-review/recovery-comparison.patch new file mode 100644 index 0000000..fd3e916 --- /dev/null +++ b/docs/controls/crash-review/recovery-comparison.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/crash-harness.mts b/scripts/crash-harness.mts +index 8379d2b..4034f8a 100644 +--- a/scripts/crash-harness.mts ++++ b/scripts/crash-harness.mts +@@ -92,7 +92,7 @@ export function compareRecovery(native: Snapshot, published: Snapshot, nativeRec + nativeState: CrashCase['state'], publishedState: CrashCase['state'], nativeJournals: Snapshot, publishedJournals: Snapshot): Omit { + const result = { bytes: sameBytes(native, published), receipt: nativeReceipt === publishedReceipt, + state: nativeState === publishedState, journals: sameBytes(nativeJournals, publishedJournals) }; +- return { ...result, ok: Object.values(result).every(Boolean) }; ++ return { ...result, ok: true }; + } + + /** Preserve an already measured verdict even if its independent synthetic reduction refuses. */ diff --git a/docs/controls/crash-review/reduction-refusal.patch b/docs/controls/crash-review/reduction-refusal.patch new file mode 100644 index 0000000..ec33645 --- /dev/null +++ b/docs/controls/crash-review/reduction-refusal.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/crash-harness.mts b/scripts/crash-harness.mts +index 8379d2b..44f581d 100644 +--- a/scripts/crash-harness.mts ++++ b/scripts/crash-harness.mts +@@ -421,7 +421,7 @@ function run(options: CrashOptions, root: string, timeout: number, maximum: numb + report.ok &&= report.sourceUnchanged; + if (!report.ok) { + // Independently replay the same corpus on a minimal synthetic tracker, never copy public histories into evidence. +- reduceFailure(report, () => runCrashCorpus({ ...options, source: undefined })); ++ report.failuresRetained = runCrashCorpus({ ...options, source: undefined }).failuresRetained; + } + } + return report; diff --git a/docs/controls/crash-review/runtime-snapshot.patch b/docs/controls/crash-review/runtime-snapshot.patch new file mode 100644 index 0000000..d579e64 --- /dev/null +++ b/docs/controls/crash-review/runtime-snapshot.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/crash-storage.mts b/scripts/crash-storage.mts +index 1db11c3..a629ed4 100644 +--- a/scripts/crash-storage.mts ++++ b/scripts/crash-storage.mts +@@ -10,7 +10,7 @@ export function snapshot(root: string, prefix = ''): Map { + if (!prefix && lstatSync(root).isSymbolicLink()) throw new Error('symlink'); + const result = new Map(); + for (const entry of readdirSync(join(root, prefix), { withFileTypes: true })) { +- if (!prefix && ['locks', 'transactions', 'checkpoints', 'search'].includes(entry.name)) continue; ++ if (!prefix && ['runtime', 'locks', 'transactions', 'checkpoints', 'search'].includes(entry.name)) continue; + if (entry.isSymbolicLink()) throw new Error('symlink'); + const key = prefix ? `${prefix}/${entry.name}` : entry.name; + if (entry.isDirectory()) { diff --git a/docs/controls/crash-review/stable-write-boundary.patch b/docs/controls/crash-review/stable-write-boundary.patch new file mode 100644 index 0000000..a641624 --- /dev/null +++ b/docs/controls/crash-review/stable-write-boundary.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/crash-process.mts b/scripts/crash-process.mts +index d235670..19aa095 100644 +--- a/scripts/crash-process.mts ++++ b/scripts/crash-process.mts +@@ -30,7 +30,7 @@ export function execute(implementation: Implementation, args: readonly string[], + COMSPEC: process.env.COMSPEC, PATHEXT: process.env.PATHEXT, + TEMP: process.env.TEMP, TMP: process.env.TMP, + PM_AUTHOR: 'conformance-agent', PM_SENTRY_DISABLED: '1', PM_TELEMETRY_SOURCE_CONTEXT: 'test', +- DO_NOT_TRACK: '1', NODE_DISABLE_COMPILE_CACHE: '1', UV_THREADPOOL_SIZE: '1', ++ DO_NOT_TRACK: '1', NODE_DISABLE_COMPILE_CACHE: '1', + GIT_CEILING_DIRECTORIES: cwd, GIT_CONFIG_GLOBAL: '/dev/null', GIT_CONFIG_NOSYSTEM: '1', + LC_ALL: 'C', TZ: 'UTC', + }, diff --git a/docs/controls/crash-review/strict-toon-failures.patch b/docs/controls/crash-review/strict-toon-failures.patch new file mode 100644 index 0000000..0ad984d --- /dev/null +++ b/docs/controls/crash-review/strict-toon-failures.patch @@ -0,0 +1,14 @@ +diff --git a/scripts/crash-output.mts b/scripts/crash-output.mts +index ab16fb5..f5de370 100644 +--- a/scripts/crash-output.mts ++++ b/scripts/crash-output.mts +@@ -20,8 +20,7 @@ export function formatCrashToon(report: CrashReport): string { + `reduction: ${report.reduction?.status ?? 'none'}`, + `parity[${report.parity.length}]{scenario,bytes,acknowledgement}:`, + ...report.parity.map(row => ` ${row.scenario},${row.bytes},${row.acknowledgement}`), +- `failures[${failures.length}]{scenario,implementation,syscall,boundary,code,remedy}:`, +- ...failures.map(row => ` ${row.scenario},${row.implementation},${row.syscall},${row.boundary},${row.failure!.code},${JSON.stringify(row.failure!.remedy)}`), ++ ...failures.map(row => `failure: ${JSON.stringify(row.failure)}`), + `recovery_failures[${recoveryFailures.length}]{scenario,syscall,boundary,bytes,receipt,state,journals,ok}:`, + ...recoveryFailures.map(row => ` ${row.scenario},${row.syscall},${row.boundary},${row.bytes},${row.receipt},${row.state},${row.journals},${row.ok}`), + `cases[${report.cases.length}]{scenario,implementation,syscall,boundary,state,history_preserved,return_status,pending_journals,failure,ok}:`, diff --git a/docs/controls/crash-review/workspace-cleanup.patch b/docs/controls/crash-review/workspace-cleanup.patch new file mode 100644 index 0000000..2f3f358 --- /dev/null +++ b/docs/controls/crash-review/workspace-cleanup.patch @@ -0,0 +1,13 @@ +diff --git a/scripts/crash-harness.mts b/scripts/crash-harness.mts +index 8379d2b..cbdebf2 100644 +--- a/scripts/crash-harness.mts ++++ b/scripts/crash-harness.mts +@@ -369,7 +369,7 @@ function run(options: CrashOptions, root: string, timeout: number, maximum: numb + report.failuresRetained++; + } + } +- rmSync(killedDirectory, { recursive: true, force: true }); ++ // Retain completed workspace (negative control). + } + } + } diff --git a/justfile b/justfile index 6d682a5..667d35a 100644 --- a/justfile +++ b/justfile @@ -51,7 +51,8 @@ crash-check: npm ci --prefix tests/harness --ignore-scripts tests/harness/node_modules/.bin/tsc -p tests/harness/tsconfig.json tests/harness/node_modules/.bin/eslint -c tests/harness/eslint.config.mjs scripts/crash-*.mts scripts/native-adapter-*.mts - node --test scripts/crash-harness.test.mts + node --test --test-concurrency=1 scripts/crash-*.test.mts + node scripts/crash-history-prefix.mts # Reproduce large synthetic non-git trackers against the requested current oracle. bench-oracle-install: diff --git a/scripts/crash-cli.mts b/scripts/crash-cli.mts index 2065db5..3c16720 100644 --- a/scripts/crash-cli.mts +++ b/scripts/crash-cli.mts @@ -1,5 +1,6 @@ import { parseArgs } from 'node:util'; import { CrashRefusal, replayCrashFailure, runCrashCorpus } from './crash-harness.mts'; +import { formatCrashToon } from './crash-output.mts'; /** Execute the standalone CLI and emit bounded, privacy-safe TOON or JSON. */ function main(): void { @@ -8,7 +9,7 @@ function main(): void { const { values } = parseArgs({ options: { native: { type: 'string' }, oracle: { type: 'string' }, source: { type: 'string' }, artifacts: { type: 'string' }, 'max-boundaries': { type: 'string' }, timeout: { type: 'string' }, - json: { type: 'boolean' }, full: { type: 'boolean' }, replay: { type: 'string' }, help: { type: 'boolean' }, + json: { type: 'boolean' }, full: { type: 'boolean' }, replay: { type: 'string' }, strace: { type: 'string' }, help: { type: 'boolean' }, } }); json = values.json ?? false; if (values.help) { @@ -16,20 +17,18 @@ function main(): void { return; } if (!values.native || !values.artifacts) throw new CrashRefusal('invalid_options', 'Supply --native and --artifacts; use --help for the full command.'); - if (values.source && values.replay) throw new CrashRefusal('invalid_options', 'Supply only one of --source and --replay.'); + if (values.source !== undefined && values.replay !== undefined) throw new CrashRefusal('invalid_options', 'Supply only one of --source and --replay.'); const options = { native: values.native, artifacts: values.artifacts, oracle: values.oracle, - source: values.source, maxBoundaries: values['max-boundaries'] === undefined ? undefined : Number(values['max-boundaries']), + source: values.source, strace: values.strace, maxBoundaries: values['max-boundaries'] === undefined ? undefined : Number(values['max-boundaries']), timeoutMs: values.timeout === undefined ? undefined : Number(values.timeout) }; - const report = values.replay ? replayCrashFailure(options, values.replay) : runCrashCorpus(options); + const report = values.replay !== undefined ? replayCrashFailure(options, values.replay) : runCrashCorpus(options); if (json) console.log(JSON.stringify(values.full ? report : { ...report, cases: report.cases.map(row => ({ scenario: row.scenario, implementation: row.implementation, syscall: row.syscall, boundary: row.boundary, state: row.state, acknowledged: row.acknowledged, - historyPreserved: row.historyPreserved, restartStatus: row.restartStatus, receiptMatches: row.receiptMatches, failure: row.failure, ok: row.ok })) })); - else { - console.log(`schema: ${JSON.stringify(report.schema)}\nok: ${report.ok}\noracle_version: ${JSON.stringify(report.oracleVersion)}\nsource_items: ${report.sourceItems}\nsource_unchanged: ${report.sourceUnchanged}\nacknowledged_comparisons: ${report.acknowledgedComparisons}\nkilled: ${report.killed}\nfailures_retained: ${report.failuresRetained}`); - console.log(`cases[${report.cases.length}]{scenario,implementation,syscall,boundary,state,history_preserved,ok}:`); - for (const row of report.cases) console.log(` ${row.scenario},${row.implementation},${row.syscall},${row.boundary},${row.state},${row.historyPreserved},${row.ok}`); - } + historyPreserved: row.historyPreserved, restartStatus: row.restartStatus, returnStatus: row.returnStatus, + journalsAtKill: row.journalsAtKill, journalsAfterRestart: row.journalsAfterRestart, journalsAfterReturn: row.journalsAfterReturn, + receiptMatches: row.receiptMatches, failure: row.failure, ok: row.ok })) })); + else console.log(formatCrashToon(report)); process.exitCode = report.ok ? 0 : 1; } catch (error) { const refusal = error instanceof CrashRefusal ? error : new CrashRefusal('invalid_options', 'Check option spelling and values; run --help.'); diff --git a/scripts/crash-harness.mts b/scripts/crash-harness.mts index 9c50380..7e1dfda 100644 --- a/scripts/crash-harness.mts +++ b/scripts/crash-harness.mts @@ -3,10 +3,12 @@ import { existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, import { tmpdir } from 'node:os'; import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { CRASH_SYSCALLS, boundaryCount, execute, killedAtBoundary } from './crash-process.mts'; +import { CRASH_CLOCK_IMPORT, CRASH_SYSCALLS, boundaryCount, execute, killedAtBoundary } from './crash-process.mts'; import type { Boundary, Implementation, ProcessReceipt } from './crash-process.mts'; -import { fingerprint, materialize, preservesHistory, recoveredState, sameBytes, snapshot } from './crash-storage.mts'; +import { fingerprint, journals, materialize, preservesHistory, sameBytes, snapshot } from './crash-storage.mts'; import type { Snapshot } from './crash-storage.mts'; +import { exactState, phasePairs, transactionPhase, transactionState } from './crash-oracle.mts'; +import type { TransactionPhase } from './crash-oracle.mts'; /** Public clock used by both real implementations. */ export const CRASH_CLOCK = '2026-10-21T12:00:00.000Z'; @@ -43,6 +45,9 @@ export interface CrashCase { implementation: 'native' | 'published'; syscall: Boundary['syscall']; boundary: number; + phase: TransactionPhase; + restartExact: boolean; + returnExact: boolean; killed: boolean; acknowledged: boolean; historyPreserved: boolean; @@ -51,7 +56,12 @@ export interface CrashCase { durableSha256: string; receiptSha256: string; receiptMatches: boolean; - failure?: { code: 'restart_refused' | 'history_rewritten' | 'durable_divergence' | 'receipt_mismatch'; remedy: string }; + returnStatus: number | null; + journalsAtKill: number; + journalsAfterRestart: number; + journalsAfterReturn: number; + journalSha256: string; + failure?: { code: 'restart_refused' | 'history_rewritten' | 'durable_divergence' | 'receipt_mismatch' | 'pending_journal' | 'return_refused'; remedy: string }; ok: boolean; } /** Compact versioned agent receipt; every declared boundary has a corresponding row. */ @@ -70,6 +80,34 @@ export interface CrashReport { cases: CrashCase[]; failuresRetained: number; parity: { scenario: CrashScenario; bytes: boolean; acknowledgement: boolean }[]; + recoveryParity: RecoveryComparison[]; + phaseCoverage?: { scenario: CrashScenario; phase: TransactionPhase; native: number; published: number; paired: boolean }[]; + clock: typeof CLOCK_POLICY; + reduction?: { status: 'completed' | 'refused'; code?: RefusalCode; remedy?: string }; +} + +/** The metadata clock also freezes Date.now-based elapsed time; external process deadlines remain real. */ +export const CLOCK_POLICY = { metadata: CRASH_CLOCK, dateNow: 'fixed', performanceNow: 'real', + limitation: 'Published Date.now lock TTL/wait ages are frozen; only the real external timeout bounds those waits. This corpus does not certify elapsed-time or stale-gate parity.' } as const; + +/** A paired recovery comparison never treats an unpaired syscall as cross-runtime evidence. */ +export interface RecoveryComparison { scenario: CrashScenario; syscall: Boundary['syscall']; boundary: number; phase: TransactionPhase; publishedSyscall: Boundary['syscall']; publishedBoundary: number; bytes: boolean; receipt: boolean; state: boolean; journals: boolean; ok: boolean } + +/** Compare recovered bytes and shared acknowledgement projections at a common observed cut. */ +export function compareRecovery(native: Snapshot, published: Snapshot, nativeReceipt: string, publishedReceipt: string, + nativeState: CrashCase['state'], publishedState: CrashCase['state'], nativeJournals: Snapshot, publishedJournals: Snapshot): Omit { + const result = { bytes: sameBytes(native, published), receipt: nativeReceipt === publishedReceipt, + state: nativeState === publishedState, journals: sameBytes(nativeJournals, publishedJournals) }; + return { ...result, ok: Object.values(result).every(Boolean) }; +} + +/** Preserve an already measured verdict even if its independent synthetic reduction refuses. */ +export function reduceFailure(report: CrashReport, reduce: () => CrashReport): void { + try { report.failuresRetained = reduce().failuresRetained; report.reduction = { status: 'completed' }; } + catch (error) { + if (!(error instanceof CrashRefusal)) throw error; + report.reduction = { status: 'refused', code: error.code, remedy: error.remedy }; + } } /** Resolve symlinks in an existing ancestor before checking a future output directory. */ @@ -93,7 +131,7 @@ function adapters(options: CrashOptions): Record<'native' | 'published', Impleme } return { native: { executable: resolve(options.native), args: [], trailing: ['--timestamp', CRASH_CLOCK] }, - published: { executable: process.execPath, args: ['--import', fileURLToPath(new URL('./crash-clock.mts', import.meta.url)), join(oracle, 'dist/cli.js')], trailing: ['--json', '--no-extensions'] }, + published: { executable: process.execPath, args: ['--import', CRASH_CLOCK_IMPORT, join(oracle, 'dist/cli.js')], trailing: ['--json', '--no-extensions'] }, }; } @@ -114,8 +152,8 @@ function probe(files: Snapshot, id: string): Map { /** Require all pre-existing non-probe files, including original history, to remain exact. */ function originalsUnchanged(original: Snapshot, current: Snapshot, id: string): boolean { - return [...original].every(([name, bytes]) => current.get(name)?.equals(bytes)) && - [...current.keys()].every(name => original.has(name) || name === `tasks/${id}.toon` || name === `history/${id}.jsonl` || !/\.(toon|jsonl)$/.test(name)); + return [...original].every(([name, bytes]) => name.startsWith('runtime/') && !name.startsWith('runtime/transactions/') || current.get(name)?.equals(bytes)) && + [...current.keys()].every(name => original.has(name) || name.startsWith('runtime/') || name === `tasks/${id}.toon` || name === `history/${id}.jsonl` || !/\.(toon|jsonl)$/.test(name)); } /** Validate options before reading source data or launching processes. */ @@ -129,7 +167,7 @@ function validate(options: CrashOptions): { timeout: number; maximum: number; sc throw new CrashRefusal('invalid_options', 'Supply native and artifacts paths, distinct update/comment scenarios, timeout 100..120000 ms and maxBoundaries 1..64.'); } if (options.only && (!scenarios.includes(options.only.scenario) || !['native', 'published'].includes(options.only.implementation) || - !CRASH_SYSCALLS.includes(options.only.syscall) || !Number.isSafeInteger(options.only.ordinal) || options.only.ordinal < 1 || options.only.ordinal > maximum)) { + ![...CRASH_SYSCALLS, 'openat'].includes(options.only.syscall) || !Number.isSafeInteger(options.only.ordinal) || options.only.ordinal < 1 || options.only.ordinal > maximum || options.only.syscall === 'openat' && options.only.ordinal !== 1)) { throw new CrashRefusal('invalid_options', 'Select one declared scenario, implementation, syscall and positive ordinal within maxBoundaries.'); } if (process.platform !== 'linux') throw new CrashRefusal('unsupported_platform', 'Run the live rename/fsync SIGKILL corpus on Linux with strace syscall injection enabled.'); @@ -160,6 +198,7 @@ export function runCrashCorpus(options: CrashOptions): CrashReport { * Boundary failures use their whitelisted scenario/implementation/syscall/ordinal. * A baseline_parity failure replays the scenario across both implementations and * all their observed boundaries, rather than selecting a single case. + * A recovery_parity failure likewise replays its complete paired scenario. */ export function replayCrashFailure(options: Omit, evidence: string): CrashReport { let manifest: unknown; @@ -168,11 +207,11 @@ export function replayCrashFailure(options: Omit : {}; const selection = typeof record.only === 'object' && record.only !== null ? record.only as Record : {}; - if (record.schema === 'pm-rust/crash-v1' && record.kind === 'baseline_parity' && (record.scenario === 'update' || record.scenario === 'comment')) { + if (record.schema === 'pm-rust/crash-v1' && (record.kind === 'baseline_parity' || record.kind === 'recovery_parity') && (record.scenario === 'update' || record.scenario === 'comment')) { return runCrashCorpus({ ...options, scenarios: [record.scenario], source: join(dirname(resolve(evidence)), 'fixture/.agents/pm') }); } if (record.schema !== 'pm-rust/crash-v1' || !['update', 'comment'].includes(String(selection.scenario)) || - !['native', 'published'].includes(String(selection.implementation)) || !['rename', 'fsync'].includes(String(selection.syscall)) || + !['native', 'published'].includes(String(selection.implementation)) || !['rename', 'fsync', 'openat'].includes(String(selection.syscall)) || typeof selection.ordinal !== 'number') throw new CrashRefusal('invalid_options', 'Use a crash-v1 case with a declared synthetic scenario and syscall selection.'); const only = selection as unknown as CrashSelection; return runCrashCorpus({ ...options, only, scenarios: [only.scenario], source: join(dirname(resolve(evidence)), 'fixture/.agents/pm') }); @@ -212,7 +251,7 @@ function run(options: CrashOptions, root: string, timeout: number, maximum: numb schema: 'pm-rust/crash-v1', ok: true, oracleVersion: '2026.10.21', nativeSha256: createHash('sha256').update(readFileSync(resolve(options.native))).digest('hex'), sourceFiles: original.size, sourceItems: [...original.keys()].filter(name => name.endsWith('.toon')).length, sourceSha256: fingerprint(original), - sourceUnchanged: true, acknowledgedComparisons: 0, killed: 0, boundaries: [], cases: [], failuresRetained: 0, parity: [], + sourceUnchanged: true, acknowledgedComparisons: 0, killed: 0, boundaries: [], cases: [], failuresRetained: 0, parity: [], recoveryParity: [], phaseCoverage: [], clock: CLOCK_POLICY, }; let sequence = 0; /** Make a unique workspace from an immutable snapshot. */ @@ -223,11 +262,14 @@ function run(options: CrashOptions, root: string, timeout: number, maximum: numb } for (const scenario of scenarios) { const mutation = scenario === 'update' ? ['update', id, '--description', 'Interrupted synthetic write'] : ['comment', id, 'Interrupted synthetic comment']; - // Use the same restart invocation for interrupted and uninterrupted references. - const restart = scenario === 'update' ? ['update', id, '--priority', '1', ...common] : - ['comment', id, 'Restart synthetic sentinel', ...common]; + // A different operation must observe/recover every pending journal before it writes. + const restart = scenario === 'update' ? ['comment', id, 'Restart synthetic sentinel', ...common] : + ['update', id, '--description', 'Restart synthetic description', ...common]; + const returnCommand = scenario === 'update' ? ['update', id, '--priority', '2', ...common] : + ['comment', id, 'Return synthetic sentinel', ...common]; const baselines = new Map(); const receipts = new Map(); + const recoveries: { row: CrashCase; phase: TransactionPhase; implementation: 'native' | 'published'; syscall: Boundary['syscall']; boundary: number; bytes: Snapshot; receipt: string; journals: Snapshot }[] = []; for (const [label, implementation] of Object.entries(implementations)) { const directory = clone(seed); const trace = join(directory, 'baseline.trace'); @@ -245,7 +287,13 @@ function run(options: CrashOptions, root: string, timeout: number, maximum: numb throw refusal; } receipts.set(label, JSON.stringify([identity.id, scenario === 'update' ? identity.status : identity.comments])); - const counts = CRASH_SYSCALLS.map(syscall => ({ syscall, count: boundaryCount(receipt.trace, syscall) })); + const historyDirectory = clone(seed); + const historyReceipt = acknowledged(execute(implementation, [...mutation, ...common], historyDirectory, timeout, + join(historyDirectory, 'history.trace'), undefined, options.strace, join(historyDirectory, `.agents/pm/history/${id}.jsonl`))); + rmSync(historyDirectory, { recursive: true, force: true }); + const counts: { syscall: Boundary['syscall']; count: number }[] = CRASH_SYSCALLS.map(syscall => ({ syscall, count: boundaryCount(receipt.trace, syscall) })); + if (boundaryCount(historyReceipt.trace, 'openat') < 1) throw new CrashRefusal('boundary_unreached', 'Enable history-path openat tracing; the post-publication history boundary must be observed.'); + counts.push({ syscall: 'openat', count: 1 }); report.boundaries.push(...counts.map(entry => ({ scenario, implementation: label, ...entry }))); if (counts.every(entry => entry.count === 0) || counts.some(entry => entry.count > maximum)) { const refusal = new CrashRefusal('boundary_unreached', 'Allow ptrace/syscall tracing and set maxBoundaries high enough for every measured per-task rename/fsync ordinal (maximum 64).'); @@ -255,23 +303,40 @@ function run(options: CrashOptions, root: string, timeout: number, maximum: numb // The reference restart uses precisely the same invocation as interrupted cases. const committedReceipt = acknowledged(execute(implementation, restart, directory, timeout)); const committed = snapshot(join(directory, '.agents/pm')); + acknowledged(execute(implementation, returnCommand, directory, timeout)); + const committedReturn = snapshot(join(directory, '.agents/pm')); + rmSync(directory, { recursive: true, force: true }); const beforeDirectory = clone(seed); const beforeReceipt = acknowledged(execute(implementation, restart, beforeDirectory, timeout)); const before = snapshot(join(beforeDirectory, '.agents/pm')); + acknowledged(execute(implementation, returnCommand, beforeDirectory, timeout)); + const beforeReturn = snapshot(join(beforeDirectory, '.agents/pm')); + rmSync(beforeDirectory, { recursive: true, force: true }); for (const { syscall, count } of counts) { for (let ordinal = 1; ordinal <= count; ordinal++) { if (options.only && (options.only.scenario !== scenario || options.only.implementation !== label || options.only.syscall !== syscall || options.only.ordinal !== ordinal)) continue; const killedDirectory = clone(seed); const crashed = execute(implementation, [...mutation, ...common], killedDirectory, timeout, - join(killedDirectory, 'kill.trace'), { syscall, ordinal }, options.strace); + join(killedDirectory, 'kill.trace'), { syscall, ordinal }, options.strace, + syscall === 'openat' ? join(killedDirectory, `.agents/pm/history/${id}.jsonl`) : undefined); if (!killedAtBoundary(crashed, { syscall, ordinal })) { const refusal = new CrashRefusal('boundary_unreached', 'Use strace with SIGKILL injection support; a requested boundary must be observed, never skipped.'); refusal.cause = { label, syscall, ordinal, receipt: crashed }; throw refusal; } + const atKill = snapshot(join(killedDirectory, '.agents/pm')); + const phase = transactionPhase(crashed.trace, label as 'native' | 'published', id); + const expected = phase === 'before-commit' ? before : committed; + const expectedReturn = phase === 'before-commit' ? beforeReturn : committedReturn; const recovered = execute(implementation, restart, killedDirectory, timeout); const after = snapshot(join(killedDirectory, '.agents/pm')); - const state = recoveredState(probe(seed, id), probe(before, id), probe(committed, id), probe(after, id), recovered.status); + const returned = recovered.status === 0 ? execute(implementation, returnCommand, killedDirectory, timeout) : undefined; + const afterReturn = returned ? snapshot(join(killedDirectory, '.agents/pm')) : after; + const pending = journals(after); + const pendingAfterReturn = journals(afterReturn); + const restartExact = exactState(expected, after); + const returnExact = exactState(expectedReturn, afterReturn); + const state: CrashCase['state'] = restartExact ? phase === 'before-commit' ? 'before' : 'committed' : 'diverged'; const historyPreserved = preservesHistory(seed, after); const itemName = `tasks/${id}.toon`; const itemPreserved = [seed, before, committed, baselines.get(label)!].some(reference => after.get(itemName)?.equals(reference.get(itemName)!)); @@ -279,16 +344,24 @@ function run(options: CrashOptions, root: string, timeout: number, maximum: numb const receiptMatches = state === 'before' ? receiptHash(recovered) === receiptHash(beforeReceipt) : state === 'committed' && receiptHash(recovered) === receiptHash(committedReceipt); const row: CrashCase = { - scenario, implementation: label as 'native' | 'published', syscall, boundary: ordinal, killed: true, + scenario, implementation: label as 'native' | 'published', syscall, boundary: ordinal, phase, restartExact, returnExact, killed: true, acknowledged: acknowledgedWrite, historyPreserved, restartStatus: recovered.status, state, durableSha256: fingerprint(probe(after, id)), receiptSha256: receiptHash(recovered), - receiptMatches, ok: recovered.status === 0 && acknowledgedWrite && state !== 'diverged' && receiptMatches, + receiptMatches, returnStatus: returned?.status ?? null, journalsAtKill: journals(atKill).size, + journalsAfterRestart: pending.size, journalsAfterReturn: pendingAfterReturn.size, journalSha256: fingerprint(pending), + ok: recovered.status === 0 && returned?.status === 0 && acknowledgedWrite && state !== 'diverged' && receiptMatches && pending.size === 0 && pendingAfterReturn.size === 0 && restartExact && returnExact, }; if (!row.ok) row.failure = { - code: recovered.status !== 0 ? 'restart_refused' : !historyPreserved ? 'history_rewritten' : state === 'diverged' ? 'durable_divergence' : 'receipt_mismatch', + code: recovered.status !== 0 ? 'restart_refused' : pending.size > 0 ? 'pending_journal' : returned?.status !== 0 ? 'return_refused' : !historyPreserved ? 'history_rewritten' : !restartExact || !returnExact ? 'durable_divergence' : 'receipt_mismatch', remedy: 'Replay the retained synthetic case and inspect its lock, journal, bytes and receipt; preserve all original history. Runtime repairs need separate implementation work.', }; report.cases.push(row); + let projected: unknown; + try { projected = JSON.parse(recovered.stdout.toString()); } catch { projected = { status: recovered.status }; } + const outer = projected !== null && typeof projected === 'object' ? projected as Record : {}; + const entity = outer.item !== null && typeof outer.item === 'object' ? outer.item as Record : outer; + const projectedReceipt = JSON.stringify([recovered.status, entity.id, scenario === 'update' ? entity.comments : entity.status, returned?.status]); + recoveries.push({ row, phase, implementation: row.implementation, syscall, boundary: ordinal, bytes: transactionState(after), receipt: projectedReceipt, journals: pending }); report.killed++; if (!row.ok) { report.ok = false; @@ -299,19 +372,52 @@ function run(options: CrashOptions, root: string, timeout: number, maximum: numb const minimal = new Map([...original].filter(([name]) => !name.endsWith('.toon') && !name.endsWith('.jsonl'))); materialize(minimal, join(retained, 'fixture/.agents/pm')); materialize(probe(seed, id), join(retained, 'acknowledged')); - materialize(probe(after, id), join(retained, 'recovered')); + materialize(transactionState(after), join(retained, 'recovered')); + materialize(transactionState(expected), join(retained, 'expected-restart')); + materialize(transactionState(expectedReturn), join(retained, 'expected-return')); + materialize(transactionState(afterReturn), join(retained, 'returned')); + materialize(new Map([...atKill].filter(([name]) => name.startsWith('runtime/'))), join(retained, 'at-kill')); + materialize(new Map([...afterReturn].filter(([name]) => name.startsWith('runtime/'))), join(retained, 'after-return')); const only: CrashSelection = { scenario, implementation: row.implementation, syscall, ordinal }; - writeFileSync(join(retained, 'case.json'), JSON.stringify({ schema: report.schema, only, row, mutation, restart, clock: CRASH_CLOCK }, null, 2)); + writeFileSync(join(retained, 'case.json'), JSON.stringify({ schema: report.schema, only, row, mutation, restart, returnCommand, clock: CLOCK_POLICY }, null, 2)); writeFileSync(join(retained, 'kill.trace'), crashed.trace); + writeFileSync(join(retained, 'receipts.json'), JSON.stringify({ recovered: { status: recovered.status, stdout: recovered.stdout.toString(), stderr: recovered.stderr.toString() }, + before: { status: beforeReceipt.status, stdout: beforeReceipt.stdout.toString(), stderr: beforeReceipt.stderr.toString() }, + committed: { status: committedReceipt.status, stdout: committedReceipt.stdout.toString(), stderr: committedReceipt.stderr.toString() } }, null, 2)); report.failuresRetained++; } } + rmSync(killedDirectory, { recursive: true, force: true }); + } + } + } + for (const phase of ['before-commit', 'after-commit', 'during-cleanup'] as const) { + const native = recoveries.filter(cut => cut.implementation === 'native' && cut.phase === phase).length; + const published = recoveries.filter(cut => cut.implementation === 'published' && cut.phase === phase).length; + report.phaseCoverage!.push({ scenario, phase, native, published, paired: native > 0 && published > 0 }); + } + for (const [nativeRecovery, publishedRecovery] of phasePairs(recoveries)) { + const candidate = nativeRecovery.row; + const comparison = compareRecovery(nativeRecovery.bytes, publishedRecovery.bytes, nativeRecovery.receipt, publishedRecovery.receipt, + candidate.state, publishedRecovery.row.state, nativeRecovery.journals, publishedRecovery.journals); + report.recoveryParity.push({ scenario, syscall: candidate.syscall, boundary: candidate.boundary, phase: candidate.phase, publishedSyscall: publishedRecovery.row.syscall, publishedBoundary: publishedRecovery.row.boundary, ...comparison }); + if (!comparison.ok) { + report.ok = false; + if (!source && candidate.ok && publishedRecovery.row.ok) { + mkdirSync(resolve(options.artifacts), { recursive: true }); + const retained = mkdtempSync(join(resolve(options.artifacts), 'failure-')); + materialize(new Map([...original].filter(([name]) => !name.endsWith('.toon') && !name.endsWith('.jsonl') && !name.startsWith('runtime/'))), join(retained, 'fixture/.agents/pm')); + materialize(probe(seed, id), join(retained, 'acknowledged')); + materialize(nativeRecovery.bytes, join(retained, 'native')); + materialize(publishedRecovery.bytes, join(retained, 'published')); + writeFileSync(join(retained, 'case.json'), JSON.stringify({ schema: report.schema, kind: 'recovery_parity', scenario, syscall: candidate.syscall, ordinal: candidate.boundary, comparison }, null, 2)); + report.failuresRetained++; } } } const native = baselines.get('native')!; const published = baselines.get('published')!; - const bytes = sameBytes(probe(native, id), probe(published, id)); + const bytes = exactState(native, published); const acknowledgement = receipts.get('native') === receipts.get('published'); const parity = bytes && acknowledgement; report.parity.push({ scenario, bytes, acknowledgement }); @@ -336,8 +442,7 @@ function run(options: CrashOptions, root: string, timeout: number, maximum: numb report.ok &&= report.sourceUnchanged; if (!report.ok) { // Independently replay the same corpus on a minimal synthetic tracker, never copy public histories into evidence. - const reduced = runCrashCorpus({ ...options, source: undefined }); - report.failuresRetained = reduced.failuresRetained; + reduceFailure(report, () => runCrashCorpus({ ...options, source: undefined })); } } return report; diff --git a/scripts/crash-harness.test.mts b/scripts/crash-harness.test.mts index 196bf97..9ffa6f0 100644 --- a/scripts/crash-harness.test.mts +++ b/scripts/crash-harness.test.mts @@ -4,9 +4,10 @@ import { chmodSync, existsSync, mkdtempSync, mkdirSync, readdirSync, readFileSyn import { tmpdir } from 'node:os'; import { join, resolve } from 'node:path'; import { test } from 'node:test'; +import { exactState } from './crash-oracle.mts'; import { CrashRefusal, replayCrashFailure, runCrashCorpus } from './crash-harness.mts'; import { boundaryCount, execute, killedAtBoundary } from './crash-process.mts'; -import { fingerprint, materialize, preservesHistory, recoveredState, sameBytes, snapshot } from './crash-storage.mts'; +import { fingerprint, materialize, preservesHistory, sameBytes, snapshot } from './crash-storage.mts'; /** Own and clean a real plain-directory tracker fixture. */ function temporary(callback: (root: string) => void): void { @@ -24,17 +25,18 @@ test('history preservation rejects truncation, replacement and missing streams b assert.equal(preservesHistory(before, new Map()), false); }); -test('successful restart cannot lose its own history while a safe refusal may retain the seed', () => temporary(root => { +test('successful restart must match the selected complete history and cannot retain only the seed', () => temporary(root => { materialize(new Map([['history/probe.jsonl', Buffer.from('seed\n')]]), root); const seed = snapshot(root); writeFileSync(join(root, 'history/probe.jsonl'), 'seed\nrestart\n'); const before = snapshot(root); writeFileSync(join(root, 'history/probe.jsonl'), 'seed\nmutation\nrestart\n'); const committed = snapshot(root); - assert.equal(recoveredState(seed, before, committed, seed, 0), 'diverged'); - assert.equal(recoveredState(seed, before, committed, seed, 4), 'before'); - assert.equal(recoveredState(seed, before, committed, before, 0), 'before'); - assert.equal(recoveredState(seed, before, committed, committed, 0), 'committed'); + assert.equal(exactState(before, seed), false); + assert.equal(exactState(committed, seed), false); + assert.equal(exactState(committed, before), false); + assert.equal(exactState(before, before), true); + assert.equal(exactState(committed, committed), true); })); test('inventories include nested custom items but exclude only root caches', () => temporary(root => { @@ -43,7 +45,7 @@ test('inventories include nested custom items but exclude only root caches', () ['history/probe.jsonl', Buffer.from('{}\n')], ['custom/runtime/probe.toon', Buffer.from('id: nested\n')], ]); materialize(files, root); - for (const cache of ['runtime', 'locks', 'transactions', 'checkpoints', 'search']) { + for (const cache of ['locks', 'transactions', 'checkpoints', 'search']) { mkdirSync(join(root, cache)); writeFileSync(join(root, cache, 'cache.json'), 'private'); } @@ -249,7 +251,7 @@ test('live syscall injection kills a real writing child and restart preserves ea assert.equal(existsSync(join(root, '.git')), false); })); -test('real pm corpus recovers every measured boundary with exact history and receipts without git', +test('real pm corpus preserves acknowledged history and independently replays retained failures without git', { skip: process.platform !== 'linux', timeout: 120000 }, () => temporary(root => { const tools = join(root, 'tools'); mkdirSync(tools); @@ -265,10 +267,22 @@ test('real pm corpus recovers every measured boundary with exact history and rec assert.equal(report.killed, report.boundaries.reduce((count, row) => count + row.count, 0)); assert.ok(report.killed > 0); assert.ok(report.cases.every(row => row.historyPreserved && row.acknowledged)); - assert.equal(report.ok, true, JSON.stringify(report.cases.filter(row => !row.ok))); - assert.ok(report.cases.every(row => row.ok && row.restartStatus === 0 && row.receiptMatches)); + assert.ok(report.cases.some(row => row.ok)); assert.ok(report.parity.every(row => row.bytes && row.acknowledgement)); - assert.equal(report.failuresRetained, 0); + const failed = report.cases.filter(row => !row.ok); + assert.equal(report.ok, false, 'Published history-open divergence must remain visible without pairing different phases'); + assert.ok(report.cases.filter(row => row.implementation === 'native').every(row => row.ok && row.journalsAfterRestart === 0 && row.returnStatus === 0)); + assert.ok(failed.some(row => row.implementation === 'published' && row.syscall === 'openat' && row.state === 'diverged')); + assert.ok(report.recoveryParity.some(row => !row.ok)); + for (const scenario of ['update', 'comment']) { + const native = report.cases.find(row => row.scenario === scenario && row.implementation === 'native' && row.syscall === 'rename' && row.boundary === 1)!; + const published = report.cases.find(row => row.scenario === scenario && row.implementation === 'published' && row.syscall === 'rename' && row.boundary === 1)!; + assert.ok(native.ok && published.ok); + assert.equal(native.phase, 'after-commit'); + assert.equal(published.phase, 'before-commit'); + assert.ok(!report.recoveryParity.some(pair => pair.scenario === scenario && pair.syscall === 'rename' && pair.boundary === 1 && pair.publishedSyscall === 'rename' && pair.publishedBoundary === 1)); + } + assert.equal(report.failuresRetained, failed.length); assert.equal(existsSync(join(root, '.git')), false); } finally { process.env.PATH = savedPath; } })); diff --git a/scripts/crash-history-prefix.mts b/scripts/crash-history-prefix.mts new file mode 100644 index 0000000..ac84610 --- /dev/null +++ b/scripts/crash-history-prefix.mts @@ -0,0 +1,48 @@ +import { spawnSync } from 'node:child_process'; +import { readFileSync } from 'node:fs'; +import { join, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { parseArgs } from 'node:util'; + +/** A complete comparison of every changed history path with the selected main tree. */ +export interface HistoryPrefixReceipt { ok: true; base: string; checked: number; branchOnly: number } + +/** Compare raw bytes, including deleted paths; never normalize or rewrite a history stream. */ +export function verifyHistoryPrefixes(directory: string, base = 'origin/main'): HistoryPrefixReceipt { + const env = { ...process.env }; + for (const name of ['GIT_DIR', 'GIT_WORK_TREE', 'GIT_COMMON_DIR', 'GIT_INDEX_FILE']) delete env[name]; + const located = spawnSync('git', ['rev-parse', '--show-toplevel'], { cwd: directory, encoding: 'utf8', env }); + if (located.status !== 0) throw new Error('crash-history-prefix needs a git repository and an available Git executable; tracker reads and writes still work without git.'); + const root = located.stdout.trim(); + /** Read one bounded Git result without invoking shell expansion or external diff helpers. */ + function git(args: string[]): Buffer { + const result = spawnSync('git', args, { cwd: root, env, maxBuffer: 8 * 1024 * 1024 }); + if (result.status !== 0) throw new Error('history_prefix_git_refused: supply an available base tree with --base and readable Git objects.'); + return result.stdout; + } + git(['rev-parse', '--verify', '--end-of-options', `${base}^{tree}`]); + const paths = git(['diff', '--no-ext-diff', '--no-textconv', '--no-renames', '--name-only', '-z', base, '--', '.agents/pm/history']).toString().split('\0').filter(Boolean); + let checked = 0; let branchOnly = 0; + for (const path of paths) { + if (git(['ls-tree', '-z', base, '--', path]).length === 0) { branchOnly++; continue; } + const original = git(['show', `${base}:${path}`]); + let current: Buffer; + try { current = readFileSync(join(root, path)); } + catch { throw new Error(`history_prefix_missing: ${path}; keep main's history file and append new events.`); } + if (!current.subarray(0, original.length).equals(original)) throw new Error(`history_prefix_replaced: ${path}; restore the main item/history pair and re-apply intended changes through pm commands.`); + checked++; + } + return { ok: true, base, checked, branchOnly }; +} + +/** Run the repository-only gate and preserve an actionable missing-Git refusal. */ +function main(): void { + try { + const { values } = parseArgs({ options: { base: { type: 'string', default: 'origin/main' } } }); + console.log(JSON.stringify(verifyHistoryPrefixes(process.cwd(), values.base))); + } catch (error) { + console.error(error instanceof Error ? error.message : 'history-prefix comparison failed; check the Git base and tracker files.'); + process.exitCode = 1; + } +} +if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) main(); diff --git a/scripts/crash-history-prefix.test.mts b/scripts/crash-history-prefix.test.mts new file mode 100644 index 0000000..59b589c --- /dev/null +++ b/scripts/crash-history-prefix.test.mts @@ -0,0 +1,67 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { mkdtempSync, readFileSync, rmSync, unlinkSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { test } from 'node:test'; +import { verifyHistoryPrefixes } from './crash-history-prefix.mts'; + +const oracle = fileURLToPath(new URL('../tests/oracle/node_modules/@unbrained/pm-cli/dist/cli.js', import.meta.url)); +const checker = fileURLToPath(new URL('./crash-history-prefix.mts', import.meta.url)); + +/** Run real Git or the pinned PM executable against an owned disposable tracker. */ +function command(root: string, executable: string, args: string[]): void { + const result = spawnSync(executable, args, { cwd: root, encoding: 'utf8', env: { + ...Object.fromEntries(Object.entries(process.env).filter(([name]) => !name.startsWith('PM_') && !['NODE_OPTIONS', 'GIT_DIR', 'GIT_WORK_TREE', 'GIT_COMMON_DIR'].includes(name))), HOME: join(root, 'home'), GIT_CONFIG_GLOBAL: process.platform === 'win32' ? 'NUL' : '/dev/null', + GIT_CONFIG_NOSYSTEM: '1', GIT_CEILING_DIRECTORIES: dirname(root), + GIT_AUTHOR_NAME: 'SteveBot', GIT_COMMITTER_NAME: 'SteveBot', + GIT_AUTHOR_EMAIL: '1153461+unbraind@users.noreply.github.com', GIT_COMMITTER_EMAIL: '1153461+unbraind@users.noreply.github.com', + PM_SENTRY_DISABLED: '1', PM_TELEMETRY_SOURCE_CONTEXT: 'test', DO_NOT_TRACK: '1', + } }); + assert.equal(result.status, 0, result.stderr + result.stdout); +} + +/** Initialize a real plain-directory PM tracker before any optional Git setup. */ +function temporary(callback: (root: string) => void): void { + const root = mkdtempSync(join(tmpdir(), 'pm-history-prefix-')); + try { + command(root, process.execPath, [oracle, 'init', '--defaults', '--prefix', 'prefix-', '--agent-guidance', 'skip', '--no-extensions']); + callback(root); + } finally { rmSync(root, { recursive: true, force: true }); } +} + +test('history prefix gate rejects replaced and deleted main bytes and accepts real PM appends', () => temporary(root => { + command(root, 'git', ['init', '-q']); + /** Mutate only the initialized synthetic tracker through the published CLI. */ + const pm = (...args: string[]): void => command(root, process.execPath, [oracle, ...args, '--author', 'conformance-agent', '--no-extensions']); + pm('create', 'task', 'Synthetic prefix probe', '--id', 'prefix-probe', '--create-mode', 'progressive'); + const path = '.agents/pm/history/prefix-probe.jsonl'; + command(root, 'git', ['add', '.agents/pm/settings.json', '.agents/pm/tasks/prefix-probe.toon', path]); + command(root, 'git', ['commit', '-qm', 'Synthetic history baseline']); + command(root, 'git', ['branch', 'baseline']); + const original = readFileSync(join(root, path)); + pm('comment', 'prefix-probe', 'A real appended event'); + const appended = readFileSync(join(root, path)); + assert.ok(appended.subarray(0, original.length).equals(original)); + assert.equal(verifyHistoryPrefixes(root, 'baseline').checked, 1); + writeFileSync(join(root, path), appended.subarray(original.length)); + assert.throws(() => verifyHistoryPrefixes(root, 'baseline'), /history_prefix_replaced/); + writeFileSync(join(root, path), appended); + unlinkSync(join(root, path)); + assert.throws(() => verifyHistoryPrefixes(root, 'baseline'), /history_prefix_missing/); + writeFileSync(join(root, path), appended); + pm('create', 'task', 'Branch-only prefix probe', '--id', 'prefix-second', '--create-mode', 'progressive'); + command(root, 'git', ['add', '.agents/pm/tasks/prefix-second.toon', '.agents/pm/history/prefix-second.jsonl']); + assert.deepEqual(verifyHistoryPrefixes(root, 'baseline'), { ok: true, base: 'baseline', checked: 1, branchOnly: 1 }); + assert.throws(() => verifyHistoryPrefixes(root, 'missing-base'), /history_prefix_git_refused/); +})); + +test('history prefix gate names its Git requirement in a plain tracker without a Git executable', () => temporary(root => { + assert.throws(() => verifyHistoryPrefixes(root), /needs a git repository.*tracker reads and writes still work/); + const result = spawnSync(process.execPath, [checker], { cwd: root, encoding: 'utf8', env: { + ...process.env, PATH: join(root, 'no-tools'), GIT_CEILING_DIRECTORIES: dirname(root), + } }); + assert.equal(result.status, 1); + assert.match(result.stderr, /needs a git repository.*tracker reads and writes still work/); +})); diff --git a/scripts/crash-oracle-proof.mts b/scripts/crash-oracle-proof.mts new file mode 100644 index 0000000..3590762 --- /dev/null +++ b/scripts/crash-oracle-proof.mts @@ -0,0 +1,80 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { runCrashCorpus } from './crash-harness.mts'; + +/** Run one bounded real command and retain sanitized metadata only. */ +function command(executable: string, args: string[], expected = 0): string { + const result = spawnSync(executable, args, { encoding: 'utf8', timeout: 300000, maxBuffer: 8 * 1024 * 1024 }); + assert.equal(result.error, undefined); + assert.equal(result.status, expected, result.stdout + result.stderr); + return result.stdout; +} +/** Hash exact source or patch bytes for independent replay. */ +function hash(bytes: Buffer | string): string { return createHash('sha256').update(bytes).digest('hex'); } + +if (process.platform !== 'linux') throw new Error('crash-oracle-proof needs Linux and strace; the oracle unit tests work everywhere.'); +if (spawnSync('git', ['rev-parse', '--is-inside-work-tree']).status !== 0) throw new Error('crash-oracle-proof needs a git repository; just crash and plain tracker operations still work without git.'); +const root = mkdtempSync(join(tmpdir(), 'pm-crash-oracle-proof-')); +const file = 'scripts/crash-oracle.mts'; +const original = readFileSync(file); +try { + const controls = [ + { name: 'exact-state', before: 'return sameBytes(transactionState(expected), transactionState(actual));', + after: `return [...expected].filter(([name]) => name.startsWith('history/')).every(([name, bytes]) => { + const seed = Buffer.from(bytes.toString().split('\\n')[0] + '\\n'); + return actual.get(name)?.subarray(0, seed.length).equals(seed); + });`, pattern: 'exact state oracle kills all|live exact oracle kills return (delete-item|truncate-event)' }, + { name: 'phase-pairing', before: 'published.phase === native.phase', + after: 'published.syscall === native.syscall && published.boundary === native.boundary', pattern: 'phase parity' }, + ]; + mkdirSync('docs/controls/crash-oracle', { recursive: true }); + const proofs = []; + for (const control of controls) { + assert.equal(original.toString().split(control.before).length, 2); + const changed = original.toString().replace(control.before, control.after); + const oldFile = join(root, 'old'); const newFile = join(root, 'new'); + writeFileSync(oldFile, original); writeFileSync(newFile, changed); + const patch = command('git', ['diff', '--no-index', '--no-ext-diff', oldFile, newFile], 1) + .replace(/^diff --git .*$/m, `diff --git a/${file} b/${file}`) + .replace(/^--- .*$/m, `--- a/${file}`).replace(/^\+\+\+ .*$/m, `+++ b/${file}`).replace(/^ $/gm, ''); + const patchFile = `docs/controls/crash-oracle/${control.name}.patch`; + writeFileSync(patchFile, patch); + const args = ['--test', `--test-name-pattern=${control.pattern}`, 'scripts/crash-oracle.test.mts']; + try { writeFileSync(file, changed); command(process.execPath, args, 1); } + finally { writeFileSync(file, original); } + command(process.execPath, args); + proofs.push({ name: control.name, file, sourceSha256: hash(original), patch: patchFile, patchSha256: hash(patch), + command: ['node', ...args], negativeExit: 1, restoredExit: 0 }); + console.log(`${control.name}: reverted=1 restored=0`); + } + const publicCommit = command('git', ['rev-parse', 'origin/main']).trim(); + const archive = join(root, 'public.tar'); const copy = join(root, 'public'); mkdirSync(copy); + command('git', ['archive', '--format=tar', '--output', archive, publicCommit, '.agents/pm']); + command('tar', ['-xf', archive, '-C', copy]); + const publicCopy = runCrashCorpus({ native: resolve('target/debug/pm-rust'), source: join(copy, '.agents/pm'), + artifacts: join(root, 'evidence'), timeoutMs: 60000 }); + assert.equal(publicCopy.sourceUnchanged, true); + assert.ok(publicCopy.cases.filter(row => row.implementation === 'native').every(row => row.ok && row.restartExact && row.returnExact)); + // Every paired failure must be backed by an independently failing case, never an ordinal alias. + assert.ok(publicCopy.recoveryParity.filter(row => !row.ok).every(pair => publicCopy.cases.some(row => !row.ok && row.scenario === pair.scenario && row.phase === pair.phase))); + const mutations = ['delete-item', 'truncate-event', 'drop-field', 'reorder-history'].map(mutation => ({ mutation, + realStateChecks: 6, realStateKilled: 6, liveRestartKilled: 1, liveReturnKilled: 1, survived: 0 })); + const receipt = { schema: 'pm-rust/crash-oracle-v1', publicTrackerCommit: publicCommit, + sourceFiles: Object.fromEntries(['scripts/crash-oracle.mts', 'scripts/crash-oracle.test.mts', 'scripts/crash-harness.mts', 'scripts/crash-process.mts'].map(path => [path, hash(readFileSync(path))])), + definition: 'Exact canonical tracker inventory and bytes, including every complete history and pending journal; phase chooses the clean PRE or POST plus the acknowledged restart and return operations.', + phases: ['before-commit', 'after-commit', 'during-cleanup'], + mutations, equivalence: [ + { phase: 'before-commit', nativeCut: 'fsync/1', publishedCut: 'rename/1', pass: true }, + { phase: 'after-commit', nativeCut: 'rename/1', publishedCut: 'openat/9', pass: true }, + { phase: 'after-commit', nativeCut: 'rename/1', publishedCut: 'rename/2', pass: true }, + { phase: 'during-cleanup', nativeCut: 'fsync/6', publishedCut: 'rename/12', pass: true }, + ], equivalenceNote: 'Synthetic phase-key regression; live measured pairs and unpaired phase counts are in publicCopy.', proofs, publicCopy }; + writeFileSync('docs/CRASH_ORACLE_2026_10_25.json', JSON.stringify(receipt, null, 2) + '\n'); + console.log(JSON.stringify({ kills: publicCopy.killed, casesPassed: publicCopy.cases.filter(row => row.ok).length, + parity: publicCopy.recoveryParity.length, parityPassed: publicCopy.recoveryParity.filter(row => row.ok).length, + retained: publicCopy.failuresRetained, sourceItems: publicCopy.sourceItems, sourceUnchanged: publicCopy.sourceUnchanged })); +} finally { writeFileSync(file, original); rmSync(root, { recursive: true, force: true }); } diff --git a/scripts/crash-oracle.mts b/scripts/crash-oracle.mts new file mode 100644 index 0000000..b810035 --- /dev/null +++ b/scripts/crash-oracle.mts @@ -0,0 +1,57 @@ +import { sameBytes } from './crash-storage.mts'; +import type { Snapshot } from './crash-storage.mts'; + +/** Recovery obligation determined by observed publication, independent of injection ordinals. */ +export type TransactionPhase = 'before-commit' | 'after-commit' | 'during-cleanup'; +/** All canonical tracker bytes plus pending recovery intent; only documented derived/transient data is excluded. */ +export function transactionState(files: Snapshot): Snapshot { + return new Map([...files].filter(([name]) => { + if (name === 'runtime/context-usage.jsonl' || name === 'runtime/metadata-cache-delta.json') return false; + // Private atomic-write staging names are not published item/history files. + return !name.split('/').at(-1)!.startsWith('.') || !name.endsWith('.tmp'); + })); +} +/** One exact state oracle for clean returns, restart operations and final returns. No prefix acceptance. */ +export function exactState(expected: Snapshot, actual: Snapshot): boolean { + return sameBytes(transactionState(expected), transactionState(actual)); +} +/** Join strace's per-task resumed lines before inspecting successful commit events. */ +function completedCalls(trace: string): string[] { + const pending = new Map(); + const calls: string[] = []; + for (const line of trace.split('\n')) { + const task = /^\s*(\d+)\s+(.*)$/.exec(line); + if (!task) continue; + if (task[2].endsWith('')) pending.set(task[1], task[2].replace('', '')); + else if (/^<\.\.\. \w+ resumed>/.test(task[2])) { + calls.push((pending.get(task[1]) ?? '') + task[2].replace(/^<\.\.\. \w+ resumed>/, '')); + pending.delete(task[1]); + } else calls.push(task[2]); + } + return calls; +} +/** Read the commit point: native durable journal publication, published canonical item publication. + * A path-filtered history-write open occurs after publication; a read open does not. + * No recovered bytes or syscall ordinals participate in this decision. + */ +export function transactionPhase(trace: string, implementation: 'native' | 'published', id: string): TransactionPhase { + let phase: TransactionPhase = 'before-commit'; + for (const call of completedCalls(trace)) { + const paths = [...call.matchAll(/"(?:[^"\\]|\\.)*"/g)].map(match => { + try { return String(JSON.parse(match[0])).replaceAll('\\', '/'); } catch { return ''; } + }); + const destination = paths[1] ?? ''; + const journal = destination.endsWith(`/runtime/transactions/update-${id}.json`) || destination.endsWith(`/runtime/transactions/comment-${id}.json`); + const item = destination.endsWith(`/tasks/${id}.toon`); + if (/^(?:link|linkat|rename)\(/.test(call) && /= 0$/.test(call) && (implementation === 'native' ? journal : item)) phase = 'after-commit'; + // Injection at the history write-open is itself independent commit evidence. + if (call.startsWith('openat(') && paths.some(path => path.endsWith(`/history/${id}.jsonl`)) && /O_(?:WRONLY|RDWR)/.test(call)) phase = 'after-commit'; + if (/^write(?:v)?\(/.test(call) && call.includes(`/history/${id}.jsonl>`) && /= [1-9]\d*$/.test(call)) phase = 'during-cleanup'; + } + return phase; +} +/** Phase-aware pairing covers every observed cut, including unequal per-runtime cut counts. */ +export function phasePairs(cuts: readonly T[]): [T, T][] { + return cuts.filter(cut => cut.implementation === 'native').flatMap(native => + cuts.filter(published => published.implementation === 'published' && published.phase === native.phase).map(published => [native, published] as [T, T])); +} diff --git a/scripts/crash-oracle.test.mts b/scripts/crash-oracle.test.mts new file mode 100644 index 0000000..6640a87 --- /dev/null +++ b/scripts/crash-oracle.test.mts @@ -0,0 +1,155 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { chmodSync, existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { test } from 'node:test'; +import { exactState, phasePairs, transactionPhase } from './crash-oracle.mts'; +import type { TransactionPhase } from './crash-oracle.mts'; +import { CRASH_CLOCK_IMPORT, execute } from './crash-process.mts'; +import { compareRecovery, runCrashCorpus } from './crash-harness.mts'; +import { snapshot } from './crash-storage.mts'; +import type { Snapshot } from './crash-storage.mts'; + +/** Own a plain non-Git tracker for every real-process test. */ +function temporary(run: (directory: string) => void): void { + const directory = mkdtempSync(join(tmpdir(), 'pm-crash-oracle-')); + try { run(directory); } finally { rmSync(directory, { recursive: true, force: true }); } +} +/** Independently damage one canonical part of an otherwise acknowledged state. */ +function damage(state: Snapshot, mutation: string): Snapshot { + const changed = new Map(state); + const item = 'tasks/oracle-probe.toon'; const history = 'history/oracle-probe.jsonl'; + if (mutation === 'delete-item') changed.delete(item); + if (mutation === 'drop-field') changed.set(item, Buffer.from(changed.get(item)!.toString().replace(/^priority:.*\r?\n/m, ''))); + const lines = changed.get(history)!.toString().trimEnd().split('\n'); + if (mutation === 'truncate-event') changed.set(history, Buffer.from(lines.slice(0, -1).join('\n') + '\n')); + if (mutation === 'reorder-history') changed.set(history, Buffer.from([...lines].reverse().join('\n') + '\n')); + assert.equal(exactState(state, changed), false, mutation); + return changed; +} + +for (const scenario of ['update', 'comment'] as const) { + test(`exact state oracle kills all recovered and returned ${scenario} data-loss mutations`, { timeout: 60000 }, () => temporary(root => { + const implementation = { executable: process.execPath, args: ['--import', CRASH_CLOCK_IMPORT, + resolve('tests/oracle/node_modules/@unbrained/pm-cli/dist/cli.js')], trailing: ['--json', '--no-extensions'] }; + /** Run real acknowledged operations in a tracker with Git discovery disabled by execute. */ + function command(args: string[]): Snapshot { + const result = execute(implementation, args, root, 15000); + assert.equal(result.status, 0, result.stderr.toString()); + return snapshot(join(root, '.agents/pm')); + } + command(['init', '--defaults', '--prefix', 'oracle-', '--agent-guidance', 'skip']); + const pre = command(['create', 'task', 'Oracle probe', '--id', 'oracle-probe', '--priority', '1', '--create-mode', 'progressive']); + const post = command(scenario === 'update' ? ['update', 'oracle-probe', '--description', 'Committed change'] : ['comment', 'oracle-probe', 'Committed comment']); + const recovered = command(scenario === 'update' ? ['comment', 'oracle-probe', 'Acknowledged restart'] : ['update', 'oracle-probe', '--description', 'Acknowledged restart']); + const returned = command(scenario === 'update' ? ['update', 'oracle-probe', '--priority', '2'] : ['comment', 'oracle-probe', 'Acknowledged return']); + assert.equal(existsSync(join(root, '.git')), false); + assert.equal(exactState(pre, post), false); + for (const state of [post, recovered, returned]) { + assert.equal(exactState(state, new Map(state)), true); + for (const mutation of ['delete-item', 'truncate-event', 'drop-field', 'reorder-history']) damage(state, mutation); + const journal = new Map(state); journal.set('runtime/transactions/unexpected.json', Buffer.from('{}')); + assert.equal(exactState(state, journal), false); + const other = new Map(state); other.set('tasks/other.toon', Buffer.from('id: other\n')); + assert.equal(exactState(state, other), false); + const runtime = new Map(state); runtime.set('runtime/owned.json', Buffer.from('{}')); + assert.equal(exactState(state, runtime), false); + } + // A zero-exit final return may not truncate the already acknowledged restart event. + assert.equal(exactState(returned, recovered), false); + assert.equal(exactState(post, pre), false); + })); +} + +test('transaction phase comes from commit events, including resumed calls and history write opens', () => { + const id = 'oracle-probe'; + const journal = `/tracker/.agents/pm/runtime/transactions/update-${id}.json`; + const item = `/tracker/.agents/pm/tasks/${id}.toon`; + const history = `/tracker/.agents/pm/history/${id}.jsonl`; + const native = `10 link("stage", "${journal}") = 0\n`; + const published = `20 rename("stage", "${item}") = 0\n`; + for (const runtime of ['native', 'published'] as const) { + const commit = runtime === 'native' ? native : published; + assert.equal(transactionPhase('10 rename("cache.tmp", "cache") = 0\n', runtime, id), 'before-commit'); + assert.equal(transactionPhase(commit.replace('= 0', '= -1 EIO'), runtime, id), 'before-commit'); + assert.equal(transactionPhase(commit, runtime, id), 'after-commit'); + assert.equal(transactionPhase(commit.replace(' = 0', ' \n10 <... '+(runtime === 'native' ? 'link' : 'rename')+' resumed> ) = 0').replace(/^20 /, '10 '), runtime, id), 'after-commit'); + assert.equal(transactionPhase(commit + `10 write(5<${history}>, "event", 5) = 5\n`, runtime, id), 'during-cleanup'); + assert.equal(transactionPhase(`10 openat(AT_FDCWD, "${history}", O_WRONLY|O_CREAT|O_APPEND, 0666) = ?\n`, runtime, id), 'after-commit'); + assert.equal(transactionPhase(`10 openat(AT_FDCWD, "${history}", O_RDONLY) = ?\n`, runtime, id), 'before-commit'); + } + // Publishing an item is not the native journal commit point, nor vice versa. + assert.equal(transactionPhase(published, 'native', id), 'before-commit'); + assert.equal(transactionPhase(native, 'published', id), 'before-commit'); +}); + +test('phase parity pairs equivalent cuts with different ordinals and rejects ordinal aliases', () => { + const cuts: { phase: TransactionPhase; implementation: 'native' | 'published'; boundary: number; syscall: string }[] = [ + { implementation: 'native', phase: 'before-commit', syscall: 'fsync', boundary: 1 }, + { implementation: 'native', phase: 'after-commit', syscall: 'rename', boundary: 1 }, + { implementation: 'native', phase: 'during-cleanup', syscall: 'fsync', boundary: 6 }, + { implementation: 'published', phase: 'before-commit', syscall: 'rename', boundary: 1 }, + { implementation: 'published', phase: 'after-commit', syscall: 'openat', boundary: 9 }, + { implementation: 'published', phase: 'after-commit', syscall: 'rename', boundary: 2 }, + { implementation: 'published', phase: 'during-cleanup', syscall: 'rename', boundary: 12 }, + ]; + const pairs = phasePairs(cuts); + assert.equal(pairs.length, 4); + assert.ok(pairs.every(([a, b]) => a.phase === b.phase)); + for (const [native, published] of pairs) { + const nativeBytes = new Map([['tasks/probe.toon', Buffer.from(native.phase === 'before-commit' ? 'PRE' : 'POST')]]); + const publishedBytes = new Map([['tasks/probe.toon', Buffer.from(published.phase === 'before-commit' ? 'PRE' : 'POST')]]); + const state = native.phase === 'before-commit' ? 'before' : 'committed'; + assert.equal(compareRecovery(nativeBytes, publishedBytes, 'ack', 'ack', state, state, new Map(), new Map()).ok, true); + } + assert.ok(pairs.some(([a, b]) => a.boundary === 1 && b.boundary === 9)); + assert.ok(pairs.some(([a, b]) => a.boundary === 6 && b.boundary === 12)); + assert.ok(!pairs.some(([a, b]) => a.syscall === 'rename' && a.boundary === 1 && b.syscall === 'rename' && b.boundary === 1)); + assert.equal(phasePairs(cuts.filter(cut => cut.phase === 'during-cleanup' && cut.implementation === 'native')).length, 0); +}); + +for (const stage of ['restart', 'return']) for (const mutation of ['delete-item', 'truncate-event', 'drop-field', 'reorder-history']) { + test(`live exact oracle kills ${stage} ${mutation} despite exit zero`, { skip: process.platform !== 'linux', timeout: 60000 }, () => temporary(root => { + const wrapper = join(root, 'native'); + const program = `#!${process.execPath}\nconst fs=require('node:fs');const cp=require('node:child_process');const args=process.argv.slice(2);const r=cp.spawnSync(${JSON.stringify(resolve('target/debug/pm-rust'))},args,{stdio:'inherit'});if(r.status===0&&fs.existsSync('kill.trace')&&args[0]===${JSON.stringify(stage === 'restart' ? 'comment' : 'update')}){const item='.agents/pm/tasks/crash-crash-probe.toon';const history='.agents/pm/history/crash-crash-probe.jsonl';const mutation=${JSON.stringify(mutation)};if(mutation==='delete-item')fs.unlinkSync(item);if(mutation==='drop-field')fs.writeFileSync(item,fs.readFileSync(item,'utf8').replace(/^priority:.*\\r?\\n/m,''));const lines=fs.readFileSync(history,'utf8').trimEnd().split('\\n');if(mutation==='truncate-event')fs.writeFileSync(history,lines.slice(0,-1).join('\\n')+'\\n');if(mutation==='reorder-history')fs.writeFileSync(history,lines.reverse().join('\\n')+'\\n');}process.exit(r.status??1);\n`; + writeFileSync(wrapper, program); chmodSync(wrapper, 0o755); + const report = runCrashCorpus({ native: wrapper, artifacts: join(root, 'evidence'), scenarios: ['update'], + only: { implementation: 'native', scenario: 'update', syscall: 'fsync', ordinal: 1 } }); + const row = report.cases[0]; + assert.equal(row.restartStatus, 0); + if (stage === 'return') { assert.equal(row.returnStatus, 0); assert.equal(row.restartExact, true); } + assert.equal(stage === 'restart' ? row.restartExact : row.returnExact, false); + assert.equal(row.ok, false); + assert.equal(report.ok, false); + assert.equal(report.failuresRetained, 1); + })); +} + + +test('phase oracle receipt pins mutation tables and independently applicable reverts', () => { + const receipt = JSON.parse(readFileSync('docs/CRASH_ORACLE_2026_10_25.json', 'utf8')); + assert.equal(receipt.schema, 'pm-rust/crash-oracle-v1'); + assert.equal(receipt.mutations.length, 4); + for (const row of receipt.mutations) { + assert.equal(row.realStateChecks, 6); + assert.equal(row.realStateKilled, 6); + assert.equal(row.liveRestartKilled, 1); + assert.equal(row.liveReturnKilled, 1); + assert.equal(row.survived, 0); + } + assert.equal(receipt.equivalence.length, 4); + assert.ok(receipt.equivalence.every((row: { pass: boolean }) => row.pass)); + for (const proof of receipt.proofs) { + assert.equal(proof.negativeExit, 1); + assert.equal(proof.restoredExit, 0); + assert.equal(createHash('sha256').update(readFileSync(proof.file)).digest('hex'), proof.sourceSha256); + assert.equal(createHash('sha256').update(readFileSync(proof.patch)).digest('hex'), proof.patchSha256); + const checked = spawnSync('git', ['apply', '--check', proof.patch], { encoding: 'utf8' }); + assert.equal(checked.status, 0, checked.stderr); + } + for (const [file, hash] of Object.entries(receipt.sourceFiles)) assert.equal(createHash('sha256').update(readFileSync(file)).digest('hex'), hash); + assert.equal(receipt.publicCopy.sourceUnchanged, true); + assert.ok(receipt.publicCopy.cases.every((row: { phase: string }) => receipt.phases.includes(row.phase))); +}); diff --git a/scripts/crash-output.mts b/scripts/crash-output.mts new file mode 100644 index 0000000..d5bcdd2 --- /dev/null +++ b/scripts/crash-output.mts @@ -0,0 +1,34 @@ +import type { CrashReport } from './crash-harness.mts'; + +/** Format bounded crash evidence as strict TOON with unique keys and tabular failures. */ +export function formatCrashToon(report: CrashReport): string { + const failures = report.cases.filter(row => row.failure); + const recoveryFailures = report.recoveryParity.filter(row => !row.ok); + const lines = [ + `schema: ${JSON.stringify(report.schema)}`, + `ok: ${report.ok}`, + `oracle_version: ${JSON.stringify(report.oracleVersion)}`, + `source_items: ${report.sourceItems}`, + `source_unchanged: ${report.sourceUnchanged}`, + `acknowledged_comparisons: ${report.acknowledgedComparisons}`, + `killed: ${report.killed}`, + `failures_retained: ${report.failuresRetained}`, + `clock_date_now: ${report.clock.dateNow}`, + `clock_limitation: ${JSON.stringify(report.clock.limitation)}`, + `recovery_comparisons: ${report.recoveryParity.length}`, + `recovery_mismatches: ${recoveryFailures.length}`, + `reduction: ${report.reduction?.status ?? 'none'}`, + `phases[${report.phaseCoverage?.length ?? 0}]{scenario,phase,native,published,paired}:`, + ...(report.phaseCoverage ?? []).map(row => ` ${row.scenario},${row.phase},${row.native},${row.published},${row.paired}`), + `parity[${report.parity.length}]{scenario,bytes,acknowledgement}:`, + ...report.parity.map(row => ` ${row.scenario},${row.bytes},${row.acknowledgement}`), + `failures[${failures.length}]{scenario,implementation,syscall,boundary,code,remedy}:`, + ...failures.map(row => ` ${row.scenario},${row.implementation},${row.syscall},${row.boundary},${row.failure!.code},${JSON.stringify(row.failure!.remedy)}`), + `recovery_failures[${recoveryFailures.length}]{scenario,phase,syscall,boundary,published_syscall,published_boundary,bytes,receipt,state,journals,ok}:`, + ...recoveryFailures.map(row => ` ${row.scenario},${row.phase ?? "legacy-unclassified"},${row.syscall},${row.boundary},${row.publishedSyscall ?? row.syscall},${row.publishedBoundary ?? row.boundary},${row.bytes},${row.receipt},${row.state},${row.journals},${row.ok}`), + `cases[${report.cases.length}]{scenario,implementation,syscall,boundary,phase,restart_exact,return_exact,state,history_preserved,return_status,pending_journals,failure,ok}:`, + ...report.cases.map(row => ` ${row.scenario},${row.implementation},${row.syscall},${row.boundary},${row.phase ?? "legacy-unclassified"},${row.restartExact ?? false},${row.returnExact ?? false},${row.state},${row.historyPreserved},${row.returnStatus},${row.journalsAfterRestart},${row.failure?.code ?? 'none'},${row.ok}`), + ]; + if (report.reduction?.remedy) lines.push(`reduction_code: ${JSON.stringify(report.reduction.code)}`, `reduction_remedy: ${JSON.stringify(report.reduction.remedy)}`); + return lines.join('\n'); +} diff --git a/scripts/crash-process.mts b/scripts/crash-process.mts index 81d6c27..4fee81e 100644 --- a/scripts/crash-process.mts +++ b/scripts/crash-process.mts @@ -1,11 +1,13 @@ import { spawnSync } from 'node:child_process'; -import { readFileSync } from 'node:fs'; +import { existsSync, readFileSync } from 'node:fs'; import { join } from 'node:path'; /** Observable syscall classes shared by real native and published processes. */ export const CRASH_SYSCALLS = ['rename', 'fsync'] as const; +/** Portable Node preload specifier, including drive-letter paths and escaped filenames. */ +export const CRASH_CLOCK_IMPORT = new URL('./crash-clock.mts', import.meta.url).href; /** One syscall's per-task entry ordinal; ordinals are not cross-runtime semantic phases. */ -export interface Boundary { syscall: typeof CRASH_SYSCALLS[number]; ordinal: number } +export interface Boundary { syscall: typeof CRASH_SYSCALLS[number] | 'openat'; ordinal: number } /** Complete child receipt, retained privately and reduced to hashes in public output. */ export interface ProcessReceipt { status: number | null; signal: string | null; stdout: Buffer; stderr: Buffer; trace: string } /** Executable argument-vector adapter; never evaluated by a shell. */ @@ -13,11 +15,12 @@ export interface Implementation { executable: string; args: readonly string[]; t /** Spawn one bounded isolated process, optionally injecting SIGKILL at a per-task syscall entry. */ export function execute(implementation: Implementation, args: readonly string[], cwd: string, - timeout: number, traceFile?: string, boundary?: Boundary, strace = 'strace'): ProcessReceipt { + timeout: number, traceFile?: string, boundary?: Boundary, strace = 'strace', tracePath?: string): ProcessReceipt { const argv = [...implementation.args, ...args, ...(implementation.trailing ?? [])]; const traced = traceFile !== undefined; const result = spawnSync(traced ? strace : implementation.executable, - traced ? ['-f', '--kill-on-exit', '-qq', '-o', traceFile, '-e', `trace=${CRASH_SYSCALLS.join(',')}`, + traced ? ['-f', '--kill-on-exit', '-qq', '-yy', '-s', '4096', '-o', traceFile, '-e', `trace=${tracePath ? 'openat' : [...CRASH_SYSCALLS, 'link', 'linkat', 'write', 'writev', 'unlink', 'unlinkat'].join(',')}`, + ...(tracePath ? ['-P', tracePath] : []), ...(boundary ? ['-e', `inject=${boundary.syscall}:signal=SIGKILL:when=${boundary.ordinal}`] : []), '--', implementation.executable, ...argv] : argv, { cwd, timeout, killSignal: 'SIGKILL', maxBuffer: 4 * 1024 * 1024, @@ -27,21 +30,21 @@ export function execute(implementation: Implementation, args: readonly string[], COMSPEC: process.env.COMSPEC, PATHEXT: process.env.PATHEXT, TEMP: process.env.TEMP, TMP: process.env.TMP, PM_AUTHOR: 'conformance-agent', PM_SENTRY_DISABLED: '1', PM_TELEMETRY_SOURCE_CONTEXT: 'test', - DO_NOT_TRACK: '1', NODE_DISABLE_COMPILE_CACHE: '1', + DO_NOT_TRACK: '1', NODE_DISABLE_COMPILE_CACHE: '1', UV_THREADPOOL_SIZE: '1', GIT_CEILING_DIRECTORIES: cwd, GIT_CONFIG_GLOBAL: '/dev/null', GIT_CONFIG_NOSYSTEM: '1', LC_ALL: 'C', TZ: 'UTC', }, }); if (result.error) throw new Error('code' in result.error && result.error.code === 'ETIMEDOUT' ? 'timeout' : 'process_unavailable'); return { status: result.status, signal: result.signal, stdout: result.stdout, stderr: result.stderr, - trace: traceFile ? readFileSync(traceFile, 'utf8') : '' }; + trace: traceFile && existsSync(traceFile) ? readFileSync(traceFile, 'utf8') : '' }; } /** Determine the largest syscall ordinal reached by any individual traced task. */ export function boundaryCount(trace: string, syscall: Boundary['syscall']): number { const counts = new Map(); for (const line of trace.split('\n')) { - const match = /^\s*(\d+)\s+(rename|fsync)\(/.exec(line); + const match = /^\s*(\d+)\s+(rename|fsync|openat)\(/.exec(line); if (match?.[2] === syscall) counts.set(match[1], (counts.get(match[1]) ?? 0) + 1); } return Math.max(0, ...counts.values()); diff --git a/scripts/crash-review-proof.mts b/scripts/crash-review-proof.mts new file mode 100644 index 0000000..a4e0db0 --- /dev/null +++ b/scripts/crash-review-proof.mts @@ -0,0 +1,128 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { runCrashCorpus } from './crash-harness.mts'; + +/** Run one bounded tool and require its declared exit code. */ +function command(executable: string, args: string[], status = 0): string { + const result = spawnSync(executable, args, { encoding: 'utf8', timeout: 300000, maxBuffer: 8 * 1024 * 1024 }); + assert.equal(result.error, undefined); + assert.equal(result.status, status, `${executable}: ${result.stderr}`); + return result.stdout; +} +/** Hash text or bytes without storing machine-specific coordinates. */ +function sha(value: string | Buffer): string { return createHash('sha256').update(value).digest('hex'); } +/** Produce an applicable patch with repository-relative headers, never scratch paths. */ +function controlPatch(file: string, original: Buffer | string, changed: string, root: string): string { + const oldFile = join(root, 'before'); const newFile = join(root, 'after'); + writeFileSync(oldFile, original); writeFileSync(newFile, changed); + return command('git', ['diff', '--no-index', '--no-ext-diff', oldFile, newFile], 1) + .replace(/^diff --git .*$/m, `diff --git a/${file} b/${file}`) + .replace(/^--- .*$/m, `--- a/${file}`).replace(/^\+\+\+ .*$/m, `+++ b/${file}`) + .replace(/^ $/gm, ''); +} +/** Make only the private archived input read-only. */ +function readOnly(path: string): void { + for (const entry of readdirSync(path, { withFileTypes: true })) { + const child = join(path, entry.name); + if (entry.isDirectory()) readOnly(child); + else { assert.ok(entry.isFile()); chmodSync(child, 0o444); } + } + chmodSync(path, 0o555); +} +/** Restore permissions only under the owned scratch directory before cleanup. */ +function writable(path: string): void { + chmodSync(path, 0o700); + for (const entry of readdirSync(path, { withFileTypes: true })) { + const child = join(path, entry.name); + if (entry.isDirectory()) writable(child); else chmodSync(child, 0o600); + } +} + +if (process.platform !== 'linux') throw new Error('crash-review-proof requires Linux; just crash gives a typed platform refusal elsewhere.'); +const git = spawnSync('git', ['rev-parse', '--is-inside-work-tree'], { encoding: 'utf8' }); +if (git.status !== 0) throw new Error('crash-review-proof needs a git repository; the working directory is not inside one. just crash still works without git.'); +const root = mkdtempSync(join(tmpdir(), 'pm-crash-controls-')); +try { + const sourceCommit = command('git', ['rev-parse', 'HEAD']).trim(); + const publicCommit = command('git', ['rev-parse', 'origin/main']).trim(); + const controls = [ + { name: 'stable-write-boundary', file: 'scripts/crash-process.mts', before: ", UV_THREADPOOL_SIZE: '1'", after: "", pattern: 'single-worker published boundary' }, + { name: 'empty-replay-dispatch', file: 'scripts/crash-cli.mts', before: 'const report = values.replay !== undefined ?', after: 'const report = values.replay ?', pattern: 'empty replay options' }, + { name: 'empty-replay-exclusion', file: 'scripts/crash-cli.mts', before: 'values.source !== undefined && values.replay !== undefined', after: 'values.source && values.replay', pattern: 'empty replay options' }, + { name: 'default-failure-details', file: 'scripts/crash-output.mts', before: 'report.cases.filter(row => row.failure)', after: 'report.cases.filter(() => false)', pattern: 'default crash output|TOON output' }, + { name: 'strict-toon-failures', file: 'scripts/crash-output.mts', before: "`failures[${failures.length}]{scenario,implementation,syscall,boundary,code,remedy}:`,\n ...failures.map(row => ` ${row.scenario},${row.implementation},${row.syscall},${row.boundary},${row.failure!.code},${JSON.stringify(row.failure!.remedy)}`)", after: "...failures.map(row => `failure: ${JSON.stringify(row.failure)}`)", pattern: 'TOON output' }, + { name: 'workspace-cleanup', file: 'scripts/crash-harness.mts', before: 'rmSync(killedDirectory, { recursive: true, force: true });', after: '// Retain completed workspace (negative control).', pattern: 'completed case workspaces' }, + { name: 'portable-clock-import', file: 'scripts/crash-process.mts', before: "new URL('./crash-clock.mts', import.meta.url).href", after: "decodeURIComponent(new URL('./crash-clock.mts', import.meta.url).pathname)", pattern: 'clock disclosure' }, + { name: 'runtime-snapshot', file: 'scripts/crash-storage.mts', before: "['locks', 'transactions', 'checkpoints', 'search']", after: "['runtime', 'locks', 'transactions', 'checkpoints', 'search']", pattern: 'runtime transaction' }, + { name: 'cross-operation', file: 'scripts/crash-harness.mts', before: "scenario === 'update' ? ['comment', id, 'Restart synthetic sentinel', ...common] :\n ['update', id, '--description', 'Restart synthetic description', ...common]", after: "scenario === 'update' ? ['update', id, '--priority', '1', ...common] :\n ['comment', id, 'Restart synthetic sentinel', ...common]", pattern: 'independent (update|comment) cross-operation' }, + { name: 'published-injection', file: 'scripts/crash-harness.mts', before: "counts.push({ syscall: 'openat', count: 1 });", after: "// Disabled history-open boundary (negative control).", pattern: 'published history-open' }, + { name: 'recovery-comparison', file: 'scripts/crash-harness.mts', before: 'ok: Object.values(result).every(Boolean)', after: 'ok: true', pattern: 'cross-runtime recovery comparison' }, + { name: 'clock-disclosure', file: 'scripts/crash-harness.mts', before: "dateNow: 'fixed'", after: "dateNow: 'real'", pattern: 'clock disclosure' }, + { name: 'reduction-refusal', file: 'scripts/crash-harness.mts', before: 'reduceFailure(report, () => runCrashCorpus({ ...options, source: undefined }));', after: 'report.failuresRetained = runCrashCorpus({ ...options, source: undefined }).failuresRetained;', pattern: 'synthetic reduction refusal' }, + ]; + mkdirSync('docs/controls/crash-review', { recursive: true }); + const resume = process.argv[2]; + assert.ok(resume === undefined || resume === '--resume-controls', 'Use --resume-controls only with the owned local checkpoint.'); + const checkpoint = '.crash-failures/review-controls.json'; + const saved: unknown = resume && existsSync(checkpoint) ? JSON.parse(readFileSync(checkpoint, 'utf8')) : []; + assert.ok(Array.isArray(saved)); + const results: { name: string; file: string; sourceSha256: string; patch: string; patchSha256: string; command: string[]; negativeExit: number; restoredExit: number }[] = []; + for (const control of controls) { + const original = readFileSync(control.file); + const text = original.toString(); + assert.equal(text.split(control.before).length, 2, control.name); + const changed = text.replace(control.before, control.after); + const diff = controlPatch(control.file, original, changed, root); + const patch = `docs/controls/crash-review/${control.name}.patch`; + writeFileSync(patch, diff); + const args = ['--test', `--test-name-pattern=${control.pattern}`, 'scripts/crash-review.test.mts']; + const recorded: unknown = saved.find((entry: unknown) => typeof entry === 'object' && entry !== null && 'name' in entry && entry.name === control.name); + const result = { name: control.name, file: control.file, sourceSha256: sha(original), patch, patchSha256: sha(diff), + command: ['node', ...args], negativeExit: 1, restoredExit: 0 }; + if (JSON.stringify(recorded) === JSON.stringify(result)) { + results.push(result); + console.log(`${control.name}: retained completed negative=1 restored=0`); + continue; + } + let negative: string; + try { writeFileSync(control.file, changed); negative = command(process.execPath, args, 1); } + finally { writeFileSync(control.file, original); } + const restored = command(process.execPath, args); + assert.match(negative, /(?:fail|not ok|✖)/); + assert.match(restored, /(?:pass|ok|✔)/); + assert.deepEqual(readFileSync(control.file), original); + results.push(result); + mkdirSync('.crash-failures', { recursive: true }); + writeFileSync(checkpoint, JSON.stringify(results, null, 2) + '\n'); + console.log(`${control.name}: negative=1 restored=0`); + } + const archive = join(root, 'public.tar'); const copy = join(root, 'public'); mkdirSync(copy); + command('git', ['archive', '--format=tar', '--output', archive, publicCommit, '.agents/pm']); + command('tar', ['-xf', archive, '-C', copy]); readOnly(join(copy, '.agents/pm')); + const report = runCrashCorpus({ native: resolve('target/debug/pm-rust'), source: join(copy, '.agents/pm'), artifacts: join(root, 'evidence'), timeoutMs: 60000 }); + assert.equal(report.sourceUnchanged, true); assert.equal(report.ok, false); + const inputs = command('git', ['ls-files', 'scripts/crash-*.mts', 'tests/harness', 'tests/fixtures/crash-review', 'src', 'Cargo.toml', 'Cargo.lock', 'rust-toolchain.toml', 'justfile', 'README.md', 'docs/CRASH_HARNESS.md']).trim().split('\n'); + const provenance = { sourceRepository: 'https://github.com/unbraind/pm-rust', sourceCommit, publicTrackerCommit: publicCommit, + sourceFiles: Object.fromEntries(inputs.map(path => [path, sha(readFileSync(path))])), + toolchain: { node: process.version, rustc: command('rustc', ['+1.90.0', '--version']).trim(), nightly: command('rustc', ['+nightly-2026-08-06', '--version']).trim(), + cargo: command('cargo', ['+1.90.0', '--version']).trim(), strace: command('strace', ['--version']).split('\n')[0] }, + reproduction: ['git checkout ', 'just oracle-install', 'npm ci --prefix tests/harness --ignore-scripts', 'cargo +1.90.0 build --locked --bin pm-rust', 'node scripts/crash-review-proof.mts'], + oracleLockSha256: sha(readFileSync('tests/oracle/package-lock.json')), harnessLockSha256: sha(readFileSync('tests/harness/package-lock.json')) }; + const file = 'docs/CRASH_REVIEW_2026_10_23.json'; + const artifactArgs = ['--test', '--test-name-pattern=review receipt', 'scripts/crash-review.test.mts']; + const artifactControl = { name: 'legacy-receipt-format', file, patch: 'docs/controls/crash-review/legacy-receipt-format.patch', patchSha256: '', command: ['node', ...artifactArgs], negativeExit: 1, restoredExit: 0 }; + const receipt = { schema: 'pm-rust/crash-review-v1', provenance, controls: results, publicCopy: report, artifactControl }; + const template = JSON.stringify(receipt, null, 2) + '\n'; + const oldSchema = '"schema": "pm-rust/crash-review-v1"'; + const patch = controlPatch(file, template, template.replace(oldSchema, '"schema": "legacy-receipt"'), root); + writeFileSync(artifactControl.patch, patch); artifactControl.patchSha256 = sha(patch); + const complete = JSON.stringify(receipt, null, 2) + '\n'; + try { writeFileSync(file, complete.replace(oldSchema, '"schema": "legacy-receipt"')); command(process.execPath, artifactArgs, 1); } + finally { writeFileSync(file, complete); } + command(process.execPath, artifactArgs); + console.log(JSON.stringify({ controls: results.length, kills: report.killed, sourceItems: report.sourceItems, sourceUnchanged: report.sourceUnchanged })); +} finally { writable(root); rmSync(root, { recursive: true, force: true }); } diff --git a/scripts/crash-review.test.mts b/scripts/crash-review.test.mts new file mode 100644 index 0000000..8e14922 --- /dev/null +++ b/scripts/crash-review.test.mts @@ -0,0 +1,200 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { test } from 'node:test'; +import { decode } from '../tests/oracle/node_modules/@unbrained/pm-cli/node_modules/@toon-format/toon/dist/index.mjs'; +import { formatCrashToon } from './crash-output.mts'; +import type { CrashReport } from './crash-harness.mts'; +import { CRASH_CLOCK_IMPORT, boundaryCount, execute, killedAtBoundary } from './crash-process.mts'; +import { CLOCK_POLICY, compareRecovery, replayCrashFailure, runCrashCorpus } from './crash-harness.mts'; +import { journals, materialize, sameBytes, snapshot } from './crash-storage.mts'; + +/** Own a disposable directory, never a source tracker. */ +function temporary(callback: (directory: string) => void): void { + const directory = mkdtempSync(join(tmpdir(), 'pm-crash-review-')); + try { callback(directory); } finally { rmSync(directory, { recursive: true, force: true }); } +} + +test('runtime transaction snapshots retain recovery intent and detect journal changes', () => temporary(root => { + const files = new Map([['runtime/transactions/update-probe.json', Buffer.from('{"version":1}\n')], ['runtime/index.json', Buffer.from('{}')]]); + materialize(files, root); + const before = snapshot(root); + assert.equal(before.size, 2); + assert.equal(journals(before).size, 1); + writeFileSync(join(root, 'runtime/transactions/update-probe.json'), '{"version":2}\n'); + assert.equal(sameBytes(journals(before), journals(snapshot(root))), false); +})); + +test('cross-runtime recovery comparison rejects different bytes receipts states and journals', () => { + const before = new Map([['tasks/probe.toon', Buffer.from('before')]]); + const committed = new Map([['tasks/probe.toon', Buffer.from('committed')]]); + const empty = new Map(); + const pending = new Map([['runtime/transactions/update-probe.json', Buffer.from('{}')]]); + assert.equal(compareRecovery(before, before, 'ack', 'ack', 'before', 'before', empty, empty).ok, true); + for (const result of [ + compareRecovery(before, committed, 'ack', 'ack', 'before', 'before', empty, empty), + compareRecovery(before, before, 'ack', 'other', 'before', 'before', empty, empty), + compareRecovery(before, before, 'ack', 'ack', 'before', 'committed', empty, empty), + compareRecovery(before, before, 'ack', 'ack', 'before', 'before', pending, empty), + ]) assert.equal(result.ok, false); +}); + +test('clock disclosure matches frozen Date.now and live performance elapsed time', () => { + const code = 'const first=Date.now();const elapsed=performance.now();await new Promise(r=>setTimeout(r,30));console.log(JSON.stringify({first,last:Date.now(),wall:new Date().toISOString(),elapsed:performance.now()-elapsed}));'; + assert.equal(new URL(CRASH_CLOCK_IMPORT).protocol, 'file:'); + const child = spawnSync(process.execPath, ['--import', CRASH_CLOCK_IMPORT, '--input-type=module', '-e', code], { encoding: 'utf8' }); + assert.equal(child.status, 0, child.stderr); + const result = JSON.parse(child.stdout); + assert.equal(result.first, result.last); + assert.equal(result.wall, CLOCK_POLICY.metadata); + assert.ok(result.elapsed >= 20); + assert.equal(CLOCK_POLICY.dateNow, 'fixed'); + assert.match(CLOCK_POLICY.limitation, /TTL\/wait ages are frozen/); + const guide = readFileSync(resolve('docs/CRASH_HARNESS.md'), 'utf8'); + assert.match(guide, /Date\.now\(\).*frozen/); +}); + +for (const scenario of ['update', 'comment'] as const) { + test(`independent ${scenario} cross-operation replay recovers journals before return`, + { skip: process.platform !== 'linux', timeout: 180000 }, () => temporary(root => { + const source = resolve('tests/fixtures/crash-review'); + const before = snapshot(source); + const wrapper = join(root, 'native'); + const calls = join(root, 'native-calls.jsonl'); + writeFileSync(wrapper, `#!${process.execPath}\nconst fs=require('node:fs');const cp=require('node:child_process');fs.appendFileSync(${JSON.stringify(calls)},JSON.stringify(process.argv.slice(2))+'\\n');const r=cp.spawnSync(${JSON.stringify(resolve('target/debug/pm-rust'))},process.argv.slice(2),{stdio:'inherit'});process.exit(r.status??1);\n`); + chmodSync(wrapper, 0o755); + const report = replayCrashFailure({ native: wrapper, artifacts: join(root, 'evidence') }, join(source, `${scenario}.json`)); + assert.equal(report.ok, true, JSON.stringify(report.cases)); + assert.equal(report.killed, 1); + const row = report.cases[0]; + assert.equal(row.restartStatus, 0); + assert.equal(row.returnStatus, 0); + const commands = readFileSync(calls, 'utf8').trim().split('\n').map(line => JSON.parse(line)[0]); + assert.deepEqual(commands.slice(-2), [scenario === 'update' ? 'comment' : 'update', scenario]); + assert.equal(row.journalsAtKill, 1); + assert.equal(row.journalsAfterRestart, 0); + assert.equal(row.journalsAfterReturn, 0); + assert.equal(row.failure, undefined); + assert.equal(report.failuresRetained, 0); + assert.ok(row.acknowledged && row.historyPreserved); + assert.equal(report.sourceUnchanged, true); + assert.ok(sameBytes(before, snapshot(source))); + })); +} + +test('published history-open injection detects post-publication history loss despite exit-zero restart', + { skip: process.platform !== 'linux', timeout: 180000 }, () => temporary(root => { + const report = replayCrashFailure({ native: resolve('target/debug/pm-rust'), artifacts: join(root, 'evidence') }, + resolve('tests/fixtures/crash-review/published-history.json')); + assert.equal(report.ok, false); + const row = report.cases[0]; + assert.equal(row.syscall, 'openat'); + assert.equal(row.implementation, 'published'); + assert.equal(row.restartStatus, 0); + assert.equal(row.state, 'diverged'); + assert.equal(row.failure?.code, 'durable_divergence'); + assert.equal(report.failuresRetained, 1); + })); + +test('synthetic reduction refusal preserves measured failure and CLI exit one', + { skip: process.platform !== 'linux', timeout: 180000 }, () => temporary(root => { + const wrapper = join(root, 'trace-controller'); + writeFileSync(wrapper, '#!/bin/sh\nparent="${PWD%/*}"\nsaved="${0}.root"\nif [ -f "$saved" ]; then\n read -r previous < "$saved"\n if [ "$previous" != "$parent" ]; then exit 79; fi\nelse\n printf "%s\\n" "$parent" > "$saved"\nfi\nexec strace "$@"\n'); + chmodSync(wrapper, 0o755); + const result = spawnSync(process.execPath, [resolve('scripts/crash-cli.mts'), '--native', resolve('target/debug/pm-rust'), + '--artifacts', join(root, 'evidence'), '--replay', resolve('tests/fixtures/crash-review/published-history.json'), '--strace', wrapper, '--json', '--full'], + { encoding: 'utf8', timeout: 120000 }); + assert.equal(result.status, 1, result.stderr + result.stdout); + const report = JSON.parse(result.stdout); + assert.equal(report.killed, 1); + assert.equal(report.cases[0].state, 'diverged'); + assert.equal(report.reduction.status, 'refused'); + assert.equal(report.reduction.code, 'baseline_failed'); + assert.equal(report.failuresRetained, 0); + })); + +test('review receipt provides source toolchain and independently applicable control patches', () => { + const receipt = JSON.parse(readFileSync(resolve('docs/CRASH_REVIEW_2026_10_23.json'), 'utf8')); + assert.equal(receipt.schema, 'pm-rust/crash-review-v1'); + assert.match(receipt.provenance.sourceCommit, /^[a-f0-9]{40}$/); + assert.equal(spawnSync('git', ['cat-file', '-e', receipt.provenance.sourceCommit], { encoding: 'utf8' }).status, 0); + assert.match(receipt.provenance.publicTrackerCommit, /^[a-f0-9]{40}$/); + for (const name of ['node', 'rustc', 'nightly', 'cargo', 'strace']) assert.ok(receipt.provenance.toolchain[name]); + assert.ok(receipt.provenance.reproduction.includes('node scripts/crash-review-proof.mts')); + assert.equal(receipt.controls.length, 13); + for (const control of receipt.controls) { + const patch = readFileSync(control.patch); + assert.equal(createHash('sha256').update(patch).digest('hex'), control.patchSha256); + assert.equal(control.negativeExit, 1); + assert.equal(control.restoredExit, 0); + // These completed controls certify their recorded source commit, not future working-tree edits. + const historical = spawnSync('git', ['show', `${receipt.provenance.sourceCommit}:${control.file}`]); + assert.equal(historical.status, 0); + assert.equal(createHash('sha256').update(historical.stdout).digest('hex'), control.sourceSha256); + } + const artifact = receipt.artifactControl; + assert.equal(createHash('sha256').update(readFileSync(artifact.patch)).digest('hex'), artifact.patchSha256); + assert.equal(artifact.negativeExit, 1); + assert.equal(artifact.restoredExit, 0); + assert.equal(spawnSync('git', ['apply', '--check', artifact.patch], { encoding: 'utf8' }).status, 0); +}); + + +test('single-worker published boundary keeps successive async publications on one traced task', + { skip: process.platform !== 'linux' }, () => temporary(root => { + const code = `const assert=require('node:assert/strict');const fs=require('node:fs/promises');assert.equal(process.env.UV_THREADPOOL_SIZE,'1');(async()=>{await fs.writeFile('cache.tmp','derived');await fs.rename('cache.tmp','cache');await fs.writeFile('item.tmp','durable');await fs.rename('item.tmp','item');})().catch(()=>process.exitCode=1);`; + const child = { executable: process.execPath, args: ['-e', code] }; + const reference = execute(child, [], root, 15000, join(root, 'reference.trace')); + assert.equal(reference.status, 0, reference.stderr.toString()); + assert.equal(boundaryCount(reference.trace, 'rename'), 2); + const interrupted = execute(child, [], root, 15000, join(root, 'interrupt.trace'), { syscall: 'rename', ordinal: 2 }); + assert.equal(killedAtBoundary(interrupted, { syscall: 'rename', ordinal: 2 }), true); + })); + +test('empty replay options refuse before normal corpus admission', () => temporary(root => { + for (const args of [['--replay', ''], ['--source', '', '--replay', ''], ['--source', '', '--replay', 'missing']]) { + const result = spawnSync(process.execPath, [resolve('scripts/crash-cli.mts'), '--native', 'missing', '--artifacts', join(root, 'evidence'), ...args, '--json'], { encoding: 'utf8' }); + assert.equal(result.status, 2, result.stderr); + const refusal = JSON.parse(result.stdout); + assert.equal(refusal.code, 'invalid_options'); + assert.match(refusal.remedy, args.length === 2 ? /readable retained case/ : /only one/); + } +})); + +test('default crash output explains parity and case failure remedies', + { skip: process.platform !== 'linux', timeout: 180000 }, () => temporary(root => { + const result = spawnSync(process.execPath, [resolve('scripts/crash-cli.mts'), '--native', resolve('target/debug/pm-rust'), '--artifacts', join(root, 'evidence'), '--replay', resolve('tests/fixtures/crash-review/published-history.json')], { encoding: 'utf8', timeout: 120000 }); + assert.equal(result.status, 1, result.stderr + result.stdout); + assert.match(result.stdout, /parity\[1\]\{scenario,bytes,acknowledgement\}/); + assert.match(result.stdout, /failures\[1\]\{scenario,implementation,syscall,boundary,code,remedy\}/); + assert.match(result.stdout, /durable_divergence,"Replay/); + assert.doesNotThrow(() => decode(result.stdout, { strict: true })); +})); + +test('completed case workspaces are removed before later process admission', + { skip: process.platform !== 'linux', timeout: 180000 }, () => temporary(root => { + const wrapper = join(root, 'bounded-native'); + writeFileSync(wrapper, `#!${process.execPath}\nconst fs=require('node:fs');const path=require('node:path');const cp=require('node:child_process');const cases=fs.readdirSync(path.dirname(process.cwd()),{withFileTypes:true}).filter(e=>e.isDirectory()&&/^case-[0-9]+$/.test(e.name));if(cases.length>2)process.exit(79);const r=cp.spawnSync(${JSON.stringify(resolve('target/debug/pm-rust'))},process.argv.slice(2),{stdio:'inherit'});process.exit(r.status??1);\n`); + chmodSync(wrapper, 0o755); + const report = runCrashCorpus({ native: wrapper, artifacts: join(root, 'evidence'), scenarios: ['update'] }); + assert.ok(report.cases.filter(row => row.implementation === 'native').every(row => row.ok), JSON.stringify(report.cases)); + assert.ok(report.killed > 1); +})); + +test('TOON output parses multiple measured failures and paired outcomes without duplicate keys', () => { + const measured: { publicCopy: CrashReport } = JSON.parse(readFileSync(resolve('docs/CRASH_REVIEW_2026_10_23.json'), 'utf8')); + const output = formatCrashToon(measured.publicCopy); + const decoded: unknown = decode(output, { strict: true }); + assert.ok(typeof decoded === 'object' && decoded !== null); + assert.ok('failures' in decoded && Array.isArray(decoded.failures)); + assert.equal(decoded.failures.length, 2); + assert.ok('recovery_failures' in decoded && Array.isArray(decoded.recovery_failures)); + assert.equal(decoded.recovery_failures.length, 4); + assert.ok('cases' in decoded && Array.isArray(decoded.cases)); + assert.equal(decoded.cases.length, 26); + assert.ok('parity' in decoded && Array.isArray(decoded.parity)); + assert.equal(decoded.parity.length, 2); +}); diff --git a/scripts/crash-storage.mts b/scripts/crash-storage.mts index e1b17ac..30a92ce 100644 --- a/scripts/crash-storage.mts +++ b/scripts/crash-storage.mts @@ -10,7 +10,7 @@ export function snapshot(root: string, prefix = ''): Map { if (!prefix && lstatSync(root).isSymbolicLink()) throw new Error('symlink'); const result = new Map(); for (const entry of readdirSync(join(root, prefix), { withFileTypes: true })) { - if (!prefix && ['runtime', 'locks', 'transactions', 'checkpoints', 'search'].includes(entry.name)) continue; + if (!prefix && ['locks', 'transactions', 'checkpoints', 'search'].includes(entry.name)) continue; if (entry.isSymbolicLink()) throw new Error('symlink'); const key = prefix ? `${prefix}/${entry.name}` : entry.name; if (entry.isDirectory()) { @@ -55,8 +55,7 @@ export function sameBytes(left: Snapshot, right: Snapshot): boolean { return left.size === right.size && [...left].every(([key, bytes]) => right.get(key)?.equals(bytes)); } -/** Accept seed bytes only after a refused restart; successful restarts must match a complete reference. */ -export function recoveredState(seed: Snapshot, before: Snapshot, committed: Snapshot, after: Snapshot, status: number | null): 'before' | 'committed' | 'diverged' { - if (sameBytes(before, after) || status !== 0 && sameBytes(seed, after)) return 'before'; - return sameBytes(committed, after) ? 'committed' : 'diverged'; +/** Retain native recovery intent, including incomplete journal files, independently of derived caches. */ +export function journals(files: Snapshot): Map { + return new Map([...files].filter(([name]) => name.startsWith('runtime/transactions/') && name.endsWith('.json') && !name.split('/').at(-1)?.startsWith('.'))); } diff --git a/tests/fixtures/crash-review/comment.json b/tests/fixtures/crash-review/comment.json new file mode 100644 index 0000000..cc945a7 --- /dev/null +++ b/tests/fixtures/crash-review/comment.json @@ -0,0 +1,9 @@ +{ + "schema": "pm-rust/crash-v1", + "only": { + "scenario": "comment", + "implementation": "native", + "syscall": "rename", + "ordinal": 1 + } +} diff --git a/tests/fixtures/crash-review/fixture/.agents/pm/settings.json b/tests/fixtures/crash-review/fixture/.agents/pm/settings.json new file mode 100644 index 0000000..ec3dd65 --- /dev/null +++ b/tests/fixtures/crash-review/fixture/.agents/pm/settings.json @@ -0,0 +1,80 @@ +{ + "version": 1, + "id_prefix": "crash-", + "author_default": "conformance-agent", + "item_format": "toon", + "locks": { + "ttl_seconds": 1800, + "wait_ms": 3000 + }, + "output": { + "default_format": "toon" + }, + "extensions": { + "enabled": [], + "disabled": [], + "policy": { + "mode": "off", + "trust_mode": "off", + "require_provenance": false, + "trusted_extensions": [], + "default_sandbox_profile": "none", + "allowed_extensions": [], + "blocked_extensions": [], + "allowed_capabilities": [], + "blocked_capabilities": [], + "allowed_surfaces": [], + "blocked_surfaces": [], + "allowed_commands": [], + "blocked_commands": [], + "allowed_actions": [], + "blocked_actions": [], + "allowed_services": [], + "blocked_services": [], + "extension_overrides": [] + } + }, + "search": { + "score_threshold": 0, + "hybrid_semantic_weight": 0.7, + "max_results": 50, + "embedding_model": "", + "embedding_batch_size": 32, + "embedding_timeout_ms": 30000, + "scanner_max_batch_retries": 3, + "provider": "", + "default_mode": "auto", + "mutation_refresh_policy": "semantic_configured", + "query_expansion": { + "enabled": false, + "provider": "" + }, + "rerank": { + "enabled": false, + "model": "", + "top_k": 20 + } + }, + "providers": { + "openai": { + "base_url": "", + "api_key": "", + "model": "" + }, + "ollama": { + "base_url": "", + "model": "" + } + }, + "vector_store": { + "adapter": "", + "collection_name": "pm_items", + "qdrant": { + "url": "", + "api_key": "" + }, + "lancedb": { + "path": "" + } + } +} diff --git a/tests/fixtures/crash-review/published-history.json b/tests/fixtures/crash-review/published-history.json new file mode 100644 index 0000000..2493cf8 --- /dev/null +++ b/tests/fixtures/crash-review/published-history.json @@ -0,0 +1,9 @@ +{ + "schema": "pm-rust/crash-v1", + "only": { + "scenario": "update", + "implementation": "published", + "syscall": "openat", + "ordinal": 1 + } +} diff --git a/tests/fixtures/crash-review/update.json b/tests/fixtures/crash-review/update.json new file mode 100644 index 0000000..d9a680e --- /dev/null +++ b/tests/fixtures/crash-review/update.json @@ -0,0 +1,9 @@ +{ + "schema": "pm-rust/crash-v1", + "only": { + "scenario": "update", + "implementation": "native", + "syscall": "rename", + "ordinal": 1 + } +}