From f705877b712850bb296f8c9ca519848c239d18df Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Wed, 28 Oct 2026 21:43:18 +0100 Subject: [PATCH 1/5] feat(sdk): bind item batches and crash recovery to PmClient Expose host-bound preview, commit, transaction status, abandonment and supersession APIs so packages can use the SDK coordinator without copying tracker resolution or author policy. Return full canonical staged records with applied/adopted receipts and explicit commit-time clock fields. Retain immutable admitted item plans and compensation policy in journals. Fence forward replay with version 2 retirement intent before compensation, retain pending and completed retirement receipts in GC, and deduplicate workspace audit events across recovery crashes. Refuse committed or foreign plans and preserve peer changes using history ownership and locked target preconditions, including deletion compensation. Add public declaration and crash-boundary regressions, synchronize generated SDK/error contracts, and document preview and recovery limits. Link work and validation to pm-gh1597 and pm-gh1598, with release, observability and GitHub inventory evidence retained in their existing canonical tracker lineages. --- .agents/pm/features/pm-gh1597.toon | 43 +++- .agents/pm/features/pm-gh1598.toon | 33 ++- .agents/pm/history/pm-0trehk.jsonl | 1 + .agents/pm/history/pm-gh1597.jsonl | 12 + .agents/pm/history/pm-gh1598.jsonl | 9 + .agents/pm/history/pm-prrlce.jsonl | 1 + .agents/pm/history/pm-xq09zu.jsonl | 1 + .agents/pm/issues/pm-0trehk.toon | 5 +- .agents/pm/issues/pm-prrlce.toon | 5 +- .agents/pm/issues/pm-xq09zu.toon | 5 +- docs/SDK.md | 61 +++++ docs/generated/REFUSAL_CLOSURE_CENSUS.md | 9 +- sdk/public-surface.json | 109 +++++++- src/core/history/operation-contract.ts | 1 + src/core/store/item-store.ts | 1 + .../generated-error-code-catalog-part-1.ts | 13 + .../generated-error-code-catalog-part-2.ts | 52 +++- src/sdk/item-transaction.ts | 148 ++++++++--- src/sdk/runtime.ts | 39 ++- src/sdk/workspace-transaction-gc.ts | 2 +- src/sdk/workspace-transaction.ts | 143 +++++++++-- tests/fixtures/contracts/full.json | 54 +++- .../semantic-preview.integration.spec.ts | 19 +- tests/types/item-transactions.test-d.ts | 15 ++ .../unit/sdk/transactions/host-bound.spec.ts | 237 ++++++++++++++++++ tests/unit/sdk/workspace-transaction.spec.ts | 1 + 26 files changed, 927 insertions(+), 92 deletions(-) create mode 100644 tests/types/item-transactions.test-d.ts create mode 100644 tests/unit/sdk/transactions/host-bound.spec.ts diff --git a/.agents/pm/features/pm-gh1597.toon b/.agents/pm/features/pm-gh1597.toon index d4bcaa0494..033476f1f5 100644 --- a/.agents/pm/features/pm-gh1597.toon +++ b/.agents/pm/features/pm-gh1597.toon @@ -2,11 +2,13 @@ id: pm-gh1597 title: "GH-1597: expose host-bound item transaction status and safe abandonment or supersession" description: "GitHub https://github.com/unbraind/pm-cli/issues/1597 requests public recovery for interrupted item-mutation journals when a peer edit changes the retry plan. Existing bulk commit and guarded compensation are shipped; extend their public host-bound lifecycle rather than duplicating private journal storage or reviving completed implementation." type: Feature -status: open +status: in_progress priority: 1 tags: [] created_at: "2026-10-26T04:54:49.262Z" -updated_at: "2026-10-26T04:54:49.262Z" +updated_at: "2026-10-28T20:39:10.736Z" +assignee: "harness:codex" +claim_principal: "harness:codex#568692524ccbb719c2f222a0" author: "harness:codex" estimated_minutes: 300 acceptance_criteria: Expose typed host-bound journal state and applied/compensated step receipts with plan identity; Provide safe abandonment and supersession using proven apply markers and existing guarded compensation; never overwrite later peer edits or silently compensate committed work; Name executable public recovery in transaction-plan-mismatch guidance and verify non-Git crash/retry/peer-edit controls plus SDK contract documentation @@ -17,6 +19,41 @@ expected_result: Extensions can inspect and recover interrupted batches through dependencies[2]{id,kind,created_at,author,source_kind,author_source}: pm-9rgaal,implements,"2026-10-26T04:54:49.262Z","harness:codex","cli:create:dep",detected pm-y9hq,discovered_from,"2026-10-26T04:54:49.262Z","harness:codex","cli:create:dep",detected -comments[1]{created_at,author,text}: +comments[4]{created_at,author,text}: "2026-10-26T04:54:49.262Z","harness:codex","Duplicate check: complete strict all-status corpus plus live request-specific searches and full terminal-lineage reads found no exact active owner. Existing SDK promotion and transaction/preview delivery remain completed; this item owns the newly requested public surface." + "2026-10-28T19:44:07.695Z","harness:codex","Implementation scope: retain original item plans in coordinator journals, expose read-only status and host-bound guarded abandonment/supersession, refuse committed and peer-edited work, preserve append-only compensation and audit evidence. Complete strict 3148-item all-status census has no omissions; 38 open GitHub issues each already have a canonical PM link comment. No open PRs or GitHub dependency/code/secret alerts at intake." + "2026-10-28T20:16:18.094Z","harness:codex","Native late-peer recovery oracle initially exposed a delete-store gap: the existing scoped item precondition was checked by update/close but not by locked deletion. Isolated candidate adds the same assertion before deletion policy/hooks and centralizes create compensation ownership checks. Close and delete both preserve a peer edit injected immediately before item-lock acquisition. Isolated focused proof passes51 tests; original checkout remains frozen for the in-flight full coverage run. Retirement intent is additionally retained before compensation to fence forward replay across recovery crashes." + "2026-10-28T20:39:10.736Z","harness:codex","Validation: linked recovery suite passed 65/65, including durable v2 retirement fencing, prepared/applied/recorded crash boundaries, interrupted compensation, audit deduplication, malformed/downgraded receipts and native peer-write races. Typecheck, ESLint, duplicate detection, registry audit and OSV passed. Full canonical coverage is running; no full-coverage success is claimed yet. First complete suite exposed contract snapshot/source-operation registration and preview clock comparison failures, now corrected; its npm package resolution failure was host NODE_PATH configuration, now explicitly set. Published 2026.10.28 verifier passed npm/npx/Bun/bunx and GitHub release checks; this does not imply publication of these branch changes." +learnings[1]{created_at,author,text}: + "2026-10-28T20:16:19.379Z","harness:codex","Retiring an interrupted batch requires a durable intent before compensation, not only a terminal status afterward. Every destructive compensation must recheck ownership under the target item lock; a pre-lock history comparison alone does not protect a late peer edit." +files[13]{path,scope}: + sdk/public-surface.json,project + src/core/history/operation-contract.ts,project + src/core/store/item-store.ts,project + src/sdk/generated/generated-error-code-catalog-part-1.ts,project + src/sdk/generated/generated-error-code-catalog-part-2.ts,project + src/sdk/item-transaction.ts,project + src/sdk/runtime.ts,project + src/sdk/workspace-transaction-gc.ts,project + src/sdk/workspace-transaction.ts,project + tests/fixtures/contracts/full.json,project + tests/types/item-transactions.test-d.ts,project + tests/unit/sdk/transactions/host-bound.spec.ts,project + tests/unit/sdk/workspace-transaction.spec.ts,project +tests[1]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: + node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts,project,300,"harness:codex","2026-10-28T19:50:40.616Z",local_mutation,feat/host-bound-item-transactions +test_runs[1]: + - run_id: test-local-mvskr61r-dyaj7d + kind: test + status: passed + started_at: "2026-10-28T20:35:47.020Z" + finished_at: "2026-10-28T20:36:15.327Z" + recorded_at: "2026-10-28T20:36:15.327Z" + passed: 1 + failed: 0 + skipped: 0 + executions[1]{command,requested_pm_context_mode,pm_context_mode,workspace_context_mode,trust_reason}: + node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts,schema,schema,source,local_source_ref +docs[1]{path,scope}: + docs/SDK.md,project body: "" diff --git a/.agents/pm/features/pm-gh1598.toon b/.agents/pm/features/pm-gh1598.toon index 05caa29ca5..b738e49315 100644 --- a/.agents/pm/features/pm-gh1598.toon +++ b/.agents/pm/features/pm-gh1598.toon @@ -2,11 +2,13 @@ id: pm-gh1598 title: "GH-1598: bind batch mutation APIs to PmClient and expose canonical staged preview records" description: "GitHub https://github.com/unbraind/pm-cli/issues/1598 requests native PmClient preview/commit methods bound to host root and author policy, plus canonical staged records for idempotent intent comparison. Current staged preview validation remains shipped; its result contains validation state, constraints and warnings rather than complete staged records." type: Feature -status: open +status: in_progress priority: 1 tags: [] created_at: "2026-10-26T04:54:51.880Z" -updated_at: "2026-10-26T04:54:51.880Z" +updated_at: "2026-10-28T20:39:13.335Z" +assignee: "harness:codex" +claim_principal: "harness:codex#568692524ccbb719c2f222a0" author: "harness:codex" estimated_minutes: 240 acceptance_criteria: "Expose typed PmClient previewItemMutations and commitItemMutations forwarding bound root and author policy to the existing SDK coordinator; Return per-mutation canonical staged ids, normalized metadata and bodies with generated-value provenance and explicit commit-time constraints; Prove preview/read-back equivalence for unchanged admitted plans and safe identical-intent replay versus typed changed-intent conflicts using native non-Git fixtures; preserve read-only previews and current guarded commit behavior" @@ -17,6 +19,31 @@ expected_result: Packages can perform host-bound atomic batches and compare norm dependencies[2]{id,kind,created_at,author,source_kind,author_source}: pm-9rgaal,implements,"2026-10-26T04:54:51.880Z","harness:codex","cli:create:dep",detected pm-gh1370,discovered_from,"2026-10-26T04:54:51.880Z","harness:codex","cli:create:dep",detected -comments[1]{created_at,author,text}: +comments[3]{created_at,author,text}: "2026-10-26T04:54:51.880Z","harness:codex","Duplicate check: complete strict all-status corpus plus live request-specific searches and full terminal-lineage reads found no exact active owner. Existing SDK promotion and transaction/preview delivery remain completed; this item owns the newly requested public surface." + "2026-10-28T19:44:10.177Z","harness:codex","Implementation scope: typed root/author-bound PmClient preview and commit; canonical full staged item snapshots per executed mutation with explicit generated clock fields. Preserve committed replay semantics and read-only staging. Group with pm-gh1597 in one reviewed delivery; no other implementation items claimed." + "2026-10-28T20:39:13.335Z","harness:codex","Validation: linked SDK plus semantic-preview integration tests passed 49/49. Staged records retain canonical body, normalized tags, author and provenance with explicit clock-field pointers, final-batch state and applied/adopted execution receipts. Committed replay returns no newly validated records. Public declaration tests and SDK surface snapshot are current. Full canonical coverage is running; the earlier 197-test focused coverage diagnostic retained the full-source denominator and is not a global coverage pass." +files[6]{path,scope}: + sdk/public-surface.json,project + src/sdk/item-transaction.ts,project + src/sdk/runtime.ts,project + tests/integration/transactions/semantic-preview.integration.spec.ts,project + tests/types/item-transactions.test-d.ts,project + tests/unit/sdk/transactions/host-bound.spec.ts,project +tests[1]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: + node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts,project,300,"harness:codex","2026-10-28T19:50:42.784Z",local_mutation,feat/host-bound-item-transactions +test_runs[1]: + - run_id: test-local-mvsks2km-d73z2v + kind: test + status: passed + started_at: "2026-10-28T20:36:16.186Z" + finished_at: "2026-10-28T20:36:57.477Z" + recorded_at: "2026-10-28T20:36:57.477Z" + passed: 1 + failed: 0 + skipped: 0 + executions[1]{command,requested_pm_context_mode,pm_context_mode,workspace_context_mode,trust_reason}: + node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts,schema,schema,source,local_source_ref +docs[1]{path,scope}: + docs/SDK.md,project body: "" diff --git a/.agents/pm/history/pm-0trehk.jsonl b/.agents/pm/history/pm-0trehk.jsonl index d89ded8d2a..41b5e3b6fe 100644 --- a/.agents/pm/history/pm-0trehk.jsonl +++ b/.agents/pm/history/pm-0trehk.jsonl @@ -7,3 +7,4 @@ {"hash_algorithm":"sha256","ts":"2026-10-25T23:59:38.264Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"9a3d0027739dfadbcc41b040","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1593","claim:pm-ycyymg","lineage:pm-ycyymg","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1593+pm-ycyymg","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1593","claim:pm-ycyymg","lineage:pm-ycyymg","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-10-25T23:59:38.263Z","author":"harness:codex","text":"Live complete Nightly Reliability40244323743 artifact confirms current fourteen shard families have3-6 completed attempts and insufficient_completed_attempts; some current and predecessor families also retain original failure_rate findings. The measurement implementation remains closed and delivered. This read-only checkpoint keeps warm-up/lineage and original product regressions separate from the selected history-integrity implementation; this item remains open and unclaimed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T23:59:38.264Z"}],"before_hash":"b51f2fb7660d86bafbc682222f6ba2e7ab019cc5d13d9f62b41cb0851bf4aeda","after_hash":"03106816f722f19dabae04fea3180f44df5840e352b36eeea3cfc85db42ee066","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":"8848d4406b95760c40426277d14d7d5a0f7097bb7163b35e039183ffe225a31e"} {"hash_algorithm":"sha256","ts":"2026-10-26T22:08:16.036Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7efbcd86a29946bbfe9221c3","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1604","claim:pm-gh1605","claim:pm-gh1607","lineage:pm-gh1607","lineage:pm-f05lsg","lineage:pm-mpbb","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1604+pm-gh1605+pm-gh1607","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1604","claim:pm-gh1605","claim:pm-gh1607","lineage:pm-gh1607","lineage:pm-f05lsg","lineage:pm-mpbb","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/4","value":{"created_at":"2026-10-26T22:08:16.036Z","author":"harness:codex","text":"Live Nightly Reliability40404782722 preserves insufficient_completed_attempts for newer four-shard populations and original failure_rate findings in current and predecessor platform families. Latest GitHub1602 is a separate current Windows shard3/4 failure: the CLI integration generic-extension-error test could not parse stderr beginning warning:se as JSON; hosted log40303228148 names jsonErrorEnvelope.ts:18 and cli.integration.spec.ts:5639. Preserve that real product/fixture signature independently of the sample-lineage debt; no thresholds, denominators or historical outcomes are changed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-26T22:08:16.036Z"}],"before_hash":"03106816f722f19dabae04fea3180f44df5840e352b36eeea3cfc85db42ee066","after_hash":"bcb38c11208b24f95ed2ebde5a13df75349250c87063a4dab65133265644c250","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":"745b409b352f51eaa0d4ab3ed2e5e421092cf0cd9a3c471604f2e2c008cfd579"} {"hash_algorithm":"sha256","ts":"2026-10-27T22:23:20.169Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"525eee5e83a0bb4065087287","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1606","claim:pm-gh1614","lineage:pm-gh1606","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1606+pm-gh1614","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1606","claim:pm-gh1614","lineage:pm-gh1606","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/5","value":{"created_at":"2026-10-27T22:23:20.169Z","author":"harness:codex","text":"Live complete Nightly Reliability40592007740 retains18 family findings:12 newer four/two-shard families have insufficient_completed_attempts, and current/predecessor families retain original failure_rate findings. Current four-shard populations have5 completed attempts. This is separate from successful main CI40591995412 and the selected SDK input delivery. Existing Windows product owners remain distinct; no original outcomes, population thresholds or causes are rewritten."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-27T22:23:20.169Z"}],"before_hash":"bcb38c11208b24f95ed2ebde5a13df75349250c87063a4dab65133265644c250","after_hash":"82f7f210936507bd02393eb88a00e20b281d7bb04b0d3bdf58a16938d6edbe42","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":"0bd06464a3e5b495d93b42088449b862fc62ba787f673285565ad0df2290f986"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:51:09.733Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/6","value":{"created_at":"2026-10-28T19:51:09.733Z","author":"harness:codex","text":"October28 independent nightly artifact40744854788: current reshaped families have6 completed attempts and retain insufficient_completed_attempts; original failure_rate findings remain in current and predecessor families. The release-ledger report passes separately. Existing sample-lineage and Windows issue owners remain canonical; no historical outcomes or denominator changes are made."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:51:09.733Z"}],"before_hash":"82f7f210936507bd02393eb88a00e20b281d7bb04b0d3bdf58a16938d6edbe42","after_hash":"c97934f4fa4124e133b20bf0dab9efde538f4415953703cec49c20efdffff7ee","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":"1865aa9ee889f334735cfb4860a257a8381757a4ce4748eb04f0f36473779251"} diff --git a/.agents/pm/history/pm-gh1597.jsonl b/.agents/pm/history/pm-gh1597.jsonl index 3dbbe865a4..aeda1e243e 100644 --- a/.agents/pm/history/pm-gh1597.jsonl +++ b/.agents/pm/history/pm-gh1597.jsonl @@ -1 +1,13 @@ {"hash_algorithm":"sha256","ts":"2026-10-26T04:54:49.262Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"9a3d0027739dfadbcc41b040","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-8skz5z","claim:pm-gh1593","lineage:pm-8skz5z","lineage:pm-wb25c1","lineage:pm-u9d0","lineage:pm-doxj"]},"topic":{"value":"workset:pm-8skz5z+pm-gh1593","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-8skz5z","claim:pm-gh1593","lineage:pm-8skz5z","lineage:pm-wb25c1","lineage:pm-u9d0","lineage:pm-doxj"]}},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-gh1597"},{"op":"add","path":"/metadata/title","value":"GH-1597: expose host-bound item transaction status and safe abandonment or supersession"},{"op":"add","path":"/metadata/description","value":"GitHub https://github.com/unbraind/pm-cli/issues/1597 requests public recovery for interrupted item-mutation journals when a peer edit changes the retry plan. Existing bulk commit and guarded compensation are shipped; extend their public host-bound lifecycle rather than duplicating private journal storage or reviving completed implementation."},{"op":"add","path":"/metadata/type","value":"Feature"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":1},{"op":"add","path":"/metadata/tags","value":[]},{"op":"add","path":"/metadata/created_at","value":"2026-10-26T04:54:49.262Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-10-26T04:54:49.262Z"},{"op":"add","path":"/metadata/author","value":"harness:codex"},{"op":"add","path":"/metadata/estimated_minutes","value":300},{"op":"add","path":"/metadata/acceptance_criteria","value":"Expose typed host-bound journal state and applied/compensated step receipts with plan identity; Provide safe abandonment and supersession using proven apply markers and existing guarded compensation; never overwrite later peer edits or silently compensate committed work; Name executable public recovery in transaction-plan-mismatch guidance and verify non-Git crash/retry/peer-edit controls plus SDK contract documentation"},{"op":"add","path":"/metadata/parent","value":"pm-9rgaal"},{"op":"add","path":"/metadata/risk","value":"high"},{"op":"add","path":"/metadata/confidence","value":"high"},{"op":"add","path":"/metadata/expected_result","value":"Extensions can inspect and recover interrupted batches through a supported root-bound API without reading private paths or recreating journal and compensation rules."},{"op":"add","path":"/metadata/dependencies","value":[{"id":"pm-9rgaal","kind":"implements","created_at":"2026-10-26T04:54:49.262Z","author":"harness:codex","source_kind":"cli:create:dep","author_source":"detected"},{"id":"pm-y9hq","kind":"discovered_from","created_at":"2026-10-26T04:54:49.262Z","author":"harness:codex","source_kind":"cli:create:dep","author_source":"detected"}]},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-10-26T04:54:49.262Z","author":"harness:codex","text":"Duplicate check: complete strict all-status corpus plus live request-specific searches and full terminal-lineage reads found no exact active owner. Existing SDK promotion and transaction/preview delivery remain completed; this item owns the newly requested public surface."}]}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"5620774ffabb8ab6d08ea6cd365c2695cda9fccbec3448eb5d30b63371c7eac4","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":"47aadb14933600c8857dda9db60d5a11c13b19e1afddb2f5cd3aaa2828b3cab4"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:40:28.847Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","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-28T19:40:28.847Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#568692524ccbb719c2f222a0"}],"before_hash":"5620774ffabb8ab6d08ea6cd365c2695cda9fccbec3448eb5d30b63371c7eac4","after_hash":"75cfe7a45a9c365f4fca85253a1967d366212f37378226e3a6a2253d0d3be189","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":"638f2dbae93360c18da6072946517e7050bf5011f405a268c19fca51ae799d2a"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:40:29.010Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"pm-gh1597","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:40:29.010Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"75cfe7a45a9c365f4fca85253a1967d366212f37378226e3a6a2253d0d3be189","after_hash":"86f390db9f8f09f846ebf644c96e9412a3cd4a2ca328b3bb36cbcb390c1422d1","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":"a24a97cd1c5c2c24e90b3c149d3001f8c9c1bba02f7cd97a4f2e9099b9376d04"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:44:07.697Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-10-28T19:44:07.695Z","author":"harness:codex","text":"Implementation scope: retain original item plans in coordinator journals, expose read-only status and host-bound guarded abandonment/supersession, refuse committed and peer-edited work, preserve append-only compensation and audit evidence. Complete strict 3148-item all-status census has no omissions; 38 open GitHub issues each already have a canonical PM link comment. No open PRs or GitHub dependency/code/secret alerts at intake."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:44:07.697Z"}],"before_hash":"86f390db9f8f09f846ebf644c96e9412a3cd4a2ca328b3bb36cbcb390c1422d1","after_hash":"155db83ee930a03f741e03114a98b30b7a63b3b21b6b12bff12197ca337f5e90","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":"0909a3a058865e8441bc1210a92132848b88b934da4d5805004d982557496606"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:48:51.131Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:48:51.131Z"},{"op":"add","path":"/metadata/files","value":[{"path":"src/sdk/item-transaction.ts","scope":"project"},{"path":"src/sdk/runtime.ts","scope":"project"},{"path":"src/sdk/workspace-transaction.ts","scope":"project"},{"path":"tests/unit/sdk/transactions/host-bound.spec.ts","scope":"project"}]}],"before_hash":"155db83ee930a03f741e03114a98b30b7a63b3b21b6b12bff12197ca337f5e90","after_hash":"77b643c8bbf4c64642a0bf4de093337ba5b718c0709fdf461a084c6e351d0f2e","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":"fa6f7a64da1bee675bb9fcd00bfa6bfb694124dcccd77ee97f94b9b366be9059"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:48:52.973Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:48:52.973Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/SDK.md","scope":"project"}]}],"before_hash":"77b643c8bbf4c64642a0bf4de093337ba5b718c0709fdf461a084c6e351d0f2e","after_hash":"ac2006b0b04af957f35c67b7e60c43618008ded624f42e8f7321b22dbd00b50b","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":"cd4508252abc348ce123471570de418dfd4b9cb110662e183290947c70e996f2"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:50:40.840Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:50:40.840Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts","scope":"project","timeout_seconds":300,"provenance":{"author":"harness:codex","created_at":"2026-10-28T19:50:40.616Z","source_kind":"local_mutation","source_ref":"feat/host-bound-item-transactions"}}]}],"before_hash":"ac2006b0b04af957f35c67b7e60c43618008ded624f42e8f7321b22dbd00b50b","after_hash":"9619e14d89b3716d20c60a95a9d57bf3c118f73ec5aeed1f4ef804dcb9b51819","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":"dcc8dd47c6c404f38c291d3eaf5088aadb7722eb3e510d32dd42087de2e3f8dd"} +{"hash_algorithm":"sha256","ts":"2026-10-28T20:16:18.095Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-10-28T20:16:18.094Z","author":"harness:codex","text":"Native late-peer recovery oracle initially exposed a delete-store gap: the existing scoped item precondition was checked by update/close but not by locked deletion. Isolated candidate adds the same assertion before deletion policy/hooks and centralizes create compensation ownership checks. Close and delete both preserve a peer edit injected immediately before item-lock acquisition. Isolated focused proof passes51 tests; original checkout remains frozen for the in-flight full coverage run. Retirement intent is additionally retained before compensation to fence forward replay across recovery crashes."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:16:18.095Z"}],"before_hash":"9619e14d89b3716d20c60a95a9d57bf3c118f73ec5aeed1f4ef804dcb9b51819","after_hash":"165203d80475d9cf8038cce9dbe06e9076c78d4cebf961764acfb2cb751f6751","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":"17a2cca8828c2f8af57d6f9a13068c7591b067b5a7257ae3e211d8ba881dcbaa"} +{"hash_algorithm":"sha256","ts":"2026-10-28T20:16:19.380Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"learning_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:16:19.380Z"},{"op":"add","path":"/metadata/learnings","value":[{"created_at":"2026-10-28T20:16:19.379Z","author":"harness:codex","text":"Retiring an interrupted batch requires a durable intent before compensation, not only a terminal status afterward. Every destructive compensation must recheck ownership under the target item lock; a pre-lock history comparison alone does not protect a late peer edit."}]}],"before_hash":"165203d80475d9cf8038cce9dbe06e9076c78d4cebf961764acfb2cb751f6751","after_hash":"3cffce46b3df143f7bac25c465ebe030f2654d0cf866368bb7c91ee2a9bcd4cc","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":"11d18a2dfe417616ffb071865632ae253ce76bdf4bd350a5d891e49fb63ba8e8"} +{"hash_algorithm":"sha256","ts":"2026-10-28T20:24:19.104Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/3/path","value":"src/sdk/item-transaction.ts"},{"op":"replace","path":"/metadata/files/2/path","value":"src/core/store/item-store.ts"},{"op":"replace","path":"/metadata/files/1/path","value":"src/core/history/operation-contract.ts"},{"op":"replace","path":"/metadata/files/0/path","value":"sdk/public-surface.json"},{"op":"add","path":"/metadata/files/4","value":{"path":"src/sdk/runtime.ts","scope":"project"}},{"op":"add","path":"/metadata/files/5","value":{"path":"src/sdk/workspace-transaction-gc.ts","scope":"project"}},{"op":"add","path":"/metadata/files/6","value":{"path":"src/sdk/workspace-transaction.ts","scope":"project"}},{"op":"add","path":"/metadata/files/7","value":{"path":"tests/types/item-transactions.test-d.ts","scope":"project"}},{"op":"add","path":"/metadata/files/8","value":{"path":"tests/unit/sdk/transactions/host-bound.spec.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:24:19.104Z"}],"before_hash":"3cffce46b3df143f7bac25c465ebe030f2654d0cf866368bb7c91ee2a9bcd4cc","after_hash":"f0e0b786715bba616631035860082758cd04a93cbf8eddcf20bcd0eedad5bd8a","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":"22fce8fe916e61b3f3b44ef9ae1acaf8993db0b9516c831492a1ab705ab56392"} +{"hash_algorithm":"sha256","ts":"2026-10-28T20:35:46.067Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/8/path","value":"src/sdk/workspace-transaction.ts"},{"op":"replace","path":"/metadata/files/7/path","value":"src/sdk/workspace-transaction-gc.ts"},{"op":"replace","path":"/metadata/files/6/path","value":"src/sdk/runtime.ts"},{"op":"replace","path":"/metadata/files/5/path","value":"src/sdk/item-transaction.ts"},{"op":"replace","path":"/metadata/files/4/path","value":"src/sdk/generated/generated-error-code-catalog-part-2.ts"},{"op":"replace","path":"/metadata/files/3/path","value":"src/sdk/generated/generated-error-code-catalog-part-1.ts"},{"op":"add","path":"/metadata/files/9","value":{"path":"tests/fixtures/contracts/full.json","scope":"project"}},{"op":"add","path":"/metadata/files/10","value":{"path":"tests/types/item-transactions.test-d.ts","scope":"project"}},{"op":"add","path":"/metadata/files/11","value":{"path":"tests/unit/sdk/transactions/host-bound.spec.ts","scope":"project"}},{"op":"add","path":"/metadata/files/12","value":{"path":"tests/unit/sdk/workspace-transaction.spec.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:35:46.067Z"}],"before_hash":"f0e0b786715bba616631035860082758cd04a93cbf8eddcf20bcd0eedad5bd8a","after_hash":"9d701c90f4b02aff035aed8378df17fa97b339b013c8c0e6ec6f9439d0e6939b","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":"6e056500113f56325b4c88fa96e787fb4f2ad938cddff2bc8e98c9aa48267b1a"} +{"hash_algorithm":"sha256","ts":"2026-10-28T20:36:15.343Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:36:15.343Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-mvskr61r-dyaj7d","kind":"test","status":"passed","started_at":"2026-10-28T20:35:47.020Z","finished_at":"2026-10-28T20:36:15.327Z","recorded_at":"2026-10-28T20:36:15.327Z","passed":1,"failed":0,"skipped":0,"executions":[{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts","requested_pm_context_mode":"schema","pm_context_mode":"schema","workspace_context_mode":"source","trust_reason":"local_source_ref"}]}]}],"before_hash":"9d701c90f4b02aff035aed8378df17fa97b339b013c8c0e6ec6f9439d0e6939b","after_hash":"48acbaee158a5a2e01b8da793d553012ca967784e9e5ff9e7eca72f8e84d292f","item_hash_version":3,"message":"Track test run summary (test-local-mvskr61r-dyaj7d)","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":"d0d5a9fbb40659a9fbe6d4fc76e0523dd0322bf4b891efa2b140981259579223"} +{"hash_algorithm":"sha256","ts":"2026-10-28T20:39:10.736Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-10-28T20:39:10.736Z","author":"harness:codex","text":"Validation: linked recovery suite passed 65/65, including durable v2 retirement fencing, prepared/applied/recorded crash boundaries, interrupted compensation, audit deduplication, malformed/downgraded receipts and native peer-write races. Typecheck, ESLint, duplicate detection, registry audit and OSV passed. Full canonical coverage is running; no full-coverage success is claimed yet. First complete suite exposed contract snapshot/source-operation registration and preview clock comparison failures, now corrected; its npm package resolution failure was host NODE_PATH configuration, now explicitly set. Published 2026.10.28 verifier passed npm/npx/Bun/bunx and GitHub release checks; this does not imply publication of these branch changes."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:39:10.736Z"}],"before_hash":"48acbaee158a5a2e01b8da793d553012ca967784e9e5ff9e7eca72f8e84d292f","after_hash":"8cc9b01c88ff15c9eee1a38f8310014037f517f2f6d5091f1cb78c3ca29755ae","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":"1789ed8f2a051adb23bba8debbfc15159bbc5ca71ab25751cf319ee9eecc1b12"} diff --git a/.agents/pm/history/pm-gh1598.jsonl b/.agents/pm/history/pm-gh1598.jsonl index 7c83f41916..8c1bb74586 100644 --- a/.agents/pm/history/pm-gh1598.jsonl +++ b/.agents/pm/history/pm-gh1598.jsonl @@ -1 +1,10 @@ {"hash_algorithm":"sha256","ts":"2026-10-26T04:54:51.880Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"9a3d0027739dfadbcc41b040","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-8skz5z","claim:pm-gh1593","lineage:pm-8skz5z","lineage:pm-wb25c1","lineage:pm-u9d0","lineage:pm-doxj"]},"topic":{"value":"workset:pm-8skz5z+pm-gh1593","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-8skz5z","claim:pm-gh1593","lineage:pm-8skz5z","lineage:pm-wb25c1","lineage:pm-u9d0","lineage:pm-doxj"]}},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-gh1598"},{"op":"add","path":"/metadata/title","value":"GH-1598: bind batch mutation APIs to PmClient and expose canonical staged preview records"},{"op":"add","path":"/metadata/description","value":"GitHub https://github.com/unbraind/pm-cli/issues/1598 requests native PmClient preview/commit methods bound to host root and author policy, plus canonical staged records for idempotent intent comparison. Current staged preview validation remains shipped; its result contains validation state, constraints and warnings rather than complete staged records."},{"op":"add","path":"/metadata/type","value":"Feature"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":1},{"op":"add","path":"/metadata/tags","value":[]},{"op":"add","path":"/metadata/created_at","value":"2026-10-26T04:54:51.880Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-10-26T04:54:51.880Z"},{"op":"add","path":"/metadata/author","value":"harness:codex"},{"op":"add","path":"/metadata/estimated_minutes","value":240},{"op":"add","path":"/metadata/acceptance_criteria","value":"Expose typed PmClient previewItemMutations and commitItemMutations forwarding bound root and author policy to the existing SDK coordinator; Return per-mutation canonical staged ids, normalized metadata and bodies with generated-value provenance and explicit commit-time constraints; Prove preview/read-back equivalence for unchanged admitted plans and safe identical-intent replay versus typed changed-intent conflicts using native non-Git fixtures; preserve read-only previews and current guarded commit behavior"},{"op":"add","path":"/metadata/parent","value":"pm-9rgaal"},{"op":"add","path":"/metadata/risk","value":"medium"},{"op":"add","path":"/metadata/confidence","value":"high"},{"op":"add","path":"/metadata/expected_result","value":"Packages can perform host-bound atomic batches and compare normalized intents using SDK-owned records instead of re-deriving roots or duplicating normalization."},{"op":"add","path":"/metadata/dependencies","value":[{"id":"pm-9rgaal","kind":"implements","created_at":"2026-10-26T04:54:51.880Z","author":"harness:codex","source_kind":"cli:create:dep","author_source":"detected"},{"id":"pm-gh1370","kind":"discovered_from","created_at":"2026-10-26T04:54:51.880Z","author":"harness:codex","source_kind":"cli:create:dep","author_source":"detected"}]},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-10-26T04:54:51.880Z","author":"harness:codex","text":"Duplicate check: complete strict all-status corpus plus live request-specific searches and full terminal-lineage reads found no exact active owner. Existing SDK promotion and transaction/preview delivery remain completed; this item owns the newly requested public surface."}]}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"8c901de2642c07ef2bf3570db75203b114bc0bacfb9d234ad65d1af1d26f9dd8","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":"51aad1705cb93e58127debfa8328d825a0ba895a43cd7cef6edd48e791d05232"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:40:29.690Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"pm-gh1597","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:40:29.690Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#568692524ccbb719c2f222a0"}],"before_hash":"8c901de2642c07ef2bf3570db75203b114bc0bacfb9d234ad65d1af1d26f9dd8","after_hash":"a95951a908abb1be2b4d65b6cec910cf3591f587c8ac68bb235d55cc93f4e04b","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":"1ac521554e89d9f84510ce582a1adb85707c981886e74ce320f725484b4c3499"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:40:29.866Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:40:29.866Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"a95951a908abb1be2b4d65b6cec910cf3591f587c8ac68bb235d55cc93f4e04b","after_hash":"253d07bb5c807eb31b4e37213b171b1fbbeb5601a466d4a50338e7e27a4ae713","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":"a4bf5575937fa0b54a5063e91beb0597e425a8af8ec1d4b95b2b43e5872cfa42"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:44:10.180Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-10-28T19:44:10.177Z","author":"harness:codex","text":"Implementation scope: typed root/author-bound PmClient preview and commit; canonical full staged item snapshots per executed mutation with explicit generated clock fields. Preserve committed replay semantics and read-only staging. Group with pm-gh1597 in one reviewed delivery; no other implementation items claimed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:44:10.180Z"}],"before_hash":"253d07bb5c807eb31b4e37213b171b1fbbeb5601a466d4a50338e7e27a4ae713","after_hash":"7c2942f806469f0585889c116bd1a762229d51b60aabb544764a1c41a62286d2","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":"dbd967b2db9e0b929fc6ef4b43307dd2ddee46a210653aa12be17edf2bd2a00a"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:48:52.000Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:48:52.000Z"},{"op":"add","path":"/metadata/files","value":[{"path":"src/sdk/item-transaction.ts","scope":"project"},{"path":"src/sdk/runtime.ts","scope":"project"},{"path":"tests/unit/sdk/transactions/host-bound.spec.ts","scope":"project"}]}],"before_hash":"7c2942f806469f0585889c116bd1a762229d51b60aabb544764a1c41a62286d2","after_hash":"8a1a2ef7cd7a58314ee350f85976f42cf328f444bb0328c65a31a4bf4ef9f51d","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":"e2307c09b9a3279539400d3a8c02abe993a0ca906a3eb465591aa4fdbba0614d"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:48:53.977Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:48:53.977Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/SDK.md","scope":"project"}]}],"before_hash":"8a1a2ef7cd7a58314ee350f85976f42cf328f444bb0328c65a31a4bf4ef9f51d","after_hash":"480055da7a5c8b6db4244024415779663fbc523f96ff6065efe74b539dad9f8a","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":"4cfabfcf5a1f3042a95447e82e729f471c71a4a632860aa77d7c220d3ef32eaf"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:50:42.948Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:50:42.948Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts","scope":"project","timeout_seconds":300,"provenance":{"author":"harness:codex","created_at":"2026-10-28T19:50:42.784Z","source_kind":"local_mutation","source_ref":"feat/host-bound-item-transactions"}}]}],"before_hash":"480055da7a5c8b6db4244024415779663fbc523f96ff6065efe74b539dad9f8a","after_hash":"aea599ec74907165cbf67204440357a86c5fc9075973f90789314a88c86544fc","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":"6d4917178db0548e897ef799ccc58ecb1f3121ed6d432efee2a240ba9610bcb9"} +{"hash_algorithm":"sha256","ts":"2026-10-28T20:24:19.918Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/2/path","value":"src/sdk/runtime.ts"},{"op":"replace","path":"/metadata/files/1/path","value":"src/sdk/item-transaction.ts"},{"op":"replace","path":"/metadata/files/0/path","value":"sdk/public-surface.json"},{"op":"add","path":"/metadata/files/3","value":{"path":"tests/integration/transactions/semantic-preview.integration.spec.ts","scope":"project"}},{"op":"add","path":"/metadata/files/4","value":{"path":"tests/types/item-transactions.test-d.ts","scope":"project"}},{"op":"add","path":"/metadata/files/5","value":{"path":"tests/unit/sdk/transactions/host-bound.spec.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:24:19.918Z"}],"before_hash":"aea599ec74907165cbf67204440357a86c5fc9075973f90789314a88c86544fc","after_hash":"a6a5a51d62e425bb7de495ddf79b8909ab8185b4c4a999a637927e9a47227f3f","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":"e78efe450a11fe7f58774debbd986e4d047510ba9d3c41b5f931de2b328c25e5"} +{"hash_algorithm":"sha256","ts":"2026-10-28T20:36:57.485Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:36:57.485Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-mvsks2km-d73z2v","kind":"test","status":"passed","started_at":"2026-10-28T20:36:16.186Z","finished_at":"2026-10-28T20:36:57.477Z","recorded_at":"2026-10-28T20:36:57.477Z","passed":1,"failed":0,"skipped":0,"executions":[{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts","requested_pm_context_mode":"schema","pm_context_mode":"schema","workspace_context_mode":"source","trust_reason":"local_source_ref"}]}]}],"before_hash":"a6a5a51d62e425bb7de495ddf79b8909ab8185b4c4a999a637927e9a47227f3f","after_hash":"4f5ca69d399c18123c43a5a7351e822e5dcffe3d3cb3849f067ef63497580abf","item_hash_version":3,"message":"Track test run summary (test-local-mvsks2km-d73z2v)","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":"7b05ad4ca46e444b77effb1d29ffd110143f0b2ef8a7e5c8d52179520dd8d8b2"} +{"hash_algorithm":"sha256","ts":"2026-10-28T20:39:13.335Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-10-28T20:39:13.335Z","author":"harness:codex","text":"Validation: linked SDK plus semantic-preview integration tests passed 49/49. Staged records retain canonical body, normalized tags, author and provenance with explicit clock-field pointers, final-batch state and applied/adopted execution receipts. Committed replay returns no newly validated records. Public declaration tests and SDK surface snapshot are current. Full canonical coverage is running; the earlier 197-test focused coverage diagnostic retained the full-source denominator and is not a global coverage pass."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:39:13.335Z"}],"before_hash":"4f5ca69d399c18123c43a5a7351e822e5dcffe3d3cb3849f067ef63497580abf","after_hash":"9df2102b70803aef37d8ad41c66b64cc48509d1861f196d9146a57f44d6a576f","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":"e9032bac56becfa855e5e9fe38e1a755375217855098f8831d36e0bac8d5e773"} diff --git a/.agents/pm/history/pm-prrlce.jsonl b/.agents/pm/history/pm-prrlce.jsonl index 5684be597b..0f4ee02595 100644 --- a/.agents/pm/history/pm-prrlce.jsonl +++ b/.agents/pm/history/pm-prrlce.jsonl @@ -174,3 +174,4 @@ {"hash_algorithm":"sha256","ts":"2026-10-25T23:59:33.202Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"9a3d0027739dfadbcc41b040","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1593","claim:pm-ycyymg","lineage:pm-ycyymg","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1593+pm-ycyymg","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1593","claim:pm-ycyymg","lineage:pm-ycyymg","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/75","value":{"created_at":"2026-10-25T23:59:33.191Z","author":"harness:codex","text":"Live Release Reliability40244323743 complete artifacts retain only dispatch_window for the release series; release-ledger reconciliation passes. Native and morning automatic publication remain independently distinct from the historical dispatch-timing finding. Existing currentUTC-day v2026.10.25 is sole published tag and npm version; read-only installed dispatcher check returns dispatch_already_attempted without sending a request or changing daily markers. The user timer is active for04:45Europe/Vienna. No extra release or policy relaxation is performed by the SDK integrity work."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-25T23:59:33.202Z"}],"before_hash":"d8eb6431115549e0e1c250dde8e38ea383a61fcbb95e2b329adb0f0a167cad7a","after_hash":"9ddc5ae83d5dce2afc3de59ff7c86f45b4d3871dacfbd9754d751452c299ae65","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":"bd5ea0572e23280100df7aa0c1a53e660d7ebb5ba2e21ade1ba65d89821d984c"} {"hash_algorithm":"sha256","ts":"2026-10-26T22:08:14.067Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7efbcd86a29946bbfe9221c3","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1604","claim:pm-gh1605","claim:pm-gh1607","lineage:pm-gh1607","lineage:pm-f05lsg","lineage:pm-mpbb","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1604+pm-gh1605+pm-gh1607","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1604","claim:pm-gh1605","claim:pm-gh1607","lineage:pm-gh1607","lineage:pm-f05lsg","lineage:pm-mpbb","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/76","value":{"created_at":"2026-10-26T22:08:14.067Z","author":"harness:codex","text":"Live 2026-10-26 reliability artifact40404782722 inspected independently of candidate CI: release series has30 original completed attempts,3 original failures and only dispatch_window policy finding. Morning dispatcher series has21 attempts with12 publications and9 retained original failures. Public release2026.10.26 passes the shared verifier including npm/npx/bunx; exactly one currentUTC-day tag is published. Native cron02:35UTC, hosted concurrency and immutable-day guard remain configured. This evidence does not clear historical timing findings or claim a second automatic release. No release is dispatched by this continuation."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-26T22:08:14.067Z"}],"before_hash":"9ddc5ae83d5dce2afc3de59ff7c86f45b4d3871dacfbd9754d751452c299ae65","after_hash":"b5fd6dee53a3a0a0b1809e8ec14a279c39b070c86dc0386a4577cf88e34e299e","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":"7e2b107093ea312805dbfbafaf055cd3595cd236cb973f326e8e54e319aa62c8"} {"hash_algorithm":"sha256","ts":"2026-10-27T22:23:17.371Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"525eee5e83a0bb4065087287","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1606","claim:pm-gh1614","lineage:pm-gh1606","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1606+pm-gh1614","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1606","claim:pm-gh1614","lineage:pm-gh1606","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/77","value":{"created_at":"2026-10-27T22:23:17.370Z","author":"harness:codex","text":"Live October27 Release Reliability40592007740 has a complete census:30 completed original release attempts,3 original failures, and only dispatch_window violated. Latest native Auto Release40472638505 confirms immutable v2026.10.27 and npm publication before preparation, without a second cut. Five recent native schedule runs are successful. The independent release-ledger report is ok. Preserve original history and daily concurrency/day identity; no additional release dispatch or threshold change is performed by this SDK delivery."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-27T22:23:17.371Z"}],"before_hash":"b5fd6dee53a3a0a0b1809e8ec14a279c39b070c86dc0386a4577cf88e34e299e","after_hash":"2aacd3d0abf7c8adbba9873e12ba90444b0b991e86233a0167a8e5130c0cb1d0","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":"6822f40024b5f913f4b38e7a88d52deceff1cbce94f559462172b9065a6a27e4"} +{"hash_algorithm":"sha256","ts":"2026-10-28T19:51:07.895Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/78","value":{"created_at":"2026-10-28T19:51:07.895Z","author":"harness:codex","text":"October28 independent artifact40744854788: complete release outcome census and passing release-ledger report; rolling scheduled reliability still fails only dispatch_window. Current npm/latest and GitHub release are2026.10.28. Preserve the one-automatic-release-per-UTC-day guard; no extra release or threshold change is justified by this SDK batch."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:51:07.895Z"}],"before_hash":"2aacd3d0abf7c8adbba9873e12ba90444b0b991e86233a0167a8e5130c0cb1d0","after_hash":"af501630af9d7bdfce3c392dae2262e6de162af509d9e47b36acd02a4caef09b","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":"dffe24e3dacf5749f07d7e846e9bdc93e3eccfb35f2f18c64d83485bed50dc1e"} diff --git a/.agents/pm/history/pm-xq09zu.jsonl b/.agents/pm/history/pm-xq09zu.jsonl index cabbf84551..1d1ea8bfca 100644 --- a/.agents/pm/history/pm-xq09zu.jsonl +++ b/.agents/pm/history/pm-xq09zu.jsonl @@ -24,3 +24,4 @@ {"hash_algorithm":"sha256","ts":"2026-10-28T15:41:10.735Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"738f7d9b84aae278517b105a","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1603","claim:pm-gh1617","lineage:pm-gh1603","lineage:pm-mpbb","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1603+pm-gh1617","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1603","claim:pm-gh1617","lineage:pm-gh1603","lineage:pm-mpbb","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/14","value":{"created_at":"2026-10-28T15:41:10.734Z","author":"harness:codex","text":"October28 live evidence: required Sentry/telemetry gate reports zero blocking Sentry issues and zero missing-code rows, but seven-day finish error rate6.04percent exceeds unchanged6percent. Independent breakdown reports594304 finishes,35947 failures and6.03percent; most failures belong to existing command_failed/automation cohorts. Recent aggregate counts mostly pair with subsecond-to-two-second ingest lag; this is not per-invocation or historical completeness proof. Broker queue is empty and SDK flush drains local queue to zero bytes. Preserve the aggregate-rate failure separately from the context-read changes and prior unmatched-start investigation."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T15:41:10.735Z"}],"before_hash":"195ae6fbffa377d375aad32bd85a4d4e09bde792bab910d67e401da5b2416354","after_hash":"22e92fc2024ff5957a9657c157fb0075c38df06a6161c8adb0f4f2daf8de0e48","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":"757cecb4a33efa17db57822bc2e6f6db78d97bad728620ee6beb84cf18c22f72"} {"hash_algorithm":"sha256","ts":"2026-10-28T16:25:11.915Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"738f7d9b84aae278517b105a","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1603","claim:pm-gh1617","lineage:pm-gh1603","lineage:pm-mpbb","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1603+pm-gh1617","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1603","claim:pm-gh1617","lineage:pm-gh1603","lineage:pm-mpbb","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/15","value":{"created_at":"2026-10-28T16:25:11.915Z","author":"harness:codex","text":"Review correction: the independently quoted counts 35,947 / 594,304 equal 6.0486%, rounded 6.05%; the previous 6.03% label was incorrect. This correction does not change the separately sampled 6.04% gate verdict or its unchanged 6% threshold. The aggregate issue remains open."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T16:25:11.915Z"}],"before_hash":"22e92fc2024ff5957a9657c157fb0075c38df06a6161c8adb0f4f2daf8de0e48","after_hash":"6c4eeca25c8445d08cca616ac0ae5f4efc619333638f0598a3f0813cf8e85431","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":"5e974082f7311ee03aec6e693a8f02feab86818058763a121b96e4bc2918521d"} {"hash_algorithm":"sha256","ts":"2026-10-28T17:20:25.176Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"738f7d9b84aae278517b105a","agent_provenance":{"model":{"value":"gpt-6-astra","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-28T17:20:25.175Z","author":"harness:codex","text":"Post-change delivery probe at 2026-10-28 17:19 UTC: context command_start and successful command_finish were both persisted independently in the remote telemetry database with 0.855s and 0.709s ingestion lag. SDK flush completed and the remote queue had zero ready/unacknowledged messages. These current delivery facts do not clear the separately reported aggregate error-rate and historical pairing limitations."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T17:20:25.176Z"}],"before_hash":"6c4eeca25c8445d08cca616ac0ae5f4efc619333638f0598a3f0813cf8e85431","after_hash":"d72befc1af2d0f3f2cfe3013a4fd342bf1182bd9c3010b1bd66d0242a523306a","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":"93798229f6700cf376bec66321d0de5a46191f9aeddee58c4aba66485419c921"} +{"hash_algorithm":"sha256","ts":"2026-10-28T20:02:08.312Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/17","value":{"created_at":"2026-10-28T20:02:08.311Z","author":"harness:codex","text":"Current live required-mode Sentry/telemetry gate passes: no blocking Sentry issues; rolling weighted telemetry finish error rate5.94% against unchanged6% threshold; zero failures missing error codes. A new pm.command context span is visible. A separate10-minute context sample has6 paired sessions and1 unmatched session, with maximum observed ingestion lag4.144seconds. This passing threshold does not resolve historical pairing debt or certify every action."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:02:08.312Z"}],"before_hash":"d72befc1af2d0f3f2cfe3013a4fd342bf1182bd9c3010b1bd66d0242a523306a","after_hash":"bed78dd29e2f04bc26051a63159fa83abe30414b15a03cfdeeb629cedbeefec6","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":"a054f7a63aae52f5d61d71c1ed59c54dc980859c736c692a48e418ce4f97d44e"} diff --git a/.agents/pm/issues/pm-0trehk.toon b/.agents/pm/issues/pm-0trehk.toon index b8a0a824db..6c22a63646 100644 --- a/.agents/pm/issues/pm-0trehk.toon +++ b/.agents/pm/issues/pm-0trehk.toon @@ -6,7 +6,7 @@ status: open priority: 2 tags[5]: ci,monitoring,nightly,recurrence,reliability created_at: "2026-10-22T18:29:04.661Z" -updated_at: "2026-10-27T22:23:20.169Z" +updated_at: "2026-10-28T19:51:09.733Z" author: "harness:claude-code" estimated_minutes: 300 acceptance_criteria: "The SDK reliability window policy accepts family declarations as objects {name, introduced_at (ISO instant the leg first ran under this name), replaces?: string[] (predecessor family names)}, while plain strings stay valid and mean no lineage and no warm-up; The collector derives introduced_at and replaces from declared workflow data only and evaluation stays in src/sdk/governance/reliability.ts; A leg whose introduced_at is inside the window and whose own completed attempts are below min_completed_attempts is reported warm_up (non-failing) with warm_up_expires_at = introduced_at + window length, including the zero-attempt case; Declared predecessor attempts inside the window are reported as lineage evidence and count toward failure_rate but never toward the leg's own coverage; Any failure_rate violation on a leg or its predecessors still fails, and after warm_up_expires_at insufficient attempts fail coverage again; The step summary separates warm-up, coverage, failure-rate and dispatch findings with their owners; Negative controls prove an undeclared rename (no lineage, no introduced_at) still fails coverage and an expired warm-up fails" @@ -20,11 +20,12 @@ actual_result: "Release Reliability runs 39817294749 and 39817302614 (2026-10-22 dependencies[2]{id,kind,created_at,author,source_kind,author_source}: pm-23lmm5,related,"2026-10-22T18:29:04.661Z","harness:claude-code","cli:create:dep",detected pm-2zjs0g,discovered_from,"2026-10-22T18:29:04.661Z","harness:claude-code","cli:create:dep",detected -comments[6]{created_at,author,text}: +comments[7]{created_at,author,text}: "2026-10-23T06:34:13.763Z","harness:codex","Live Release Reliability39897809658 on October23 still reports new partition families at zero completed attempts and insufficient_completed_attempts, alongside retained historical native family failure rates. Latest required main CI39894565527 passed. Keep warm-up/lineage accounting distinct from product validation and preserve original failures; this read-envelope delivery does not change reliability policy or its population." "2026-10-23T12:04:15.333Z","harness:codex","Independent nightly intake, not a monitor-policy repair: run39930064018 on ce9452103131129261db381f738931da715c9c44 failed the Windows Node24 shard1 merge-portability audit/rollback case at the unchanged30000ms Vitest limit. Its Ubuntu Node24 aggregate failed the SHARD_RESULT check because it depends on the whole nightly matrix; its log does not establish a separate Ubuntu product failure. GH1558 already carries the canonical recurrence link. Preserve the original attempt and keep completed measurement/serialization work closed; this linked-resource delivery does not claim to fix that timeout. Intake only, no claim on this open lineage item." "2026-10-23T23:40:35.622Z","harness:codex","Live continuation confirms the latest Release Reliability39992667751 remains failed on scheduled and nightly recurrence evaluation, while the previous main CI39992655202 passed. This delivery retains the original failure logs and existing nightly Windows recurrence ownership; neither successful public artifact acceptance nor current PR validation is asserted to repair rolling history or family warm-up accounting." "2026-10-25T23:59:38.263Z","harness:codex",Live complete Nightly Reliability40244323743 artifact confirms current fourteen shard families have3-6 completed attempts and insufficient_completed_attempts; some current and predecessor families also retain original failure_rate findings. The measurement implementation remains closed and delivered. This read-only checkpoint keeps warm-up/lineage and original product regressions separate from the selected history-integrity implementation; this item remains open and unclaimed. "2026-10-26T22:08:16.036Z","harness:codex","Live Nightly Reliability40404782722 preserves insufficient_completed_attempts for newer four-shard populations and original failure_rate findings in current and predecessor platform families. Latest GitHub1602 is a separate current Windows shard3/4 failure: the CLI integration generic-extension-error test could not parse stderr beginning warning:se as JSON; hosted log40303228148 names jsonErrorEnvelope.ts:18 and cli.integration.spec.ts:5639. Preserve that real product/fixture signature independently of the sample-lineage debt; no thresholds, denominators or historical outcomes are changed." "2026-10-27T22:23:20.169Z","harness:codex","Live complete Nightly Reliability40592007740 retains18 family findings:12 newer four/two-shard families have insufficient_completed_attempts, and current/predecessor families retain original failure_rate findings. Current four-shard populations have5 completed attempts. This is separate from successful main CI40591995412 and the selected SDK input delivery. Existing Windows product owners remain distinct; no original outcomes, population thresholds or causes are rewritten." + "2026-10-28T19:51:09.733Z","harness:codex","October28 independent nightly artifact40744854788: current reshaped families have6 completed attempts and retain insufficient_completed_attempts; original failure_rate findings remain in current and predecessor families. The release-ledger report passes separately. Existing sample-lineage and Windows issue owners remain canonical; no historical outcomes or denominator changes are made." body: "" diff --git a/.agents/pm/issues/pm-prrlce.toon b/.agents/pm/issues/pm-prrlce.toon index e380d5622d..3df8ba5384 100644 --- a/.agents/pm/issues/pm-prrlce.toon +++ b/.agents/pm/issues/pm-prrlce.toon @@ -6,7 +6,7 @@ status: open priority: 1 tags[4]: "area:release",automation,diagnostics,"horizon:current" created_at: "2026-09-28T15:31:49.498Z" -updated_at: "2026-10-27T22:23:17.371Z" +updated_at: "2026-10-28T19:51:07.895Z" author: "harness:claude-code" estimated_minutes: 300 acceptance_criteria: "Every Auto Release and Release run carries an explicit trigger origin (native schedule, morning dispatcher, blocker retry, operator) from a declared input and its run name, never inferred from event or actor; Release reliability reports a separate series per origin, including the dispatcher's attempts, failures and failing stages, while the native scheduled denominator stays unchanged as decided on pm-9url9h; The same-day manual follow-up of pm-uenmu9 requires an explicit follow-up request from the operator origin; negative control: a dispatcher-origin run after a same-day tag exists skips before any version mutation; The 2026-09-28 dispatcher failure is visible in the new series or recorded as an explicit pre-attribution gap" @@ -24,7 +24,7 @@ dependencies[6]{id,kind,created_at,author,source_kind,author_source}: pm-z329kd,discovered_from,"2026-09-28T15:41:04.958Z","harness:claude-code","cli:update:dep",detected pm-uenmu9,discovered_from,"2026-09-29T09:47:31.174Z","harness:codex","cli:update:dep",detected pm-0trehk,related,"2026-10-24T16:33:36.972Z","harness:codex","cli:update:dep",detected -comments[78]{created_at,author,text}: +comments[79]{created_at,author,text}: "2026-09-29T10:00:31.279Z","harness:codex","Implemented declared Auto Release origin in workflow run names and attempt receipts; morning dispatcher now passes its own origin. Reliability collection includes schedule, dispatch, and issue runs while keeping the native scheduled policy denominator intact; the dispatcher has a separate count, failure rate, stage series, and historical unattributed-run gap. New same-day dispatcher runs take the early immutable-tag guard. Release exact-tag dispatch carries origin; tag-push runs retain tag_push provenance. Linked tests passed (72), full coverage passed 9,428 tests at 100/100/100/100, and packed npm/Bun manual acceptance passed. Remaining acceptance: per-origin reliability series for operator and blocker retry, and upstream origin propagation into tag-push Release runs; operator-only ordinal follow-up remains owned by pm-uenmu9. No hosted release run or live new-origin receipt has yet been observed." "2026-09-29T10:28:52.881Z","harness:codex",PR #1350 review found the new origin-bearing Release run name no longer matched exact-tag recovery selection. Added exact declared-origin run-name matching with wrong-tag and unknown-origin negative controls; focused selector tests pass. Greptile discussion #4132270479. "2026-09-29T12:22:02.811Z","harness:codex","PR #1350 CodeRabbit discussion #4133333546 identified that dispatcher observations used the native 02:35 UTC cron for nominal occurrence and dispatch delay. Dispatcher rows now omit those schedule-specific timing fields, retain queue delay/outcome/failure stage, and focused negative controls prove native scheduled rows still keep their timing. Documentation states the boundary." @@ -103,6 +103,7 @@ comments[78]{created_at,author,text}: "2026-10-25T23:59:33.191Z","harness:codex","Live Release Reliability40244323743 complete artifacts retain only dispatch_window for the release series; release-ledger reconciliation passes. Native and morning automatic publication remain independently distinct from the historical dispatch-timing finding. Existing currentUTC-day v2026.10.25 is sole published tag and npm version; read-only installed dispatcher check returns dispatch_already_attempted without sending a request or changing daily markers. The user timer is active for04:45Europe/Vienna. No extra release or policy relaxation is performed by the SDK integrity work." "2026-10-26T22:08:14.067Z","harness:codex","Live 2026-10-26 reliability artifact40404782722 inspected independently of candidate CI: release series has30 original completed attempts,3 original failures and only dispatch_window policy finding. Morning dispatcher series has21 attempts with12 publications and9 retained original failures. Public release2026.10.26 passes the shared verifier including npm/npx/bunx; exactly one currentUTC-day tag is published. Native cron02:35UTC, hosted concurrency and immutable-day guard remain configured. This evidence does not clear historical timing findings or claim a second automatic release. No release is dispatched by this continuation." "2026-10-27T22:23:17.370Z","harness:codex","Live October27 Release Reliability40592007740 has a complete census:30 completed original release attempts,3 original failures, and only dispatch_window violated. Latest native Auto Release40472638505 confirms immutable v2026.10.27 and npm publication before preparation, without a second cut. Five recent native schedule runs are successful. The independent release-ledger report is ok. Preserve original history and daily concurrency/day identity; no additional release dispatch or threshold change is performed by this SDK delivery." + "2026-10-28T19:51:07.895Z","harness:codex","October28 independent artifact40744854788: complete release outcome census and passing release-ledger report; rolling scheduled reliability still fails only dispatch_window. Current npm/latest and GitHub release are2026.10.28. Preserve the one-automatic-release-per-UTC-day guard; no extra release or threshold change is justified by this SDK batch." notes[3]{created_at,author,text}: "2026-09-29T10:00:32.043Z","harness:codex",A tag-push Release run currently knows only tag_push in its run name. Do not equate that with the upstream Auto Release trigger; completing the accepted provenance contract needs immutable upstream attribution through the tag or an explicitly dispatched Release workflow without duplicate publish runs. "2026-10-10T09:36:49.416Z","harness:codex","Additional owned-temporary native Git acceptance confirms that a missing legacy inventory throws ENOENT and malformed inventory JSON throws SyntaxError before publication; both probes restore their copied inventory. The real tracker and source policy are untouched. Publication admission has no inferred date cutoff, actor inference, external authentication fallback or automatically extended compatibility set. Local tag preparation remains readable context but requires a hosted producer before new hosted publication." diff --git a/.agents/pm/issues/pm-xq09zu.toon b/.agents/pm/issues/pm-xq09zu.toon index 7daaa105f6..881a7e0743 100644 --- a/.agents/pm/issues/pm-xq09zu.toon +++ b/.agents/pm/issues/pm-xq09zu.toon @@ -6,7 +6,7 @@ status: open priority: 2 tags: [] created_at: "2026-10-25T19:40:57.328Z" -updated_at: "2026-10-28T17:20:25.176Z" +updated_at: "2026-10-28T20:02:08.312Z" author: "harness:codex" estimated_minutes: 90 acceptance_criteria: Identify the producing automation and whether termination or ingestion explains each unmatched start; Reproduce any confirmed lifecycle defect with isolated positive and negative controls; Preserve sampling and distinguish intentional interruption from missing finalization without fabricating success @@ -17,7 +17,7 @@ expected_result: Identify why each of the four 2026.10.24 automation aggregate s actual_result: "Latest complete bounded installation audit through2026-10-27T11:27:56.303Z, from08:41:00Z:143starts/142finishes, exactly one unequal history group at09:23:31.637UTC, independently re-read. All seven native history-reader processes in the original closure audit exited0; actual causation remains unproven. Fresh11:23UTC history start/finish ingestion0.738039/0.601494seconds and Sentry pm history root27.091ms are visible; span attribute enrichment is unavailable. Required observability gate passes at5.51percent errors<=6 with zero missing codes or blocking Sentry issues. Client event/OTLP queues are empty; last broker snapshot has0ready/1unacknowledged message, so no global drainage claim. Earlier post-source10/9,82/81 checkpoints, older388/387 changelog window and original four2026.10.24 starts remain separate unresolved observations. No synthetic terminal event or lifecycle repair." dependencies[1]{id,kind,created_at,author,source_kind,author_source}: pm-wrdctq,related,"2026-10-25T20:35:11.340Z","harness:codex","cli:update:dep",detected -comments[17]{created_at,author,text}: +comments[18]{created_at,author,text}: "2026-10-25T19:40:57.328Z","harness:codex","Duplicate check: strict complete3115-item all-status corpus plus refreshed open/in_progress inventories and request-specific aggregate telemetry pairing search; full live pm-5oj5 and closed paired-sampling lineage pm-wrdctq were read. No canonical owner matched this newly observed four-row cohort. Intake only and unclaimed." "2026-10-25T19:41:57.802Z","harness:codex","Refined source attribution: the four unmatched aggregate starts all report pm_version2026.10.24 and source_context automation. No current2026.10.25 mismatch is established by that cohort. Keep the intake open/unclaimed and retain termination or timeout as an unverified explanation rather than asserting ingestion loss." "2026-10-26T05:30:06.130Z","harness:codex","Fresh October26 live telemetry evidence extends this existing investigation: complete installation/session/command pairing since2026-10-25T23:39Z over producer2026.10.25/26 found1398 starts,1394 finishes and four settled unmatched starts. All four are producer2026.10.25 with source_context automation: aggregate at00:06:48Z, assurance at01:16:16Z, get at01:29:56Z and aggregate at03:17:42Z. Termination versus ingestion remains unverified; no2026.10.26 mismatch was established by this cohort. Keep the canonical investigation open and unclaimed. Forty command families show average ingestion1.229seconds; required seven-day error/code gate passes at5.22percent with zero missing failure codes. A fresh Sentry pm.command contracts span at05:26:14Z is visible, but streamed span detail is temporarily unavailable from the provider. This is operational evidence, not proof that every historical action has a finish." @@ -35,6 +35,7 @@ comments[17]{created_at,author,text}: "2026-10-28T15:41:10.734Z","harness:codex","October28 live evidence: required Sentry/telemetry gate reports zero blocking Sentry issues and zero missing-code rows, but seven-day finish error rate6.04percent exceeds unchanged6percent. Independent breakdown reports594304 finishes,35947 failures and6.03percent; most failures belong to existing command_failed/automation cohorts. Recent aggregate counts mostly pair with subsecond-to-two-second ingest lag; this is not per-invocation or historical completeness proof. Broker queue is empty and SDK flush drains local queue to zero bytes. Preserve the aggregate-rate failure separately from the context-read changes and prior unmatched-start investigation." "2026-10-28T16:25:11.915Z","harness:codex","Review correction: the independently quoted counts 35,947 / 594,304 equal 6.0486%, rounded 6.05%; the previous 6.03% label was incorrect. This correction does not change the separately sampled 6.04% gate verdict or its unchanged 6% threshold. The aggregate issue remains open." "2026-10-28T17:20:25.175Z","harness:codex","Post-change delivery probe at 2026-10-28 17:19 UTC: context command_start and successful command_finish were both persisted independently in the remote telemetry database with 0.855s and 0.709s ingestion lag. SDK flush completed and the remote queue had zero ready/unacknowledged messages. These current delivery facts do not clear the separately reported aggregate error-rate and historical pairing limitations." + "2026-10-28T20:02:08.311Z","harness:codex","Current live required-mode Sentry/telemetry gate passes: no blocking Sentry issues; rolling weighted telemetry finish error rate5.94% against unchanged6% threshold; zero failures missing error codes. A new pm.command context span is visible. A separate10-minute context sample has6 paired sessions and1 unmatched session, with maximum observed ingestion lag4.144seconds. This passing threshold does not resolve historical pairing debt or certify every action." files[1]{path,scope}: tests/unit/core/telemetry/telemetry-worker-lifecycle.spec.ts,project body: "" diff --git a/docs/SDK.md b/docs/SDK.md index c6dee56362..443c31cae4 100644 --- a/docs/SDK.md +++ b/docs/SDK.md @@ -1649,6 +1649,67 @@ the same durable coordinator, restoring annotations, linked artifacts, lifecycle fields, and claim ownership on failure. It is the SDK primitive behind `pm item complete`. +Host-bound batch and recovery APIs are tracked by +[pm-gh1598](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/features/pm-gh1598.toon) and +[pm-gh1597](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/features/pm-gh1597.toon) +(tracker records excluded from npm). A `PmClient` acquired from an +extension host supports the same batch coordinator without reconstructing its +tracker root or overriding the host author policy: + +```ts +const plan = { transactionId: "sync-42", mutations }; +const preview = await client.previewItemMutations(plan); +await client.commitItemMutations(plan); +const receipt = await client.itemTransactions.status("sync-42"); +``` + +Each mutation in a newly staged batch contributes a `records` row with its +original `index`, canonical `id`, operation, and full public `item` projection +including body after the complete batch. Repeated targets therefore show the +same final staged state. `execution` distinguishes a newly `applied` mutation +from `adopted` existing state; adopted values do not certify the unused create +options. `commit_time_fields` lists JSON pointers to potentially +regenerated clocks, conservatively including existing or explicitly supplied +clocks. These preview values are observations, not reserved commit values. +Compare normalized intent separately from those clocks; commit still evaluates +current state, attribution, extension policy and concurrency. A committed replay returns an empty +`records` array, not a reconstruction of its original write values. Replaying +the identical committed plan performs no item write; changing its ordered +payload under the same id refuses with `transaction_plan_mismatch`. + +New item journals retain their original mutation plan and compensation policy. +The status receipt contains the validated journal and a SHA-256 `planDigest` +over its ordered payload-bound step identifiers. Started/completed lists report +persisted coordinator progress: a crash after apply but before recording can +leave an applied step listed only as started. Recovery re-inspects durable item +history before compensation. No retained journal returns `undefined`; corrupt +journals refuse instead of appearing absent. + +```ts +await client.itemTransactions.supersede("interrupted-sync", "sync-43", { + reason: "Re-plan against the current item revision", +}); +// Read current items and build the replacement only after retirement succeeds. +await client.commitItemMutations({ transactionId: "sync-43", mutations: replanned }); +``` + +`abandon(id, { reason })` durably fences forward replay before compensating +interrupted owned effects in reverse order, +records a workspace audit event, and marks the identity `abandoned`. Retirement +upgrades the journal to schema version 2 so older coordinators refuse the pending +intent instead of silently resuming it. +`supersede(id, newId, { reason })` performs that retirement and records the +replacement identity; it does not atomically commit the replacement plan or +reserve its id. Repeating the same retirement is idempotent. Committed journals +cannot be abandoned. A later peer edit refuses with +`transaction_partial_mutation` and retains recovery data; it is never silently +overwritten. Legacy journals without a retained item plan require the original +plan and adapter for replay. Abandoned receipts remain retained by transaction +GC, including pending retirement intents, so their identities cannot silently +become reusable. Mutation inputs are copied before coordinator admission; later +caller edits cannot change the payload whose identity and recovery plan were +recorded. + `previewItemMutations` validates an ordered plan with the same transaction coordinator and lifecycle primitives as apply, using a disposable copy of the tracker. Earlier staged creates, evidence updates and closures participate in diff --git a/docs/generated/REFUSAL_CLOSURE_CENSUS.md b/docs/generated/REFUSAL_CLOSURE_CENSUS.md index e424fee8c5..1af174dc0d 100644 --- a/docs/generated/REFUSAL_CLOSURE_CENSUS.md +++ b/docs/generated/REFUSAL_CLOSURE_CENSUS.md @@ -4,12 +4,12 @@ Tracker: `pm-f05lsg`. Every catalog code is listed. An `uncovered` row is an explicit closure obligation, never an omission or implied approval. -- Catalog error codes: 431 +- Catalog error codes: 434 - Executable error codes: 19 - Executable-code ratchet floor: 18 - Required executable canonical codes: `bulk_ids_input_empty`, `bulk_ids_input_missing_path`, `bulk_ids_input_unreadable`, `invalid_argument_value`, `manifest_unknown_key`, `missing_lifecycle_target`, `missing_required_argument`, `no_version_bounds_declared`, `projection_options_mutually_exclusive`, `tracker_not_initialized`, `tracker_root_missing`, `tracker_root_not_directory`, `tracker_root_unreadable`, `unknown_context_intent`, `unknown_field_projection`, `unknown_option`, `unknown_subcommand` -- Uncovered error codes: 412 -- Coverage fraction: 0.044084 +- Uncovered error codes: 415 +- Coverage fraction: 0.043779 - Closed-domain probes: 19 - Grammar probes: 117 @@ -349,6 +349,8 @@ Every catalog code is listed. An `uncovered` row is an explicit closure obligati | `tracker_root_missing` | `tracker_root_missing` | executable | owned_state | 1 | | `tracker_root_not_directory` | `tracker_root_not_directory` | executable | owned_state | 1 | | `tracker_root_unreadable` | `tracker_root_unreadable` | executable | owned_state | 1 | +| `transaction_abandoned` | `transaction_abandoned` | uncovered | none | 0 | +| `transaction_committed` | `transaction_committed` | uncovered | none | 0 | | `transaction_create_compensated` | `transaction_create_compensated` | uncovered | none | 0 | | `transaction_journal_invalid` | `transaction_journal_invalid` | uncovered | none | 0 | | `transaction_partial_mutation` | `transaction_partial_mutation` | uncovered | none | 0 | @@ -356,6 +358,7 @@ Every catalog code is listed. An `uncovered` row is an explicit closure obligati | `transaction_preview_external_schema` | `transaction_preview_external_schema` | uncovered | none | 0 | | `transaction_preview_non_regular_file` | `transaction_preview_non_regular_file` | uncovered | none | 0 | | `transaction_preview_snapshot_changed` | `transaction_preview_snapshot_changed` | uncovered | none | 0 | +| `transaction_recovery_plan_missing` | `transaction_recovery_plan_missing` | uncovered | none | 0 | | `type_duplicate` | `type_duplicate` | uncovered | none | 0 | | `type_invalid` | `type_invalid` | uncovered | none | 0 | | `undeclared_observation` | `undeclared_observation` | uncovered | none | 0 | diff --git a/sdk/public-surface.json b/sdk/public-surface.json index 6f74dda309..b6a914ed9e 100644 --- a/sdk/public-surface.json +++ b/sdk/public-surface.json @@ -2857,6 +2857,28 @@ ], "package_version": "2026.10.28", "reason": "pm-gh1603: additive optional column_order metadata preserves omitted null column positions; existing table decoders and default encodings remain compatible." + }, + { + "changes": [ + "signature ./sdk:CommitWorkspaceTransactionOptions", + "signature ./sdk:ItemMutationPreviewValidation", + "signature ./sdk:PM_HISTORY_OPERATION_CONTRACT", + "signature ./sdk:PM_WORKSPACE_HISTORY_OPERATIONS", + "signature ./sdk:PmClient", + "signature ./sdk/contracts:PM_HISTORY_OPERATION_CONTRACT", + "signature ./sdk/contracts:PM_WORKSPACE_HISTORY_OPERATIONS", + "signature ./sdk/core:PmClient", + "signature ./sdk/runtime:PmClient" + ], + "package_version": "2026.10.28", + "reason": "Add host-bound transaction methods, staged preview records, recovery data and retirement receipts without removing existing calls; callers constructing preview receipt mocks must supply records." + }, + { + "changes": [ + "signature ./sdk:WorkspaceTransactionJournal" + ], + "package_version": "2026.10.28", + "reason": "Host-bound batch and recovery additions retain existing calls; preview receipt constructors must supply records, and journal readers must recognize version 2 retirement fences." } ], "entrypoints": { @@ -2971,6 +2993,30 @@ "name": "_testOnlyWorkspacePosition", "signature": "{ commandForWorkspacePositionState: typeof commandForWorkspacePositionState; normalizeWorkspaceHistoryDrift: typeof normalizeWorkspaceHistoryDrift; selectWorkspacePositionState: typeof selectWorkspacePositionState; }" }, + { + "classification": "advanced_export", + "kind": "function", + "name": "abandonItemTransaction", + "signature": "(options: AbandonItemTransactionOptions) => Promise | calls: (options: AbandonItemTransactionOptions) => Promise" + }, + { + "classification": "advanced_export", + "kind": "type", + "name": "AbandonItemTransactionOptions", + "signature": "export type AbandonItemTransactionOptions = Omit;" + }, + { + "classification": "advanced_export", + "kind": "function", + "name": "abandonWorkspaceTransaction", + "signature": "(options: AbandonWorkspaceTransactionOptions) => Promise | calls: (options: AbandonWorkspaceTransactionOptions) => Promise" + }, + { + "classification": "advanced_export", + "kind": "interface", + "name": "AbandonWorkspaceTransactionOptions", + "signature": "export interface AbandonWorkspaceTransactionOptions extends Omit { reason: string; supersededBy?: string; resolveSteps(journal: WorkspaceTransactionJournal): readonly WorkspaceTransactionStep[]; }" + }, { "classification": "supported", "kind": "function", @@ -5531,7 +5577,7 @@ "classification": "advanced_export", "kind": "interface", "name": "CommitWorkspaceTransactionOptions", - "signature": "export interface CommitWorkspaceTransactionOptions { pmRoot: string; transactionId: string; author: string; steps: readonly WorkspaceTransactionStep[]; lockTtlSeconds?: number; lockWaitMs?: number; onTransition?(context: WorkspaceTransactionTransitionContext): void | Promise; }" + "signature": "export interface CommitWorkspaceTransactionOptions { pmRoot: string; transactionId: string; author: string; steps: readonly WorkspaceTransactionStep[]; recoveryData?: WorkspaceTransactionJsonValue; lockTtlSeconds?: number; lockWaitMs?: number; onTransition?(context: WorkspaceTransactionTransitionContext): void | Promise; }" }, { "classification": "advanced_export", @@ -10781,7 +10827,13 @@ "classification": "advanced_export", "kind": "interface", "name": "ItemMutationPreviewValidation", - "signature": "export interface ItemMutationPreviewValidation { validated: boolean; state: \"staged_snapshot\" | \"replayed_committed_plan\"; unresolved_commit_constraints: readonly string[]; warnings: { index: number; id: string; op: \"create\"; warnings: readonly string[]; }[]; }" + "signature": "export interface ItemMutationPreviewValidation { records: ItemMutationStagedRecord[]; validated: boolean; state: \"staged_snapshot\" | \"replayed_committed_plan\"; unresolved_commit_constraints: readonly string[]; warnings: { index: number; id: string; op: \"create\"; warnings: readonly string[]; }[]; }" + }, + { + "classification": "advanced_export", + "kind": "interface", + "name": "ItemMutationStagedRecord", + "signature": "export interface ItemMutationStagedRecord { index: number; id: string; op: BulkItemMutation[\"op\"]; execution: \"applied\" | \"adopted\"; item: GetResult[\"item\"]; commit_time_fields: string[]; }" }, { "classification": "advanced_export", @@ -10825,6 +10877,12 @@ "name": "ItemStatus", "signature": "export type ItemStatus = string;" }, + { + "classification": "advanced_export", + "kind": "interface", + "name": "ItemTransactionStatus", + "signature": "export interface ItemTransactionStatus { journal: WorkspaceTransactionJournal; planDigest: string; }" + }, { "classification": "supported", "kind": "type", @@ -13397,7 +13455,7 @@ "classification": "contract_data", "kind": "value", "name": "PM_HISTORY_OPERATION_CONTRACT", - "signature": "{ readonly version: 1; readonly item: readonly [\"append\", \"cancel\", \"claim\", \"close\", \"comment_add\", \"comment_edit\", \"comment_delete\", \"create\", \"delete\", \"docs_add\", \"docs_remove\", \"files_add\", \"files_remove\", \"files_discover\", \"history_author_acknowledge\", \"history_compact\", \"history_compact_baseline\", \"history_redact\", \"history_repair\", \"history_salvage\", \"import\", \"improvement_observe\", \"learning_add\", \"learning_edit\", \"learning_delete\", \"normalize\", \"note_add\", \"note_edit\", \"note_delete\", \"plan_create_metadata\", \"plan_create_initial_step\", \"plan_add_step\", \"plan_reorder_step\", \"plan_remove_step\", \"plan_link_step\", \"plan_unlink_step\", \"plan_append_decision\", \"plan_append_discovery\", \"plan_append_validation\", \"plan_resume\", \"plan_approve\", \"plan_materialize\", \"plan_update_step\", \"plan_complete_step\", \"plan_block_step\", \"policy_approve\", \"policy_refused\", \"release\", \"reopen\", \"restore\", \"schema_migration\", \"schema_migration_reference\", \"test_run_track\", \"tests_add\", \"tests_remove\", \"tests_update\", \"update\", \"update_audit\", \"update_ownership_bypass\", \"workspace_snapshot_restore\", \"extension_migrations_apply\", \"merge_reconcile\"]; readonly workspace: readonly [\"history:author-acknowledge\", \"settings:write\", \"init:type_preset\", \"templates:save\", \"profile:apply-types\", \"profile:apply-statuses\", \"profile:apply-fields\", \"profile:apply-config\", \"schema:add-type\", \"schema:remove-type\", \"schema:add-status\", \"schema:remove-status\", \"schema:add-field\", \"schema:remove-field\", \"schema:apply-preset\", \"schema:infer-types\", \"schema:policy-put\", \"schema:policy-remove\", \"schema:policy-mode\", \"assurance:bundle:apply\", \"assurance:gate:verdict\", \"telemetry:install_id\", \"telemetry:first_run_prompt\", \"telemetry:clear\", \"item_format:auto_select_default\"]; readonly aliases: Readonly>; readonly patterns: readonly [\"^config:(?:set|unset):[a-z][a-z0-9_.:-]*$\", \"^assurance:(?:measurement|invariant|gate):(?:put|remove)$\", \"^schema_(?:rename_type|rename_status|remap_status|rename_field|remove_type|remove_status|remove_field)(?:_compensate)?$\", \"^extension:[a-z][a-z0-9_-]*:[a-z][a-z0-9_]*$\"]; readonly read_policy: \"preserve_original_operation\"; readonly custom_operation_grammar: \"extension::\"; readonly legacy_custom_operation_grammar: \"lowercase segments separated by underscore, hyphen, colon, or dot; optional opaque colon-suffixed retry key\"; readonly excluded_surfaces: readonly [\"json_patch\", \"on_write_hook\", \"telemetry_span\"]; }" + "signature": "{ readonly version: 1; readonly item: readonly [\"append\", \"cancel\", \"claim\", \"close\", \"comment_add\", \"comment_edit\", \"comment_delete\", \"create\", \"delete\", \"docs_add\", \"docs_remove\", \"files_add\", \"files_remove\", \"files_discover\", \"history_author_acknowledge\", \"history_compact\", \"history_compact_baseline\", \"history_redact\", \"history_repair\", \"history_salvage\", \"import\", \"improvement_observe\", \"learning_add\", \"learning_edit\", \"learning_delete\", \"normalize\", \"note_add\", \"note_edit\", \"note_delete\", \"plan_create_metadata\", \"plan_create_initial_step\", \"plan_add_step\", \"plan_reorder_step\", \"plan_remove_step\", \"plan_link_step\", \"plan_unlink_step\", \"plan_append_decision\", \"plan_append_discovery\", \"plan_append_validation\", \"plan_resume\", \"plan_approve\", \"plan_materialize\", \"plan_update_step\", \"plan_complete_step\", \"plan_block_step\", \"policy_approve\", \"policy_refused\", \"release\", \"reopen\", \"restore\", \"schema_migration\", \"schema_migration_reference\", \"test_run_track\", \"tests_add\", \"tests_remove\", \"tests_update\", \"update\", \"update_audit\", \"update_ownership_bypass\", \"workspace_snapshot_restore\", \"extension_migrations_apply\", \"merge_reconcile\"]; readonly workspace: readonly [\"history:author-acknowledge\", \"settings:write\", \"init:type_preset\", \"templates:save\", \"profile:apply-types\", \"profile:apply-statuses\", \"profile:apply-fields\", \"profile:apply-config\", \"schema:add-type\", \"schema:remove-type\", \"schema:add-status\", \"schema:remove-status\", \"schema:add-field\", \"schema:remove-field\", \"schema:apply-preset\", \"schema:infer-types\", \"schema:policy-put\", \"schema:policy-remove\", \"schema:policy-mode\", \"assurance:bundle:apply\", \"assurance:gate:verdict\", \"telemetry:install_id\", \"telemetry:first_run_prompt\", \"telemetry:clear\", \"item_format:auto_select_default\", \"transaction_abandon\"]; readonly aliases: Readonly>; readonly patterns: readonly [\"^config:(?:set|unset):[a-z][a-z0-9_.:-]*$\", \"^assurance:(?:measurement|invariant|gate):(?:put|remove)$\", \"^schema_(?:rename_type|rename_status|remap_status|rename_field|remove_type|remove_status|remove_field)(?:_compensate)?$\", \"^extension:[a-z][a-z0-9_-]*:[a-z][a-z0-9_]*$\"]; readonly read_policy: \"preserve_original_operation\"; readonly custom_operation_grammar: \"extension::\"; readonly legacy_custom_operation_grammar: \"lowercase segments separated by underscore, hyphen, colon, or dot; optional opaque colon-suffixed retry key\"; readonly excluded_surfaces: readonly [\"json_patch\", \"on_write_hook\", \"telemetry_span\"]; }" }, { "classification": "contract_data", @@ -13811,7 +13869,7 @@ "classification": "contract_data", "kind": "value", "name": "PM_WORKSPACE_HISTORY_OPERATIONS", - "signature": "readonly [\"history:author-acknowledge\", \"settings:write\", \"init:type_preset\", \"templates:save\", \"profile:apply-types\", \"profile:apply-statuses\", \"profile:apply-fields\", \"profile:apply-config\", \"schema:add-type\", \"schema:remove-type\", \"schema:add-status\", \"schema:remove-status\", \"schema:add-field\", \"schema:remove-field\", \"schema:apply-preset\", \"schema:infer-types\", \"schema:policy-put\", \"schema:policy-remove\", \"schema:policy-mode\", \"assurance:bundle:apply\", \"assurance:gate:verdict\", \"telemetry:install_id\", \"telemetry:first_run_prompt\", \"telemetry:clear\", \"item_format:auto_select_default\"]" + "signature": "readonly [\"history:author-acknowledge\", \"settings:write\", \"init:type_preset\", \"templates:save\", \"profile:apply-types\", \"profile:apply-statuses\", \"profile:apply-fields\", \"profile:apply-config\", \"schema:add-type\", \"schema:remove-type\", \"schema:add-status\", \"schema:remove-status\", \"schema:add-field\", \"schema:remove-field\", \"schema:apply-preset\", \"schema:infer-types\", \"schema:policy-put\", \"schema:policy-remove\", \"schema:policy-mode\", \"assurance:bundle:apply\", \"assurance:gate:verdict\", \"telemetry:install_id\", \"telemetry:first_run_prompt\", \"telemetry:clear\", \"item_format:auto_select_default\", \"transaction_abandon\"]" }, { "classification": "advanced_export", @@ -13907,7 +13965,7 @@ "classification": "supported", "kind": "class", "name": "PmClient", - "signature": "export declare class PmClient { private readonly defaults; constructor(options?: PmClientOptions); static forActiveExtensionHost(options: PmClientOptions): PmClient; run(action: PmActionName, args?: PmClientRunArgs): Promise; private runTyped; context = InitialReadOptions>(options?: Options): ReadPromise; listAllItemMetadataLight(): Promise; list = InitialReadOptions>(options?: Options): ReadPromise; listAllComplete(options?: PmCompleteListOptions): Promise; search = InitialReadOptions>(query: string, options?: Options): ReadPromise; get = GetOptions>(id: string, options?: Options): ReadPromise; next = NextOptions>(options?: Options): ReadPromise; aggregate = AggregateOptions>(options?: Options): ReadPromise; stats = StatsCommandOptions>(options?: Options): ReadPromise; duplicates = DuplicatesCommandOptions>(options?: Options): ReadPromise; comments = CommentsCommandOptions>(id: string, options?: Options): ReadPromise; notes = NotesCommandOptions>(id: string, options?: Options): ReadPromise; learnings(id: string, options?: LearningsCommandOptions): Promise; files = FilesCommandOptions>(id: string, options?: Options): ReadPromise; filesDiscover(id: string, options?: FilesDiscoverOptions): Promise; filesLookup(options: FilesLookupOptions): Promise; docs = DocsCommandOptions>(id: string, options?: Options): ReadPromise; deps = DepsCommandOptions>(id: string, options?: Options): ReadPromise; graph = GraphCommandOptions>(subcommand: GraphSubcommand, ids?: { id?: string; target?: string; }, options?: Options): ReadPromise; append(id: string, body: string, options?: PmClientFullMutationOptions): Promise; init(prefix?: string, options?: InitCommandOptions): Promise; config(scope: string, configAction: string, key?: string, value?: string, options?: ConfigCommandOptions): Promise; schema(subcommand: SchemaSubcommand, options?: PmActionOptions): Promise; workflowPolicy(action: WorkflowPolicyAction, name?: string, options?: WorkflowPolicyActionOptions): Promise; schemaList(): Promise; schemaShow(name: string): Promise; schemaAddType(name: string, options?: SchemaAddTypeCommandOptions): Promise; schemaRemoveType(name: string, options?: SchemaRemoveTypeCommandOptions): Promise; schemaAddStatus(name: string, options?: SchemaAddStatusCommandOptions): Promise; schemaRemoveStatus(name: string, options?: SchemaRemoveStatusCommandOptions): Promise; schemaAddField(name: string, options?: SchemaAddFieldCommandOptions): Promise; schemaRemoveField(name: string, options?: SchemaRemoveFieldCommandOptions): Promise; schemaListFields(): Promise; schemaShowField(name: string): Promise; schemaApplyPreset(typePreset: string, options?: SchemaApplyPresetCommandOptions): Promise; schemaInferTypes(options?: SchemaAddTypeInferCommandOptions): Promise; schemaRenameType(from: string, to: string, options: RunSchemaEvolutionMigrationOptions): Promise; schemaRenameField(from: string, to: string, options: RunSchemaEvolutionMigrationOptions, type?: string): Promise; schemaRemapStatus(from: string, to: string, options: RunSchemaEvolutionMigrationOptions): Promise; schemaShowStatus(name: string): Promise; profile(subcommand: ProfileSubcommand, options?: PmActionOptions): Promise; profileList(): Promise; profileShow(name: string): Promise; profileApply(name: string, options?: ProfileApplyCommandOptions): Promise; profileLint(name: string): Promise; validate & { counts: true; }>(options: Options): ReadPromise; validate & { counts?: false; } = ValidateCommandOptions & { counts?: false; }>(options?: Options): ReadPromise; validate>(options: Options): ReadPromise; health = RunHealthOptions>(options?: Options): ReadPromise; gc(options?: GcCommandOptions): Promise; assurance(input: AssuranceActionInput): Promise; historyRedact(id: string, options: HistoryRedactCommandOptions): Promise; historyRepair(id: string, options?: HistoryRepairCommandOptions): Promise; historyRepairAll(options?: HistoryRepairCommandOptions): Promise; historyAttest(options?: HistoryAttestCommandOptions): ReturnType; historyCompact(id: string, options?: HistoryCompactCommandOptions): Promise; historyCompactBulk(options: HistoryCompactBulkCommandOptions): Promise; historyAuthorAcknowledge(options: AcknowledgeUnknownAuthorEventsOptions): Promise; plan(subcommand: PlanSubcommand, id?: string, options?: PlanCommandOptions, stepRef?: string, reorderTo?: number): Promise; planCreate(options: PlanCommandOptions): Promise; planShow(id: string, options?: PlanCommandOptions): Promise; planAddStep(id: string, options: PlanCommandOptions): Promise; planUpdateStep(id: string, stepRef: string, options: PlanCommandOptions): Promise; planCompleteStep(id: string, stepRef: string, options?: PlanCommandOptions): Promise; planBlockStep(id: string, stepRef: string, options: PlanCommandOptions): Promise; planReorderStep(id: string, stepRef: string, reorderTo: number, options?: PlanCommandOptions): Promise; planRemoveStep(id: string, stepRef: string, options?: PlanCommandOptions): Promise; planLink(id: string, stepRef: string, options: PlanCommandOptions): Promise; planUnlink(id: string, stepRef: string, options: PlanCommandOptions): Promise; planDecision(id: string, options: PlanCommandOptions): Promise; planDiscovery(id: string, options: PlanCommandOptions): Promise; planValidation(id: string, options: PlanCommandOptions): Promise; planResume(id: string, options: PlanCommandOptions): Promise; planApprove(id: string, options?: PlanCommandOptions): Promise; planMaterialize(id: string, options: PlanCommandOptions): Promise; create(options?: PmCreateActionOptions): Promise; update(id: string, options?: PmUpdateActionOptions): Promise; reopen(id: string, reason: string, options?: ReopenCommandOptions): Promise; close(id: string, reason: string, options: PmClientCloseActionOptions & { releaseAssignment: true; }): Promise; close(id: string, reason: string, options?: PmClientCloseActionOptions & { releaseAssignment?: false; }): Promise; close(id: string, reason: string, options?: PmClientCloseActionOptions & { releaseAssignment?: boolean; }): Promise; claim(id: string, options: PmClientFullMutationOptions & { start: true; }): Promise; claim(id: string, options?: PmClientFullMutationOptions & { start?: false; }): Promise; claim(id: string, options?: PmClientFullMutationOptions & { start?: boolean; }): Promise; claimNext(options?: ClaimNextOptions): Promise; release(id: string, options: PmClientFullMutationOptions & ReleaseMutationOptions & { pause: true; }): Promise; release(id: string, options?: PmClientFullMutationOptions & ReleaseMutationOptions & { pause?: false; }): Promise; release(id: string, options?: PmClientFullMutationOptions & ReleaseMutationOptions & { pause?: boolean; }): Promise; copy(id: string, options?: PmClientFullMutationOptions): Promise; delete(id: string, options?: PmClientFullMutationOptions): Promise; restore(id: string, target: string, options?: PmClientFullMutationOptions): Promise; focus(id?: string, options?: PmClientFullMutationOptions): Promise; startTask(id: string, options?: PmClientFullMutationOptions): Promise; pauseTask(id: string, options?: PmClientFullMutationOptions): Promise; closeTask(id: string, reason: string, options?: PmClientFullMutationOptions): Promise; extension(target?: string, options?: ExtensionCommandOptions): Promise; extensionList(options?: ExtensionCommandOptions): Promise; extensionActivate(target: string, options?: ExtensionCommandOptions): Promise; extensionDeactivate(target: string, options?: ExtensionCommandOptions): Promise; package(target?: string, options?: PackageCommandOptions): Promise; packageList(options?: PackageCommandOptions): Promise; packageInstall(target: string, options?: PackageCommandOptions): Promise; packageUninstall(target: string, options?: PackageCommandOptions): Promise; packageDoctor(options?: PackageCommandOptions): Promise; packageManage(target?: string, options?: PackageCommandOptions): Promise; packageDescribe(target?: string, options?: PackageCommandOptions): Promise; packageReload(options?: PackageCommandOptions): Promise; packageCatalog = PackageCommandOptions>(options?: Options): ReadPromise; packageActivate(target: string, options?: PackageCommandOptions): Promise; packageDeactivate(target: string, options?: PackageCommandOptions): Promise; packageMigrate(options?: PackageCommandOptions): Promise; upgrade(target?: string, options?: UpgradeCommandOptions): Promise; }" + "signature": "export declare class PmClient { private readonly defaults; constructor(options?: PmClientOptions); static forActiveExtensionHost(options: PmClientOptions): PmClient; run(action: PmActionName, args?: PmClientRunArgs): Promise; private runTyped; private withItemTransactionContext; previewItemMutations(options: Pick): Promise; commitItemMutations(options: Omit): Promise; get itemTransactions(): { status: (transactionId: string) => Promise; abandon: (transactionId: string, options: Omit) => Promise; supersede: (transactionId: string, newId: string, options: Omit) => Promise; }; context = InitialReadOptions>(options?: Options): ReadPromise; listAllItemMetadataLight(): Promise; list = InitialReadOptions>(options?: Options): ReadPromise; listAllComplete(options?: PmCompleteListOptions): Promise; search = InitialReadOptions>(query: string, options?: Options): ReadPromise; get = GetOptions>(id: string, options?: Options): ReadPromise; next = NextOptions>(options?: Options): ReadPromise; aggregate = AggregateOptions>(options?: Options): ReadPromise; stats = StatsCommandOptions>(options?: Options): ReadPromise; duplicates = DuplicatesCommandOptions>(options?: Options): ReadPromise; comments = CommentsCommandOptions>(id: string, options?: Options): ReadPromise; notes = NotesCommandOptions>(id: string, options?: Options): ReadPromise; learnings(id: string, options?: LearningsCommandOptions): Promise; files = FilesCommandOptions>(id: string, options?: Options): ReadPromise; filesDiscover(id: string, options?: FilesDiscoverOptions): Promise; filesLookup(options: FilesLookupOptions): Promise; docs = DocsCommandOptions>(id: string, options?: Options): ReadPromise; deps = DepsCommandOptions>(id: string, options?: Options): ReadPromise; graph = GraphCommandOptions>(subcommand: GraphSubcommand, ids?: { id?: string; target?: string; }, options?: Options): ReadPromise; append(id: string, body: string, options?: PmClientFullMutationOptions): Promise; init(prefix?: string, options?: InitCommandOptions): Promise; config(scope: string, configAction: string, key?: string, value?: string, options?: ConfigCommandOptions): Promise; schema(subcommand: SchemaSubcommand, options?: PmActionOptions): Promise; workflowPolicy(action: WorkflowPolicyAction, name?: string, options?: WorkflowPolicyActionOptions): Promise; schemaList(): Promise; schemaShow(name: string): Promise; schemaAddType(name: string, options?: SchemaAddTypeCommandOptions): Promise; schemaRemoveType(name: string, options?: SchemaRemoveTypeCommandOptions): Promise; schemaAddStatus(name: string, options?: SchemaAddStatusCommandOptions): Promise; schemaRemoveStatus(name: string, options?: SchemaRemoveStatusCommandOptions): Promise; schemaAddField(name: string, options?: SchemaAddFieldCommandOptions): Promise; schemaRemoveField(name: string, options?: SchemaRemoveFieldCommandOptions): Promise; schemaListFields(): Promise; schemaShowField(name: string): Promise; schemaApplyPreset(typePreset: string, options?: SchemaApplyPresetCommandOptions): Promise; schemaInferTypes(options?: SchemaAddTypeInferCommandOptions): Promise; schemaRenameType(from: string, to: string, options: RunSchemaEvolutionMigrationOptions): Promise; schemaRenameField(from: string, to: string, options: RunSchemaEvolutionMigrationOptions, type?: string): Promise; schemaRemapStatus(from: string, to: string, options: RunSchemaEvolutionMigrationOptions): Promise; schemaShowStatus(name: string): Promise; profile(subcommand: ProfileSubcommand, options?: PmActionOptions): Promise; profileList(): Promise; profileShow(name: string): Promise; profileApply(name: string, options?: ProfileApplyCommandOptions): Promise; profileLint(name: string): Promise; validate & { counts: true; }>(options: Options): ReadPromise; validate & { counts?: false; } = ValidateCommandOptions & { counts?: false; }>(options?: Options): ReadPromise; validate>(options: Options): ReadPromise; health = RunHealthOptions>(options?: Options): ReadPromise; gc(options?: GcCommandOptions): Promise; assurance(input: AssuranceActionInput): Promise; historyRedact(id: string, options: HistoryRedactCommandOptions): Promise; historyRepair(id: string, options?: HistoryRepairCommandOptions): Promise; historyRepairAll(options?: HistoryRepairCommandOptions): Promise; historyAttest(options?: HistoryAttestCommandOptions): ReturnType; historyCompact(id: string, options?: HistoryCompactCommandOptions): Promise; historyCompactBulk(options: HistoryCompactBulkCommandOptions): Promise; historyAuthorAcknowledge(options: AcknowledgeUnknownAuthorEventsOptions): Promise; plan(subcommand: PlanSubcommand, id?: string, options?: PlanCommandOptions, stepRef?: string, reorderTo?: number): Promise; planCreate(options: PlanCommandOptions): Promise; planShow(id: string, options?: PlanCommandOptions): Promise; planAddStep(id: string, options: PlanCommandOptions): Promise; planUpdateStep(id: string, stepRef: string, options: PlanCommandOptions): Promise; planCompleteStep(id: string, stepRef: string, options?: PlanCommandOptions): Promise; planBlockStep(id: string, stepRef: string, options: PlanCommandOptions): Promise; planReorderStep(id: string, stepRef: string, reorderTo: number, options?: PlanCommandOptions): Promise; planRemoveStep(id: string, stepRef: string, options?: PlanCommandOptions): Promise; planLink(id: string, stepRef: string, options: PlanCommandOptions): Promise; planUnlink(id: string, stepRef: string, options: PlanCommandOptions): Promise; planDecision(id: string, options: PlanCommandOptions): Promise; planDiscovery(id: string, options: PlanCommandOptions): Promise; planValidation(id: string, options: PlanCommandOptions): Promise; planResume(id: string, options: PlanCommandOptions): Promise; planApprove(id: string, options?: PlanCommandOptions): Promise; planMaterialize(id: string, options: PlanCommandOptions): Promise; create(options?: PmCreateActionOptions): Promise; update(id: string, options?: PmUpdateActionOptions): Promise; reopen(id: string, reason: string, options?: ReopenCommandOptions): Promise; close(id: string, reason: string, options: PmClientCloseActionOptions & { releaseAssignment: true; }): Promise; close(id: string, reason: string, options?: PmClientCloseActionOptions & { releaseAssignment?: false; }): Promise; close(id: string, reason: string, options?: PmClientCloseActionOptions & { releaseAssignment?: boolean; }): Promise; claim(id: string, options: PmClientFullMutationOptions & { start: true; }): Promise; claim(id: string, options?: PmClientFullMutationOptions & { start?: false; }): Promise; claim(id: string, options?: PmClientFullMutationOptions & { start?: boolean; }): Promise; claimNext(options?: ClaimNextOptions): Promise; release(id: string, options: PmClientFullMutationOptions & ReleaseMutationOptions & { pause: true; }): Promise; release(id: string, options?: PmClientFullMutationOptions & ReleaseMutationOptions & { pause?: false; }): Promise; release(id: string, options?: PmClientFullMutationOptions & ReleaseMutationOptions & { pause?: boolean; }): Promise; copy(id: string, options?: PmClientFullMutationOptions): Promise; delete(id: string, options?: PmClientFullMutationOptions): Promise; restore(id: string, target: string, options?: PmClientFullMutationOptions): Promise; focus(id?: string, options?: PmClientFullMutationOptions): Promise; startTask(id: string, options?: PmClientFullMutationOptions): Promise; pauseTask(id: string, options?: PmClientFullMutationOptions): Promise; closeTask(id: string, reason: string, options?: PmClientFullMutationOptions): Promise; extension(target?: string, options?: ExtensionCommandOptions): Promise; extensionList(options?: ExtensionCommandOptions): Promise; extensionActivate(target: string, options?: ExtensionCommandOptions): Promise; extensionDeactivate(target: string, options?: ExtensionCommandOptions): Promise; package(target?: string, options?: PackageCommandOptions): Promise; packageList(options?: PackageCommandOptions): Promise; packageInstall(target: string, options?: PackageCommandOptions): Promise; packageUninstall(target: string, options?: PackageCommandOptions): Promise; packageDoctor(options?: PackageCommandOptions): Promise; packageManage(target?: string, options?: PackageCommandOptions): Promise; packageDescribe(target?: string, options?: PackageCommandOptions): Promise; packageReload(options?: PackageCommandOptions): Promise; packageCatalog = PackageCommandOptions>(options?: Options): ReadPromise; packageActivate(target: string, options?: PackageCommandOptions): Promise; packageDeactivate(target: string, options?: PackageCommandOptions): Promise; packageMigrate(options?: PackageCommandOptions): Promise; upgrade(target?: string, options?: UpgradeCommandOptions): Promise; }" }, { "classification": "advanced_export", @@ -15991,6 +16049,12 @@ "name": "readItemMetadataDerivedIndexState", "signature": "(pmRoot: string, folders?: readonly string[]) => Promise | calls: (pmRoot: string, folders?: readonly string[]) => Promise" }, + { + "classification": "advanced_export", + "kind": "function", + "name": "readItemTransaction", + "signature": "(pmRoot: string, transactionId: string) => Promise | calls: (pmRoot: string, transactionId: string) => Promise" + }, { "classification": "advanced_export", "kind": "function", @@ -16159,6 +16223,12 @@ "name": "readWorkspacePosition", "signature": "(global: GlobalOptions) => Promise | calls: (global: GlobalOptions) => Promise" }, + { + "classification": "advanced_export", + "kind": "function", + "name": "readWorkspaceTransaction", + "signature": "(pmRoot: string, transactionId: string) => Promise | calls: (pmRoot: string, transactionId: string) => Promise" + }, { "classification": "advanced_export", "kind": "function", @@ -22015,12 +22085,30 @@ "name": "WorkspaceTransactionInterruptedError", "signature": "export declare class WorkspaceTransactionInterruptedError extends Error { constructor(message?: string); }" }, + { + "classification": "advanced_export", + "kind": "interface", + "name": "WorkspaceTransactionJournal", + "signature": "export interface WorkspaceTransactionJournal { schemaVersion: 1 | 2; transactionId: string; author: string; status: WorkspaceTransactionJournalStatus; attempt: number; createdAt: string; updatedAt: string; stepIds: string[]; startedStepIds: string[]; completedStepIds: string[]; results: Record; compensationData: Record; recoveryData?: WorkspaceTransactionJsonValue; abandonment?: { reason: string; author: string; supersededBy?: string; }; }" + }, + { + "classification": "advanced_export", + "kind": "type", + "name": "WorkspaceTransactionJournalStatus", + "signature": "export type WorkspaceTransactionJournalStatus = \"applying\" | \"compensating\" | \"compensated\" | \"committed\" | \"abandoned\";" + }, { "classification": "advanced_export", "kind": "type", "name": "WorkspaceTransactionJsonValue", "signature": "export type WorkspaceTransactionJsonValue = null | boolean | number | string | WorkspaceTransactionJsonValue[] | { [key: string]: WorkspaceTransactionJsonValue; };" }, + { + "classification": "advanced_export", + "kind": "function", + "name": "workspaceTransactionPlanDigest", + "signature": "(journal: Pick) => string | calls: (journal: Pick) => string" + }, { "classification": "advanced_export", "kind": "interface", @@ -24611,7 +24699,7 @@ "classification": "contract_data", "kind": "value", "name": "PM_HISTORY_OPERATION_CONTRACT", - "signature": "{ readonly version: 1; readonly item: readonly [\"append\", \"cancel\", \"claim\", \"close\", \"comment_add\", \"comment_edit\", \"comment_delete\", \"create\", \"delete\", \"docs_add\", \"docs_remove\", \"files_add\", \"files_remove\", \"files_discover\", \"history_author_acknowledge\", \"history_compact\", \"history_compact_baseline\", \"history_redact\", \"history_repair\", \"history_salvage\", \"import\", \"improvement_observe\", \"learning_add\", \"learning_edit\", \"learning_delete\", \"normalize\", \"note_add\", \"note_edit\", \"note_delete\", \"plan_create_metadata\", \"plan_create_initial_step\", \"plan_add_step\", \"plan_reorder_step\", \"plan_remove_step\", \"plan_link_step\", \"plan_unlink_step\", \"plan_append_decision\", \"plan_append_discovery\", \"plan_append_validation\", \"plan_resume\", \"plan_approve\", \"plan_materialize\", \"plan_update_step\", \"plan_complete_step\", \"plan_block_step\", \"policy_approve\", \"policy_refused\", \"release\", \"reopen\", \"restore\", \"schema_migration\", \"schema_migration_reference\", \"test_run_track\", \"tests_add\", \"tests_remove\", \"tests_update\", \"update\", \"update_audit\", \"update_ownership_bypass\", \"workspace_snapshot_restore\", \"extension_migrations_apply\", \"merge_reconcile\"]; readonly workspace: readonly [\"history:author-acknowledge\", \"settings:write\", \"init:type_preset\", \"templates:save\", \"profile:apply-types\", \"profile:apply-statuses\", \"profile:apply-fields\", \"profile:apply-config\", \"schema:add-type\", \"schema:remove-type\", \"schema:add-status\", \"schema:remove-status\", \"schema:add-field\", \"schema:remove-field\", \"schema:apply-preset\", \"schema:infer-types\", \"schema:policy-put\", \"schema:policy-remove\", \"schema:policy-mode\", \"assurance:bundle:apply\", \"assurance:gate:verdict\", \"telemetry:install_id\", \"telemetry:first_run_prompt\", \"telemetry:clear\", \"item_format:auto_select_default\"]; readonly aliases: Readonly>; readonly patterns: readonly [\"^config:(?:set|unset):[a-z][a-z0-9_.:-]*$\", \"^assurance:(?:measurement|invariant|gate):(?:put|remove)$\", \"^schema_(?:rename_type|rename_status|remap_status|rename_field|remove_type|remove_status|remove_field)(?:_compensate)?$\", \"^extension:[a-z][a-z0-9_-]*:[a-z][a-z0-9_]*$\"]; readonly read_policy: \"preserve_original_operation\"; readonly custom_operation_grammar: \"extension::\"; readonly legacy_custom_operation_grammar: \"lowercase segments separated by underscore, hyphen, colon, or dot; optional opaque colon-suffixed retry key\"; readonly excluded_surfaces: readonly [\"json_patch\", \"on_write_hook\", \"telemetry_span\"]; }" + "signature": "{ readonly version: 1; readonly item: readonly [\"append\", \"cancel\", \"claim\", \"close\", \"comment_add\", \"comment_edit\", \"comment_delete\", \"create\", \"delete\", \"docs_add\", \"docs_remove\", \"files_add\", \"files_remove\", \"files_discover\", \"history_author_acknowledge\", \"history_compact\", \"history_compact_baseline\", \"history_redact\", \"history_repair\", \"history_salvage\", \"import\", \"improvement_observe\", \"learning_add\", \"learning_edit\", \"learning_delete\", \"normalize\", \"note_add\", \"note_edit\", \"note_delete\", \"plan_create_metadata\", \"plan_create_initial_step\", \"plan_add_step\", \"plan_reorder_step\", \"plan_remove_step\", \"plan_link_step\", \"plan_unlink_step\", \"plan_append_decision\", \"plan_append_discovery\", \"plan_append_validation\", \"plan_resume\", \"plan_approve\", \"plan_materialize\", \"plan_update_step\", \"plan_complete_step\", \"plan_block_step\", \"policy_approve\", \"policy_refused\", \"release\", \"reopen\", \"restore\", \"schema_migration\", \"schema_migration_reference\", \"test_run_track\", \"tests_add\", \"tests_remove\", \"tests_update\", \"update\", \"update_audit\", \"update_ownership_bypass\", \"workspace_snapshot_restore\", \"extension_migrations_apply\", \"merge_reconcile\"]; readonly workspace: readonly [\"history:author-acknowledge\", \"settings:write\", \"init:type_preset\", \"templates:save\", \"profile:apply-types\", \"profile:apply-statuses\", \"profile:apply-fields\", \"profile:apply-config\", \"schema:add-type\", \"schema:remove-type\", \"schema:add-status\", \"schema:remove-status\", \"schema:add-field\", \"schema:remove-field\", \"schema:apply-preset\", \"schema:infer-types\", \"schema:policy-put\", \"schema:policy-remove\", \"schema:policy-mode\", \"assurance:bundle:apply\", \"assurance:gate:verdict\", \"telemetry:install_id\", \"telemetry:first_run_prompt\", \"telemetry:clear\", \"item_format:auto_select_default\", \"transaction_abandon\"]; readonly aliases: Readonly>; readonly patterns: readonly [\"^config:(?:set|unset):[a-z][a-z0-9_.:-]*$\", \"^assurance:(?:measurement|invariant|gate):(?:put|remove)$\", \"^schema_(?:rename_type|rename_status|remap_status|rename_field|remove_type|remove_status|remove_field)(?:_compensate)?$\", \"^extension:[a-z][a-z0-9_-]*:[a-z][a-z0-9_]*$\"]; readonly read_policy: \"preserve_original_operation\"; readonly custom_operation_grammar: \"extension::\"; readonly legacy_custom_operation_grammar: \"lowercase segments separated by underscore, hyphen, colon, or dot; optional opaque colon-suffixed retry key\"; readonly excluded_surfaces: readonly [\"json_patch\", \"on_write_hook\", \"telemetry_span\"]; }" }, { "classification": "contract_data", @@ -24767,7 +24855,7 @@ "classification": "contract_data", "kind": "value", "name": "PM_WORKSPACE_HISTORY_OPERATIONS", - "signature": "readonly [\"history:author-acknowledge\", \"settings:write\", \"init:type_preset\", \"templates:save\", \"profile:apply-types\", \"profile:apply-statuses\", \"profile:apply-fields\", \"profile:apply-config\", \"schema:add-type\", \"schema:remove-type\", \"schema:add-status\", \"schema:remove-status\", \"schema:add-field\", \"schema:remove-field\", \"schema:apply-preset\", \"schema:infer-types\", \"schema:policy-put\", \"schema:policy-remove\", \"schema:policy-mode\", \"assurance:bundle:apply\", \"assurance:gate:verdict\", \"telemetry:install_id\", \"telemetry:first_run_prompt\", \"telemetry:clear\", \"item_format:auto_select_default\"]" + "signature": "readonly [\"history:author-acknowledge\", \"settings:write\", \"init:type_preset\", \"templates:save\", \"profile:apply-types\", \"profile:apply-statuses\", \"profile:apply-fields\", \"profile:apply-config\", \"schema:add-type\", \"schema:remove-type\", \"schema:add-status\", \"schema:remove-status\", \"schema:add-field\", \"schema:remove-field\", \"schema:apply-preset\", \"schema:infer-types\", \"schema:policy-put\", \"schema:policy-remove\", \"schema:policy-mode\", \"assurance:bundle:apply\", \"assurance:gate:verdict\", \"telemetry:install_id\", \"telemetry:first_run_prompt\", \"telemetry:clear\", \"item_format:auto_select_default\", \"transaction_abandon\"]" }, { "classification": "contract_data", @@ -26915,7 +27003,7 @@ "classification": "supported", "kind": "class", "name": "PmClient", - "signature": "export declare class PmClient { private readonly defaults; constructor(options?: PmClientOptions); static forActiveExtensionHost(options: PmClientOptions): PmClient; run(action: PmActionName, args?: PmClientRunArgs): Promise; private runTyped; context = InitialReadOptions>(options?: Options): ReadPromise; listAllItemMetadataLight(): Promise; list = InitialReadOptions>(options?: Options): ReadPromise; listAllComplete(options?: PmCompleteListOptions): Promise; search = InitialReadOptions>(query: string, options?: Options): ReadPromise; get = GetOptions>(id: string, options?: Options): ReadPromise; next = NextOptions>(options?: Options): ReadPromise; aggregate = AggregateOptions>(options?: Options): ReadPromise; stats = StatsCommandOptions>(options?: Options): ReadPromise; duplicates = DuplicatesCommandOptions>(options?: Options): ReadPromise; comments = CommentsCommandOptions>(id: string, options?: Options): ReadPromise; notes = NotesCommandOptions>(id: string, options?: Options): ReadPromise; learnings(id: string, options?: LearningsCommandOptions): Promise; files = FilesCommandOptions>(id: string, options?: Options): ReadPromise; filesDiscover(id: string, options?: FilesDiscoverOptions): Promise; filesLookup(options: FilesLookupOptions): Promise; docs = DocsCommandOptions>(id: string, options?: Options): ReadPromise; deps = DepsCommandOptions>(id: string, options?: Options): ReadPromise; graph = GraphCommandOptions>(subcommand: GraphSubcommand, ids?: { id?: string; target?: string; }, options?: Options): ReadPromise; append(id: string, body: string, options?: PmClientFullMutationOptions): Promise; init(prefix?: string, options?: InitCommandOptions): Promise; config(scope: string, configAction: string, key?: string, value?: string, options?: ConfigCommandOptions): Promise; schema(subcommand: SchemaSubcommand, options?: PmActionOptions): Promise; workflowPolicy(action: WorkflowPolicyAction, name?: string, options?: WorkflowPolicyActionOptions): Promise; schemaList(): Promise; schemaShow(name: string): Promise; schemaAddType(name: string, options?: SchemaAddTypeCommandOptions): Promise; schemaRemoveType(name: string, options?: SchemaRemoveTypeCommandOptions): Promise; schemaAddStatus(name: string, options?: SchemaAddStatusCommandOptions): Promise; schemaRemoveStatus(name: string, options?: SchemaRemoveStatusCommandOptions): Promise; schemaAddField(name: string, options?: SchemaAddFieldCommandOptions): Promise; schemaRemoveField(name: string, options?: SchemaRemoveFieldCommandOptions): Promise; schemaListFields(): Promise; schemaShowField(name: string): Promise; schemaApplyPreset(typePreset: string, options?: SchemaApplyPresetCommandOptions): Promise; schemaInferTypes(options?: SchemaAddTypeInferCommandOptions): Promise; schemaRenameType(from: string, to: string, options: RunSchemaEvolutionMigrationOptions): Promise; schemaRenameField(from: string, to: string, options: RunSchemaEvolutionMigrationOptions, type?: string): Promise; schemaRemapStatus(from: string, to: string, options: RunSchemaEvolutionMigrationOptions): Promise; schemaShowStatus(name: string): Promise; profile(subcommand: ProfileSubcommand, options?: PmActionOptions): Promise; profileList(): Promise; profileShow(name: string): Promise; profileApply(name: string, options?: ProfileApplyCommandOptions): Promise; profileLint(name: string): Promise; validate & { counts: true; }>(options: Options): ReadPromise; validate & { counts?: false; } = ValidateCommandOptions & { counts?: false; }>(options?: Options): ReadPromise; validate>(options: Options): ReadPromise; health = RunHealthOptions>(options?: Options): ReadPromise; gc(options?: GcCommandOptions): Promise; assurance(input: AssuranceActionInput): Promise; historyRedact(id: string, options: HistoryRedactCommandOptions): Promise; historyRepair(id: string, options?: HistoryRepairCommandOptions): Promise; historyRepairAll(options?: HistoryRepairCommandOptions): Promise; historyAttest(options?: HistoryAttestCommandOptions): ReturnType; historyCompact(id: string, options?: HistoryCompactCommandOptions): Promise; historyCompactBulk(options: HistoryCompactBulkCommandOptions): Promise; historyAuthorAcknowledge(options: AcknowledgeUnknownAuthorEventsOptions): Promise; plan(subcommand: PlanSubcommand, id?: string, options?: PlanCommandOptions, stepRef?: string, reorderTo?: number): Promise; planCreate(options: PlanCommandOptions): Promise; planShow(id: string, options?: PlanCommandOptions): Promise; planAddStep(id: string, options: PlanCommandOptions): Promise; planUpdateStep(id: string, stepRef: string, options: PlanCommandOptions): Promise; planCompleteStep(id: string, stepRef: string, options?: PlanCommandOptions): Promise; planBlockStep(id: string, stepRef: string, options: PlanCommandOptions): Promise; planReorderStep(id: string, stepRef: string, reorderTo: number, options?: PlanCommandOptions): Promise; planRemoveStep(id: string, stepRef: string, options?: PlanCommandOptions): Promise; planLink(id: string, stepRef: string, options: PlanCommandOptions): Promise; planUnlink(id: string, stepRef: string, options: PlanCommandOptions): Promise; planDecision(id: string, options: PlanCommandOptions): Promise; planDiscovery(id: string, options: PlanCommandOptions): Promise; planValidation(id: string, options: PlanCommandOptions): Promise; planResume(id: string, options: PlanCommandOptions): Promise; planApprove(id: string, options?: PlanCommandOptions): Promise; planMaterialize(id: string, options: PlanCommandOptions): Promise; create(options?: PmCreateActionOptions): Promise; update(id: string, options?: PmUpdateActionOptions): Promise; reopen(id: string, reason: string, options?: ReopenCommandOptions): Promise; close(id: string, reason: string, options: PmClientCloseActionOptions & { releaseAssignment: true; }): Promise; close(id: string, reason: string, options?: PmClientCloseActionOptions & { releaseAssignment?: false; }): Promise; close(id: string, reason: string, options?: PmClientCloseActionOptions & { releaseAssignment?: boolean; }): Promise; claim(id: string, options: PmClientFullMutationOptions & { start: true; }): Promise; claim(id: string, options?: PmClientFullMutationOptions & { start?: false; }): Promise; claim(id: string, options?: PmClientFullMutationOptions & { start?: boolean; }): Promise; claimNext(options?: ClaimNextOptions): Promise; release(id: string, options: PmClientFullMutationOptions & ReleaseMutationOptions & { pause: true; }): Promise; release(id: string, options?: PmClientFullMutationOptions & ReleaseMutationOptions & { pause?: false; }): Promise; release(id: string, options?: PmClientFullMutationOptions & ReleaseMutationOptions & { pause?: boolean; }): Promise; copy(id: string, options?: PmClientFullMutationOptions): Promise; delete(id: string, options?: PmClientFullMutationOptions): Promise; restore(id: string, target: string, options?: PmClientFullMutationOptions): Promise; focus(id?: string, options?: PmClientFullMutationOptions): Promise; startTask(id: string, options?: PmClientFullMutationOptions): Promise; pauseTask(id: string, options?: PmClientFullMutationOptions): Promise; closeTask(id: string, reason: string, options?: PmClientFullMutationOptions): Promise; extension(target?: string, options?: ExtensionCommandOptions): Promise; extensionList(options?: ExtensionCommandOptions): Promise; extensionActivate(target: string, options?: ExtensionCommandOptions): Promise; extensionDeactivate(target: string, options?: ExtensionCommandOptions): Promise; package(target?: string, options?: PackageCommandOptions): Promise; packageList(options?: PackageCommandOptions): Promise; packageInstall(target: string, options?: PackageCommandOptions): Promise; packageUninstall(target: string, options?: PackageCommandOptions): Promise; packageDoctor(options?: PackageCommandOptions): Promise; packageManage(target?: string, options?: PackageCommandOptions): Promise; packageDescribe(target?: string, options?: PackageCommandOptions): Promise; packageReload(options?: PackageCommandOptions): Promise; packageCatalog = PackageCommandOptions>(options?: Options): ReadPromise; packageActivate(target: string, options?: PackageCommandOptions): Promise; packageDeactivate(target: string, options?: PackageCommandOptions): Promise; packageMigrate(options?: PackageCommandOptions): Promise; upgrade(target?: string, options?: UpgradeCommandOptions): Promise; }" + "signature": "export declare class PmClient { private readonly defaults; constructor(options?: PmClientOptions); static forActiveExtensionHost(options: PmClientOptions): PmClient; run(action: PmActionName, args?: PmClientRunArgs): Promise; private runTyped; private withItemTransactionContext; previewItemMutations(options: Pick): Promise; commitItemMutations(options: Omit): Promise; get itemTransactions(): { status: (transactionId: string) => Promise; abandon: (transactionId: string, options: Omit) => Promise; supersede: (transactionId: string, newId: string, options: Omit) => Promise; }; context = InitialReadOptions>(options?: Options): ReadPromise; listAllItemMetadataLight(): Promise; list = InitialReadOptions>(options?: Options): ReadPromise; listAllComplete(options?: PmCompleteListOptions): Promise; search = InitialReadOptions>(query: string, options?: Options): ReadPromise; get = GetOptions>(id: string, options?: Options): ReadPromise; next = NextOptions>(options?: Options): ReadPromise; aggregate = AggregateOptions>(options?: Options): ReadPromise; stats = StatsCommandOptions>(options?: Options): ReadPromise; duplicates = DuplicatesCommandOptions>(options?: Options): ReadPromise; comments = CommentsCommandOptions>(id: string, options?: Options): ReadPromise; notes = NotesCommandOptions>(id: string, options?: Options): ReadPromise; learnings(id: string, options?: LearningsCommandOptions): Promise; files = FilesCommandOptions>(id: string, options?: Options): ReadPromise; filesDiscover(id: string, options?: FilesDiscoverOptions): Promise; filesLookup(options: FilesLookupOptions): Promise; docs = DocsCommandOptions>(id: string, options?: Options): ReadPromise; deps = DepsCommandOptions>(id: string, options?: Options): ReadPromise; graph = GraphCommandOptions>(subcommand: GraphSubcommand, ids?: { id?: string; target?: string; }, options?: Options): ReadPromise; append(id: string, body: string, options?: PmClientFullMutationOptions): Promise; init(prefix?: string, options?: InitCommandOptions): Promise; config(scope: string, configAction: string, key?: string, value?: string, options?: ConfigCommandOptions): Promise; schema(subcommand: SchemaSubcommand, options?: PmActionOptions): Promise; workflowPolicy(action: WorkflowPolicyAction, name?: string, options?: WorkflowPolicyActionOptions): Promise; schemaList(): Promise; schemaShow(name: string): Promise; schemaAddType(name: string, options?: SchemaAddTypeCommandOptions): Promise; schemaRemoveType(name: string, options?: SchemaRemoveTypeCommandOptions): Promise; schemaAddStatus(name: string, options?: SchemaAddStatusCommandOptions): Promise; schemaRemoveStatus(name: string, options?: SchemaRemoveStatusCommandOptions): Promise; schemaAddField(name: string, options?: SchemaAddFieldCommandOptions): Promise; schemaRemoveField(name: string, options?: SchemaRemoveFieldCommandOptions): Promise; schemaListFields(): Promise; schemaShowField(name: string): Promise; schemaApplyPreset(typePreset: string, options?: SchemaApplyPresetCommandOptions): Promise; schemaInferTypes(options?: SchemaAddTypeInferCommandOptions): Promise; schemaRenameType(from: string, to: string, options: RunSchemaEvolutionMigrationOptions): Promise; schemaRenameField(from: string, to: string, options: RunSchemaEvolutionMigrationOptions, type?: string): Promise; schemaRemapStatus(from: string, to: string, options: RunSchemaEvolutionMigrationOptions): Promise; schemaShowStatus(name: string): Promise; profile(subcommand: ProfileSubcommand, options?: PmActionOptions): Promise; profileList(): Promise; profileShow(name: string): Promise; profileApply(name: string, options?: ProfileApplyCommandOptions): Promise; profileLint(name: string): Promise; validate & { counts: true; }>(options: Options): ReadPromise; validate & { counts?: false; } = ValidateCommandOptions & { counts?: false; }>(options?: Options): ReadPromise; validate>(options: Options): ReadPromise; health = RunHealthOptions>(options?: Options): ReadPromise; gc(options?: GcCommandOptions): Promise; assurance(input: AssuranceActionInput): Promise; historyRedact(id: string, options: HistoryRedactCommandOptions): Promise; historyRepair(id: string, options?: HistoryRepairCommandOptions): Promise; historyRepairAll(options?: HistoryRepairCommandOptions): Promise; historyAttest(options?: HistoryAttestCommandOptions): ReturnType; historyCompact(id: string, options?: HistoryCompactCommandOptions): Promise; historyCompactBulk(options: HistoryCompactBulkCommandOptions): Promise; historyAuthorAcknowledge(options: AcknowledgeUnknownAuthorEventsOptions): Promise; plan(subcommand: PlanSubcommand, id?: string, options?: PlanCommandOptions, stepRef?: string, reorderTo?: number): Promise; planCreate(options: PlanCommandOptions): Promise; planShow(id: string, options?: PlanCommandOptions): Promise; planAddStep(id: string, options: PlanCommandOptions): Promise; planUpdateStep(id: string, stepRef: string, options: PlanCommandOptions): Promise; planCompleteStep(id: string, stepRef: string, options?: PlanCommandOptions): Promise; planBlockStep(id: string, stepRef: string, options: PlanCommandOptions): Promise; planReorderStep(id: string, stepRef: string, reorderTo: number, options?: PlanCommandOptions): Promise; planRemoveStep(id: string, stepRef: string, options?: PlanCommandOptions): Promise; planLink(id: string, stepRef: string, options: PlanCommandOptions): Promise; planUnlink(id: string, stepRef: string, options: PlanCommandOptions): Promise; planDecision(id: string, options: PlanCommandOptions): Promise; planDiscovery(id: string, options: PlanCommandOptions): Promise; planValidation(id: string, options: PlanCommandOptions): Promise; planResume(id: string, options: PlanCommandOptions): Promise; planApprove(id: string, options?: PlanCommandOptions): Promise; planMaterialize(id: string, options: PlanCommandOptions): Promise; create(options?: PmCreateActionOptions): Promise; update(id: string, options?: PmUpdateActionOptions): Promise; reopen(id: string, reason: string, options?: ReopenCommandOptions): Promise; close(id: string, reason: string, options: PmClientCloseActionOptions & { releaseAssignment: true; }): Promise; close(id: string, reason: string, options?: PmClientCloseActionOptions & { releaseAssignment?: false; }): Promise; close(id: string, reason: string, options?: PmClientCloseActionOptions & { releaseAssignment?: boolean; }): Promise; claim(id: string, options: PmClientFullMutationOptions & { start: true; }): Promise; claim(id: string, options?: PmClientFullMutationOptions & { start?: false; }): Promise; claim(id: string, options?: PmClientFullMutationOptions & { start?: boolean; }): Promise; claimNext(options?: ClaimNextOptions): Promise; release(id: string, options: PmClientFullMutationOptions & ReleaseMutationOptions & { pause: true; }): Promise; release(id: string, options?: PmClientFullMutationOptions & ReleaseMutationOptions & { pause?: false; }): Promise; release(id: string, options?: PmClientFullMutationOptions & ReleaseMutationOptions & { pause?: boolean; }): Promise; copy(id: string, options?: PmClientFullMutationOptions): Promise; delete(id: string, options?: PmClientFullMutationOptions): Promise; restore(id: string, target: string, options?: PmClientFullMutationOptions): Promise; focus(id?: string, options?: PmClientFullMutationOptions): Promise; startTask(id: string, options?: PmClientFullMutationOptions): Promise; pauseTask(id: string, options?: PmClientFullMutationOptions): Promise; closeTask(id: string, reason: string, options?: PmClientFullMutationOptions): Promise; extension(target?: string, options?: ExtensionCommandOptions): Promise; extensionList(options?: ExtensionCommandOptions): Promise; extensionActivate(target: string, options?: ExtensionCommandOptions): Promise; extensionDeactivate(target: string, options?: ExtensionCommandOptions): Promise; package(target?: string, options?: PackageCommandOptions): Promise; packageList(options?: PackageCommandOptions): Promise; packageInstall(target: string, options?: PackageCommandOptions): Promise; packageUninstall(target: string, options?: PackageCommandOptions): Promise; packageDoctor(options?: PackageCommandOptions): Promise; packageManage(target?: string, options?: PackageCommandOptions): Promise; packageDescribe(target?: string, options?: PackageCommandOptions): Promise; packageReload(options?: PackageCommandOptions): Promise; packageCatalog = PackageCommandOptions>(options?: Options): ReadPromise; packageActivate(target: string, options?: PackageCommandOptions): Promise; packageDeactivate(target: string, options?: PackageCommandOptions): Promise; packageMigrate(options?: PackageCommandOptions): Promise; upgrade(target?: string, options?: UpgradeCommandOptions): Promise; }" }, { "classification": "supported", @@ -34703,7 +34791,7 @@ "classification": "supported", "kind": "class", "name": "PmClient", - "signature": "export declare class PmClient { private readonly defaults; constructor(options?: PmClientOptions); static forActiveExtensionHost(options: PmClientOptions): PmClient; run(action: PmActionName, args?: PmClientRunArgs): Promise; private runTyped; context = InitialReadOptions>(options?: Options): ReadPromise; listAllItemMetadataLight(): Promise; list = InitialReadOptions>(options?: Options): ReadPromise; listAllComplete(options?: PmCompleteListOptions): Promise; search = InitialReadOptions>(query: string, options?: Options): ReadPromise; get = GetOptions>(id: string, options?: Options): ReadPromise; next = NextOptions>(options?: Options): ReadPromise; aggregate = AggregateOptions>(options?: Options): ReadPromise; stats = StatsCommandOptions>(options?: Options): ReadPromise; duplicates = DuplicatesCommandOptions>(options?: Options): ReadPromise; comments = CommentsCommandOptions>(id: string, options?: Options): ReadPromise; notes = NotesCommandOptions>(id: string, options?: Options): ReadPromise; learnings(id: string, options?: LearningsCommandOptions): Promise; files = FilesCommandOptions>(id: string, options?: Options): ReadPromise; filesDiscover(id: string, options?: FilesDiscoverOptions): Promise; filesLookup(options: FilesLookupOptions): Promise; docs = DocsCommandOptions>(id: string, options?: Options): ReadPromise; deps = DepsCommandOptions>(id: string, options?: Options): ReadPromise; graph = GraphCommandOptions>(subcommand: GraphSubcommand, ids?: { id?: string; target?: string; }, options?: Options): ReadPromise; append(id: string, body: string, options?: PmClientFullMutationOptions): Promise; init(prefix?: string, options?: InitCommandOptions): Promise; config(scope: string, configAction: string, key?: string, value?: string, options?: ConfigCommandOptions): Promise; schema(subcommand: SchemaSubcommand, options?: PmActionOptions): Promise; workflowPolicy(action: WorkflowPolicyAction, name?: string, options?: WorkflowPolicyActionOptions): Promise; schemaList(): Promise; schemaShow(name: string): Promise; schemaAddType(name: string, options?: SchemaAddTypeCommandOptions): Promise; schemaRemoveType(name: string, options?: SchemaRemoveTypeCommandOptions): Promise; schemaAddStatus(name: string, options?: SchemaAddStatusCommandOptions): Promise; schemaRemoveStatus(name: string, options?: SchemaRemoveStatusCommandOptions): Promise; schemaAddField(name: string, options?: SchemaAddFieldCommandOptions): Promise; schemaRemoveField(name: string, options?: SchemaRemoveFieldCommandOptions): Promise; schemaListFields(): Promise; schemaShowField(name: string): Promise; schemaApplyPreset(typePreset: string, options?: SchemaApplyPresetCommandOptions): Promise; schemaInferTypes(options?: SchemaAddTypeInferCommandOptions): Promise; schemaRenameType(from: string, to: string, options: RunSchemaEvolutionMigrationOptions): Promise; schemaRenameField(from: string, to: string, options: RunSchemaEvolutionMigrationOptions, type?: string): Promise; schemaRemapStatus(from: string, to: string, options: RunSchemaEvolutionMigrationOptions): Promise; schemaShowStatus(name: string): Promise; profile(subcommand: ProfileSubcommand, options?: PmActionOptions): Promise; profileList(): Promise; profileShow(name: string): Promise; profileApply(name: string, options?: ProfileApplyCommandOptions): Promise; profileLint(name: string): Promise; validate & { counts: true; }>(options: Options): ReadPromise; validate & { counts?: false; } = ValidateCommandOptions & { counts?: false; }>(options?: Options): ReadPromise; validate>(options: Options): ReadPromise; health = RunHealthOptions>(options?: Options): ReadPromise; gc(options?: GcCommandOptions): Promise; assurance(input: AssuranceActionInput): Promise; historyRedact(id: string, options: HistoryRedactCommandOptions): Promise; historyRepair(id: string, options?: HistoryRepairCommandOptions): Promise; historyRepairAll(options?: HistoryRepairCommandOptions): Promise; historyAttest(options?: HistoryAttestCommandOptions): ReturnType; historyCompact(id: string, options?: HistoryCompactCommandOptions): Promise; historyCompactBulk(options: HistoryCompactBulkCommandOptions): Promise; historyAuthorAcknowledge(options: AcknowledgeUnknownAuthorEventsOptions): Promise; plan(subcommand: PlanSubcommand, id?: string, options?: PlanCommandOptions, stepRef?: string, reorderTo?: number): Promise; planCreate(options: PlanCommandOptions): Promise; planShow(id: string, options?: PlanCommandOptions): Promise; planAddStep(id: string, options: PlanCommandOptions): Promise; planUpdateStep(id: string, stepRef: string, options: PlanCommandOptions): Promise; planCompleteStep(id: string, stepRef: string, options?: PlanCommandOptions): Promise; planBlockStep(id: string, stepRef: string, options: PlanCommandOptions): Promise; planReorderStep(id: string, stepRef: string, reorderTo: number, options?: PlanCommandOptions): Promise; planRemoveStep(id: string, stepRef: string, options?: PlanCommandOptions): Promise; planLink(id: string, stepRef: string, options: PlanCommandOptions): Promise; planUnlink(id: string, stepRef: string, options: PlanCommandOptions): Promise; planDecision(id: string, options: PlanCommandOptions): Promise; planDiscovery(id: string, options: PlanCommandOptions): Promise; planValidation(id: string, options: PlanCommandOptions): Promise; planResume(id: string, options: PlanCommandOptions): Promise; planApprove(id: string, options?: PlanCommandOptions): Promise; planMaterialize(id: string, options: PlanCommandOptions): Promise; create(options?: PmCreateActionOptions): Promise; update(id: string, options?: PmUpdateActionOptions): Promise; reopen(id: string, reason: string, options?: ReopenCommandOptions): Promise; close(id: string, reason: string, options: PmClientCloseActionOptions & { releaseAssignment: true; }): Promise; close(id: string, reason: string, options?: PmClientCloseActionOptions & { releaseAssignment?: false; }): Promise; close(id: string, reason: string, options?: PmClientCloseActionOptions & { releaseAssignment?: boolean; }): Promise; claim(id: string, options: PmClientFullMutationOptions & { start: true; }): Promise; claim(id: string, options?: PmClientFullMutationOptions & { start?: false; }): Promise; claim(id: string, options?: PmClientFullMutationOptions & { start?: boolean; }): Promise; claimNext(options?: ClaimNextOptions): Promise; release(id: string, options: PmClientFullMutationOptions & ReleaseMutationOptions & { pause: true; }): Promise; release(id: string, options?: PmClientFullMutationOptions & ReleaseMutationOptions & { pause?: false; }): Promise; release(id: string, options?: PmClientFullMutationOptions & ReleaseMutationOptions & { pause?: boolean; }): Promise; copy(id: string, options?: PmClientFullMutationOptions): Promise; delete(id: string, options?: PmClientFullMutationOptions): Promise; restore(id: string, target: string, options?: PmClientFullMutationOptions): Promise; focus(id?: string, options?: PmClientFullMutationOptions): Promise; startTask(id: string, options?: PmClientFullMutationOptions): Promise; pauseTask(id: string, options?: PmClientFullMutationOptions): Promise; closeTask(id: string, reason: string, options?: PmClientFullMutationOptions): Promise; extension(target?: string, options?: ExtensionCommandOptions): Promise; extensionList(options?: ExtensionCommandOptions): Promise; extensionActivate(target: string, options?: ExtensionCommandOptions): Promise; extensionDeactivate(target: string, options?: ExtensionCommandOptions): Promise; package(target?: string, options?: PackageCommandOptions): Promise; packageList(options?: PackageCommandOptions): Promise; packageInstall(target: string, options?: PackageCommandOptions): Promise; packageUninstall(target: string, options?: PackageCommandOptions): Promise; packageDoctor(options?: PackageCommandOptions): Promise; packageManage(target?: string, options?: PackageCommandOptions): Promise; packageDescribe(target?: string, options?: PackageCommandOptions): Promise; packageReload(options?: PackageCommandOptions): Promise; packageCatalog = PackageCommandOptions>(options?: Options): ReadPromise; packageActivate(target: string, options?: PackageCommandOptions): Promise; packageDeactivate(target: string, options?: PackageCommandOptions): Promise; packageMigrate(options?: PackageCommandOptions): Promise; upgrade(target?: string, options?: UpgradeCommandOptions): Promise; }" + "signature": "export declare class PmClient { private readonly defaults; constructor(options?: PmClientOptions); static forActiveExtensionHost(options: PmClientOptions): PmClient; run(action: PmActionName, args?: PmClientRunArgs): Promise; private runTyped; private withItemTransactionContext; previewItemMutations(options: Pick): Promise; commitItemMutations(options: Omit): Promise; get itemTransactions(): { status: (transactionId: string) => Promise; abandon: (transactionId: string, options: Omit) => Promise; supersede: (transactionId: string, newId: string, options: Omit) => Promise; }; context = InitialReadOptions>(options?: Options): ReadPromise; listAllItemMetadataLight(): Promise; list = InitialReadOptions>(options?: Options): ReadPromise; listAllComplete(options?: PmCompleteListOptions): Promise; search = InitialReadOptions>(query: string, options?: Options): ReadPromise; get = GetOptions>(id: string, options?: Options): ReadPromise; next = NextOptions>(options?: Options): ReadPromise; aggregate = AggregateOptions>(options?: Options): ReadPromise; stats = StatsCommandOptions>(options?: Options): ReadPromise; duplicates = DuplicatesCommandOptions>(options?: Options): ReadPromise; comments = CommentsCommandOptions>(id: string, options?: Options): ReadPromise; notes = NotesCommandOptions>(id: string, options?: Options): ReadPromise; learnings(id: string, options?: LearningsCommandOptions): Promise; files = FilesCommandOptions>(id: string, options?: Options): ReadPromise; filesDiscover(id: string, options?: FilesDiscoverOptions): Promise; filesLookup(options: FilesLookupOptions): Promise; docs = DocsCommandOptions>(id: string, options?: Options): ReadPromise; deps = DepsCommandOptions>(id: string, options?: Options): ReadPromise; graph = GraphCommandOptions>(subcommand: GraphSubcommand, ids?: { id?: string; target?: string; }, options?: Options): ReadPromise; append(id: string, body: string, options?: PmClientFullMutationOptions): Promise; init(prefix?: string, options?: InitCommandOptions): Promise; config(scope: string, configAction: string, key?: string, value?: string, options?: ConfigCommandOptions): Promise; schema(subcommand: SchemaSubcommand, options?: PmActionOptions): Promise; workflowPolicy(action: WorkflowPolicyAction, name?: string, options?: WorkflowPolicyActionOptions): Promise; schemaList(): Promise; schemaShow(name: string): Promise; schemaAddType(name: string, options?: SchemaAddTypeCommandOptions): Promise; schemaRemoveType(name: string, options?: SchemaRemoveTypeCommandOptions): Promise; schemaAddStatus(name: string, options?: SchemaAddStatusCommandOptions): Promise; schemaRemoveStatus(name: string, options?: SchemaRemoveStatusCommandOptions): Promise; schemaAddField(name: string, options?: SchemaAddFieldCommandOptions): Promise; schemaRemoveField(name: string, options?: SchemaRemoveFieldCommandOptions): Promise; schemaListFields(): Promise; schemaShowField(name: string): Promise; schemaApplyPreset(typePreset: string, options?: SchemaApplyPresetCommandOptions): Promise; schemaInferTypes(options?: SchemaAddTypeInferCommandOptions): Promise; schemaRenameType(from: string, to: string, options: RunSchemaEvolutionMigrationOptions): Promise; schemaRenameField(from: string, to: string, options: RunSchemaEvolutionMigrationOptions, type?: string): Promise; schemaRemapStatus(from: string, to: string, options: RunSchemaEvolutionMigrationOptions): Promise; schemaShowStatus(name: string): Promise; profile(subcommand: ProfileSubcommand, options?: PmActionOptions): Promise; profileList(): Promise; profileShow(name: string): Promise; profileApply(name: string, options?: ProfileApplyCommandOptions): Promise; profileLint(name: string): Promise; validate & { counts: true; }>(options: Options): ReadPromise; validate & { counts?: false; } = ValidateCommandOptions & { counts?: false; }>(options?: Options): ReadPromise; validate>(options: Options): ReadPromise; health = RunHealthOptions>(options?: Options): ReadPromise; gc(options?: GcCommandOptions): Promise; assurance(input: AssuranceActionInput): Promise; historyRedact(id: string, options: HistoryRedactCommandOptions): Promise; historyRepair(id: string, options?: HistoryRepairCommandOptions): Promise; historyRepairAll(options?: HistoryRepairCommandOptions): Promise; historyAttest(options?: HistoryAttestCommandOptions): ReturnType; historyCompact(id: string, options?: HistoryCompactCommandOptions): Promise; historyCompactBulk(options: HistoryCompactBulkCommandOptions): Promise; historyAuthorAcknowledge(options: AcknowledgeUnknownAuthorEventsOptions): Promise; plan(subcommand: PlanSubcommand, id?: string, options?: PlanCommandOptions, stepRef?: string, reorderTo?: number): Promise; planCreate(options: PlanCommandOptions): Promise; planShow(id: string, options?: PlanCommandOptions): Promise; planAddStep(id: string, options: PlanCommandOptions): Promise; planUpdateStep(id: string, stepRef: string, options: PlanCommandOptions): Promise; planCompleteStep(id: string, stepRef: string, options?: PlanCommandOptions): Promise; planBlockStep(id: string, stepRef: string, options: PlanCommandOptions): Promise; planReorderStep(id: string, stepRef: string, reorderTo: number, options?: PlanCommandOptions): Promise; planRemoveStep(id: string, stepRef: string, options?: PlanCommandOptions): Promise; planLink(id: string, stepRef: string, options: PlanCommandOptions): Promise; planUnlink(id: string, stepRef: string, options: PlanCommandOptions): Promise; planDecision(id: string, options: PlanCommandOptions): Promise; planDiscovery(id: string, options: PlanCommandOptions): Promise; planValidation(id: string, options: PlanCommandOptions): Promise; planResume(id: string, options: PlanCommandOptions): Promise; planApprove(id: string, options?: PlanCommandOptions): Promise; planMaterialize(id: string, options: PlanCommandOptions): Promise; create(options?: PmCreateActionOptions): Promise; update(id: string, options?: PmUpdateActionOptions): Promise; reopen(id: string, reason: string, options?: ReopenCommandOptions): Promise; close(id: string, reason: string, options: PmClientCloseActionOptions & { releaseAssignment: true; }): Promise; close(id: string, reason: string, options?: PmClientCloseActionOptions & { releaseAssignment?: false; }): Promise; close(id: string, reason: string, options?: PmClientCloseActionOptions & { releaseAssignment?: boolean; }): Promise; claim(id: string, options: PmClientFullMutationOptions & { start: true; }): Promise; claim(id: string, options?: PmClientFullMutationOptions & { start?: false; }): Promise; claim(id: string, options?: PmClientFullMutationOptions & { start?: boolean; }): Promise; claimNext(options?: ClaimNextOptions): Promise; release(id: string, options: PmClientFullMutationOptions & ReleaseMutationOptions & { pause: true; }): Promise; release(id: string, options?: PmClientFullMutationOptions & ReleaseMutationOptions & { pause?: false; }): Promise; release(id: string, options?: PmClientFullMutationOptions & ReleaseMutationOptions & { pause?: boolean; }): Promise; copy(id: string, options?: PmClientFullMutationOptions): Promise; delete(id: string, options?: PmClientFullMutationOptions): Promise; restore(id: string, target: string, options?: PmClientFullMutationOptions): Promise; focus(id?: string, options?: PmClientFullMutationOptions): Promise; startTask(id: string, options?: PmClientFullMutationOptions): Promise; pauseTask(id: string, options?: PmClientFullMutationOptions): Promise; closeTask(id: string, reason: string, options?: PmClientFullMutationOptions): Promise; extension(target?: string, options?: ExtensionCommandOptions): Promise; extensionList(options?: ExtensionCommandOptions): Promise; extensionActivate(target: string, options?: ExtensionCommandOptions): Promise; extensionDeactivate(target: string, options?: ExtensionCommandOptions): Promise; package(target?: string, options?: PackageCommandOptions): Promise; packageList(options?: PackageCommandOptions): Promise; packageInstall(target: string, options?: PackageCommandOptions): Promise; packageUninstall(target: string, options?: PackageCommandOptions): Promise; packageDoctor(options?: PackageCommandOptions): Promise; packageManage(target?: string, options?: PackageCommandOptions): Promise; packageDescribe(target?: string, options?: PackageCommandOptions): Promise; packageReload(options?: PackageCommandOptions): Promise; packageCatalog = PackageCommandOptions>(options?: Options): ReadPromise; packageActivate(target: string, options?: PackageCommandOptions): Promise; packageDeactivate(target: string, options?: PackageCommandOptions): Promise; packageMigrate(options?: PackageCommandOptions): Promise; upgrade(target?: string, options?: UpgradeCommandOptions): Promise; }" }, { "classification": "advanced_export", @@ -37277,6 +37365,8 @@ "tracker_root_missing", "tracker_root_not_directory", "tracker_root_unreadable", + "transaction_abandoned", + "transaction_committed", "transaction_create_compensated", "transaction_journal_invalid", "transaction_partial_mutation", @@ -37284,6 +37374,7 @@ "transaction_preview_external_schema", "transaction_preview_non_regular_file", "transaction_preview_snapshot_changed", + "transaction_recovery_plan_missing", "type_duplicate", "type_invalid", "undeclared_observation", diff --git a/src/core/history/operation-contract.ts b/src/core/history/operation-contract.ts index 851c11c8cf..30d4ba82b0 100644 --- a/src/core/history/operation-contract.ts +++ b/src/core/history/operation-contract.ts @@ -96,6 +96,7 @@ export const PM_WORKSPACE_HISTORY_OPERATIONS = [ "telemetry:first_run_prompt", "telemetry:clear", "item_format:auto_select_default", + "transaction_abandon", ] as const; /** Retired writer spellings; readers preserve original bytes and may resolve aliases explicitly. */ diff --git a/src/core/store/item-store.ts b/src/core/store/item-store.ts index 471a591c71..c358d119a9 100644 --- a/src/core/store/item-store.ts +++ b/src/core/store/item-store.ts @@ -1091,6 +1091,7 @@ export async function deleteItem(params: { } = prepared; try { + assertItemMutationPreconditions(params.pmRoot, document); const extensionFieldNames = resolveActiveExtensionFieldNames(undefined); const beforeDocument = canonicalDocument(document, { schema: params.settings.schema, diff --git a/src/sdk/generated/generated-error-code-catalog-part-1.ts b/src/sdk/generated/generated-error-code-catalog-part-1.ts index c075e7f615..fec7ebb10b 100644 --- a/src/sdk/generated/generated-error-code-catalog-part-1.ts +++ b/src/sdk/generated/generated-error-code-catalog-part-1.ts @@ -2856,4 +2856,17 @@ export const PM_ERROR_CODE_CATALOG_PART_1: PmErrorCodeContract[] = [ canonical_code: "merge_reconcile_receipt_evidence_untrusted", aliases: [], }, + { + code: "merge_root_not_found", + meaning: "Merge root not found condition.", + stability: "stable", + exit_code: 3, + class: "not_found", + recovery: + "Inspect the structured error guidance and retry the suggested command.", + sources: ["sdk/merge/install.ts"], + emitting_commands: ["*"], + canonical_code: "merge_root_not_found", + aliases: [], + }, ]; diff --git a/src/sdk/generated/generated-error-code-catalog-part-2.ts b/src/sdk/generated/generated-error-code-catalog-part-2.ts index 001748248a..5169d5f03f 100644 --- a/src/sdk/generated/generated-error-code-catalog-part-2.ts +++ b/src/sdk/generated/generated-error-code-catalog-part-2.ts @@ -7,19 +7,6 @@ import type { PmErrorCodeContract } from "../error-code-catalog.js"; /** Generated partition 2 of the exhaustive error-code catalog. */ export const PM_ERROR_CODE_CATALOG_PART_2: PmErrorCodeContract[] = [ - { - code: "merge_root_not_found", - meaning: "Merge root not found condition.", - stability: "stable", - exit_code: 3, - class: "not_found", - recovery: - "Inspect the structured error guidance and retry the suggested command.", - sources: ["sdk/merge/install.ts"], - emitting_commands: ["*"], - canonical_code: "merge_root_not_found", - aliases: [], - }, { code: "merge_settlement_hook_conflict", meaning: "Merge settlement hook conflict condition.", @@ -1575,6 +1562,32 @@ export const PM_ERROR_CODE_CATALOG_PART_2: PmErrorCodeContract[] = [ { state: "selected_tracker_root_is_not_readable", probe_id: "tracker-root-unreadable", entrypoints: ["list"], expected_exit_class: "generic_failure" }, ], }, + { + code: "transaction_abandoned", + meaning: "Transaction abandoned condition.", + stability: "provisional", + exit_code: 4, + class: "conflict", + recovery: + "Inspect the structured error guidance and retry the suggested command.", + sources: ["sdk/workspace-transaction.ts"], + emitting_commands: ["*"], + canonical_code: "transaction_abandoned", + aliases: [], + }, + { + code: "transaction_committed", + meaning: "Transaction committed condition.", + stability: "provisional", + exit_code: 4, + class: "conflict", + recovery: + "Inspect the structured error guidance and retry the suggested command.", + sources: ["sdk/workspace-transaction.ts"], + emitting_commands: ["*"], + canonical_code: "transaction_committed", + aliases: [], + }, { code: "transaction_create_compensated", meaning: "Transaction create compensated condition.", @@ -1666,6 +1679,19 @@ export const PM_ERROR_CODE_CATALOG_PART_2: PmErrorCodeContract[] = [ canonical_code: "transaction_preview_snapshot_changed", aliases: [], }, + { + code: "transaction_recovery_plan_missing", + meaning: "Transaction recovery plan missing condition.", + stability: "provisional", + exit_code: 4, + class: "conflict", + recovery: + "Inspect the structured error guidance and retry the suggested command.", + sources: ["sdk/item-transaction.ts"], + emitting_commands: ["*"], + canonical_code: "transaction_recovery_plan_missing", + aliases: [], + }, { code: "type_duplicate", meaning: "Type duplicate condition.", diff --git a/src/sdk/item-transaction.ts b/src/sdk/item-transaction.ts index 17fb35cb47..5b859086c7 100644 --- a/src/sdk/item-transaction.ts +++ b/src/sdk/item-transaction.ts @@ -6,6 +6,7 @@ * with correct-by-construction inspection and compensation wiring. */ import crypto from "node:crypto"; +import { runGet, type GetResult } from "./query/get.js"; import { constants, type Stats } from "node:fs"; import { isFileMissingError, readRegularFile, transactionPreviewNonRegularFileError } from "../core/fs/fs-utils.js"; import { cp, lstat, mkdir, mkdtemp, open, readdir, realpath, rm, stat, writeFile } from "node:fs/promises"; @@ -46,6 +47,11 @@ import { } from "./runtime.js"; import { commitWorkspaceTransaction, + abandonWorkspaceTransaction, + readWorkspaceTransaction, + workspaceTransactionPlanDigest, + type WorkspaceTransactionJournal, + type AbandonWorkspaceTransactionOptions, validateWorkspaceTransactionIdentity, type CommitWorkspaceTransactionOptions, type WorkspaceTransactionJsonValue, @@ -593,6 +599,7 @@ function buildCreateStep( mergeTransactionMutationOptions(mutation.options, { author: config.author, id: mutation.id, + message: bulkHistoryMarker(config.transactionId, stepId, "apply"), }), { pmRoot: config.pmRoot }, ); @@ -602,35 +609,30 @@ function buildCreateStep( return { id: String(createdItem.id), op: "create" }; }, async compensate(): Promise { - const snapshot = await readItemSnapshot(config.pmRoot, mutation.id); - if (snapshot === undefined) { - return; - } - if (config.createCompensation === "delete") { - await deleteItem( - mutation.id, - { - force: true, - author: config.author, - message: `Compensate interrupted bulk transaction ${config.transactionId}`, - }, - { pmRoot: config.pmRoot }, - ); - return; - } - if (snapshot.closedAt !== undefined) { - return; - } - await close( - mutation.id, - `Compensated: interrupted bulk transaction ${config.transactionId}`, - { force: true, author: config.author }, - { pmRoot: config.pmRoot }, - ); + await compensateCreatedItem(config, mutation.id, stepId); }, }; } +/** Prove ownership and recheck the locked record before retiring a transaction-created item. */ +async function compensateCreatedItem(config: BulkMutationStepConfig, id: string, stepId: string): Promise { + const snapshot = await readItemSnapshot(config.pmRoot, id); + if (snapshot === undefined || (config.createCompensation === "close" && snapshot.closedAt !== undefined)) return; + const history = await readHistoryEntries(path.join(config.pmRoot, "history", `${snapshot.id}.jsonl`), snapshot.id); + const applyMarker = bulkHistoryMarker(config.transactionId, stepId, "apply"); + const compensationMarker = bulkHistoryMarker(config.transactionId, stepId, "compensate"); + const latestMarker = history.filter(entry => entry.message === applyMarker || entry.message === compensationMarker).at(-1); + if (latestMarker?.message === compensationMarker) return; + if (latestMarker === undefined || !history.every(entry => isTransactionHistoryEntry(entry, config.transactionId))) throw partialMutationError(config, snapshot.id, stepId); + await runWithItemMutationPrecondition({ pmRoot: config.pmRoot, id: snapshot.id, validate: document => { + if (hashDocument(document) !== history.at(-1)!.after_hash) throw partialMutationError(config, snapshot.id, stepId); + } }, async () => { + const options = { force: true, author: config.author, message: compensationMarker }; + if (config.createCompensation === "delete") await deleteItem(id, options, { pmRoot: config.pmRoot }); + else await close(id, `Compensated: interrupted bulk transaction ${config.transactionId}`, options, { pmRoot: config.pmRoot }); + }); +} + /** Build the workspace-transaction step for one item update. */ function buildUpdateStep( config: BulkMutationStepConfig, @@ -883,8 +885,21 @@ function assertValidBulkMutations(mutations: readonly BulkItemMutation[]): void } } +/** Freeze admitted intent before waiting on storage while retaining the caller's literal-input policy. */ +function snapshotBulkMutations(input: readonly BulkItemMutation[]): BulkItemMutation[] { + const mutations = [...input]; + assertValidBulkMutations(mutations); + return mutations.map(mutation => { + const snapshot = structuredClone(mutation); + if (mutation.options !== undefined && snapshot.options !== undefined) transferMutationStdinTokenPolicy(mutation.options, snapshot.options); + return snapshot; + }); +} + /** Evidence and explicit limits of a non-writing semantic transaction preview. */ export interface ItemMutationPreviewValidation { + /** Final canonical staged records for each mutation; committed replays return no staged records. */ + records: ItemMutationStagedRecord[]; /** True when the coordinator executed staged validation; false for an already committed journal replay. */ validated: boolean; /** Distinguishes newly staged execution from idempotent replay without fresh step validation. */ @@ -904,6 +919,32 @@ export interface ItemMutationPreviewValidation { }[]; } +/** Canonical preview record and the values that commit may regenerate. */ +export interface ItemMutationStagedRecord { + /** Zero-based position in the original mutation plan. */ + index: number; + /** Canonical item id. */ + id: string; + /** Lifecycle operation producing this snapshot. */ + op: BulkItemMutation["op"]; + /** Whether this staged run executed the mutation or adopted already-applied state. */ + execution: "applied" | "adopted"; + /** Full public get projection, including body, after the complete staged batch. */ + item: GetResult["item"]; + /** JSON pointers to clock fields; conservatively includes retained or caller-supplied timestamps. */ + commit_time_fields: string[]; +} + +/** Enumerate potentially regenerated clocks without hiding metadata from the canonical record. */ +function previewClockFields(value: unknown, pointer = ""): string[] { + if (value === null || typeof value !== "object") return []; + return Object.entries(value).flatMap(([key, nested]) => { + const current = `${pointer}/${key.replaceAll("~", "~0").replaceAll("/", "~1")}`; + return /^(created_at|updated_at|closed_at|completed_at|timestamp)$/u.test(key) + ? [current] : previewClockFields(nested, current); + }); +} + /** Attach the resolved batch position while preserving lifecycle error classification. */ async function validateMutationOperation(mutation: BulkItemMutation, index: number, run: () => Promise): Promise { try { @@ -1143,8 +1184,7 @@ async function stagePreviewTracker(sourceRoot: string, stagedRoot: string, regis /** Validate ordered mutations using apply's coordinator in a disposable tracker, without source writes, journals or extension hooks. */ export async function previewItemMutations(options: Pick): Promise { const identity = validateWorkspaceTransactionIdentity(options); - const mutations = [...options.mutations]; - assertValidBulkMutations(mutations); + const mutations = snapshotBulkMutations(options.mutations); const registrations = getActiveExtensionRegistrations(); const root = await mkdtemp(path.join(tmpdir(), "pm-transaction-preview-")); const stagedRoot = path.join(root, "tracker"); @@ -1152,6 +1192,8 @@ export async function previewItemMutations(options: Pick(); await runWithActiveExtensions({ path: stagedRoot, noExtensions: true }, async () => { setActiveExtensionRegistrations(registrations); const config: BulkMutationStepConfig = { ...identity, pmRoot: stagedRoot, createCompensation: "close", uniqueIndex: createUniqueKeyIndex(stagedRoot) }; @@ -1163,12 +1205,20 @@ export async function previewItemMutations(options: Pick validateMutationOperation(mutation, index, () => step.inspect()), prepareCompensation: () => validateMutationOperation(mutation, index, async () => step.prepareCompensation?.()), - apply: () => validateMutationOperation(mutation, index, () => step.apply()), + apply: () => validateMutationOperation(mutation, index, async () => { + const outcome = await step.apply(); + applied.add(index); + return outcome; + }), }; }); await commitWorkspaceTransaction({ ...identity, pmRoot: stagedRoot, steps, onTransition: ({ transition }) => { if (transition === "committed") validated = true; } }); + if (validated) for (const [index, mutation] of mutations.entries()) { + const item = (await runGet(mutation.id, { path: stagedRoot }, { full: true })).item; + records.push({ index, id: String(item.id), op: mutation.op, execution: applied.has(index) ? "applied" : "adopted", item, commit_time_fields: previewClockFields(item) }); + } }); - return { validated, state: validated ? "staged_snapshot" : "replayed_committed_plan", warnings, unresolved_commit_constraints: ["concurrent_tracker_changes", "extension_mutation_guards_and_hooks", "derived_extension_dependencies_excluded"] }; + return { records, validated, state: validated ? "staged_snapshot" : "replayed_committed_plan", warnings, unresolved_commit_constraints: ["concurrent_tracker_changes", "extension_mutation_guards_and_hooks", "derived_extension_dependencies_excluded", "generated_timestamps_and_provenance"] }; } finally { await rm(root, { recursive: true, force: true }); } @@ -1188,8 +1238,7 @@ export async function previewItemMutations(options: Pick { - const mutations = [...options.mutations]; - assertValidBulkMutations(mutations); + const mutations = snapshotBulkMutations(options.mutations); const createCompensation = options.createCompensation ?? "close"; if (!["close", "delete"].includes(createCompensation)) { throw new TypeError( @@ -1210,6 +1259,7 @@ export async function commitItemMutations( steps: mutations.map((mutation, index) => buildStepForMutation(stepConfig, mutation, index), ), + recoveryData: JSON.parse(JSON.stringify({ kind: "item-mutations-v1", mutations, createCompensation })) as WorkspaceTransactionJsonValue, ...(options.lockTtlSeconds === undefined ? {} : { lockTtlSeconds: options.lockTtlSeconds }), @@ -1332,3 +1382,39 @@ export const _testOnlyItemTransaction = { isUpdateMarkerApplied, readItemSnapshot, }; + +/** Durable item-batch receipt with an ordered-plan fingerprint. */ +export interface ItemTransactionStatus { + /** Validated coordinator journal, including original recovery plan when available. */ + journal: WorkspaceTransactionJournal; + /** SHA-256 identity of the ordered payload-bound steps. */ + planDigest: string; +} + +/** Read a retained item-batch journal without touching private storage paths or mutating state. */ +export async function readItemTransaction(pmRoot: string, transactionId: string): Promise { + const journal = await readWorkspaceTransaction(pmRoot, transactionId); + return journal === undefined ? undefined : { journal, planDigest: workspaceTransactionPlanDigest(journal) }; +} + +/** Host-independent recovery parameters for an interrupted item batch. */ +export type AbandonItemTransactionOptions = Omit; + +/** Reconstruct only a retained item plan; legacy or foreign journals require their original adapter. */ +function recoveryItemSteps(options: AbandonItemTransactionOptions, journal: WorkspaceTransactionJournal): WorkspaceTransactionStep[] { + const data = journal.recoveryData; + if (data === null || typeof data !== "object" || Array.isArray(data) || data.kind !== "item-mutations-v1" || !Array.isArray(data.mutations) || !["close", "delete"].includes(String(data.createCompensation))) { + throw new PmCliError("Transaction has no supported item recovery plan", EXIT_CODE.CONFLICT, { code: "transaction_recovery_plan_missing", required: "Resume with the original plan and its original adapter.", why: "Legacy or foreign journals cannot safely reconstruct item compensation." }); + } + const mutations = data.mutations as unknown as BulkItemMutation[]; + assertValidBulkMutations(mutations); + const config: BulkMutationStepConfig = { ...options, createCompensation: data.createCompensation as "close" | "delete", uniqueIndex: createUniqueKeyIndex(options.pmRoot) }; + return mutations.map((mutation, index) => buildStepForMutation(config, mutation, index)); +} + +/** Guardedly compensate an interrupted batch and retire its identity, optionally naming a fresh replacement. */ +export async function abandonItemTransaction(options: AbandonItemTransactionOptions): Promise { + const identity = validateWorkspaceTransactionIdentity(options); + const journal = await abandonWorkspaceTransaction({ ...options, ...identity, resolveSteps: receipt => recoveryItemSteps({ ...options, ...identity }, receipt) }); + return { journal, planDigest: workspaceTransactionPlanDigest(journal) }; +} diff --git a/src/sdk/runtime.ts b/src/sdk/runtime.ts index 45d290a79b..4013095526 100644 --- a/src/sdk/runtime.ts +++ b/src/sdk/runtime.ts @@ -37,7 +37,9 @@ import { assertMutationOptionBag } from "./runtime/mutation-value-validation.js" export { withCliMutationInput, withLiteralMutationInput } from "./lifecycle/cli-input.js"; import { createAsyncReadWriteGate } from "../core/shared/serial-queue.js"; import { getSettingsPath,resolvePmRoot } from "../core/store/paths.js"; -import { readSettings } from "../core/store/settings.js"; +import { readSettings, runWithConfigurationOnlySettings } from "../core/store/settings.js"; +import { resolveAuthor } from "../core/shared/author.js"; +import type { CommitItemMutationsOptions, CommitItemMutationsResult, ItemMutationPreviewValidation, ItemTransactionStatus, AbandonItemTransactionOptions } from "./item-transaction.js"; import type { ItemMetadata } from "../types/index.js"; import { type AcknowledgeUnknownAuthorEventsOptions, @@ -745,6 +747,41 @@ export class PmClient { return this.run(action, args) as Promise; } + /** Execute a direct transaction using the bound root, author policy and active extension host. */ + private async withItemTransactionContext(run: (identity: { pmRoot: string; author: string }) => Promise): Promise { + const pmRoot = resolvePmRoot(this.defaults.cwd ?? process.cwd(), this.defaults.path); + const execute = async () => { + const settings = await runWithConfigurationOnlySettings(pmRoot, () => readSettings(pmRoot)); + return run({ pmRoot, author: resolveAuthor(this.defaults.author, settings.author_default) }); + }; + if (this.defaults[ACTIVE_EXTENSION_HOST_CONTEXT] === true || activeExtensionScope.getStore() === true) return execute(); + return runWithActiveExtensions({ ...this.defaults, path: pmRoot }, execute); + } + + /** Validate a batch in disposable state and return normalized staged records under this host's identity. */ + previewItemMutations(options: Pick): Promise { + return this.withItemTransactionContext(async identity => (await import("./item-transaction.js")).previewItemMutations({ ...options, ...identity })); + } + + /** Commit or replay a batch using the bound tracker and author, without per-call root overrides. */ + commitItemMutations(options: Omit): Promise { + return this.withItemTransactionContext(async identity => (await import("./item-transaction.js")).commitItemMutations({ ...options, ...identity })); + } + + /** Inspect or explicitly retire this host's interrupted item transactions. Supersession retires the old id before a separately planned commit. */ + get itemTransactions(): { + status: (transactionId: string) => Promise; + abandon: (transactionId: string, options: Omit) => Promise; + supersede: (transactionId: string, newId: string, options: Omit) => Promise; + } { + const abandon = (transactionId: string, options: Omit) => this.withItemTransactionContext(async identity => (await import("./item-transaction.js")).abandonItemTransaction({ ...options, ...identity, transactionId })); + return { + status: transactionId => this.withItemTransactionContext(async identity => (await import("./item-transaction.js")).readItemTransaction(identity.pmRoot, transactionId)), + abandon, + supersede: (transactionId, newId, options) => abandon(transactionId, { ...options, supersededBy: newId }), + }; + } + /** Return the same context snapshot produced by `pm context`. */ context = InitialReadOptions>( options: Options = {} as Options, diff --git a/src/sdk/workspace-transaction-gc.ts b/src/sdk/workspace-transaction-gc.ts index e4ec9d0f89..7c951bc219 100644 --- a/src/sdk/workspace-transaction-gc.ts +++ b/src/sdk/workspace-transaction-gc.ts @@ -82,7 +82,7 @@ function readJournalStatusAndTimestamp(raw: string): { } const record = parsed as Record; return { - status: typeof record.status === "string" ? record.status : null, + status: record.abandonment !== undefined ? "abandoned" : (typeof record.status === "string" ? record.status : null), updatedAt: typeof record.updatedAt === "string" ? record.updatedAt : null, }; } diff --git a/src/sdk/workspace-transaction.ts b/src/sdk/workspace-transaction.ts index 6d86c7f202..48cbb596af 100644 --- a/src/sdk/workspace-transaction.ts +++ b/src/sdk/workspace-transaction.ts @@ -6,6 +6,9 @@ */ import { mkdir, readFile } from "node:fs/promises"; import path from "node:path"; +import { createHash } from "node:crypto"; +import { appendWorkspaceAuditEvent, getWorkspaceHistoryPath, WORKSPACE_HISTORY_ID } from "../core/history/workspace-history.js"; +import { readHistoryEntries } from "./history-read.js"; import { acquireLock } from "../core/lock/lock.js"; import { isFileMissingError, writeFileAtomic } from "../core/fs/fs-utils.js"; import { nowIso } from "../core/shared/time.js"; @@ -85,6 +88,8 @@ export interface CommitWorkspaceTransactionOptions { author: string; /** Ordered idempotent mutations; compensations run in reverse order. */ steps: readonly WorkspaceTransactionStep[]; + /** JSON plan retained for adapter-owned recovery; callers must not store secrets. */ + recoveryData?: WorkspaceTransactionJsonValue; /** Lock lifetime in seconds; size this above the longest expected attempt. */ lockTtlSeconds?: number; /** Maximum time to wait for the workspace writer lock. */ @@ -120,25 +125,44 @@ export class WorkspaceTransactionInterruptedError extends Error { } } -type WorkspaceTransactionJournalStatus = +/** Durable coordinator lifecycle, including explicitly retired identities. */ +export type WorkspaceTransactionJournalStatus = | "applying" | "compensating" | "compensated" - | "committed"; + | "committed" + | "abandoned"; -interface WorkspaceTransactionJournal { - schemaVersion: 1; +/** Durable coordinator receipt; step lists describe journaled progress, not a fresh domain inspection. */ +export interface WorkspaceTransactionJournal { + /** Version 2 fences older coordinators once explicit retirement begins. */ + schemaVersion: 1 | 2; + /** Stable transaction identity. */ transactionId: string; + /** Actor who prepared the attempt. */ author: string; + /** Last durable lifecycle state. */ status: WorkspaceTransactionJournalStatus; + /** One-based attempt number. */ attempt: number; + /** Initial preparation timestamp. */ createdAt: string; + /** Latest journal write timestamp. */ updatedAt: string; + /** Ordered payload-bound step identifiers. */ stepIds: string[]; + /** Steps durably admitted before forward execution. */ startedStepIds: string[]; + /** Steps recorded as applied. */ completedStepIds: string[]; + /** Recorded results for completed steps. */ results: Record; + /** Captured pre-write recovery receipts. */ compensationData: Record; + /** Adapter-owned original plan, absent in legacy journals. */ + recoveryData?: WorkspaceTransactionJsonValue; + /** Explicit retirement rationale and optional replacement identity. */ + abandonment?: { reason: string; author: string; supersededBy?: string }; } const WORKSPACE_TRANSACTION_LOCK_ID = "sdk-workspace-transaction"; @@ -204,10 +228,21 @@ function hasValidJournalMetadata( Number.isInteger(journal.attempt) && typeof journal.author === "string" && typeof journal.createdAt === "string" && - typeof journal.updatedAt === "string" + typeof journal.updatedAt === "string" && + hasValidAbandonment(journal) ); } +/** Retirement requests remain valid through interrupted compensation and fence forward replay. */ +function hasValidAbandonment(journal: Partial): boolean { + const retirement = journal.abandonment; + if (retirement === undefined) return journal.schemaVersion === 1 && journal.status !== "abandoned"; + if (journal.schemaVersion !== 2 || retirement === null || typeof retirement !== "object" || journal.status === "committed") return false; + return typeof retirement.reason === "string" && retirement.reason.trim().length > 0 && + typeof retirement.author === "string" && retirement.author.trim().length > 0 && + (retirement.supersededBy === undefined || (typeof retirement.supersededBy === "string" && TRANSACTION_ID_PATTERN.test(retirement.supersededBy) && retirement.supersededBy !== journal.transactionId)); +} + function createResultMap( source?: Record, ): Record { @@ -301,7 +336,7 @@ function hasValidJournalLifecycle( if (journal.status === "committed") return stepIds.every((stepId) => completed.has(stepId)); return ( - journal.status !== "compensated" || + !["compensated", "abandoned"].includes(journal.status ?? "") || (completed.size === 0 && started.size === 0) ); } @@ -330,22 +365,28 @@ function journalPlanMismatch(transactionId: string): PmCliError { EXIT_CODE.CONFLICT, { code: "transaction_plan_mismatch", - required: "Replay the exact plan that started this transaction, or start a new transaction with a different id.", + required: "Replay the original plan or safely abandon the interrupted transaction before replacing it.", why: "A journal records the plan it is resuming; applying a different plan under the same id could skip or duplicate steps.", nextSteps: [ "Re-run with the original document to resume or replay it.", - "Pass --transaction-id (or a new transactionId over MCP) to commit the changed plan as its own transaction.", + "For item batches use client.itemTransactions.status(transactionId), then client.itemTransactions.abandon(transactionId, { reason }) before committing a changed plan with a new transactionId.", "Run pm ops gc --scope transactions --dry-run to inspect abandoned journals before pruning them.", ], }, ); } +/** Status reads omit a requested plan; fully compensated attempts can be replanned. */ +function matchesJournalSteps(status: string, recorded: readonly string[], requested: readonly string[] | undefined): boolean { + return requested === undefined || status === "compensated" || + (recorded.length === requested.length && recorded.every((id, index) => id === requested[index])); +} + /** Validate stored integrity independently of the caller's requested replay plan. */ function parseJournal( raw: string, transactionId: string, - stepIds: readonly string[], + stepIds?: readonly string[], ): WorkspaceTransactionJournal { let parsed: unknown; try { @@ -357,7 +398,7 @@ function parseJournal( throw invalidJournal(transactionId, "expected an object"); const journal = parsed as Partial; const identityMatches = - journal.schemaVersion === 1 && journal.transactionId === transactionId; + (journal.schemaVersion === 1 || journal.schemaVersion === 2) && journal.transactionId === transactionId; if (!identityMatches) throw invalidJournal(transactionId, "schema version or transaction id does not match the journal file"); const recordedStepIds = journal.stepIds; if ( @@ -366,15 +407,12 @@ function parseJournal( !hasValidJournalLifecycle(journal, recordedStepIds) || !hasValidJournalMetadata(journal) || typeof journal.status !== "string" || - !["applying", "compensating", "compensated", "committed"].includes(journal.status) + !["applying", "compensating", "compensated", "committed", "abandoned"].includes(journal.status) ) throw invalidJournal(transactionId, "invalid lifecycle, metadata, status or step ids"); // A compensated attempt was rolled back step by step and holds nothing to // resume, so a re-planned document may start a fresh attempt under the same // id; every other status must replay the exact plan it recorded. - const stepsMatch = - journal.status === "compensated" || - (recordedStepIds.length === stepIds.length && - recordedStepIds.every((stepId, index) => stepId === stepIds[index])); + const stepsMatch = matchesJournalSteps(journal.status, recordedStepIds, stepIds); if (!stepsMatch) throw journalPlanMismatch(transactionId); return { ...(journal as WorkspaceTransactionJournal), @@ -412,6 +450,7 @@ async function prepareJournalForApply( completedStepIds: [], results: createResultMap(), compensationData: createResultMap(), + ...(options.recoveryData === undefined ? {} : { recoveryData: cloneJournalValue(options.recoveryData, "Transaction recovery data") }), }; await writeJournal(options.pmRoot, journal); await emitTransition(options, journal, "prepared"); @@ -501,7 +540,7 @@ async function applyPreparedTransaction( async function loadJournal( pmRoot: string, transactionId: string, - stepIds: readonly string[], + stepIds?: readonly string[], ): Promise { try { return parseJournal( @@ -653,6 +692,7 @@ export async function commitWorkspaceTransaction( ); try { const existing = await loadJournal(pmRoot, transactionId, stepIds); + if (existing?.status === "abandoned" || existing?.abandonment !== undefined) throw retiredTransaction(transactionId); const recovered = existing !== undefined; if (existing?.status === "committed") return { @@ -677,3 +717,74 @@ export async function commitWorkspaceTransaction( await release(); } } + +/** Reject replay of a retired id without applying a new plan under that identity. */ +function retiredTransaction(transactionId: string): PmCliError { + return new PmCliError(`Transaction ${transactionId} has been abandoned`, EXIT_CODE.CONFLICT, { + code: "transaction_abandoned", required: "Use a new transactionId for the replacement plan.", + why: "An explicitly retired transaction identity cannot be resumed.", + }); +} + +/** Read an atomically published journal without changing tracker state; undefined means no retained receipt. */ +export async function readWorkspaceTransaction(pmRoot: string, transactionId: string): Promise { + const identity = validateWorkspaceTransactionIdentity({ pmRoot, transactionId, author: "reader" }); + return loadJournal(identity.pmRoot, identity.transactionId); +} + +/** SHA-256 identity of the ordered, payload-bound step identifiers. */ +export function workspaceTransactionPlanDigest(journal: Pick): string { + return createHash("sha256").update(JSON.stringify(journal.stepIds)).digest("hex"); +} + +/** Explicit recovery request; the adapter reconstructs compensation from the retained original plan under the coordinator lock. */ +export interface AbandonWorkspaceTransactionOptions extends Omit { + /** Required human-readable recovery rationale. */ + reason: string; + /** Optional fresh identity reserved by the caller for its replacement plan. */ + supersededBy?: string; + /** Rebuild original steps without applying forward mutations. */ + resolveSteps(journal: WorkspaceTransactionJournal): readonly WorkspaceTransactionStep[]; +} + +/** Compensate interrupted owned effects and permanently retire the id; committed work is never undone. */ +export async function abandonWorkspaceTransaction(options: AbandonWorkspaceTransactionOptions): Promise { + const identity = validateWorkspaceTransactionIdentity(options); + const reason = requiredText(options.reason, "Abandonment reason"); + const supersededBy = options.supersededBy === undefined ? undefined : requiredIdentifier(options.supersededBy, "Replacement transaction id"); + if (supersededBy === identity.transactionId) throw new TypeError("Replacement transaction id must differ from the abandoned id"); + const lockTtlSeconds = positiveInteger(options.lockTtlSeconds, DEFAULT_LOCK_TTL_SECONDS, "Transaction lock TTL"); + const lockWaitMs = positiveInteger(options.lockWaitMs, DEFAULT_LOCK_WAIT_MS, "Transaction lock wait"); + const release = await acquireLock(identity.pmRoot, WORKSPACE_TRANSACTION_LOCK_ID, lockTtlSeconds, identity.author, false, false, lockWaitMs); + try { + const journal = await loadJournal(identity.pmRoot, identity.transactionId); + if (journal === undefined) throw new PmCliError(`Transaction ${identity.transactionId} was not found`, EXIT_CODE.NOT_FOUND); + if (journal.status === "committed") throw new PmCliError(`Transaction ${identity.transactionId} is committed and cannot be abandoned`, EXIT_CODE.CONFLICT, { code: "transaction_committed", required: "Plan a separate explicit corrective mutation.", why: "Recovery cannot silently undo committed work." }); + if (journal.abandonment !== undefined && journal.abandonment.supersededBy !== supersededBy) throw retiredTransaction(identity.transactionId); + if (journal.status === "abandoned") return journal; + if (supersededBy !== undefined && await loadJournal(identity.pmRoot, supersededBy) !== undefined) throw new PmCliError(`Replacement transaction ${supersededBy} already exists`, EXIT_CODE.CONFLICT); + const steps = options.resolveSteps(structuredClone(journal)); + if (JSON.stringify(steps.map(step => step.id)) !== JSON.stringify(journal.stepIds)) throw journalPlanMismatch(identity.transactionId); + if (journal.abandonment === undefined) { + journal.schemaVersion = 2; + journal.abandonment = { reason, author: identity.author, ...(supersededBy === undefined ? {} : { supersededBy }) }; + await writeJournal(identity.pmRoot, journal); + } + if (journal.status !== "compensated") await compensateAppliedSteps({ ...options, ...identity, steps }, journal); + await auditTransactionAbandonment(journal, identity.pmRoot, lockTtlSeconds, lockWaitMs); + journal.status = "abandoned"; + await writeJournal(identity.pmRoot, journal); + return journal; + } finally { + await release(); + } +} + +/** Record one retirement per attempt even if the final journal write was interrupted after the audit append. */ +async function auditTransactionAbandonment(journal: WorkspaceTransactionJournal, pmRoot: string, lockTtlSeconds: number, lockWaitMs: number): Promise { + const planDigest = workspaceTransactionPlanDigest(journal); + const history = await readHistoryEntries(getWorkspaceHistoryPath(pmRoot), WORKSPACE_HISTORY_ID); + if (history.some(entry => entry.op === "transaction_abandon" && entry.context?.transaction_id === journal.transactionId && entry.context?.attempt === journal.attempt && entry.context?.plan_digest === planDigest)) return; + const abandonment = journal.abandonment!; + await appendWorkspaceAuditEvent({ pmRoot, author: abandonment.author, lockTtlSeconds, lockWaitMs, op: "transaction_abandon", message: abandonment.reason, context: { transaction_id: journal.transactionId, attempt: journal.attempt, plan_digest: planDigest, ...(abandonment.supersededBy === undefined ? {} : { superseded_by: abandonment.supersededBy }) } }); +} diff --git a/tests/fixtures/contracts/full.json b/tests/fixtures/contracts/full.json index 18179bcd68..0a50a6019f 100644 --- a/tests/fixtures/contracts/full.json +++ b/tests/fixtures/contracts/full.json @@ -27059,6 +27059,40 @@ ], "stability": "provisional" }, + { + "aliases": [], + "canonical_code": "transaction_abandoned", + "class": "conflict", + "code": "transaction_abandoned", + "emitting_commands": [ + "*" + ], + "exit_code": 4, + "meaning": "Transaction abandoned condition.", + "owned_states": [], + "recovery": "Inspect the structured error guidance and retry the suggested command.", + "sources": [ + "sdk/workspace-transaction.ts" + ], + "stability": "provisional" + }, + { + "aliases": [], + "canonical_code": "transaction_committed", + "class": "conflict", + "code": "transaction_committed", + "emitting_commands": [ + "*" + ], + "exit_code": 4, + "meaning": "Transaction committed condition.", + "owned_states": [], + "recovery": "Inspect the structured error guidance and retry the suggested command.", + "sources": [ + "sdk/workspace-transaction.ts" + ], + "stability": "provisional" + }, { "aliases": [], "canonical_code": "transaction_create_compensated", @@ -27178,6 +27212,23 @@ ], "stability": "provisional" }, + { + "aliases": [], + "canonical_code": "transaction_recovery_plan_missing", + "class": "conflict", + "code": "transaction_recovery_plan_missing", + "emitting_commands": [ + "*" + ], + "exit_code": 4, + "meaning": "Transaction recovery plan missing condition.", + "owned_states": [], + "recovery": "Inspect the structured error guidance and retry the suggested command.", + "sources": [ + "sdk/item-transaction.ts" + ], + "stability": "provisional" + }, { "aliases": [], "canonical_code": "type_duplicate", @@ -33438,7 +33489,8 @@ "telemetry:install_id", "telemetry:first_run_prompt", "telemetry:clear", - "item_format:auto_select_default" + "item_format:auto_select_default", + "transaction_abandon" ] }, "list_projections": [ diff --git a/tests/integration/transactions/semantic-preview.integration.spec.ts b/tests/integration/transactions/semantic-preview.integration.spec.ts index f3d08b5d6a..22074cd130 100644 --- a/tests/integration/transactions/semantic-preview.integration.spec.ts +++ b/tests/integration/transactions/semantic-preview.integration.spec.ts @@ -3,7 +3,7 @@ import path from "node:path"; import { execFileSync, spawnSync } from "node:child_process"; import { describe, expect, it } from "vitest"; import { handleRequest } from "../../../src/mcp/server.js"; -import { buildItemCompletionMutations, commitItemMutations, previewItemMutations } from "../../../src/sdk/item-transaction.js"; +import { buildItemCompletionMutations, commitItemMutations, previewItemMutations, type ItemMutationPreviewValidation } from "../../../src/sdk/item-transaction.js"; import { createEmptyExtensionHookRegistry, setActiveExtensionHooks } from "../../../src/core/extensions/index.js"; import { runPmCli } from "../../../src/cli/main.js"; import { runDirectDistCli, runInProcessDistCli } from "../../helpers/cliRunner.js"; @@ -33,6 +33,15 @@ async function durableSnapshot(root: string): Promise> { return bytes; } +/** Compare stable preview facts across processes while independently checking the two generated create clocks. */ +function previewWithClockMatchers(validation: ItemMutationPreviewValidation): ItemMutationPreviewValidation { + return { ...validation, records: validation.records.map(record => ({ ...record, item: { + ...record.item, + created_at: expect.stringMatching(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u), + updated_at: expect.stringMatching(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u), + } })) }; +} + describe("semantic transaction previews (GH-1370)", () => { it.skipIf(process.platform === "win32")("preserves native filesystem failures without writing the source tracker", async () => { await withTempPmPath(async (context) => { @@ -62,7 +71,7 @@ describe("semantic transaction previews (GH-1370)", () => { expect(cli.code).toBe(0); const mcp = await handleRequest({ jsonrpc: "2.0", id: "managed-preview", method: "tools/call", params: { name: "pm_mutate", arguments: { path: context.pmPath, transactionId: "managed-preview", dryRun: true, mutations } } }); expect(cli.json).toMatchObject({ validation: { validated: true, unresolved_commit_constraints: expect.arrayContaining(["derived_extension_dependencies_excluded"]) } }); - expect(mcp?.structuredContent).toMatchObject({ result: { validation: (cli.json as { validation: unknown }).validation } }); + expect(mcp?.structuredContent).toMatchObject({ result: { validation: previewWithClockMatchers((cli.json as { validation: ItemMutationPreviewValidation }).validation) } }); expect(await readFile(settingsPath, "utf8")).toBe(before); expect(await readFile(sentinel, "utf8")).toBe("Unchanged external dependency"); expect((await lstat(dependencyLink)).isSymbolicLink()).toBe(true); @@ -88,8 +97,8 @@ describe("semantic transaction previews (GH-1370)", () => { expect(cli.code).toBe(0); const response = await mcp; if (!response?.structuredContent) throw new Error("MCP preview response must contain structured content."); - const receipt = response.structuredContent as { result: { rows: unknown[]; validation: unknown } }; - expect(cli.json).toMatchObject({ rows: receipt.result.rows, validation: receipt.result.validation }); + const receipt = response.structuredContent as { result: { rows: unknown[]; validation: ItemMutationPreviewValidation } }; + expect(cli.json).toMatchObject({ rows: receipt.result.rows, validation: previewWithClockMatchers(receipt.result.validation) }); for (const [index, ref] of ["original", "later"].entries()) { expect(receipt.result.rows[index]).toMatchObject({ index, ref, ...(mode === "advisory" ? { warnings: expect.arrayContaining([expect.stringContaining("likely_duplicates:pm-canonical")]) } : {}) }); if (mode === "off") expect(receipt.result.rows[index]).not.toHaveProperty("warnings"); @@ -388,7 +397,7 @@ describe("semantic transaction previews (GH-1370)", () => { const beforeValid = await durableSnapshot(context.pmPath); const preview = context.runCli([...valid, "--dry-run"], { expectJson: true }); expect(preview.code).toBe(0); - expect(preview.json).toMatchObject({ mutation_count: 3, validation: { validated: true, state: "staged_snapshot", unresolved_commit_constraints: ["concurrent_tracker_changes", "extension_mutation_guards_and_hooks", "derived_extension_dependencies_excluded"] } }); + expect(preview.json).toMatchObject({ mutation_count: 3, validation: { validated: true, state: "staged_snapshot", unresolved_commit_constraints: ["concurrent_tracker_changes", "extension_mutation_guards_and_hooks", "derived_extension_dependencies_excluded", "generated_timestamps_and_provenance"] } }); expect(await durableSnapshot(context.pmPath)).toEqual(beforeValid); expect(context.runCli(valid).code).toBe(0); expect(context.runCli(["get", "pm-complete", "--full", "--json"], { expectJson: true }).json).toMatchObject({ item: { status: "closed", resolution: "Delivered", comments: [expect.objectContaining({ text: "Staged completion evidence" })] } }); diff --git a/tests/types/item-transactions.test-d.ts b/tests/types/item-transactions.test-d.ts new file mode 100644 index 0000000000..d927252701 --- /dev/null +++ b/tests/types/item-transactions.test-d.ts @@ -0,0 +1,15 @@ +/** Host-bound transaction identity and typed receipt contracts (pm-gh1597, pm-gh1598). */ +import type { PmClient, ItemMutationPreviewValidation, CommitItemMutationsResult, ItemTransactionStatus, BulkItemMutation } from "../../src/sdk/index.js"; +declare const client: PmClient; +declare const mutations: BulkItemMutation[]; +const preview: Promise = client.previewItemMutations({ transactionId: "id", mutations }); +const commit: Promise = client.commitItemMutations({ transactionId: "id", mutations }); +const status: Promise = client.itemTransactions.status("id"); +const recovery: Promise = client.itemTransactions.supersede("id", "new-id", { reason: "Replan" }); +void [preview, commit, status, recovery]; +// @ts-expect-error Bound clients do not accept per-batch tracker overrides. +void client.commitItemMutations({ transactionId: "id", mutations, pmRoot: "/another" }); +// @ts-expect-error Bound clients retain the host author policy. +void client.previewItemMutations({ transactionId: "id", mutations, author: "another" }); +// @ts-expect-error Retirement requires an explicit reason. +void client.itemTransactions.abandon("id", {}); diff --git a/tests/unit/sdk/transactions/host-bound.spec.ts b/tests/unit/sdk/transactions/host-bound.spec.ts new file mode 100644 index 0000000000..7c1000355f --- /dev/null +++ b/tests/unit/sdk/transactions/host-bound.spec.ts @@ -0,0 +1,237 @@ +import { readFile, writeFile } from "node:fs/promises"; +import path from "node:path"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { PmClient, WorkspaceTransactionInterruptedError, runWithActiveExtensions, runWorkspaceTransactionGc, type BulkItemMutation } from "../../../../src/sdk/index.js"; +import { withTempPmPath } from "../../../helpers/withTempPmPath.js"; + +afterEach(() => { vi.useRealTimers(); vi.restoreAllMocks(); }); + +const stopAfterApply = ({ transition }: { transition: string }) => { + if (transition === "step_applied") throw new WorkspaceTransactionInterruptedError("Interrupted after durable apply"); +}; + +describe("host-bound item batches and recovery (pm-gh1597, pm-gh1598)", () => { + it("returns canonical final staged records and honors root and author over untyped overrides", async () => { + await withTempPmPath(async ({ pmPath }) => { + vi.useFakeTimers({ toFake: ["Date"] }); + const client = new PmClient({ pmRoot: pmPath, author: "bound-actor", noExtensions: true }); + const mutations: BulkItemMutation[] = [ + { op: "create", id: "staged", options: { title: "Staged", type: "Task", body: "# Body", tags: "B,a", author: "wrong" } }, + { op: "update", id: "staged", options: { description: "Canonical update", comment: ["text=Evidence"] } }, + ]; + const input = { transactionId: "canonical", mutations, pmRoot: "/not-the-host", author: "wrong" }; + const preview = await client.previewItemMutations(input); + expect(preview).toMatchObject({ validated: true, state: "staged_snapshot" }); + expect(preview.records).toHaveLength(2); + expect(preview.records[0]).toMatchObject({ index: 0, id: "pm-staged", op: "create", execution: "applied", item: { body: "# Body", tags: ["a", "b"], author: "bound-actor" } }); + expect(preview.records[0].commit_time_fields).toContain("/created_at"); + await expect(client.get("staged")).rejects.toThrow(); + expect(await client.itemTransactions.status("canonical")).toBeUndefined(); + await client.commitItemMutations(input); + expect((await client.get("staged", { full: true })).item).toEqual(preview.records[1].item); + const historyPath = path.join(pmPath, "history", "pm-staged.jsonl"); + const history = await readFile(historyPath, "utf8"); + expect((await client.commitItemMutations(input)).recovered).toBe(true); + expect(await readFile(historyPath, "utf8")).toBe(history); + expect(await client.previewItemMutations(input)).toMatchObject({ validated: false, state: "replayed_committed_plan", records: [] }); + await expect(client.commitItemMutations({ ...input, mutations: [{ op: "update", id: "staged", options: { title: "Changed intent" } }] })).rejects.toMatchObject({ context: { code: "transaction_plan_mismatch" } }); + await expect(client.itemTransactions.abandon("canonical", { reason: "Cannot undo completed work" })).rejects.toMatchObject({ context: { code: "transaction_committed" } }); + }); + }); + + it.each(["prepared", "step_applied", "step_recorded"])("retires interrupted updates from %s, audits once and permits a separately planned replacement", async transition => { + await withTempPmPath(async ({ pmPath }) => { + const client = new PmClient({ pmRoot: pmPath, author: "recovery-actor", noExtensions: true }); + const original = (await client.create({ title: "Original", type: "Task" })).item; + const options = { transactionId: "retired", mutations: [{ op: "update", id: original.id, options: { title: "Forward" } }] satisfies BulkItemMutation[] }; + await expect(client.commitItemMutations({ ...options, onTransition: event => { if (event.transition === transition) throw new WorkspaceTransactionInterruptedError("Crash"); } })).rejects.toThrow("Crash"); + const before = await client.itemTransactions.status("retired"); + expect(before?.journal.status).toBe("applying"); + expect(before?.planDigest).toMatch(/^[a-f0-9]{64}$/u); + const retired = await client.itemTransactions.supersede("retired", "replacement", { reason: "Re-plan against current state" }); + expect(retired.journal).toMatchObject({ schemaVersion: 2, status: "abandoned", startedStepIds: [], completedStepIds: [], abandonment: { author: "recovery-actor", supersededBy: "replacement" } }); + expect((await client.get(original.id)).item.title).toBe("Original"); + const journalBytes = await readFile(path.join(pmPath, "transactions", "sdk", "retired.json"), "utf8"); + await client.itemTransactions.supersede("retired", "replacement", { reason: "Retry request" }); + expect(await readFile(path.join(pmPath, "transactions", "sdk", "retired.json"), "utf8")).toBe(journalBytes); + await expect(client.commitItemMutations(options)).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); + await expect(client.itemTransactions.abandon("retired", { reason: "Different replacement" })).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); + await client.commitItemMutations({ ...options, transactionId: "replacement", mutations: [{ op: "update", id: original.id, options: { title: "Replanned" } }] }); + expect((await client.get(original.id)).item.title).toBe("Replanned"); + }); + }); + + it.each(["update", "create"] as const)("retains peer edits and recovery receipts for interrupted %s", async op => { + await withTempPmPath(async ({ pmPath }) => { + const client = new PmClient({ pmRoot: pmPath, noExtensions: true }); + if (op === "update") await client.create({ id: "peer", title: "Original", type: "Task" }); + await expect(client.commitItemMutations({ transactionId: "peer", createCompensation: "delete", mutations: [{ op, id: "peer", options: { title: "Forward", type: "Task" } }], onTransition: stopAfterApply })).rejects.toThrow("Interrupted"); + await client.comments("peer", { add: "Peer evidence must survive" }); + await expect(client.itemTransactions.abandon("peer", { reason: "Recover" })).rejects.toMatchObject({ context: { code: "transaction_partial_mutation" } }); + expect((await client.get("peer", { full: true })).item).toMatchObject({ title: "Forward", comments: [expect.objectContaining({ text: "Peer evidence must survive" })] }); + expect((await client.itemTransactions.status("peer"))?.journal.status).toBe("compensating"); + }); + }); + + it.each(["close", "delete"] as const)("compensates owned creations using the recorded %s policy", async createCompensation => { + await withTempPmPath(async ({ pmPath }) => { + const client = new PmClient({ pmRoot: pmPath, noExtensions: true }); + await expect(client.commitItemMutations({ transactionId: "create", createCompensation, mutations: [{ op: "create", id: "created", options: { title: "Owned", type: "Task" } }], onTransition: stopAfterApply })).rejects.toThrow("Interrupted"); + expect((await client.itemTransactions.abandon("create", { reason: "Retire" })).journal.status).toBe("abandoned"); + if (createCompensation === "close") expect((await client.get("created")).item.status).toBe("closed"); + else await expect(client.get("created")).rejects.toThrow(); + }); + }); + + it("refuses missing, malformed and legacy plans without retiring recovery state", async () => { + await withTempPmPath(async ({ pmPath }) => { + const client = new PmClient({ pmRoot: pmPath, noExtensions: true }); + await expect(client.itemTransactions.abandon("missing", { reason: "Absent" })).rejects.toThrow("not found"); + await expect(client.itemTransactions.supersede("same", "same", { reason: "Bad replacement" })).rejects.toThrow("must differ"); + await expect(client.itemTransactions.abandon("id", { reason: " " })).rejects.toThrow("non-empty"); + await client.create({ id: "original", title: "Original", type: "Task" }); + await expect(client.commitItemMutations({ transactionId: "legacy", mutations: [{ op: "update", id: "original", options: { title: "Forward" } }], onTransition: stopAfterApply })).rejects.toThrow("Interrupted"); + const journalPath = path.join(pmPath, "transactions", "sdk", "legacy.json"); + const journal = JSON.parse(await readFile(journalPath, "utf8")); + delete journal.recoveryData; + await writeFile(journalPath, JSON.stringify(journal)); + await expect(client.itemTransactions.abandon("legacy", { reason: "No plan" })).rejects.toMatchObject({ context: { code: "transaction_recovery_plan_missing" } }); + expect((await client.itemTransactions.status("legacy"))?.journal.status).toBe("applying"); + await writeFile(journalPath, "{"); + await expect(client.itemTransactions.status("legacy")).rejects.toMatchObject({ context: { code: "transaction_journal_invalid" } }); + }); + }); + it("inherits active extension hosts and resolves cwd-bound clients", async () => { + await withTempPmPath(async ({ pmPath, tempRoot }) => { + await runWithActiveExtensions({ path: pmPath, noExtensions: true }, async () => { + const client = PmClient.forActiveExtensionHost({ pmRoot: pmPath, author: "extension-host" }); + await client.commitItemMutations({ transactionId: "host", mutations: [{ op: "create", id: "host", options: { title: "Host", type: "Task" } }] }); + expect((await client.itemTransactions.status("host"))?.journal.author).toBe("extension-host"); + }); + const client = new PmClient({ cwd: tempRoot, pmRoot: pmPath, noExtensions: true }); + expect((await client.itemTransactions.status("host"))?.journal.status).toBe("committed"); + }); + }); + + it.each(["close", "delete"] as const)("resumes an interrupted %s compensation and refuses an already-used replacement id", async createCompensation => { + await withTempPmPath(async ({ pmPath }) => { + const client = new PmClient({ pmRoot: pmPath, noExtensions: true }); + const options = { transactionId: "compensation", createCompensation, mutations: [{ op: "create", id: "compensated", options: { title: "Owned", type: "Task" } }] satisfies BulkItemMutation[], onTransition: stopAfterApply }; + await expect(client.commitItemMutations(options)).rejects.toThrow("Interrupted"); + const fsUtils = await import("../../../../src/core/fs/fs-utils.js"); + const write = fsUtils.writeFileAtomic; + vi.spyOn(fsUtils, "writeFileAtomic").mockImplementation(async (...args) => { + if (args[0] === path.join(pmPath, "transactions", "sdk", "compensation.json")) { + const receipt = JSON.parse(String(args[1])); + if (receipt.status === "compensating" && receipt.startedStepIds.length === 0) throw new Error("Stop compensation"); + } + return write(...args); + }); + await expect(client.itemTransactions.abandon("compensation", { reason: "Retire" })).rejects.toThrow("Stop compensation"); + vi.restoreAllMocks(); + expect((await client.itemTransactions.status("compensation"))?.journal.schemaVersion).toBe(2); + if (createCompensation === "close") await client.reopen("compensated", "Peer reopens after completed compensation"); + await expect(client.commitItemMutations(options)).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); + expect((await client.itemTransactions.abandon("compensation", { reason: "Resume retirement" })).journal.status).toBe("abandoned"); + if (createCompensation === "close") expect((await client.get("compensated")).item.status).toBe("open"); + await client.create({ id: "later", title: "Later", type: "Task" }); + await expect(client.commitItemMutations({ transactionId: "later", mutations: [{ op: "update", id: "later", options: { title: "Forward" } }], onTransition: stopAfterApply })).rejects.toThrow("Interrupted"); + await expect(client.itemTransactions.supersede("later", "compensation", { reason: "Already used" })).rejects.toThrow("already exists"); + }); + }); + + it("retains the original plan on mismatch and deduplicates audit after a final journal write fails", async () => { + await withTempPmPath(async ({ pmPath }) => { + const client = new PmClient({ pmRoot: pmPath, noExtensions: true }); + await client.create({ id: "audit", title: "Original", type: "Task" }); + await expect(client.commitItemMutations({ transactionId: "audit", mutations: [{ op: "update", id: "audit", options: { title: "Forward" } }], onTransition: stopAfterApply })).rejects.toThrow("Interrupted"); + const file = path.join(pmPath, "transactions", "sdk", "audit.json"); + const original = await readFile(file, "utf8"); + const corrupt = JSON.parse(original); + corrupt.recoveryData.mutations[0].options.title = "Wrong plan"; + await writeFile(file, JSON.stringify(corrupt)); + await expect(client.itemTransactions.abandon("audit", { reason: "Mismatch" })).rejects.toMatchObject({ context: { code: "transaction_plan_mismatch" } }); + await writeFile(file, original); + const fsUtils = await import("../../../../src/core/fs/fs-utils.js"); + const write = fsUtils.writeFileAtomic; + vi.spyOn(fsUtils, "writeFileAtomic").mockImplementation(async (...args) => { + if (args[0] === file && String(args[1]).includes('"status": "abandoned"')) throw new Error("Final journal write failed"); + return write(...args); + }); + await expect(client.itemTransactions.abandon("audit", { reason: "Retire" })).rejects.toThrow("Final journal write failed"); + vi.restoreAllMocks(); + const auditPath = path.join(pmPath, "history", "_workspace.jsonl"); + const audit = await readFile(auditPath, "utf8"); + await expect(client.commitItemMutations({ transactionId: "audit", mutations: [{ op: "update", id: "audit", options: { title: "Forward" } }] })).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); + const collected = await runWorkspaceTransactionGc(pmPath, { dryRun: true, retentionDays: 0, now: Date.now() + 86400000 }); + expect(collected.retained).toContain("transactions/sdk/audit.json"); + expect((await client.itemTransactions.abandon("audit", { reason: "Retry with another explanation" })).journal.abandonment?.reason).toBe("Retire"); + expect(await readFile(auditPath, "utf8")).toBe(audit); + expect((await client.get("audit")).item.title).toBe("Original"); + }); + }); + + it("identifies adopted values and returns final staged state for repeated targets", async () => { + await withTempPmPath(async ({ pmPath }) => { + const client = new PmClient({ pmRoot: pmPath, noExtensions: true }); + await client.create({ id: "existing", title: "Existing", type: "Task" }); + const input = { transactionId: "adopt", mutations: [ + { op: "create", id: "existing", options: { title: "Unused create input", type: "Task" } }, + { op: "update", id: "existing", options: { title: "Final value" } }, + ] satisfies BulkItemMutation[] }; + const preview = await client.previewItemMutations(input); + expect(preview.records.map(row => [row.execution, row.item.title])).toEqual([["adopted", "Final value"], ["applied", "Final value"]]); + expect((await client.get("existing")).item.title).toBe("Existing"); + }); + }); + + it.each(["close", "delete"] as const)("refuses a peer edit at the item-lock boundary of create %s compensation", async createCompensation => { + await withTempPmPath(async context => { + const client = new PmClient({ pmRoot: context.pmPath, noExtensions: true }); + await expect(client.commitItemMutations({ transactionId: "late-peer", createCompensation, mutations: [{ op: "create", id: "created", options: { title: "Created", type: "Task" } }], onTransition: stopAfterApply })).rejects.toThrow("Interrupted"); + const locks = await import("../../../../src/core/lock/lock.js"); + const acquire = locks.acquireLockLease; + let peerWrote = false; + vi.spyOn(locks, "acquireLockLease").mockImplementation(async (...args) => { + if (args[0] === context.pmPath && args[1] === "pm-created" && !peerWrote) { + peerWrote = true; + expect(context.runCli(["update", "pm-created", "--description", "Late peer", "--json"]).code).toBe(0); + } + return acquire(...args); + }); + await expect(client.itemTransactions.abandon("late-peer", { reason: "Retire" })).rejects.toMatchObject({ context: { code: "transaction_partial_mutation" } }); + expect(peerWrote).toBe(true); + expect((await client.get("created")).item).toMatchObject({ status: "open", description: "Late peer" }); + }); + }); + + it("rejects malformed retirement receipts instead of certifying an abandoned identity", async () => { + await withTempPmPath(async ({ pmPath }) => { + const client = new PmClient({ pmRoot: pmPath, noExtensions: true }); + await expect(client.commitItemMutations({ transactionId: "invalid-retirement", mutations: [{ op: "create", id: "created", options: { title: "Created", type: "Task" } }], onTransition: stopAfterApply })).rejects.toThrow("Interrupted"); + const file = path.join(pmPath, "transactions", "sdk", "invalid-retirement.json"); + const journal = JSON.parse(await readFile(file, "utf8")); + for (const abandonment of [null, {}, { reason: "", author: "actor" }, { reason: "Reason", author: "" }, { reason: "Reason", author: "actor", supersededBy: "../bad" }, { reason: "Reason", author: "actor", supersededBy: "invalid-retirement" }]) { + await writeFile(file, JSON.stringify({ ...journal, schemaVersion: 2, abandonment })); + await expect(client.itemTransactions.status("invalid-retirement")).rejects.toMatchObject({ context: { code: "transaction_journal_invalid" } }); + } + await writeFile(file, JSON.stringify({ ...journal, schemaVersion: 2, status: "committed", completedStepIds: journal.stepIds, abandonment: { reason: "Invalid retirement", author: "actor" } })); + await expect(client.itemTransactions.status("invalid-retirement")).rejects.toMatchObject({ context: { code: "transaction_journal_invalid" } }); + await writeFile(file, JSON.stringify({ ...journal, schemaVersion: 1, abandonment: { reason: "Downgraded retirement", author: "actor" } })); + await expect(client.itemTransactions.status("invalid-retirement")).rejects.toMatchObject({ context: { code: "transaction_journal_invalid" } }); + await writeFile(file, JSON.stringify({ ...journal, status: "abandoned", startedStepIds: [], completedStepIds: [], compensationData: {} })); + await expect(client.itemTransactions.status("invalid-retirement")).rejects.toMatchObject({ context: { code: "transaction_journal_invalid" } }); + }); + }); + + it("retains admitted intent when caller-owned option objects change after journal preparation", async () => { + await withTempPmPath(async ({ pmPath }) => { + const client = new PmClient({ pmRoot: pmPath, noExtensions: true }); + const options = { title: "Admitted intent", type: "Task" }; + await client.commitItemMutations({ transactionId: "stable-intent", mutations: [{ op: "create", id: "stable", options }], onTransition: event => { if (event.transition === "prepared") options.title = "Changed after admission"; } }); + expect((await client.get("stable")).item.title).toBe("Admitted intent"); + expect((await client.itemTransactions.status("stable-intent"))?.journal.recoveryData).toMatchObject({ mutations: [{ options: { title: "Admitted intent" } }] }); + }); + }); + +}); diff --git a/tests/unit/sdk/workspace-transaction.spec.ts b/tests/unit/sdk/workspace-transaction.spec.ts index 9f2e81f726..94c665d321 100644 --- a/tests/unit/sdk/workspace-transaction.spec.ts +++ b/tests/unit/sdk/workspace-transaction.spec.ts @@ -740,6 +740,7 @@ describe("workspace SDK transactions", () => { { ...base, createdAt: null }, { ...base, updatedAt: null }, { ...base, status: "unknown" }, + { ...base, status: undefined }, { ...base, status: { toString: null } }, ]; for (const journal of malformed) { From 512184eb96e12ad291e990961f166be2c1d96cb6 Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Wed, 28 Oct 2026 23:10:20 +0100 Subject: [PATCH 2/5] fix(sdk): preserve transaction recovery identity and read-only bootstrap Normalize transaction identity before constructing mutation steps so durable apply markers and coordinator receipts refer to the same transaction. Exercise padded identities through crash recovery to prevent false compensation success. Keep preview and status extension activation inside configuration-only reads, then validate storage before opening optional schemas. Native child-process controls prove FIFOs cannot hang the public host-bound preview path. Resume durable supersession intent even when the replacement identity has been used after an interrupted final journal write. Preserve the original retirement reason and deduplicate the audit receipt across retries. Document transaction-journal retention outside history redaction, ordinary writer isolation limits, and retained GC receipts. Include structured PM closure, linked regression evidence, generated changelog, release and observability audit receipts, and canonical intake of the new concurrent-writer report. Validation: 11540 passing tests with exact 100/100/100/100 source coverage; linked recovery 65/65 and semantic preview 49/49; types, lint, generated contracts and packed Node/Bun consumer checks. Local transport budgets also fail unchanged base; hosted performance gates remain required and unchanged. --- .../pm/extensions/.managed-extensions.json | 2 +- .agents/pm/features/pm-gh1576.toon | 5 ++- .agents/pm/features/pm-gh1597.toon | 38 ++++++++++++++----- .agents/pm/features/pm-gh1598.toon | 36 ++++++++++++++---- .agents/pm/history/pm-gh1576.jsonl | 1 + .agents/pm/history/pm-gh1597.jsonl | 9 +++++ .agents/pm/history/pm-gh1598.jsonl | 8 ++++ .agents/pm/history/pm-prrlce.jsonl | 1 + .agents/pm/history/pm-xq09zu.jsonl | 1 + .agents/pm/issues/pm-prrlce.toon | 5 ++- .agents/pm/issues/pm-xq09zu.toon | 5 ++- CHANGELOG.md | 5 +++ docs/SDK.md | 12 +++++- src/sdk/item-transaction.ts | 14 +++---- src/sdk/runtime.ts | 9 +++-- src/sdk/workspace-transaction.ts | 9 +++-- .../semantic-preview.integration.spec.ts | 19 +++++++++- .../unit/sdk/transactions/host-bound.spec.ts | 11 +++--- 18 files changed, 144 insertions(+), 46 deletions(-) diff --git a/.agents/pm/extensions/.managed-extensions.json b/.agents/pm/extensions/.managed-extensions.json index 4a4dafe276..2f4e91af0c 100644 --- a/.agents/pm/extensions/.managed-extensions.json +++ b/.agents/pm/extensions/.managed-extensions.json @@ -1,6 +1,6 @@ { "version": 1, - "updated_at": "2026-10-28T17:20:30.881Z", + "updated_at": "2026-10-28T22:08:25.524Z", "entries": [ { "name": "builtin-calendar", diff --git a/.agents/pm/features/pm-gh1576.toon b/.agents/pm/features/pm-gh1576.toon index 068df6220e..f7da4e4659 100644 --- a/.agents/pm/features/pm-gh1576.toon +++ b/.agents/pm/features/pm-gh1576.toon @@ -6,7 +6,7 @@ status: open priority: 1 tags[3]: concurrency,"gh:1576",sdk created_at: "2026-10-24T16:12:40.963Z" -updated_at: "2026-10-24T16:12:40.963Z" +updated_at: "2026-10-28T22:03:09.177Z" author: "harness:codex" estimated_minutes: 360 acceptance_criteria: "Define a public optional expected revision/hash contract across single-item and bulk SDK/CLI/MCP mutations; Check each precondition under the authoritative item lock at commit time and refuse stale writes without acknowledged item or history changes; Return typed current revision and bounded actionable change evidence; Deterministic concurrent controls cover closeout tags, collection cleanup, claim and bulk partial outcomes without weakening lease fencing." @@ -18,6 +18,7 @@ dependencies[3]{id,kind,created_at,author,source_kind,author_source}: pm-a8lnoh,related,"2026-10-24T16:12:40.963Z","harness:codex","cli:create:dep",detected pm-gh1359,related,"2026-10-24T16:12:40.963Z","harness:codex","cli:create:dep",detected pm-gh1549,related,"2026-10-24T16:12:40.963Z","harness:codex","cli:create:dep",detected -comments[1]{created_at,author,text}: +comments[2]{created_at,author,text}: "2026-10-24T16:12:40.963Z","harness:codex","Intake source: https://github.com/unbraind/pm-cli/issues/1576. Duplicate check: complete strict 3098-item all-status corpus with no omissions plus fresh request-specific searches and current open/in_progress lists; no existing owner matches this distinct acceptance. Full live related lineage was read. Existing delivered lease-fencing/focus behavior remains historically closed. This report is planning evidence; no current independent reproduction or fix is claimed. Queued open and unclaimed under the SDK outcome milestone." + "2026-10-28T22:03:09.177Z","harness:codex","Additional consumer report: https://github.com/unbraind/pm-cli/issues/1620 (2026-10-28). Its proposed option 2 is the existing expected-revision acceptance here, so reuse this canonical feature instead of creating duplicate work. Reporter describes a separate-process ordinary SDK writer entering between a transaction inspect and apply, losing title/parent/relation/assignee changes. Current source uses WORKSPACE_TRANSACTION_LOCK_ID for the coordinator while item writes take their own lock; the report is consistent with those distinct scopes, but this intake has not independently executed its probe. Include precise transaction-isolation documentation and a native concurrent-writer negative control in this feature. The host-bound recovery delivery only guards compensation ownership; it does not claim general read-decide-write isolation. Item remains open and unclaimed." body: "## Summary\n\nAgents and extensions often read an item, decide something from it (which PR delivered it, whether its acceptance criteria are met, which checkpoint to resume), and then write. Neither the SDK nor the CLI can apply that write only if the item is still the revision the decision was based on. `update`, `close`, `comments --add` and their SDK equivalents take no expected item hash or revision. A concurrent edit between the read and the write is silently built on, so the agent records a decision about state that no longer exists.\n\nThe lock-TTL fencing from #1549 makes a single mutation safe. It doesn't cover the gap between an agent's read and its later write.\n\n## Evidence (fleet packages, 2026-10-24, pm 2026.10.20–2026.10.24)\n\nRead-only reviews blocked three separate packages on this class in one day, each reproduced against the real SDK:\n\n- **pm-github closeout:** the delivering PR is chosen from the item's `delivery-pr` tag. If the tag changes from PR #1 to PR #2 while evidence is being fetched, the item still closes with PR #1's provenance. The workaround is a scoped `beforeMutation` hash guard under the item lock plus one retry. The API the agent asked for: `close(id, reason, { expectedItemHash })`.\n- **pm-rlm:** failure cleanup read a checkpoint, then saved that stale copy over a concurrent resume's answer, steps and token charges.\n- **pm-slack:** outbox retry cleanup deleted a peer drainer's newer group mappings.\n\nEach package had to hand-roll its own guard.\n\n## Reproduction (plain directory, no git)\n\n1. Agent A: `pm get --json`, records `item_hash` H1, decides to close based on the tags it read.\n2. Agent B: `pm update --tags delivery-pr:2`, so the hash is now H2.\n3. Agent A: `pm close \"Delivered by PR 1\"` succeeds. There is no way to say \"only if the hash is still H1\".\n\n## Expected\n\nAn optional precondition on every mutating command and SDK method, for example `--expect-hash ` / `{ expectedItemHash }`, checked under the item lock as part of the write. On mismatch the write is refused with a typed code (for example `stale_precondition`, exit 2). The refusal returns the current hash, plus a compact summary of which fields changed since H1, so the agent can re-decide in one call. The same option belongs on `update`, `close`, `claim`, `comments/notes/learnings --add`, `files/docs/test --add` and bulk mutations (one hash per id).\n\n## Why core\n\nRead-decide-write is the normal agent loop on a shared tracker. Without a native precondition, every package re-implements a lock-plus-hash check, and the races above ship until a reviewer finds them. This is part of making many agents on one tracker safe without git (#1516 measured the throughput side of the same workload)." diff --git a/.agents/pm/features/pm-gh1597.toon b/.agents/pm/features/pm-gh1597.toon index 033476f1f5..68d2e3eef7 100644 --- a/.agents/pm/features/pm-gh1597.toon +++ b/.agents/pm/features/pm-gh1597.toon @@ -2,30 +2,37 @@ id: pm-gh1597 title: "GH-1597: expose host-bound item transaction status and safe abandonment or supersession" description: "GitHub https://github.com/unbraind/pm-cli/issues/1597 requests public recovery for interrupted item-mutation journals when a peer edit changes the retry plan. Existing bulk commit and guarded compensation are shipped; extend their public host-bound lifecycle rather than duplicating private journal storage or reviving completed implementation." type: Feature -status: in_progress +status: closed priority: 1 tags: [] created_at: "2026-10-26T04:54:49.262Z" -updated_at: "2026-10-28T20:39:10.736Z" -assignee: "harness:codex" -claim_principal: "harness:codex#568692524ccbb719c2f222a0" +updated_at: "2026-10-28T22:07:24.128Z" +closed_at: "2026-10-28T22:07:22.951Z" +completed_at: "2026-10-28T22:07:22.951Z" author: "harness:codex" estimated_minutes: 300 acceptance_criteria: Expose typed host-bound journal state and applied/compensated step receipts with plan identity; Provide safe abandonment and supersession using proven apply markers and existing guarded compensation; never overwrite later peer edits or silently compensate committed work; Name executable public recovery in transaction-plan-mismatch guidance and verify non-Git crash/retry/peer-edit controls plus SDK contract documentation parent: pm-9rgaal risk: high confidence: high -expected_result: Extensions can inspect and recover interrupted batches through a supported root-bound API without reading private paths or recreating journal and compensation rules. +resolution: "Implemented bound status, abandon and supersede APIs with retained original plans, versioned durable retirement intent, idempotent audit and guarded compensation that preserves peer edits. Recovery normalizes identity before markers and can resume retirement after the replacement identity is used. Documented journal retention, redaction scope and the ordinary-writer isolation limit." +expected_result: Packages can inspect and safely retire interrupted item batches through their configured client without rebuilding private journal rules. +actual_result: "65/65 linked recovery tests and full 11540-test exact-coverage run passed; crash, peer-write, padded-identity and replacement-after-crash negative controls verified. Node and Bun packed artifact checks passed. Reviewed delivery is PR #1621; publication remains separate." dependencies[2]{id,kind,created_at,author,source_kind,author_source}: pm-9rgaal,implements,"2026-10-26T04:54:49.262Z","harness:codex","cli:create:dep",detected pm-y9hq,discovered_from,"2026-10-26T04:54:49.262Z","harness:codex","cli:create:dep",detected -comments[4]{created_at,author,text}: +comments[8]{created_at,author,text}: "2026-10-26T04:54:49.262Z","harness:codex","Duplicate check: complete strict all-status corpus plus live request-specific searches and full terminal-lineage reads found no exact active owner. Existing SDK promotion and transaction/preview delivery remain completed; this item owns the newly requested public surface." "2026-10-28T19:44:07.695Z","harness:codex","Implementation scope: retain original item plans in coordinator journals, expose read-only status and host-bound guarded abandonment/supersession, refuse committed and peer-edited work, preserve append-only compensation and audit evidence. Complete strict 3148-item all-status census has no omissions; 38 open GitHub issues each already have a canonical PM link comment. No open PRs or GitHub dependency/code/secret alerts at intake." "2026-10-28T20:16:18.094Z","harness:codex","Native late-peer recovery oracle initially exposed a delete-store gap: the existing scoped item precondition was checked by update/close but not by locked deletion. Isolated candidate adds the same assertion before deletion policy/hooks and centralizes create compensation ownership checks. Close and delete both preserve a peer edit injected immediately before item-lock acquisition. Isolated focused proof passes51 tests; original checkout remains frozen for the in-flight full coverage run. Retirement intent is additionally retained before compensation to fence forward replay across recovery crashes." "2026-10-28T20:39:10.736Z","harness:codex","Validation: linked recovery suite passed 65/65, including durable v2 retirement fencing, prepared/applied/recorded crash boundaries, interrupted compensation, audit deduplication, malformed/downgraded receipts and native peer-write races. Typecheck, ESLint, duplicate detection, registry audit and OSV passed. Full canonical coverage is running; no full-coverage success is claimed yet. First complete suite exposed contract snapshot/source-operation registration and preview clock comparison failures, now corrected; its npm package resolution failure was host NODE_PATH configuration, now explicitly set. Published 2026.10.28 verifier passed npm/npx/Bun/bunx and GitHub release checks; this does not imply publication of these branch changes." -learnings[1]{created_at,author,text}: + "2026-10-28T21:13:01.117Z","harness:codex","Review remediation: CodeRabbit correctly identified that a durable supersession retry could be permanently blocked if another commit used the chosen replacement id after a crash. The extended final-journal-write interruption regression reproduced the refusal before the fix. Replacement freshness is now checked only when starting retirement; retries retain their original intent and finish without touching the replacement. Added an assertion that plan-mismatch guidance names client.itemTransactions.abandon. Documented journal value retention outside history-redact. Release/telemetry PM observations remain in this grouped delivery because the requested scope explicitly includes these audits; they are not new claims of infrastructure remediation." + "2026-10-28T21:31:47.832Z","harness:codex","Additional crash regression: a padded transaction id was normalized by the coordinator but not by item-history markers. The extended existing prepared/applied/recorded table proved that applied and recorded attempts could retire while leaving the forward value unchanged. Normalize identity once before building any item step, unique-key index or journal. Local transport admission remains failed; a separately built unchanged base commit also fails all six transport budgets on this host, while the isolated candidate SDK import-cost gate passes. Thresholds are unchanged; exact-head hosted transport admission is required." + "2026-10-28T21:46:03.949Z","harness:codex","Hosted initial-head evidence: CI job 123098074387 on f705877b712850bb296f8c9ca519848c239d18df passed the SDK import-cost and six-operation CLI transport-floor gates with unchanged budgets. Its static failure was graph-composition prose-edge gaps 1234 > 1233, now corrected by the genuine related edge between the grouped features; local graph and record-integrity gates pass. Bounded mutation evidence is 352 classified mutants, 345 killed, 7 equivalent, no gate failures. Updated packed Node/Bun consumers and unsafe-source rejection passed. Final revised-head hosted checks remain required." + "2026-10-28T22:07:21.136Z","harness:codex","Final candidate validation: full sandboxed source coverage passed 11540 tests (3 platform skips), 880 passing files and 1 skipped file, with exact 71421/71421 statements, 55025/55025 branches, 14707/14707 functions and 67487/67487 lines. Linked recovery 65/65 and SDK/semantic-preview 49/49 passed, along with typecheck, ESLint, duplicate checks, generated contracts/surface/catalogs, docs links, graph composition and record integrity. Bounded mutation lane: 345 killed and 7 equivalent of 352, no failures. Final packed npm tarball passed Node and Bun batch/replay/retirement/replacement and unsafe-preview bootstrap controls. Local transport performance also failed unchanged base; thresholds remain unchanged and the initial PR head passed both hosted performance gates. Final revised head must pass hosted checks before merge. New APIs are not yet claimed as published." +learnings[2]{created_at,author,text}: "2026-10-28T20:16:19.379Z","harness:codex","Retiring an interrupted batch requires a durable intent before compensation, not only a terminal status afterward. Every destructive compensation must recheck ownership under the target item lock; a pre-lock history comparison alone does not protect a late peer edit." + "2026-10-28T21:55:42.128Z","harness:codex",Normalize transaction identity before building both durable effects and journal receipts. Normalizing only the coordinator key can make recovery miss its own apply markers and falsely report compensation. files[13]{path,scope}: sdk/public-surface.json,project src/core/history/operation-contract.ts,project @@ -42,7 +49,7 @@ files[13]{path,scope}: tests/unit/sdk/workspace-transaction.spec.ts,project tests[1]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts,project,300,"harness:codex","2026-10-28T19:50:40.616Z",local_mutation,feat/host-bound-item-transactions -test_runs[1]: +test_runs[2]: - run_id: test-local-mvskr61r-dyaj7d kind: test status: passed @@ -54,6 +61,19 @@ test_runs[1]: skipped: 0 executions[1]{command,requested_pm_context_mode,pm_context_mode,workspace_context_mode,trust_reason}: node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts,schema,schema,source,local_source_ref -docs[1]{path,scope}: + - run_id: test-local-mvsmrb98-86y99l + kind: test + status: passed + started_at: "2026-10-28T21:31:48.716Z" + finished_at: "2026-10-28T21:32:21.308Z" + recorded_at: "2026-10-28T21:32:21.308Z" + passed: 1 + failed: 0 + skipped: 0 + executions[1]{command,requested_pm_context_mode,pm_context_mode,workspace_context_mode,trust_reason}: + node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts,schema,schema,source,local_source_ref +docs[2]{path,scope}: + docs/generated/REFUSAL_CLOSURE_CENSUS.md,project docs/SDK.md,project +close_reason: Implementation and regression evidence complete; closure travels with the reviewed delivery. body: "" diff --git a/.agents/pm/features/pm-gh1598.toon b/.agents/pm/features/pm-gh1598.toon index b738e49315..631976b6e0 100644 --- a/.agents/pm/features/pm-gh1598.toon +++ b/.agents/pm/features/pm-gh1598.toon @@ -2,27 +2,35 @@ id: pm-gh1598 title: "GH-1598: bind batch mutation APIs to PmClient and expose canonical staged preview records" description: "GitHub https://github.com/unbraind/pm-cli/issues/1598 requests native PmClient preview/commit methods bound to host root and author policy, plus canonical staged records for idempotent intent comparison. Current staged preview validation remains shipped; its result contains validation state, constraints and warnings rather than complete staged records." type: Feature -status: in_progress +status: closed priority: 1 tags: [] created_at: "2026-10-26T04:54:51.880Z" -updated_at: "2026-10-28T20:39:13.335Z" -assignee: "harness:codex" -claim_principal: "harness:codex#568692524ccbb719c2f222a0" +updated_at: "2026-10-28T22:07:25.991Z" +closed_at: "2026-10-28T22:07:25.021Z" +completed_at: "2026-10-28T22:07:25.021Z" author: "harness:codex" estimated_minutes: 240 acceptance_criteria: "Expose typed PmClient previewItemMutations and commitItemMutations forwarding bound root and author policy to the existing SDK coordinator; Return per-mutation canonical staged ids, normalized metadata and bodies with generated-value provenance and explicit commit-time constraints; Prove preview/read-back equivalence for unchanged admitted plans and safe identical-intent replay versus typed changed-intent conflicts using native non-Git fixtures; preserve read-only previews and current guarded commit behavior" parent: pm-9rgaal risk: medium confidence: high -expected_result: Packages can perform host-bound atomic batches and compare normalized intents using SDK-owned records instead of re-deriving roots or duplicating normalization. -dependencies[2]{id,kind,created_at,author,source_kind,author_source}: +resolution: "Implemented host-bound preview and commit methods with canonical final staged records, applied/adopted state, commit-time clock pointers and explicit replay constraints. Configuration-only bootstrap protects preview/status from optional-schema FIFO reads before staging." +expected_result: Packages can use SDK-owned normalized preview records and bound identity while preserving read-only preview and replay safety. +actual_result: "49/49 linked SDK/semantic-preview tests and full 11540-test exact-coverage run passed. Native unsafe-storage negative controls, type surface and Node/Bun packed artifact passed. Reviewed delivery is PR #1621; publication remains separate." +dependencies[3]{id,kind,created_at,author,source_kind,author_source}: pm-9rgaal,implements,"2026-10-26T04:54:51.880Z","harness:codex","cli:create:dep",detected pm-gh1370,discovered_from,"2026-10-26T04:54:51.880Z","harness:codex","cli:create:dep",detected -comments[3]{created_at,author,text}: + pm-gh1597,related,"2026-10-28T21:37:27.052Z","harness:codex","cli:update:dep",detected +comments[6]{created_at,author,text}: "2026-10-26T04:54:51.880Z","harness:codex","Duplicate check: complete strict all-status corpus plus live request-specific searches and full terminal-lineage reads found no exact active owner. Existing SDK promotion and transaction/preview delivery remain completed; this item owns the newly requested public surface." "2026-10-28T19:44:10.177Z","harness:codex","Implementation scope: typed root/author-bound PmClient preview and commit; canonical full staged item snapshots per executed mutation with explicit generated clock fields. Preserve committed replay semantics and read-only staging. Group with pm-gh1597 in one reviewed delivery; no other implementation items claimed." "2026-10-28T20:39:13.335Z","harness:codex","Validation: linked SDK plus semantic-preview integration tests passed 49/49. Staged records retain canonical body, normalized tags, author and provenance with explicit clock-field pointers, final-batch state and applied/adopted execution receipts. Committed replay returns no newly validated records. Public declaration tests and SDK surface snapshot are current. Full canonical coverage is running; the earlier 197-test focused coverage diagnostic retained the full-source denominator and is not a global coverage pass." + "2026-10-28T21:08:13.590Z","harness:codex","Investigation and regression proof: the initial host wrapper activated extensions using hydrated source settings before safe preview setup. Native installed-package and isolated integration negative controls timed out on optional-schema and settings FIFOs. Configuration-only activation for preview/status fixes both before source reads; the same four unsafe-path fixtures then pass. This remains within host-bound preview ownership. The full candidate run completed 11539 passing tests with one 30-second timeout in existing literal-input coverage; no canonical coverage receipt was produced. Focused retry and hosted full coverage remain required." + "2026-10-28T21:37:28.300Z","harness:codex",Recorded the real related relationship to the grouped recovery feature. The graph-composition gate detected that this delivery relationship existed only in prose; the typed edge now represents the shared host-bound transaction surface without inventing dependency or hierarchy depth. + "2026-10-28T22:07:22.006Z","harness:codex","Final candidate validation: full sandboxed source coverage passed 11540 tests (3 platform skips), 880 passing files and 1 skipped file, with exact 71421/71421 statements, 55025/55025 branches, 14707/14707 functions and 67487/67487 lines. Linked recovery 65/65 and SDK/semantic-preview 49/49 passed, along with typecheck, ESLint, duplicate checks, generated contracts/surface/catalogs, docs links, graph composition and record integrity. Bounded mutation lane: 345 killed and 7 equivalent of 352, no failures. Final packed npm tarball passed Node and Bun batch/replay/retirement/replacement and unsafe-preview bootstrap controls. Local transport performance also failed unchanged base; thresholds remain unchanged and the initial PR head passed both hosted performance gates. Final revised head must pass hosted checks before merge. New APIs are not yet claimed as published." +learnings[1]{created_at,author,text}: + "2026-10-28T21:55:43.375Z","harness:codex","A read-only preview must protect the whole host bootstrap path, including configuration and extension setup. Staging guards alone are too late if bootstrap has already opened an optional-schema FIFO." files[6]{path,scope}: sdk/public-surface.json,project src/sdk/item-transaction.ts,project @@ -32,7 +40,7 @@ files[6]{path,scope}: tests/unit/sdk/transactions/host-bound.spec.ts,project tests[1]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts,project,300,"harness:codex","2026-10-28T19:50:42.784Z",local_mutation,feat/host-bound-item-transactions -test_runs[1]: +test_runs[2]: - run_id: test-local-mvsks2km-d73z2v kind: test status: passed @@ -44,6 +52,18 @@ test_runs[1]: skipped: 0 executions[1]{command,requested_pm_context_mode,pm_context_mode,workspace_context_mode,trust_reason}: node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts,schema,schema,source,local_source_ref + - run_id: test-local-mvsmscqj-fuogm6 + kind: test + status: passed + started_at: "2026-10-28T21:32:22.354Z" + finished_at: "2026-10-28T21:33:09.883Z" + recorded_at: "2026-10-28T21:33:09.883Z" + passed: 1 + failed: 0 + skipped: 0 + executions[1]{command,requested_pm_context_mode,pm_context_mode,workspace_context_mode,trust_reason}: + node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts,schema,schema,source,local_source_ref docs[1]{path,scope}: docs/SDK.md,project +close_reason: Implementation and regression evidence complete; closure travels with the reviewed delivery. body: "" diff --git a/.agents/pm/history/pm-gh1576.jsonl b/.agents/pm/history/pm-gh1576.jsonl index 7738b1321b..838694d79a 100644 --- a/.agents/pm/history/pm-gh1576.jsonl +++ b/.agents/pm/history/pm-gh1576.jsonl @@ -1 +1,2 @@ {"hash_algorithm":"sha256","ts":"2026-10-24T16:12:40.963Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"60c1516fbaad734506a1fc5e","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1554","lineage:pm-gh1554","lineage:pm-5t33or","lineage:pm-n7rr","lineage:pm-mpbb","lineage:pm-doxj"]},"topic":{"value":"pm-gh1554","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1554","lineage:pm-gh1554","lineage:pm-5t33or","lineage:pm-n7rr","lineage:pm-mpbb","lineage:pm-doxj"]}},"op":"create","patch":[{"op":"replace","path":"/body","value":"## Summary\n\nAgents and extensions often read an item, decide something from it (which PR delivered it, whether its acceptance criteria are met, which checkpoint to resume), and then write. Neither the SDK nor the CLI can apply that write only if the item is still the revision the decision was based on. `update`, `close`, `comments --add` and their SDK equivalents take no expected item hash or revision. A concurrent edit between the read and the write is silently built on, so the agent records a decision about state that no longer exists.\n\nThe lock-TTL fencing from #1549 makes a single mutation safe. It doesn't cover the gap between an agent's read and its later write.\n\n## Evidence (fleet packages, 2026-10-24, pm 2026.10.20–2026.10.24)\n\nRead-only reviews blocked three separate packages on this class in one day, each reproduced against the real SDK:\n\n- **pm-github closeout:** the delivering PR is chosen from the item's `delivery-pr` tag. If the tag changes from PR #1 to PR #2 while evidence is being fetched, the item still closes with PR #1's provenance. The workaround is a scoped `beforeMutation` hash guard under the item lock plus one retry. The API the agent asked for: `close(id, reason, { expectedItemHash })`.\n- **pm-rlm:** failure cleanup read a checkpoint, then saved that stale copy over a concurrent resume's answer, steps and token charges.\n- **pm-slack:** outbox retry cleanup deleted a peer drainer's newer group mappings.\n\nEach package had to hand-roll its own guard.\n\n## Reproduction (plain directory, no git)\n\n1. Agent A: `pm get --json`, records `item_hash` H1, decides to close based on the tags it read.\n2. Agent B: `pm update --tags delivery-pr:2`, so the hash is now H2.\n3. Agent A: `pm close \"Delivered by PR 1\"` succeeds. There is no way to say \"only if the hash is still H1\".\n\n## Expected\n\nAn optional precondition on every mutating command and SDK method, for example `--expect-hash ` / `{ expectedItemHash }`, checked under the item lock as part of the write. On mismatch the write is refused with a typed code (for example `stale_precondition`, exit 2). The refusal returns the current hash, plus a compact summary of which fields changed since H1, so the agent can re-decide in one call. The same option belongs on `update`, `close`, `claim`, `comments/notes/learnings --add`, `files/docs/test --add` and bulk mutations (one hash per id).\n\n## Why core\n\nRead-decide-write is the normal agent loop on a shared tracker. Without a native precondition, every package re-implements a lock-plus-hash check, and the races above ship until a reviewer finds them. This is part of making many agents on one tracker safe without git (#1516 measured the throughput side of the same workload)."},{"op":"add","path":"/metadata/id","value":"pm-gh1576"},{"op":"add","path":"/metadata/title","value":"GH-1576: guard SDK and CLI mutations with expected item revisions"},{"op":"add","path":"/metadata/description","value":"Reported read-decide-write races in extension consumers need an optional atomic expected-item-hash precondition checked at the mutation commit boundary. Preserve existing no-precondition behavior and distinguish this from mutation lease fencing."},{"op":"add","path":"/metadata/type","value":"Feature"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":1},{"op":"add","path":"/metadata/tags","value":["concurrency","gh:1576","sdk"]},{"op":"add","path":"/metadata/created_at","value":"2026-10-24T16:12:40.963Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-10-24T16:12:40.963Z"},{"op":"add","path":"/metadata/author","value":"harness:codex"},{"op":"add","path":"/metadata/estimated_minutes","value":360},{"op":"add","path":"/metadata/acceptance_criteria","value":"Define a public optional expected revision/hash contract across single-item and bulk SDK/CLI/MCP mutations; Check each precondition under the authoritative item lock at commit time and refuse stale writes without acknowledged item or history changes; Return typed current revision and bounded actionable change evidence; Deterministic concurrent controls cover closeout tags, collection cleanup, claim and bulk partial outcomes without weakening lease fencing."},{"op":"add","path":"/metadata/parent","value":"pm-9rgaal"},{"op":"add","path":"/metadata/risk","value":"medium"},{"op":"add","path":"/metadata/confidence","value":"medium"},{"op":"add","path":"/metadata/expected_result","value":"A write based on a stale observed revision refuses atomically and supplies bounded recovery evidence."},{"op":"add","path":"/metadata/dependencies","value":[{"id":"pm-a8lnoh","kind":"related","created_at":"2026-10-24T16:12:40.963Z","author":"harness:codex","source_kind":"cli:create:dep","author_source":"detected"},{"id":"pm-gh1359","kind":"related","created_at":"2026-10-24T16:12:40.963Z","author":"harness:codex","source_kind":"cli:create:dep","author_source":"detected"},{"id":"pm-gh1549","kind":"related","created_at":"2026-10-24T16:12:40.963Z","author":"harness:codex","source_kind":"cli:create:dep","author_source":"detected"}]},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-10-24T16:12:40.963Z","author":"harness:codex","text":"Intake source: https://github.com/unbraind/pm-cli/issues/1576. Duplicate check: complete strict 3098-item all-status corpus with no omissions plus fresh request-specific searches and current open/in_progress lists; no existing owner matches this distinct acceptance. Full live related lineage was read. Existing delivered lease-fencing/focus behavior remains historically closed. This report is planning evidence; no current independent reproduction or fix is claimed. Queued open and unclaimed under the SDK outcome milestone."}]}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"8f27347e5d82f02c863ed09d82bdce383a6aaad65a24e7748ecb0d7747f7a6a3","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":"788fc0462d41421d16893a52ad257a4261021de5ef491c8ff1f7f2f4993de0cd"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:03:09.177Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-10-28T22:03:09.177Z","author":"harness:codex","text":"Additional consumer report: https://github.com/unbraind/pm-cli/issues/1620 (2026-10-28). Its proposed option 2 is the existing expected-revision acceptance here, so reuse this canonical feature instead of creating duplicate work. Reporter describes a separate-process ordinary SDK writer entering between a transaction inspect and apply, losing title/parent/relation/assignee changes. Current source uses WORKSPACE_TRANSACTION_LOCK_ID for the coordinator while item writes take their own lock; the report is consistent with those distinct scopes, but this intake has not independently executed its probe. Include precise transaction-isolation documentation and a native concurrent-writer negative control in this feature. The host-bound recovery delivery only guards compensation ownership; it does not claim general read-decide-write isolation. Item remains open and unclaimed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:03:09.177Z"}],"before_hash":"8f27347e5d82f02c863ed09d82bdce383a6aaad65a24e7748ecb0d7747f7a6a3","after_hash":"c672d7ba8387d6f84cefa8042c0f014e6adab9abc0cd51bfdcc99be6ae0346dd","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":"146d7513800b142fdc595da4094ac25b5aa4c698a27b0c6710a0d59c021fa237"} diff --git a/.agents/pm/history/pm-gh1597.jsonl b/.agents/pm/history/pm-gh1597.jsonl index aeda1e243e..cb54534421 100644 --- a/.agents/pm/history/pm-gh1597.jsonl +++ b/.agents/pm/history/pm-gh1597.jsonl @@ -11,3 +11,12 @@ {"hash_algorithm":"sha256","ts":"2026-10-28T20:35:46.067Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/8/path","value":"src/sdk/workspace-transaction.ts"},{"op":"replace","path":"/metadata/files/7/path","value":"src/sdk/workspace-transaction-gc.ts"},{"op":"replace","path":"/metadata/files/6/path","value":"src/sdk/runtime.ts"},{"op":"replace","path":"/metadata/files/5/path","value":"src/sdk/item-transaction.ts"},{"op":"replace","path":"/metadata/files/4/path","value":"src/sdk/generated/generated-error-code-catalog-part-2.ts"},{"op":"replace","path":"/metadata/files/3/path","value":"src/sdk/generated/generated-error-code-catalog-part-1.ts"},{"op":"add","path":"/metadata/files/9","value":{"path":"tests/fixtures/contracts/full.json","scope":"project"}},{"op":"add","path":"/metadata/files/10","value":{"path":"tests/types/item-transactions.test-d.ts","scope":"project"}},{"op":"add","path":"/metadata/files/11","value":{"path":"tests/unit/sdk/transactions/host-bound.spec.ts","scope":"project"}},{"op":"add","path":"/metadata/files/12","value":{"path":"tests/unit/sdk/workspace-transaction.spec.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:35:46.067Z"}],"before_hash":"f0e0b786715bba616631035860082758cd04a93cbf8eddcf20bcd0eedad5bd8a","after_hash":"9d701c90f4b02aff035aed8378df17fa97b339b013c8c0e6ec6f9439d0e6939b","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":"6e056500113f56325b4c88fa96e787fb4f2ad938cddff2bc8e98c9aa48267b1a"} {"hash_algorithm":"sha256","ts":"2026-10-28T20:36:15.343Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:36:15.343Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-mvskr61r-dyaj7d","kind":"test","status":"passed","started_at":"2026-10-28T20:35:47.020Z","finished_at":"2026-10-28T20:36:15.327Z","recorded_at":"2026-10-28T20:36:15.327Z","passed":1,"failed":0,"skipped":0,"executions":[{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts","requested_pm_context_mode":"schema","pm_context_mode":"schema","workspace_context_mode":"source","trust_reason":"local_source_ref"}]}]}],"before_hash":"9d701c90f4b02aff035aed8378df17fa97b339b013c8c0e6ec6f9439d0e6939b","after_hash":"48acbaee158a5a2e01b8da793d553012ca967784e9e5ff9e7eca72f8e84d292f","item_hash_version":3,"message":"Track test run summary (test-local-mvskr61r-dyaj7d)","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":"d0d5a9fbb40659a9fbe6d4fc76e0523dd0322bf4b891efa2b140981259579223"} {"hash_algorithm":"sha256","ts":"2026-10-28T20:39:10.736Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-10-28T20:39:10.736Z","author":"harness:codex","text":"Validation: linked recovery suite passed 65/65, including durable v2 retirement fencing, prepared/applied/recorded crash boundaries, interrupted compensation, audit deduplication, malformed/downgraded receipts and native peer-write races. Typecheck, ESLint, duplicate detection, registry audit and OSV passed. Full canonical coverage is running; no full-coverage success is claimed yet. First complete suite exposed contract snapshot/source-operation registration and preview clock comparison failures, now corrected; its npm package resolution failure was host NODE_PATH configuration, now explicitly set. Published 2026.10.28 verifier passed npm/npx/Bun/bunx and GitHub release checks; this does not imply publication of these branch changes."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:39:10.736Z"}],"before_hash":"48acbaee158a5a2e01b8da793d553012ca967784e9e5ff9e7eca72f8e84d292f","after_hash":"8cc9b01c88ff15c9eee1a38f8310014037f517f2f6d5091f1cb78c3ca29755ae","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":"1789ed8f2a051adb23bba8debbfc15159bbc5ca71ab25751cf319ee9eecc1b12"} +{"hash_algorithm":"sha256","ts":"2026-10-28T21:13:01.117Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/4","value":{"created_at":"2026-10-28T21:13:01.117Z","author":"harness:codex","text":"Review remediation: CodeRabbit correctly identified that a durable supersession retry could be permanently blocked if another commit used the chosen replacement id after a crash. The extended final-journal-write interruption regression reproduced the refusal before the fix. Replacement freshness is now checked only when starting retirement; retries retain their original intent and finish without touching the replacement. Added an assertion that plan-mismatch guidance names client.itemTransactions.abandon. Documented journal value retention outside history-redact. Release/telemetry PM observations remain in this grouped delivery because the requested scope explicitly includes these audits; they are not new claims of infrastructure remediation."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T21:13:01.117Z"}],"before_hash":"8cc9b01c88ff15c9eee1a38f8310014037f517f2f6d5091f1cb78c3ca29755ae","after_hash":"8f94b47e0c8d5d17df88d713acf422eb1585b2a7444ff91b1bcc667e11802b2b","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":"907614ff687be326dc210f7e24194f706e0e8523152dc8be0bee2aed39e2e35a"} +{"hash_algorithm":"sha256","ts":"2026-10-28T21:31:47.006Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/0/path","value":"docs/generated/REFUSAL_CLOSURE_CENSUS.md"},{"op":"add","path":"/metadata/docs/1","value":{"path":"docs/SDK.md","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T21:31:47.006Z"}],"before_hash":"8f94b47e0c8d5d17df88d713acf422eb1585b2a7444ff91b1bcc667e11802b2b","after_hash":"abc0b65dffa66f85586af7b171f6bb99008ab38cbdc18a2400b7a31e009bc3f1","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":"4f9dd77e4e0298f8dbccdb734852b6d336cd6d7c4a6f69755de344c55902deef"} +{"hash_algorithm":"sha256","ts":"2026-10-28T21:31:47.832Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/5","value":{"created_at":"2026-10-28T21:31:47.832Z","author":"harness:codex","text":"Additional crash regression: a padded transaction id was normalized by the coordinator but not by item-history markers. The extended existing prepared/applied/recorded table proved that applied and recorded attempts could retire while leaving the forward value unchanged. Normalize identity once before building any item step, unique-key index or journal. Local transport admission remains failed; a separately built unchanged base commit also fails all six transport budgets on this host, while the isolated candidate SDK import-cost gate passes. Thresholds are unchanged; exact-head hosted transport admission is required."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T21:31:47.832Z"}],"before_hash":"abc0b65dffa66f85586af7b171f6bb99008ab38cbdc18a2400b7a31e009bc3f1","after_hash":"0cf5dff8b5e4d0c9eabb59182d31343cda453cafed8de5a8f0a9f61554e40655","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":"fb91d622f2f2078b65d3644403dac94d714d92271b1dd92d07afb4e72000f54c"} +{"hash_algorithm":"sha256","ts":"2026-10-28T21:32:21.317Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"test_run_track","patch":[{"op":"add","path":"/metadata/test_runs/1","value":{"run_id":"test-local-mvsmrb98-86y99l","kind":"test","status":"passed","started_at":"2026-10-28T21:31:48.716Z","finished_at":"2026-10-28T21:32:21.308Z","recorded_at":"2026-10-28T21:32:21.308Z","passed":1,"failed":0,"skipped":0,"executions":[{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts","requested_pm_context_mode":"schema","pm_context_mode":"schema","workspace_context_mode":"source","trust_reason":"local_source_ref"}]}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T21:32:21.317Z"}],"before_hash":"0cf5dff8b5e4d0c9eabb59182d31343cda453cafed8de5a8f0a9f61554e40655","after_hash":"7cb5cefb46910391ffb3ba981d5ab1cb57d8bb0d7eb58e532bde4fc46d95bd8e","item_hash_version":3,"message":"Track test run summary (test-local-mvsmrb98-86y99l)","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":"f24cc34436114224a0d8a1783f100b8a28c0b27ad5834924d3540d998d945850"} +{"hash_algorithm":"sha256","ts":"2026-10-28T21:46:03.949Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/6","value":{"created_at":"2026-10-28T21:46:03.949Z","author":"harness:codex","text":"Hosted initial-head evidence: CI job 123098074387 on f705877b712850bb296f8c9ca519848c239d18df passed the SDK import-cost and six-operation CLI transport-floor gates with unchanged budgets. Its static failure was graph-composition prose-edge gaps 1234 > 1233, now corrected by the genuine related edge between the grouped features; local graph and record-integrity gates pass. Bounded mutation evidence is 352 classified mutants, 345 killed, 7 equivalent, no gate failures. Updated packed Node/Bun consumers and unsafe-source rejection passed. Final revised-head hosted checks remain required."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T21:46:03.949Z"}],"before_hash":"7cb5cefb46910391ffb3ba981d5ab1cb57d8bb0d7eb58e532bde4fc46d95bd8e","after_hash":"66f3963286d3fc2a024422555d86c036f2ba935446e73c055368682f61399c32","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":"909c9869b75eaa3d085cf85ed8be381ea6909fbb232465535f592acfe7536df9"} +{"hash_algorithm":"sha256","ts":"2026-10-28T21:55:42.128Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"learning_add","patch":[{"op":"add","path":"/metadata/learnings/1","value":{"created_at":"2026-10-28T21:55:42.128Z","author":"harness:codex","text":"Normalize transaction identity before building both durable effects and journal receipts. Normalizing only the coordinator key can make recovery miss its own apply markers and falsely report compensation."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T21:55:42.128Z"}],"before_hash":"66f3963286d3fc2a024422555d86c036f2ba935446e73c055368682f61399c32","after_hash":"4b86dcc7caa815c500e30225522d58424773c10b171b15c453b1c4a4f062a5c6","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":"cc888e29874d5cedd82d26f019c616ad07b0bbe3d3f32b4b0713fa7dcebfd20b"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:07:21.136Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/7","value":{"created_at":"2026-10-28T22:07:21.136Z","author":"harness:codex","text":"Final candidate validation: full sandboxed source coverage passed 11540 tests (3 platform skips), 880 passing files and 1 skipped file, with exact 71421/71421 statements, 55025/55025 branches, 14707/14707 functions and 67487/67487 lines. Linked recovery 65/65 and SDK/semantic-preview 49/49 passed, along with typecheck, ESLint, duplicate checks, generated contracts/surface/catalogs, docs links, graph composition and record integrity. Bounded mutation lane: 345 killed and 7 equivalent of 352, no failures. Final packed npm tarball passed Node and Bun batch/replay/retirement/replacement and unsafe-preview bootstrap controls. Local transport performance also failed unchanged base; thresholds remain unchanged and the initial PR head passed both hosted performance gates. Final revised head must pass hosted checks before merge. New APIs are not yet claimed as published."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:07:21.136Z"}],"before_hash":"4b86dcc7caa815c500e30225522d58424773c10b171b15c453b1c4a4f062a5c6","after_hash":"a3b0f2401f1d70f161b5efbaf893ae8eca41909809252de03a09435486d8cdb4","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":"192a0018760e7d507682ea6bfd37f3d971a4d05a9070dda50f80a142a20b9263"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:07:22.979Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"close","patch":[{"op":"replace","path":"/metadata/expected_result","value":"Packages can inspect and safely retire interrupted item batches through their configured client without rebuilding private journal rules."},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:07:22.979Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-10-28T22:07:22.951Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-10-28T22:07:22.951Z"},{"op":"add","path":"/metadata/resolution","value":"Implemented bound status, abandon and supersede APIs with retained original plans, versioned durable retirement intent, idempotent audit and guarded compensation that preserves peer edits. Recovery normalizes identity before markers and can resume retirement after the replacement identity is used. Documented journal retention, redaction scope and the ordinary-writer isolation limit."},{"op":"add","path":"/metadata/actual_result","value":"65/65 linked recovery tests and full 11540-test exact-coverage run passed; crash, peer-write, padded-identity and replacement-after-crash negative controls verified. Node and Bun packed artifact checks passed. Reviewed delivery is PR #1621; publication remains separate."},{"op":"add","path":"/metadata/close_reason","value":"Implementation and regression evidence complete; closure travels with the reviewed delivery."}],"before_hash":"a3b0f2401f1d70f161b5efbaf893ae8eca41909809252de03a09435486d8cdb4","after_hash":"327a1b120d9c1299b940391186a9d43958c1a3be78e51e49857d2db877d1d65b","item_hash_version":3,"context":{"completion":{"timestamp":"2026-10-28T22:07:22.951Z","source":"close_time"},"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":"80d0cb899ca870958b5ad36e8ca6395eb3cf7bbbf0aee89f81b3313a049645a8"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:07:24.128Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:07:24.128Z"}],"before_hash":"327a1b120d9c1299b940391186a9d43958c1a3be78e51e49857d2db877d1d65b","after_hash":"2bcad58dfdef882a00065e3a8a0606d24f0e86f0aaa3dd5d81b9ddded4785165","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":"ddf08040175df14609d51497891c420c21eb876b52f019ee0aefed52b866e9e4"} diff --git a/.agents/pm/history/pm-gh1598.jsonl b/.agents/pm/history/pm-gh1598.jsonl index 8c1bb74586..508444d520 100644 --- a/.agents/pm/history/pm-gh1598.jsonl +++ b/.agents/pm/history/pm-gh1598.jsonl @@ -8,3 +8,11 @@ {"hash_algorithm":"sha256","ts":"2026-10-28T20:24:19.918Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/2/path","value":"src/sdk/runtime.ts"},{"op":"replace","path":"/metadata/files/1/path","value":"src/sdk/item-transaction.ts"},{"op":"replace","path":"/metadata/files/0/path","value":"sdk/public-surface.json"},{"op":"add","path":"/metadata/files/3","value":{"path":"tests/integration/transactions/semantic-preview.integration.spec.ts","scope":"project"}},{"op":"add","path":"/metadata/files/4","value":{"path":"tests/types/item-transactions.test-d.ts","scope":"project"}},{"op":"add","path":"/metadata/files/5","value":{"path":"tests/unit/sdk/transactions/host-bound.spec.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:24:19.918Z"}],"before_hash":"aea599ec74907165cbf67204440357a86c5fc9075973f90789314a88c86544fc","after_hash":"a6a5a51d62e425bb7de495ddf79b8909ab8185b4c4a999a637927e9a47227f3f","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":"e78efe450a11fe7f58774debbd986e4d047510ba9d3c41b5f931de2b328c25e5"} {"hash_algorithm":"sha256","ts":"2026-10-28T20:36:57.485Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:36:57.485Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-mvsks2km-d73z2v","kind":"test","status":"passed","started_at":"2026-10-28T20:36:16.186Z","finished_at":"2026-10-28T20:36:57.477Z","recorded_at":"2026-10-28T20:36:57.477Z","passed":1,"failed":0,"skipped":0,"executions":[{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts","requested_pm_context_mode":"schema","pm_context_mode":"schema","workspace_context_mode":"source","trust_reason":"local_source_ref"}]}]}],"before_hash":"a6a5a51d62e425bb7de495ddf79b8909ab8185b4c4a999a637927e9a47227f3f","after_hash":"4f5ca69d399c18123c43a5a7351e822e5dcffe3d3cb3849f067ef63497580abf","item_hash_version":3,"message":"Track test run summary (test-local-mvsks2km-d73z2v)","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":"7b05ad4ca46e444b77effb1d29ffd110143f0b2ef8a7e5c8d52179520dd8d8b2"} {"hash_algorithm":"sha256","ts":"2026-10-28T20:39:13.335Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-10-28T20:39:13.335Z","author":"harness:codex","text":"Validation: linked SDK plus semantic-preview integration tests passed 49/49. Staged records retain canonical body, normalized tags, author and provenance with explicit clock-field pointers, final-batch state and applied/adopted execution receipts. Committed replay returns no newly validated records. Public declaration tests and SDK surface snapshot are current. Full canonical coverage is running; the earlier 197-test focused coverage diagnostic retained the full-source denominator and is not a global coverage pass."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:39:13.335Z"}],"before_hash":"4f5ca69d399c18123c43a5a7351e822e5dcffe3d3cb3849f067ef63497580abf","after_hash":"9df2102b70803aef37d8ad41c66b64cc48509d1861f196d9146a57f44d6a576f","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":"e9032bac56becfa855e5e9fe38e1a755375217855098f8831d36e0bac8d5e773"} +{"hash_algorithm":"sha256","ts":"2026-10-28T21:08:13.591Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-10-28T21:08:13.590Z","author":"harness:codex","text":"Investigation and regression proof: the initial host wrapper activated extensions using hydrated source settings before safe preview setup. Native installed-package and isolated integration negative controls timed out on optional-schema and settings FIFOs. Configuration-only activation for preview/status fixes both before source reads; the same four unsafe-path fixtures then pass. This remains within host-bound preview ownership. The full candidate run completed 11539 passing tests with one 30-second timeout in existing literal-input coverage; no canonical coverage receipt was produced. Focused retry and hosted full coverage remain required."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T21:08:13.591Z"}],"before_hash":"9df2102b70803aef37d8ad41c66b64cc48509d1861f196d9146a57f44d6a576f","after_hash":"578b7180dc4590138b4f2749dc3261ff26bf5a78a506121feea1b1896fdbb76f","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":"1801e671954e1f23041953c9f8032ee4dbaa55b81f5b8108ac0938eee7916f00"} +{"hash_algorithm":"sha256","ts":"2026-10-28T21:33:09.893Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"test_run_track","patch":[{"op":"add","path":"/metadata/test_runs/1","value":{"run_id":"test-local-mvsmscqj-fuogm6","kind":"test","status":"passed","started_at":"2026-10-28T21:32:22.354Z","finished_at":"2026-10-28T21:33:09.883Z","recorded_at":"2026-10-28T21:33:09.883Z","passed":1,"failed":0,"skipped":0,"executions":[{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts","requested_pm_context_mode":"schema","pm_context_mode":"schema","workspace_context_mode":"source","trust_reason":"local_source_ref"}]}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T21:33:09.893Z"}],"before_hash":"578b7180dc4590138b4f2749dc3261ff26bf5a78a506121feea1b1896fdbb76f","after_hash":"b4021612dbd652165c94bd00b9a68a527d18e7e0b823e94defe5b4ed8c0646dc","item_hash_version":3,"message":"Track test run summary (test-local-mvsmscqj-fuogm6)","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":"daa2e64e0fea436fe03693376a3507fb41f80718f4747533da4b9ed7466f4368"} +{"hash_algorithm":"sha256","ts":"2026-10-28T21:37:27.429Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"update","patch":[{"op":"add","path":"/metadata/dependencies/2","value":{"id":"pm-gh1597","kind":"related","created_at":"2026-10-28T21:37:27.052Z","author":"harness:codex","source_kind":"cli:update:dep","author_source":"detected"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T21:37:27.429Z"}],"before_hash":"b4021612dbd652165c94bd00b9a68a527d18e7e0b823e94defe5b4ed8c0646dc","after_hash":"82d577fbf2a30d863f734135693856cefb90ddfee3224516acf2bc351e250511","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":"f3913a1a513a6b52ca2f15ddb8a6d0a160280c37a0e2aba31f74c1c67179b0d8"} +{"hash_algorithm":"sha256","ts":"2026-10-28T21:37:28.301Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/4","value":{"created_at":"2026-10-28T21:37:28.300Z","author":"harness:codex","text":"Recorded the real related relationship to the grouped recovery feature. The graph-composition gate detected that this delivery relationship existed only in prose; the typed edge now represents the shared host-bound transaction surface without inventing dependency or hierarchy depth."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T21:37:28.301Z"}],"before_hash":"82d577fbf2a30d863f734135693856cefb90ddfee3224516acf2bc351e250511","after_hash":"73ccd4311f7d63e7354f128791f945bc8bd6bd4599c8b069229e4fb9eeb3c81b","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":"b89734103f3b65ec4a6f78414a371922fdc2c4e0d395d248c0052e1dd689f918"} +{"hash_algorithm":"sha256","ts":"2026-10-28T21:55:43.376Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"learning_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T21:55:43.376Z"},{"op":"add","path":"/metadata/learnings","value":[{"created_at":"2026-10-28T21:55:43.375Z","author":"harness:codex","text":"A read-only preview must protect the whole host bootstrap path, including configuration and extension setup. Staging guards alone are too late if bootstrap has already opened an optional-schema FIFO."}]}],"before_hash":"73ccd4311f7d63e7354f128791f945bc8bd6bd4599c8b069229e4fb9eeb3c81b","after_hash":"4a27cd36289577bfee3c89157d2a2d99d58f4f84e0b3cf4ae5b09695327e68b7","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":"d9b78329cd665cea2cbc2894739cff0224c01405d862cd9c271d943bda5459a7"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:07:22.006Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/5","value":{"created_at":"2026-10-28T22:07:22.006Z","author":"harness:codex","text":"Final candidate validation: full sandboxed source coverage passed 11540 tests (3 platform skips), 880 passing files and 1 skipped file, with exact 71421/71421 statements, 55025/55025 branches, 14707/14707 functions and 67487/67487 lines. Linked recovery 65/65 and SDK/semantic-preview 49/49 passed, along with typecheck, ESLint, duplicate checks, generated contracts/surface/catalogs, docs links, graph composition and record integrity. Bounded mutation lane: 345 killed and 7 equivalent of 352, no failures. Final packed npm tarball passed Node and Bun batch/replay/retirement/replacement and unsafe-preview bootstrap controls. Local transport performance also failed unchanged base; thresholds remain unchanged and the initial PR head passed both hosted performance gates. Final revised head must pass hosted checks before merge. New APIs are not yet claimed as published."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:07:22.006Z"}],"before_hash":"4a27cd36289577bfee3c89157d2a2d99d58f4f84e0b3cf4ae5b09695327e68b7","after_hash":"90444480833a3bef07493c8a63930ce369e3eda69bf8afac86fe6daf70524227","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":"3586366a7baf07d05c01160e95241e83a7a61f075a979fdf19cc7ec640ed8164"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:07:25.052Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"release-operator","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]},"topic":{"value":"pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]}},"op":"close","patch":[{"op":"replace","path":"/metadata/expected_result","value":"Packages can use SDK-owned normalized preview records and bound identity while preserving read-only preview and replay safety."},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:07:25.052Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-10-28T22:07:25.021Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-10-28T22:07:25.021Z"},{"op":"add","path":"/metadata/resolution","value":"Implemented host-bound preview and commit methods with canonical final staged records, applied/adopted state, commit-time clock pointers and explicit replay constraints. Configuration-only bootstrap protects preview/status from optional-schema FIFO reads before staging."},{"op":"add","path":"/metadata/actual_result","value":"49/49 linked SDK/semantic-preview tests and full 11540-test exact-coverage run passed. Native unsafe-storage negative controls, type surface and Node/Bun packed artifact passed. Reviewed delivery is PR #1621; publication remains separate."},{"op":"add","path":"/metadata/close_reason","value":"Implementation and regression evidence complete; closure travels with the reviewed delivery."}],"before_hash":"90444480833a3bef07493c8a63930ce369e3eda69bf8afac86fe6daf70524227","after_hash":"abcaa5f8dc4695f7c4328239fd75389dc106ba2a940b287c4bdb629849346163","item_hash_version":3,"context":{"completion":{"timestamp":"2026-10-28T22:07:25.021Z","source":"close_time"},"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":"e75bcca6a77e76fee83bc466744ebb5f3e2ee2c6b231c741ed63e259797a7598"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:07:25.991Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"release-operator","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]},"topic":{"value":"pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:07:25.991Z"}],"before_hash":"abcaa5f8dc4695f7c4328239fd75389dc106ba2a940b287c4bdb629849346163","after_hash":"e8f41c540cc2c192f998100df5b6578951f0ff3ebf9f29546e3e88d1c530a788","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":"b6787d67cc3297565b43a41c47ecdb32fe6b27cd64a78a6672dcd932e29c14b2"} diff --git a/.agents/pm/history/pm-prrlce.jsonl b/.agents/pm/history/pm-prrlce.jsonl index 0f4ee02595..404229200a 100644 --- a/.agents/pm/history/pm-prrlce.jsonl +++ b/.agents/pm/history/pm-prrlce.jsonl @@ -175,3 +175,4 @@ {"hash_algorithm":"sha256","ts":"2026-10-26T22:08:14.067Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"7efbcd86a29946bbfe9221c3","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1604","claim:pm-gh1605","claim:pm-gh1607","lineage:pm-gh1607","lineage:pm-f05lsg","lineage:pm-mpbb","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1604+pm-gh1605+pm-gh1607","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1604","claim:pm-gh1605","claim:pm-gh1607","lineage:pm-gh1607","lineage:pm-f05lsg","lineage:pm-mpbb","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/76","value":{"created_at":"2026-10-26T22:08:14.067Z","author":"harness:codex","text":"Live 2026-10-26 reliability artifact40404782722 inspected independently of candidate CI: release series has30 original completed attempts,3 original failures and only dispatch_window policy finding. Morning dispatcher series has21 attempts with12 publications and9 retained original failures. Public release2026.10.26 passes the shared verifier including npm/npx/bunx; exactly one currentUTC-day tag is published. Native cron02:35UTC, hosted concurrency and immutable-day guard remain configured. This evidence does not clear historical timing findings or claim a second automatic release. No release is dispatched by this continuation."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-26T22:08:14.067Z"}],"before_hash":"9ddc5ae83d5dce2afc3de59ff7c86f45b4d3871dacfbd9754d751452c299ae65","after_hash":"b5fd6dee53a3a0a0b1809e8ec14a279c39b070c86dc0386a4577cf88e34e299e","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":"7e2b107093ea312805dbfbafaf055cd3595cd236cb973f326e8e54e319aa62c8"} {"hash_algorithm":"sha256","ts":"2026-10-27T22:23:17.371Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"525eee5e83a0bb4065087287","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"xhigh","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1606","claim:pm-gh1614","lineage:pm-gh1606","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1606+pm-gh1614","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1606","claim:pm-gh1614","lineage:pm-gh1606","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/77","value":{"created_at":"2026-10-27T22:23:17.370Z","author":"harness:codex","text":"Live October27 Release Reliability40592007740 has a complete census:30 completed original release attempts,3 original failures, and only dispatch_window violated. Latest native Auto Release40472638505 confirms immutable v2026.10.27 and npm publication before preparation, without a second cut. Five recent native schedule runs are successful. The independent release-ledger report is ok. Preserve original history and daily concurrency/day identity; no additional release dispatch or threshold change is performed by this SDK delivery."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-27T22:23:17.371Z"}],"before_hash":"b5fd6dee53a3a0a0b1809e8ec14a279c39b070c86dc0386a4577cf88e34e299e","after_hash":"2aacd3d0abf7c8adbba9873e12ba90444b0b991e86233a0167a8e5130c0cb1d0","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":"6822f40024b5f913f4b38e7a88d52deceff1cbce94f559462172b9065a6a27e4"} {"hash_algorithm":"sha256","ts":"2026-10-28T19:51:07.895Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/78","value":{"created_at":"2026-10-28T19:51:07.895Z","author":"harness:codex","text":"October28 independent artifact40744854788: complete release outcome census and passing release-ledger report; rolling scheduled reliability still fails only dispatch_window. Current npm/latest and GitHub release are2026.10.28. Preserve the one-automatic-release-per-UTC-day guard; no extra release or threshold change is justified by this SDK batch."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T19:51:07.895Z"}],"before_hash":"2aacd3d0abf7c8adbba9873e12ba90444b0b991e86233a0167a8e5130c0cb1d0","after_hash":"af501630af9d7bdfce3c392dae2262e6de162af509d9e47b36acd02a4caef09b","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":"dffe24e3dacf5749f07d7e846e9bdc93e3eccfb35f2f18c64d83485bed50dc1e"} +{"hash_algorithm":"sha256","ts":"2026-10-28T20:51:37.199Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/79","value":{"created_at":"2026-10-28T20:51:37.199Z","author":"harness:codex","text":"Current-day publication verification: verify-published-release.mjs --version 2026.10.28 passed the registry/package, npx/Bun/bunx and GitHub Release checks. Native scheduled run 40660287046 explicitly selected existing tag v2026.10.28, required successful immutable publisher run 40631211289, verified npm and GitHub publication at b5241ced02ad3cf6a83b684db4f186ebf8c51397, and skipped preparation rather than publishing a second automatic release. This proves the same-day guard and current artifact availability, not remediation of the separately reported dispatch_window timing debt."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:51:37.199Z"}],"before_hash":"af501630af9d7bdfce3c392dae2262e6de162af509d9e47b36acd02a4caef09b","after_hash":"95277bad30c6bacd54c7aa9acf8563cc6e1abe4ad0655d56ec1a6c56a3ea6775","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":"2622d051b2934be9ee6f44643ce795890b7e216394baa1d512b1e1d38d3bfb04"} diff --git a/.agents/pm/history/pm-xq09zu.jsonl b/.agents/pm/history/pm-xq09zu.jsonl index 1d1ea8bfca..cef410ae2c 100644 --- a/.agents/pm/history/pm-xq09zu.jsonl +++ b/.agents/pm/history/pm-xq09zu.jsonl @@ -25,3 +25,4 @@ {"hash_algorithm":"sha256","ts":"2026-10-28T16:25:11.915Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"738f7d9b84aae278517b105a","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1603","claim:pm-gh1617","lineage:pm-gh1603","lineage:pm-mpbb","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1603+pm-gh1617","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1603","claim:pm-gh1617","lineage:pm-gh1603","lineage:pm-mpbb","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/15","value":{"created_at":"2026-10-28T16:25:11.915Z","author":"harness:codex","text":"Review correction: the independently quoted counts 35,947 / 594,304 equal 6.0486%, rounded 6.05%; the previous 6.03% label was incorrect. This correction does not change the separately sampled 6.04% gate verdict or its unchanged 6% threshold. The aggregate issue remains open."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T16:25:11.915Z"}],"before_hash":"22e92fc2024ff5957a9657c157fb0075c38df06a6161c8adb0f4f2daf8de0e48","after_hash":"6c4eeca25c8445d08cca616ac0ae5f4efc619333638f0598a3f0813cf8e85431","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":"5e974082f7311ee03aec6e693a8f02feab86818058763a121b96e4bc2918521d"} {"hash_algorithm":"sha256","ts":"2026-10-28T17:20:25.176Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"738f7d9b84aae278517b105a","agent_provenance":{"model":{"value":"gpt-6-astra","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-28T17:20:25.175Z","author":"harness:codex","text":"Post-change delivery probe at 2026-10-28 17:19 UTC: context command_start and successful command_finish were both persisted independently in the remote telemetry database with 0.855s and 0.709s ingestion lag. SDK flush completed and the remote queue had zero ready/unacknowledged messages. These current delivery facts do not clear the separately reported aggregate error-rate and historical pairing limitations."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T17:20:25.176Z"}],"before_hash":"6c4eeca25c8445d08cca616ac0ae5f4efc619333638f0598a3f0813cf8e85431","after_hash":"d72befc1af2d0f3f2cfe3013a4fd342bf1182bd9c3010b1bd66d0242a523306a","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":"93798229f6700cf376bec66321d0de5a46191f9aeddee58c4aba66485419c921"} {"hash_algorithm":"sha256","ts":"2026-10-28T20:02:08.312Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/17","value":{"created_at":"2026-10-28T20:02:08.311Z","author":"harness:codex","text":"Current live required-mode Sentry/telemetry gate passes: no blocking Sentry issues; rolling weighted telemetry finish error rate5.94% against unchanged6% threshold; zero failures missing error codes. A new pm.command context span is visible. A separate10-minute context sample has6 paired sessions and1 unmatched session, with maximum observed ingestion lag4.144seconds. This passing threshold does not resolve historical pairing debt or certify every action."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:02:08.312Z"}],"before_hash":"d72befc1af2d0f3f2cfe3013a4fd342bf1182bd9c3010b1bd66d0242a523306a","after_hash":"bed78dd29e2f04bc26051a63159fa83abe30414b15a03cfdeeb629cedbeefec6","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":"a054f7a63aae52f5d61d71c1ed59c54dc980859c736c692a48e418ce4f97d44e"} +{"hash_algorithm":"sha256","ts":"2026-10-28T20:55:00.034Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/18","value":{"created_at":"2026-10-28T20:55:00.033Z","author":"harness:codex","text":"Current bounded observability evidence: zero unresolved Sentry issues; a recent remote context/automation sample has 6 sessions, 6 matched start/finish pairs, zero unmatched and maximum ingestion lag 2.395836 seconds. Physical broker queue was 0 messages / 0 ready / 0 unacknowledged. A broader recent interval had 313 automation starts and finishes with lag <=5.831581 seconds; the 163-second outlier was explicitly source_context=test, so it is not attributed to user-command ingestion. These samples and the passing 5.94 percent weighted-error gate do not prove complete historical pairing or remove this existing debt."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T20:55:00.034Z"}],"before_hash":"bed78dd29e2f04bc26051a63159fa83abe30414b15a03cfdeeb629cedbeefec6","after_hash":"dd1487dc52ee9079a31cc933c82b7b51469434b61afc64e2fbea69207e5b04ff","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":"32076104fa668e59801e55b7ad28c174311186bcb9fc75c0e5560772167ded07"} diff --git a/.agents/pm/issues/pm-prrlce.toon b/.agents/pm/issues/pm-prrlce.toon index 3df8ba5384..f7cbd337e7 100644 --- a/.agents/pm/issues/pm-prrlce.toon +++ b/.agents/pm/issues/pm-prrlce.toon @@ -6,7 +6,7 @@ status: open priority: 1 tags[4]: "area:release",automation,diagnostics,"horizon:current" created_at: "2026-09-28T15:31:49.498Z" -updated_at: "2026-10-28T19:51:07.895Z" +updated_at: "2026-10-28T20:51:37.199Z" author: "harness:claude-code" estimated_minutes: 300 acceptance_criteria: "Every Auto Release and Release run carries an explicit trigger origin (native schedule, morning dispatcher, blocker retry, operator) from a declared input and its run name, never inferred from event or actor; Release reliability reports a separate series per origin, including the dispatcher's attempts, failures and failing stages, while the native scheduled denominator stays unchanged as decided on pm-9url9h; The same-day manual follow-up of pm-uenmu9 requires an explicit follow-up request from the operator origin; negative control: a dispatcher-origin run after a same-day tag exists skips before any version mutation; The 2026-09-28 dispatcher failure is visible in the new series or recorded as an explicit pre-attribution gap" @@ -24,7 +24,7 @@ dependencies[6]{id,kind,created_at,author,source_kind,author_source}: pm-z329kd,discovered_from,"2026-09-28T15:41:04.958Z","harness:claude-code","cli:update:dep",detected pm-uenmu9,discovered_from,"2026-09-29T09:47:31.174Z","harness:codex","cli:update:dep",detected pm-0trehk,related,"2026-10-24T16:33:36.972Z","harness:codex","cli:update:dep",detected -comments[79]{created_at,author,text}: +comments[80]{created_at,author,text}: "2026-09-29T10:00:31.279Z","harness:codex","Implemented declared Auto Release origin in workflow run names and attempt receipts; morning dispatcher now passes its own origin. Reliability collection includes schedule, dispatch, and issue runs while keeping the native scheduled policy denominator intact; the dispatcher has a separate count, failure rate, stage series, and historical unattributed-run gap. New same-day dispatcher runs take the early immutable-tag guard. Release exact-tag dispatch carries origin; tag-push runs retain tag_push provenance. Linked tests passed (72), full coverage passed 9,428 tests at 100/100/100/100, and packed npm/Bun manual acceptance passed. Remaining acceptance: per-origin reliability series for operator and blocker retry, and upstream origin propagation into tag-push Release runs; operator-only ordinal follow-up remains owned by pm-uenmu9. No hosted release run or live new-origin receipt has yet been observed." "2026-09-29T10:28:52.881Z","harness:codex",PR #1350 review found the new origin-bearing Release run name no longer matched exact-tag recovery selection. Added exact declared-origin run-name matching with wrong-tag and unknown-origin negative controls; focused selector tests pass. Greptile discussion #4132270479. "2026-09-29T12:22:02.811Z","harness:codex","PR #1350 CodeRabbit discussion #4133333546 identified that dispatcher observations used the native 02:35 UTC cron for nominal occurrence and dispatch delay. Dispatcher rows now omit those schedule-specific timing fields, retain queue delay/outcome/failure stage, and focused negative controls prove native scheduled rows still keep their timing. Documentation states the boundary." @@ -104,6 +104,7 @@ comments[79]{created_at,author,text}: "2026-10-26T22:08:14.067Z","harness:codex","Live 2026-10-26 reliability artifact40404782722 inspected independently of candidate CI: release series has30 original completed attempts,3 original failures and only dispatch_window policy finding. Morning dispatcher series has21 attempts with12 publications and9 retained original failures. Public release2026.10.26 passes the shared verifier including npm/npx/bunx; exactly one currentUTC-day tag is published. Native cron02:35UTC, hosted concurrency and immutable-day guard remain configured. This evidence does not clear historical timing findings or claim a second automatic release. No release is dispatched by this continuation." "2026-10-27T22:23:17.370Z","harness:codex","Live October27 Release Reliability40592007740 has a complete census:30 completed original release attempts,3 original failures, and only dispatch_window violated. Latest native Auto Release40472638505 confirms immutable v2026.10.27 and npm publication before preparation, without a second cut. Five recent native schedule runs are successful. The independent release-ledger report is ok. Preserve original history and daily concurrency/day identity; no additional release dispatch or threshold change is performed by this SDK delivery." "2026-10-28T19:51:07.895Z","harness:codex","October28 independent artifact40744854788: complete release outcome census and passing release-ledger report; rolling scheduled reliability still fails only dispatch_window. Current npm/latest and GitHub release are2026.10.28. Preserve the one-automatic-release-per-UTC-day guard; no extra release or threshold change is justified by this SDK batch." + "2026-10-28T20:51:37.199Z","harness:codex","Current-day publication verification: verify-published-release.mjs --version 2026.10.28 passed the registry/package, npx/Bun/bunx and GitHub Release checks. Native scheduled run 40660287046 explicitly selected existing tag v2026.10.28, required successful immutable publisher run 40631211289, verified npm and GitHub publication at b5241ced02ad3cf6a83b684db4f186ebf8c51397, and skipped preparation rather than publishing a second automatic release. This proves the same-day guard and current artifact availability, not remediation of the separately reported dispatch_window timing debt." notes[3]{created_at,author,text}: "2026-09-29T10:00:32.043Z","harness:codex",A tag-push Release run currently knows only tag_push in its run name. Do not equate that with the upstream Auto Release trigger; completing the accepted provenance contract needs immutable upstream attribution through the tag or an explicitly dispatched Release workflow without duplicate publish runs. "2026-10-10T09:36:49.416Z","harness:codex","Additional owned-temporary native Git acceptance confirms that a missing legacy inventory throws ENOENT and malformed inventory JSON throws SyntaxError before publication; both probes restore their copied inventory. The real tracker and source policy are untouched. Publication admission has no inferred date cutoff, actor inference, external authentication fallback or automatically extended compatibility set. Local tag preparation remains readable context but requires a hosted producer before new hosted publication." diff --git a/.agents/pm/issues/pm-xq09zu.toon b/.agents/pm/issues/pm-xq09zu.toon index 881a7e0743..67aa4b0d3d 100644 --- a/.agents/pm/issues/pm-xq09zu.toon +++ b/.agents/pm/issues/pm-xq09zu.toon @@ -6,7 +6,7 @@ status: open priority: 2 tags: [] created_at: "2026-10-25T19:40:57.328Z" -updated_at: "2026-10-28T20:02:08.312Z" +updated_at: "2026-10-28T20:55:00.034Z" author: "harness:codex" estimated_minutes: 90 acceptance_criteria: Identify the producing automation and whether termination or ingestion explains each unmatched start; Reproduce any confirmed lifecycle defect with isolated positive and negative controls; Preserve sampling and distinguish intentional interruption from missing finalization without fabricating success @@ -17,7 +17,7 @@ expected_result: Identify why each of the four 2026.10.24 automation aggregate s actual_result: "Latest complete bounded installation audit through2026-10-27T11:27:56.303Z, from08:41:00Z:143starts/142finishes, exactly one unequal history group at09:23:31.637UTC, independently re-read. All seven native history-reader processes in the original closure audit exited0; actual causation remains unproven. Fresh11:23UTC history start/finish ingestion0.738039/0.601494seconds and Sentry pm history root27.091ms are visible; span attribute enrichment is unavailable. Required observability gate passes at5.51percent errors<=6 with zero missing codes or blocking Sentry issues. Client event/OTLP queues are empty; last broker snapshot has0ready/1unacknowledged message, so no global drainage claim. Earlier post-source10/9,82/81 checkpoints, older388/387 changelog window and original four2026.10.24 starts remain separate unresolved observations. No synthetic terminal event or lifecycle repair." dependencies[1]{id,kind,created_at,author,source_kind,author_source}: pm-wrdctq,related,"2026-10-25T20:35:11.340Z","harness:codex","cli:update:dep",detected -comments[18]{created_at,author,text}: +comments[19]{created_at,author,text}: "2026-10-25T19:40:57.328Z","harness:codex","Duplicate check: strict complete3115-item all-status corpus plus refreshed open/in_progress inventories and request-specific aggregate telemetry pairing search; full live pm-5oj5 and closed paired-sampling lineage pm-wrdctq were read. No canonical owner matched this newly observed four-row cohort. Intake only and unclaimed." "2026-10-25T19:41:57.802Z","harness:codex","Refined source attribution: the four unmatched aggregate starts all report pm_version2026.10.24 and source_context automation. No current2026.10.25 mismatch is established by that cohort. Keep the intake open/unclaimed and retain termination or timeout as an unverified explanation rather than asserting ingestion loss." "2026-10-26T05:30:06.130Z","harness:codex","Fresh October26 live telemetry evidence extends this existing investigation: complete installation/session/command pairing since2026-10-25T23:39Z over producer2026.10.25/26 found1398 starts,1394 finishes and four settled unmatched starts. All four are producer2026.10.25 with source_context automation: aggregate at00:06:48Z, assurance at01:16:16Z, get at01:29:56Z and aggregate at03:17:42Z. Termination versus ingestion remains unverified; no2026.10.26 mismatch was established by this cohort. Keep the canonical investigation open and unclaimed. Forty command families show average ingestion1.229seconds; required seven-day error/code gate passes at5.22percent with zero missing failure codes. A fresh Sentry pm.command contracts span at05:26:14Z is visible, but streamed span detail is temporarily unavailable from the provider. This is operational evidence, not proof that every historical action has a finish." @@ -36,6 +36,7 @@ comments[18]{created_at,author,text}: "2026-10-28T16:25:11.915Z","harness:codex","Review correction: the independently quoted counts 35,947 / 594,304 equal 6.0486%, rounded 6.05%; the previous 6.03% label was incorrect. This correction does not change the separately sampled 6.04% gate verdict or its unchanged 6% threshold. The aggregate issue remains open." "2026-10-28T17:20:25.175Z","harness:codex","Post-change delivery probe at 2026-10-28 17:19 UTC: context command_start and successful command_finish were both persisted independently in the remote telemetry database with 0.855s and 0.709s ingestion lag. SDK flush completed and the remote queue had zero ready/unacknowledged messages. These current delivery facts do not clear the separately reported aggregate error-rate and historical pairing limitations." "2026-10-28T20:02:08.311Z","harness:codex","Current live required-mode Sentry/telemetry gate passes: no blocking Sentry issues; rolling weighted telemetry finish error rate5.94% against unchanged6% threshold; zero failures missing error codes. A new pm.command context span is visible. A separate10-minute context sample has6 paired sessions and1 unmatched session, with maximum observed ingestion lag4.144seconds. This passing threshold does not resolve historical pairing debt or certify every action." + "2026-10-28T20:55:00.033Z","harness:codex","Current bounded observability evidence: zero unresolved Sentry issues; a recent remote context/automation sample has 6 sessions, 6 matched start/finish pairs, zero unmatched and maximum ingestion lag 2.395836 seconds. Physical broker queue was 0 messages / 0 ready / 0 unacknowledged. A broader recent interval had 313 automation starts and finishes with lag <=5.831581 seconds; the 163-second outlier was explicitly source_context=test, so it is not attributed to user-command ingestion. These samples and the passing 5.94 percent weighted-error gate do not prove complete historical pairing or remove this existing debt." files[1]{path,scope}: tests/unit/core/telemetry/telemetry-worker-lifecycle.spec.ts,project body: "" diff --git a/CHANGELOG.md b/CHANGELOG.md index 17eb829364..62f28543c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +### Added + +- GH-1598: bind batch mutation APIs to PmClient and expose canonical staged preview records ([pm-gh1598](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/features/pm-gh1598.toon)) +- GH-1597: expose host-bound item transaction status and safe abandonment or supersession ([pm-gh1597](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/features/pm-gh1597.toon)) + ### Fixed - GH-1617: make history display order explicit and consistent across projections ([pm-gh1617](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-gh1617.toon)) diff --git a/docs/SDK.md b/docs/SDK.md index 443c31cae4..47087494c1 100644 --- a/docs/SDK.md +++ b/docs/SDK.md @@ -1663,6 +1663,9 @@ await client.commitItemMutations(plan); const receipt = await client.itemTransactions.status("sync-42"); ``` +Preview and status setup use configuration-only source reads, so activation +does not open optional schema files before preview validates their storage. + Each mutation in a newly staged batch contributes a `records` row with its original `index`, canonical `id`, operation, and full public `item` projection including body after the complete batch. Repeated targets therefore show the @@ -1677,7 +1680,14 @@ current state, attribution, extension policy and concurrency. A committed replay the identical committed plan performs no item write; changing its ordered payload under the same id refuses with `transaction_plan_mismatch`. +The workspace transaction lock serializes transaction coordinators. Ordinary +SDK and CLI item writers can still interleave between a step's read and write; +the lock does not provide a general read-decide-write critical section. + New item journals retain their original mutation plan and compensation policy. +History redaction does not rewrite transaction journals: values removed from +item history can remain in interrupted or abandoned journals. GC retains those +recovery receipts. Do not include secrets in batch mutations. The status receipt contains the validated journal and a SHA-256 `planDigest` over its ordered payload-bound step identifiers. Started/completed lists report persisted coordinator progress: a crash after apply but before recording can @@ -1701,7 +1711,7 @@ intent instead of silently resuming it. `supersede(id, newId, { reason })` performs that retirement and records the replacement identity; it does not atomically commit the replacement plan or reserve its id. Repeating the same retirement is idempotent. Committed journals -cannot be abandoned. A later peer edit refuses with +cannot be abandoned. During compensation, a later peer edit refuses with `transaction_partial_mutation` and retains recovery data; it is never silently overwritten. Legacy journals without a retained item plan require the original plan and adapter for replay. Abandoned receipts remain retained by transaction diff --git a/src/sdk/item-transaction.ts b/src/sdk/item-transaction.ts index 5b859086c7..fc25cd1611 100644 --- a/src/sdk/item-transaction.ts +++ b/src/sdk/item-transaction.ts @@ -312,7 +312,7 @@ export interface CommitItemMutationsOptions { transactionId: string; /** Attributable actor recorded in the journal and forwarded to mutations. */ author: string; - /** Ordered item mutations; compensations run in reverse order. */ + /** Ordered mutations retained in the journal, outside history redaction; do not include secrets. Compensations run in reverse order. */ mutations: readonly BulkItemMutation[]; /** * Compensation strategy for created items: `close` (default) preserves the @@ -1238,6 +1238,7 @@ export async function previewItemMutations(options: Pick { + const identity = validateWorkspaceTransactionIdentity(options); const mutations = snapshotBulkMutations(options.mutations); const createCompensation = options.createCompensation ?? "close"; if (!["close", "delete"].includes(createCompensation)) { @@ -1246,19 +1247,16 @@ export async function commitItemMutations( ); } const stepConfig: BulkMutationStepConfig = { - pmRoot: options.pmRoot, - author: options.author, - transactionId: options.transactionId, + ...identity, createCompensation, - uniqueIndex: createUniqueKeyIndex(options.pmRoot), + uniqueIndex: createUniqueKeyIndex(identity.pmRoot), }; const committed = await commitWorkspaceTransaction({ - pmRoot: options.pmRoot, - transactionId: options.transactionId, - author: options.author, + ...identity, steps: mutations.map((mutation, index) => buildStepForMutation(stepConfig, mutation, index), ), + // Recovery values remain in interrupted and abandoned journals; history redaction does not rewrite this plan. recoveryData: JSON.parse(JSON.stringify({ kind: "item-mutations-v1", mutations, createCompensation })) as WorkspaceTransactionJsonValue, ...(options.lockTtlSeconds === undefined ? {} diff --git a/src/sdk/runtime.ts b/src/sdk/runtime.ts index 4013095526..8169b1ec43 100644 --- a/src/sdk/runtime.ts +++ b/src/sdk/runtime.ts @@ -748,19 +748,20 @@ export class PmClient { } /** Execute a direct transaction using the bound root, author policy and active extension host. */ - private async withItemTransactionContext(run: (identity: { pmRoot: string; author: string }) => Promise): Promise { + private async withItemTransactionContext(run: (identity: { pmRoot: string; author: string }) => Promise, configurationOnly = false): Promise { const pmRoot = resolvePmRoot(this.defaults.cwd ?? process.cwd(), this.defaults.path); const execute = async () => { const settings = await runWithConfigurationOnlySettings(pmRoot, () => readSettings(pmRoot)); return run({ pmRoot, author: resolveAuthor(this.defaults.author, settings.author_default) }); }; if (this.defaults[ACTIVE_EXTENSION_HOST_CONTEXT] === true || activeExtensionScope.getStore() === true) return execute(); - return runWithActiveExtensions({ ...this.defaults, path: pmRoot }, execute); + const activate = () => runWithActiveExtensions({ ...this.defaults, path: pmRoot }, execute); + return configurationOnly ? runWithConfigurationOnlySettings(pmRoot, activate) : activate(); } /** Validate a batch in disposable state and return normalized staged records under this host's identity. */ previewItemMutations(options: Pick): Promise { - return this.withItemTransactionContext(async identity => (await import("./item-transaction.js")).previewItemMutations({ ...options, ...identity })); + return this.withItemTransactionContext(async identity => (await import("./item-transaction.js")).previewItemMutations({ ...options, ...identity }), true); } /** Commit or replay a batch using the bound tracker and author, without per-call root overrides. */ @@ -776,7 +777,7 @@ export class PmClient { } { const abandon = (transactionId: string, options: Omit) => this.withItemTransactionContext(async identity => (await import("./item-transaction.js")).abandonItemTransaction({ ...options, ...identity, transactionId })); return { - status: transactionId => this.withItemTransactionContext(async identity => (await import("./item-transaction.js")).readItemTransaction(identity.pmRoot, transactionId)), + status: transactionId => this.withItemTransactionContext(async identity => (await import("./item-transaction.js")).readItemTransaction(identity.pmRoot, transactionId), true), abandon, supersede: (transactionId, newId, options) => abandon(transactionId, { ...options, supersededBy: newId }), }; diff --git a/src/sdk/workspace-transaction.ts b/src/sdk/workspace-transaction.ts index 48cbb596af..7bfb44ddc8 100644 --- a/src/sdk/workspace-transaction.ts +++ b/src/sdk/workspace-transaction.ts @@ -221,6 +221,7 @@ async function writeJournal( await writeFileAtomic(target, `${JSON.stringify(journal, null, 2)}\n`); } +/** Require attributable attempt metadata and a retirement receipt consistent with its schema version. */ function hasValidJournalMetadata( journal: Partial, ): boolean { @@ -311,6 +312,7 @@ function hasUniqueKnownStepIds( ); } +/** Reject progress receipts whose ownership sets disagree or whose terminal state retains active steps. */ function hasValidJournalLifecycle( journal: Partial, stepIds: readonly string[], @@ -370,7 +372,7 @@ function journalPlanMismatch(transactionId: string): PmCliError { nextSteps: [ "Re-run with the original document to resume or replay it.", "For item batches use client.itemTransactions.status(transactionId), then client.itemTransactions.abandon(transactionId, { reason }) before committing a changed plan with a new transactionId.", - "Run pm ops gc --scope transactions --dry-run to inspect abandoned journals before pruning them.", + "Run pm ops gc --scope transactions --dry-run to inspect retention; active and explicitly abandoned journals remain protected.", ], }, ); @@ -421,6 +423,7 @@ function parseJournal( }; } +/** Resume matching progress or start a fresh compensated attempt with a copied recovery plan. */ async function prepareJournalForApply( options: CommitWorkspaceTransactionOptions, transactionId: string, @@ -741,7 +744,7 @@ export function workspaceTransactionPlanDigest(journal: Pick { /** Required human-readable recovery rationale. */ reason: string; - /** Optional fresh identity reserved by the caller for its replacement plan. */ + /** Optional fresh identity chosen by the caller for its replacement plan; this does not reserve it. */ supersededBy?: string; /** Rebuild original steps without applying forward mutations. */ resolveSteps(journal: WorkspaceTransactionJournal): readonly WorkspaceTransactionStep[]; @@ -762,10 +765,10 @@ export async function abandonWorkspaceTransaction(options: AbandonWorkspaceTrans if (journal.status === "committed") throw new PmCliError(`Transaction ${identity.transactionId} is committed and cannot be abandoned`, EXIT_CODE.CONFLICT, { code: "transaction_committed", required: "Plan a separate explicit corrective mutation.", why: "Recovery cannot silently undo committed work." }); if (journal.abandonment !== undefined && journal.abandonment.supersededBy !== supersededBy) throw retiredTransaction(identity.transactionId); if (journal.status === "abandoned") return journal; - if (supersededBy !== undefined && await loadJournal(identity.pmRoot, supersededBy) !== undefined) throw new PmCliError(`Replacement transaction ${supersededBy} already exists`, EXIT_CODE.CONFLICT); const steps = options.resolveSteps(structuredClone(journal)); if (JSON.stringify(steps.map(step => step.id)) !== JSON.stringify(journal.stepIds)) throw journalPlanMismatch(identity.transactionId); if (journal.abandonment === undefined) { + if (supersededBy !== undefined && await loadJournal(identity.pmRoot, supersededBy) !== undefined) throw new PmCliError(`Replacement transaction ${supersededBy} already exists`, EXIT_CODE.CONFLICT); journal.schemaVersion = 2; journal.abandonment = { reason, author: identity.author, ...(supersededBy === undefined ? {} : { supersededBy }) }; await writeJournal(identity.pmRoot, journal); diff --git a/tests/integration/transactions/semantic-preview.integration.spec.ts b/tests/integration/transactions/semantic-preview.integration.spec.ts index 22074cd130..fe6de3781c 100644 --- a/tests/integration/transactions/semantic-preview.integration.spec.ts +++ b/tests/integration/transactions/semantic-preview.integration.spec.ts @@ -13,7 +13,7 @@ import { resolveExtensionMigrationStatePath } from "../../../src/sdk/extension/m import { EXIT_CODE, setFocusedItem } from "../../../src/sdk/runtime-primitives.js"; import { readSettings } from "../../../src/core/store/settings.js"; import { waitForPendingFlush } from "../../../src/core/telemetry/runtime.js"; -import { withTempPmPath } from "../../helpers/withTempPmPath.js"; +import { withTempPmPath, type TempPmContext } from "../../helpers/withTempPmPath.js"; /** Snapshot durable tracker bytes, including session and telemetry state but excluding queues, caches, and locks. */ async function durableSnapshot(root: string): Promise> { @@ -42,6 +42,22 @@ function previewWithClockMatchers(validation: ItemMutationPreviewValidation): It } })) }; } +/** Exercise host-bound bootstrap in a native child so an unsafe FIFO read fails by a bounded timeout. */ +function assertUnsafeHostPreview(context: TempPmContext, command: string, noExtensions: boolean, kind: string): void { + if (command !== "mutate") return; + const entrypoint = new URL("../../../dist/sdk/index.js", import.meta.url).href; + const script = `import { PmClient } from ${JSON.stringify(entrypoint)}; + try { + const client = new PmClient({ pmRoot: process.env.PM_PATH, noExtensions: ${noExtensions} }); + ${kind === "pipe" ? 'if (await client.itemTransactions.status("missing") !== undefined) throw new Error("Unexpected journal");' : ""} + await client.previewItemMutations({ transactionId: "unsafe-sdk", mutations: [{ op: "update", id: "pm-unsafe", options: { title: "Staged title" } }] }); + } catch (error) { console.log(JSON.stringify({ code: error.context?.code })); process.exitCode = 2; }`; + const sdk = spawnSync(process.execPath, ["--input-type=module", "-e", script], { env: context.env, encoding: "utf8", timeout: 10_000 }); + expect(sdk.error).toBeUndefined(); + expect(sdk.status).toBe(2); + expect(JSON.parse(sdk.stdout)).toMatchObject({ code: "transaction_preview_non_regular_file" }); +} + describe("semantic transaction previews (GH-1370)", () => { it.skipIf(process.platform === "win32")("preserves native filesystem failures without writing the source tracker", async () => { await withTempPmPath(async (context) => { @@ -184,6 +200,7 @@ describe("semantic transaction previews (GH-1370)", () => { expect(result.status).toBe(2); expect(JSON.parse(result.stderr)).toMatchObject({ code: "transaction_preview_non_regular_file", preview_storage: { relative_entry: entry, entry_redacted: false }, next_steps: expect.arrayContaining([expect.stringContaining("retry the original dry-run")]) }); expect(result.stderr).not.toContain(context.pmPath); + assertUnsafeHostPreview(context, command, noExtensions, kind); if (kind === "settings-pipe") expect((await lstat(settingsPath)).isFIFO()).toBe(true); else expect(await readFile(settingsPath, "utf8")).toBe(beforeSettings); expect(await readFile(itemPath, "utf8")).toBe(beforeItem); diff --git a/tests/unit/sdk/transactions/host-bound.spec.ts b/tests/unit/sdk/transactions/host-bound.spec.ts index 7c1000355f..3192dcdc9c 100644 --- a/tests/unit/sdk/transactions/host-bound.spec.ts +++ b/tests/unit/sdk/transactions/host-bound.spec.ts @@ -34,7 +34,7 @@ describe("host-bound item batches and recovery (pm-gh1597, pm-gh1598)", () => { expect((await client.commitItemMutations(input)).recovered).toBe(true); expect(await readFile(historyPath, "utf8")).toBe(history); expect(await client.previewItemMutations(input)).toMatchObject({ validated: false, state: "replayed_committed_plan", records: [] }); - await expect(client.commitItemMutations({ ...input, mutations: [{ op: "update", id: "staged", options: { title: "Changed intent" } }] })).rejects.toMatchObject({ context: { code: "transaction_plan_mismatch" } }); + await expect(client.commitItemMutations({ ...input, mutations: [{ op: "update", id: "staged", options: { title: "Changed intent" } }] })).rejects.toMatchObject({ context: { code: "transaction_plan_mismatch", nextSteps: expect.arrayContaining([expect.stringContaining("client.itemTransactions.abandon")]) } }); await expect(client.itemTransactions.abandon("canonical", { reason: "Cannot undo completed work" })).rejects.toMatchObject({ context: { code: "transaction_committed" } }); }); }); @@ -43,7 +43,7 @@ describe("host-bound item batches and recovery (pm-gh1597, pm-gh1598)", () => { await withTempPmPath(async ({ pmPath }) => { const client = new PmClient({ pmRoot: pmPath, author: "recovery-actor", noExtensions: true }); const original = (await client.create({ title: "Original", type: "Task" })).item; - const options = { transactionId: "retired", mutations: [{ op: "update", id: original.id, options: { title: "Forward" } }] satisfies BulkItemMutation[] }; + const options = { transactionId: " retired ", mutations: [{ op: "update", id: original.id, options: { title: "Forward" } }] satisfies BulkItemMutation[] }; await expect(client.commitItemMutations({ ...options, onTransition: event => { if (event.transition === transition) throw new WorkspaceTransactionInterruptedError("Crash"); } })).rejects.toThrow("Crash"); const before = await client.itemTransactions.status("retired"); expect(before?.journal.status).toBe("applying"); @@ -158,16 +158,17 @@ describe("host-bound item batches and recovery (pm-gh1597, pm-gh1598)", () => { if (args[0] === file && String(args[1]).includes('"status": "abandoned"')) throw new Error("Final journal write failed"); return write(...args); }); - await expect(client.itemTransactions.abandon("audit", { reason: "Retire" })).rejects.toThrow("Final journal write failed"); + await expect(client.itemTransactions.supersede("audit", "audit-replacement", { reason: "Retire" })).rejects.toThrow("Final journal write failed"); vi.restoreAllMocks(); const auditPath = path.join(pmPath, "history", "_workspace.jsonl"); const audit = await readFile(auditPath, "utf8"); await expect(client.commitItemMutations({ transactionId: "audit", mutations: [{ op: "update", id: "audit", options: { title: "Forward" } }] })).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); const collected = await runWorkspaceTransactionGc(pmPath, { dryRun: true, retentionDays: 0, now: Date.now() + 86400000 }); expect(collected.retained).toContain("transactions/sdk/audit.json"); - expect((await client.itemTransactions.abandon("audit", { reason: "Retry with another explanation" })).journal.abandonment?.reason).toBe("Retire"); + await client.commitItemMutations({ transactionId: "audit-replacement", mutations: [{ op: "update", id: "audit", options: { title: "Replacement" } }] }); + expect((await client.itemTransactions.supersede("audit", "audit-replacement", { reason: "Retry with another explanation" })).journal.abandonment?.reason).toBe("Retire"); expect(await readFile(auditPath, "utf8")).toBe(audit); - expect((await client.get("audit")).item.title).toBe("Original"); + expect((await client.get("audit")).item.title).toBe("Replacement"); }); }); From 4d2a20af11734e3eddc41a6cf5b7fc25375af195 Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Wed, 28 Oct 2026 23:55:55 +0100 Subject: [PATCH 3/5] fix(sdk): return retirement recovery guidance before plan mismatch Validate retained journal structure, then let valid retirement metadata reach the permanent transaction_abandoned refusal regardless of the requested plan. A changed payload must not tell callers to abandon an identity that is already retired. Extend native interrupted-compensation and completed-retirement cases; all five assertions reproduce the old misleading plan-mismatch response. Qualify committed-plan replay guarantees by journal retention. Transaction GC can remove old committed receipts, after which their identities may be treated as new. Preserve the distinct permanent retention of abandoned receipts. Carry review remediation, linked tests and structured PM closure in the same reviewed delivery. No thresholds or checks are weakened. --- .../pm/extensions/.managed-extensions.json | 2 +- .agents/pm/features/pm-gh1597.toon | 31 +++++++++++++------ .agents/pm/features/pm-gh1598.toon | 31 +++++++++++++------ .agents/pm/history/pm-gh1597.jsonl | 8 +++++ .agents/pm/history/pm-gh1598.jsonl | 8 +++++ docs/SDK.md | 9 ++++-- src/sdk/workspace-transaction.ts | 11 ++++--- .../unit/sdk/transactions/host-bound.spec.ts | 4 ++- 8 files changed, 76 insertions(+), 28 deletions(-) diff --git a/.agents/pm/extensions/.managed-extensions.json b/.agents/pm/extensions/.managed-extensions.json index 2f4e91af0c..4c9354968d 100644 --- a/.agents/pm/extensions/.managed-extensions.json +++ b/.agents/pm/extensions/.managed-extensions.json @@ -1,6 +1,6 @@ { "version": 1, - "updated_at": "2026-10-28T22:08:25.524Z", + "updated_at": "2026-10-28T22:53:52.778Z", "entries": [ { "name": "builtin-calendar", diff --git a/.agents/pm/features/pm-gh1597.toon b/.agents/pm/features/pm-gh1597.toon index 68d2e3eef7..16d7b5ad1c 100644 --- a/.agents/pm/features/pm-gh1597.toon +++ b/.agents/pm/features/pm-gh1597.toon @@ -6,22 +6,22 @@ status: closed priority: 1 tags: [] created_at: "2026-10-26T04:54:49.262Z" -updated_at: "2026-10-28T22:07:24.128Z" -closed_at: "2026-10-28T22:07:22.951Z" -completed_at: "2026-10-28T22:07:22.951Z" +updated_at: "2026-10-28T22:52:51.392Z" +closed_at: "2026-10-28T22:52:50.315Z" +completed_at: "2026-10-28T22:52:50.315Z" author: "harness:codex" estimated_minutes: 300 acceptance_criteria: Expose typed host-bound journal state and applied/compensated step receipts with plan identity; Provide safe abandonment and supersession using proven apply markers and existing guarded compensation; never overwrite later peer edits or silently compensate committed work; Name executable public recovery in transaction-plan-mismatch guidance and verify non-Git crash/retry/peer-edit controls plus SDK contract documentation parent: pm-9rgaal risk: high confidence: high -resolution: "Implemented bound status, abandon and supersede APIs with retained original plans, versioned durable retirement intent, idempotent audit and guarded compensation that preserves peer edits. Recovery normalizes identity before markers and can resume retirement after the replacement identity is used. Documented journal retention, redaction scope and the ordinary-writer isolation limit." -expected_result: Packages can inspect and safely retire interrupted item batches through their configured client without rebuilding private journal rules. -actual_result: "65/65 linked recovery tests and full 11540-test exact-coverage run passed; crash, peer-write, padded-identity and replacement-after-crash negative controls verified. Node and Bun packed artifact checks passed. Reviewed delivery is PR #1621; publication remains separate." +resolution: Delivered host-bound transaction recovery with durable retirement and peer-safe compensation. Retired identities return actionable retirement guidance before plan comparison. +expected_result: Extensions can inspect and recover interrupted batches through a supported root-bound API without reading private paths or recreating journal and compensation rules. +actual_result: "Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge." dependencies[2]{id,kind,created_at,author,source_kind,author_source}: pm-9rgaal,implements,"2026-10-26T04:54:49.262Z","harness:codex","cli:create:dep",detected pm-y9hq,discovered_from,"2026-10-26T04:54:49.262Z","harness:codex","cli:create:dep",detected -comments[8]{created_at,author,text}: +comments[10]{created_at,author,text}: "2026-10-26T04:54:49.262Z","harness:codex","Duplicate check: complete strict all-status corpus plus live request-specific searches and full terminal-lineage reads found no exact active owner. Existing SDK promotion and transaction/preview delivery remain completed; this item owns the newly requested public surface." "2026-10-28T19:44:07.695Z","harness:codex","Implementation scope: retain original item plans in coordinator journals, expose read-only status and host-bound guarded abandonment/supersession, refuse committed and peer-edited work, preserve append-only compensation and audit evidence. Complete strict 3148-item all-status census has no omissions; 38 open GitHub issues each already have a canonical PM link comment. No open PRs or GitHub dependency/code/secret alerts at intake." "2026-10-28T20:16:18.094Z","harness:codex","Native late-peer recovery oracle initially exposed a delete-store gap: the existing scoped item precondition was checked by update/close but not by locked deletion. Isolated candidate adds the same assertion before deletion policy/hooks and centralizes create compensation ownership checks. Close and delete both preserve a peer edit injected immediately before item-lock acquisition. Isolated focused proof passes51 tests; original checkout remains frozen for the in-flight full coverage run. Retirement intent is additionally retained before compensation to fence forward replay across recovery crashes." @@ -30,6 +30,8 @@ comments[8]{created_at,author,text}: "2026-10-28T21:31:47.832Z","harness:codex","Additional crash regression: a padded transaction id was normalized by the coordinator but not by item-history markers. The extended existing prepared/applied/recorded table proved that applied and recorded attempts could retire while leaving the forward value unchanged. Normalize identity once before building any item step, unique-key index or journal. Local transport admission remains failed; a separately built unchanged base commit also fails all six transport budgets on this host, while the isolated candidate SDK import-cost gate passes. Thresholds are unchanged; exact-head hosted transport admission is required." "2026-10-28T21:46:03.949Z","harness:codex","Hosted initial-head evidence: CI job 123098074387 on f705877b712850bb296f8c9ca519848c239d18df passed the SDK import-cost and six-operation CLI transport-floor gates with unchanged budgets. Its static failure was graph-composition prose-edge gaps 1234 > 1233, now corrected by the genuine related edge between the grouped features; local graph and record-integrity gates pass. Bounded mutation evidence is 352 classified mutants, 345 killed, 7 equivalent, no gate failures. Updated packed Node/Bun consumers and unsafe-source rejection passed. Final revised-head hosted checks remain required." "2026-10-28T22:07:21.136Z","harness:codex","Final candidate validation: full sandboxed source coverage passed 11540 tests (3 platform skips), 880 passing files and 1 skipped file, with exact 71421/71421 statements, 55025/55025 branches, 14707/14707 functions and 67487/67487 lines. Linked recovery 65/65 and SDK/semantic-preview 49/49 passed, along with typecheck, ESLint, duplicate checks, generated contracts/surface/catalogs, docs links, graph composition and record integrity. Bounded mutation lane: 345 killed and 7 equivalent of 352, no failures. Final packed npm tarball passed Node and Bun batch/replay/retirement/replacement and unsafe-preview bootstrap controls. Local transport performance also failed unchanged base; thresholds remain unchanged and the initial PR head passed both hosted performance gates. Final revised head must pass hosted checks before merge. New APIs are not yet claimed as published." + "2026-10-28T22:24:14.492Z","harness:codex","Second review cycle on PR #1621: five native recovery cases reproduced the retired-ID precedence defect, returning transaction_plan_mismatch for changed payloads after durable retirement or during interrupted compensation. Journal validation now preserves structural checks but defers plan comparison for valid retirement metadata so the coordinator returns transaction_abandoned before any forward step. Existing crash tables exercise unchanged items after refusal. Linked tests and exact full coverage are being rerun; this item is actively claimed only for this review remediation." + "2026-10-28T22:52:49.339Z","harness:codex","Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge." learnings[2]{created_at,author,text}: "2026-10-28T20:16:19.379Z","harness:codex","Retiring an interrupted batch requires a durable intent before compensation, not only a terminal status afterward. Every destructive compensation must recheck ownership under the target item lock; a pre-lock history comparison alone does not protect a late peer edit." "2026-10-28T21:55:42.128Z","harness:codex",Normalize transaction identity before building both durable effects and journal receipts. Normalizing only the coordinator key can make recovery miss its own apply markers and falsely report compensation. @@ -49,7 +51,7 @@ files[13]{path,scope}: tests/unit/sdk/workspace-transaction.spec.ts,project tests[1]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts,project,300,"harness:codex","2026-10-28T19:50:40.616Z",local_mutation,feat/host-bound-item-transactions -test_runs[2]: +test_runs[3]: - run_id: test-local-mvskr61r-dyaj7d kind: test status: passed @@ -72,8 +74,19 @@ test_runs[2]: skipped: 0 executions[1]{command,requested_pm_context_mode,pm_context_mode,workspace_context_mode,trust_reason}: node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts,schema,schema,source,local_source_ref + - run_id: test-local-mvsom3bl-m6llz8 + kind: test + status: passed + started_at: "2026-10-28T22:23:51.686Z" + finished_at: "2026-10-28T22:24:16.977Z" + recorded_at: "2026-10-28T22:24:16.977Z" + passed: 1 + failed: 0 + skipped: 0 + executions[1]{command,requested_pm_context_mode,pm_context_mode,workspace_context_mode,trust_reason}: + node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts,schema,schema,source,local_source_ref docs[2]{path,scope}: docs/generated/REFUSAL_CLOSURE_CENSUS.md,project docs/SDK.md,project -close_reason: Implementation and regression evidence complete; closure travels with the reviewed delivery. +close_reason: Implementation and review remediation verified; closure included in PR #1621. body: "" diff --git a/.agents/pm/features/pm-gh1598.toon b/.agents/pm/features/pm-gh1598.toon index 631976b6e0..a97104cfae 100644 --- a/.agents/pm/features/pm-gh1598.toon +++ b/.agents/pm/features/pm-gh1598.toon @@ -6,29 +6,31 @@ status: closed priority: 1 tags: [] created_at: "2026-10-26T04:54:51.880Z" -updated_at: "2026-10-28T22:07:25.991Z" -closed_at: "2026-10-28T22:07:25.021Z" -completed_at: "2026-10-28T22:07:25.021Z" +updated_at: "2026-10-28T22:52:54.188Z" +closed_at: "2026-10-28T22:52:53.234Z" +completed_at: "2026-10-28T22:52:53.234Z" author: "harness:codex" estimated_minutes: 240 acceptance_criteria: "Expose typed PmClient previewItemMutations and commitItemMutations forwarding bound root and author policy to the existing SDK coordinator; Return per-mutation canonical staged ids, normalized metadata and bodies with generated-value provenance and explicit commit-time constraints; Prove preview/read-back equivalence for unchanged admitted plans and safe identical-intent replay versus typed changed-intent conflicts using native non-Git fixtures; preserve read-only previews and current guarded commit behavior" parent: pm-9rgaal risk: medium confidence: high -resolution: "Implemented host-bound preview and commit methods with canonical final staged records, applied/adopted state, commit-time clock pointers and explicit replay constraints. Configuration-only bootstrap protects preview/status from optional-schema FIFO reads before staging." -expected_result: Packages can use SDK-owned normalized preview records and bound identity while preserving read-only preview and replay safety. -actual_result: "49/49 linked SDK/semantic-preview tests and full 11540-test exact-coverage run passed. Native unsafe-storage negative controls, type surface and Node/Bun packed artifact passed. Reviewed delivery is PR #1621; publication remains separate." +resolution: Delivered bound batch preview and commit with canonical staged records and safe preview bootstrap.Replay guarantees explicitly depend on retaining committed journals; GC removal can admit the identity as new. +expected_result: Packages can perform host-bound atomic batches and compare normalized intents using SDK-owned records instead of re-deriving roots or duplicating normalization. +actual_result: "Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge." dependencies[3]{id,kind,created_at,author,source_kind,author_source}: pm-9rgaal,implements,"2026-10-26T04:54:51.880Z","harness:codex","cli:create:dep",detected pm-gh1370,discovered_from,"2026-10-26T04:54:51.880Z","harness:codex","cli:create:dep",detected pm-gh1597,related,"2026-10-28T21:37:27.052Z","harness:codex","cli:update:dep",detected -comments[6]{created_at,author,text}: +comments[8]{created_at,author,text}: "2026-10-26T04:54:51.880Z","harness:codex","Duplicate check: complete strict all-status corpus plus live request-specific searches and full terminal-lineage reads found no exact active owner. Existing SDK promotion and transaction/preview delivery remain completed; this item owns the newly requested public surface." "2026-10-28T19:44:10.177Z","harness:codex","Implementation scope: typed root/author-bound PmClient preview and commit; canonical full staged item snapshots per executed mutation with explicit generated clock fields. Preserve committed replay semantics and read-only staging. Group with pm-gh1597 in one reviewed delivery; no other implementation items claimed." "2026-10-28T20:39:13.335Z","harness:codex","Validation: linked SDK plus semantic-preview integration tests passed 49/49. Staged records retain canonical body, normalized tags, author and provenance with explicit clock-field pointers, final-batch state and applied/adopted execution receipts. Committed replay returns no newly validated records. Public declaration tests and SDK surface snapshot are current. Full canonical coverage is running; the earlier 197-test focused coverage diagnostic retained the full-source denominator and is not a global coverage pass." "2026-10-28T21:08:13.590Z","harness:codex","Investigation and regression proof: the initial host wrapper activated extensions using hydrated source settings before safe preview setup. Native installed-package and isolated integration negative controls timed out on optional-schema and settings FIFOs. Configuration-only activation for preview/status fixes both before source reads; the same four unsafe-path fixtures then pass. This remains within host-bound preview ownership. The full candidate run completed 11539 passing tests with one 30-second timeout in existing literal-input coverage; no canonical coverage receipt was produced. Focused retry and hosted full coverage remain required." "2026-10-28T21:37:28.300Z","harness:codex",Recorded the real related relationship to the grouped recovery feature. The graph-composition gate detected that this delivery relationship existed only in prose; the typed edge now represents the shared host-bound transaction surface without inventing dependency or hierarchy depth. "2026-10-28T22:07:22.006Z","harness:codex","Final candidate validation: full sandboxed source coverage passed 11540 tests (3 platform skips), 880 passing files and 1 skipped file, with exact 71421/71421 statements, 55025/55025 branches, 14707/14707 functions and 67487/67487 lines. Linked recovery 65/65 and SDK/semantic-preview 49/49 passed, along with typecheck, ESLint, duplicate checks, generated contracts/surface/catalogs, docs links, graph composition and record integrity. Bounded mutation lane: 345 killed and 7 equivalent of 352, no failures. Final packed npm tarball passed Node and Bun batch/replay/retirement/replacement and unsafe-preview bootstrap controls. Local transport performance also failed unchanged base; thresholds remain unchanged and the initial PR head passed both hosted performance gates. Final revised head must pass hosted checks before merge. New APIs are not yet claimed as published." + "2026-10-28T22:24:15.477Z","harness:codex",Second review cycle on PR #1621 clarified that identical-plan replay and changed-plan mismatch guarantees require retention of the committed journal. Existing GC may remove old committed receipts and the identity can then be treated as new; explicitly abandoned receipts remain protected. Documentation now states the boundary. Linked tests and full coverage are being rerun before reviewed closure. + "2026-10-28T22:52:52.365Z","harness:codex","Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge." learnings[1]{created_at,author,text}: "2026-10-28T21:55:43.375Z","harness:codex","A read-only preview must protect the whole host bootstrap path, including configuration and extension setup. Staging guards alone are too late if bootstrap has already opened an optional-schema FIFO." files[6]{path,scope}: @@ -40,7 +42,7 @@ files[6]{path,scope}: tests/unit/sdk/transactions/host-bound.spec.ts,project tests[1]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts,project,300,"harness:codex","2026-10-28T19:50:42.784Z",local_mutation,feat/host-bound-item-transactions -test_runs[2]: +test_runs[3]: - run_id: test-local-mvsks2km-d73z2v kind: test status: passed @@ -63,7 +65,18 @@ test_runs[2]: skipped: 0 executions[1]{command,requested_pm_context_mode,pm_context_mode,workspace_context_mode,trust_reason}: node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts,schema,schema,source,local_source_ref + - run_id: test-local-mvson46t-8nw20g + kind: test + status: passed + started_at: "2026-10-28T22:24:17.796Z" + finished_at: "2026-10-28T22:25:04.757Z" + recorded_at: "2026-10-28T22:25:04.757Z" + passed: 1 + failed: 0 + skipped: 0 + executions[1]{command,requested_pm_context_mode,pm_context_mode,workspace_context_mode,trust_reason}: + node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts,schema,schema,source,local_source_ref docs[1]{path,scope}: docs/SDK.md,project -close_reason: Implementation and regression evidence complete; closure travels with the reviewed delivery. +close_reason: Implementation and review remediation verified; closure included in PR #1621. body: "" diff --git a/.agents/pm/history/pm-gh1597.jsonl b/.agents/pm/history/pm-gh1597.jsonl index cb54534421..6b9b7287fd 100644 --- a/.agents/pm/history/pm-gh1597.jsonl +++ b/.agents/pm/history/pm-gh1597.jsonl @@ -20,3 +20,11 @@ {"hash_algorithm":"sha256","ts":"2026-10-28T22:07:21.136Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/7","value":{"created_at":"2026-10-28T22:07:21.136Z","author":"harness:codex","text":"Final candidate validation: full sandboxed source coverage passed 11540 tests (3 platform skips), 880 passing files and 1 skipped file, with exact 71421/71421 statements, 55025/55025 branches, 14707/14707 functions and 67487/67487 lines. Linked recovery 65/65 and SDK/semantic-preview 49/49 passed, along with typecheck, ESLint, duplicate checks, generated contracts/surface/catalogs, docs links, graph composition and record integrity. Bounded mutation lane: 345 killed and 7 equivalent of 352, no failures. Final packed npm tarball passed Node and Bun batch/replay/retirement/replacement and unsafe-preview bootstrap controls. Local transport performance also failed unchanged base; thresholds remain unchanged and the initial PR head passed both hosted performance gates. Final revised head must pass hosted checks before merge. New APIs are not yet claimed as published."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:07:21.136Z"}],"before_hash":"4b86dcc7caa815c500e30225522d58424773c10b171b15c453b1c4a4f062a5c6","after_hash":"a3b0f2401f1d70f161b5efbaf893ae8eca41909809252de03a09435486d8cdb4","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":"192a0018760e7d507682ea6bfd37f3d971a4d05a9070dda50f80a142a20b9263"} {"hash_algorithm":"sha256","ts":"2026-10-28T22:07:22.979Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"close","patch":[{"op":"replace","path":"/metadata/expected_result","value":"Packages can inspect and safely retire interrupted item batches through their configured client without rebuilding private journal rules."},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:07:22.979Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-10-28T22:07:22.951Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-10-28T22:07:22.951Z"},{"op":"add","path":"/metadata/resolution","value":"Implemented bound status, abandon and supersede APIs with retained original plans, versioned durable retirement intent, idempotent audit and guarded compensation that preserves peer edits. Recovery normalizes identity before markers and can resume retirement after the replacement identity is used. Documented journal retention, redaction scope and the ordinary-writer isolation limit."},{"op":"add","path":"/metadata/actual_result","value":"65/65 linked recovery tests and full 11540-test exact-coverage run passed; crash, peer-write, padded-identity and replacement-after-crash negative controls verified. Node and Bun packed artifact checks passed. Reviewed delivery is PR #1621; publication remains separate."},{"op":"add","path":"/metadata/close_reason","value":"Implementation and regression evidence complete; closure travels with the reviewed delivery."}],"before_hash":"a3b0f2401f1d70f161b5efbaf893ae8eca41909809252de03a09435486d8cdb4","after_hash":"327a1b120d9c1299b940391186a9d43958c1a3be78e51e49857d2db877d1d65b","item_hash_version":3,"context":{"completion":{"timestamp":"2026-10-28T22:07:22.951Z","source":"close_time"},"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":"80d0cb899ca870958b5ad36e8ca6395eb3cf7bbbf0aee89f81b3313a049645a8"} {"hash_algorithm":"sha256","ts":"2026-10-28T22:07:24.128Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:07:24.128Z"}],"before_hash":"327a1b120d9c1299b940391186a9d43958c1a3be78e51e49857d2db877d1d65b","after_hash":"2bcad58dfdef882a00065e3a8a0606d24f0e86f0aaa3dd5d81b9ddded4785165","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":"ddf08040175df14609d51497891c420c21eb876b52f019ee0aefed52b866e9e4"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:23:01.443Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"reopen","patch":[{"op":"remove","path":"/metadata/close_reason"},{"op":"remove","path":"/metadata/actual_result"},{"op":"remove","path":"/metadata/expected_result"},{"op":"remove","path":"/metadata/resolution"},{"op":"remove","path":"/metadata/completed_at"},{"op":"remove","path":"/metadata/closed_at"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:23:01.443Z"},{"op":"replace","path":"/metadata/status","value":"open"}],"before_hash":"2bcad58dfdef882a00065e3a8a0606d24f0e86f0aaa3dd5d81b9ddded4785165","after_hash":"4574545ba277f58c23d6310d9d05168ca2df7c17155b1090851f9e7efdeee011","item_hash_version":3,"context":{"recurrence":{"reason":"PR #1621 review found retired-ID error precedence returning plan mismatch before the permanent retirement refusal.","from_status":"closed","to_status":"open","previous_terminal":{"close_reason":"Implementation and regression evidence complete; closure travels with the reviewed delivery.","resolution":"Implemented bound status, abandon and supersede APIs with retained original plans, versioned durable retirement intent, idempotent audit and guarded compensation that preserves peer edits. Recovery normalizes identity before markers and can resume retirement after the replacement identity is used. Documented journal retention, redaction scope and the ordinary-writer isolation limit.","expected_result":"Packages can inspect and safely retire interrupted item batches through their configured client without rebuilding private journal rules.","actual_result":"65/65 linked recovery tests and full 11540-test exact-coverage run passed; crash, peer-write, padded-identity and replacement-after-crash negative controls verified. Node and Bun packed artifact checks passed. Reviewed delivery is PR #1621; publication remains separate."}},"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":"ae9072445541c4e59002f48c00cf0e2cf8595e8bef60392549eac5b98d76e669"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:23:02.215Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","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-28T22:23:02.215Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#568692524ccbb719c2f222a0"}],"before_hash":"4574545ba277f58c23d6310d9d05168ca2df7c17155b1090851f9e7efdeee011","after_hash":"a91633b79bb21074b206f1df9cc1289642c8551bf5fba202ea3dbbf28903af15","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":"b3224b35f26d719e406818b6fd0c301ca772d28738c574f967f1ffd0571a605a"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:23:02.361Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"pm-gh1597","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:23:02.361Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"a91633b79bb21074b206f1df9cc1289642c8551bf5fba202ea3dbbf28903af15","after_hash":"7c55623b6a4dd763b7632f8190665332993a67f0ab06b95e6757acec753105e9","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":"b8cbea362793e4ac4ab16e51ce3f1ac8f152ec7b433128d9b48c70827a39b1c5"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:24:14.493Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/8","value":{"created_at":"2026-10-28T22:24:14.492Z","author":"harness:codex","text":"Second review cycle on PR #1621: five native recovery cases reproduced the retired-ID precedence defect, returning transaction_plan_mismatch for changed payloads after durable retirement or during interrupted compensation. Journal validation now preserves structural checks but defers plan comparison for valid retirement metadata so the coordinator returns transaction_abandoned before any forward step. Existing crash tables exercise unchanged items after refusal. Linked tests and exact full coverage are being rerun; this item is actively claimed only for this review remediation."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:24:14.493Z"}],"before_hash":"7c55623b6a4dd763b7632f8190665332993a67f0ab06b95e6757acec753105e9","after_hash":"88b5d3d8a063fabe5ba20c8e9861ba2611152af5f44f3adb3086ab945c7e93c5","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":"a77971b76238d27d9cc0e3222c5ea670b1b3432cb7931a9ec938c5dd5513df23"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:24:16.997Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"test_run_track","patch":[{"op":"add","path":"/metadata/test_runs/2","value":{"run_id":"test-local-mvsom3bl-m6llz8","kind":"test","status":"passed","started_at":"2026-10-28T22:23:51.686Z","finished_at":"2026-10-28T22:24:16.977Z","recorded_at":"2026-10-28T22:24:16.977Z","passed":1,"failed":0,"skipped":0,"executions":[{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts","requested_pm_context_mode":"schema","pm_context_mode":"schema","workspace_context_mode":"source","trust_reason":"local_source_ref"}]}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:24:16.997Z"}],"before_hash":"88b5d3d8a063fabe5ba20c8e9861ba2611152af5f44f3adb3086ab945c7e93c5","after_hash":"b60d0b25ba9d0271f632b7457c96414266cae998b14184dbf493dbaac0be593e","item_hash_version":3,"message":"Track test run summary (test-local-mvsom3bl-m6llz8)","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":"036db00f5c1f05b6928298806c3e4be8147a857799fdbaad8e99ffdff90f0875"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:52:49.339Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/9","value":{"created_at":"2026-10-28T22:52:49.339Z","author":"harness:codex","text":"Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:52:49.339Z"}],"before_hash":"b60d0b25ba9d0271f632b7457c96414266cae998b14184dbf493dbaac0be593e","after_hash":"189b7e49b26b2c4810b887bd40a6662fd7b3514759d242ac4474196e327cd653","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":"1e5db91c798318078a8611301ea88f317dc7c7d9ba08a524c84ceb3e57cc9591"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:52:50.348Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:52:50.348Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-10-28T22:52:50.315Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-10-28T22:52:50.315Z"},{"op":"add","path":"/metadata/resolution","value":"Delivered host-bound transaction recovery with durable retirement and peer-safe compensation. Retired identities return actionable retirement guidance before plan comparison."},{"op":"add","path":"/metadata/expected_result","value":"Extensions can inspect and recover interrupted batches through a supported root-bound API without reading private paths or recreating journal and compensation rules."},{"op":"add","path":"/metadata/actual_result","value":"Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge."},{"op":"add","path":"/metadata/close_reason","value":"Implementation and review remediation verified; closure included in PR #1621."}],"before_hash":"189b7e49b26b2c4810b887bd40a6662fd7b3514759d242ac4474196e327cd653","after_hash":"b07b1f2a2c6e69986c70e833637755f6cccaea5df34bb0b20db859fe91f2b1f1","item_hash_version":3,"context":{"completion":{"timestamp":"2026-10-28T22:52:50.315Z","source":"close_time"},"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":"3f73d9c2ff2dd39e9250dafbedd378932a697023c2a1161c2c0ce7e112a6be99"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:52:51.392Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:52:51.392Z"}],"before_hash":"b07b1f2a2c6e69986c70e833637755f6cccaea5df34bb0b20db859fe91f2b1f1","after_hash":"dd677c322e8c8a1cb005908f3510b3c2fb95c4129d975f1bbec9c53834b4cc41","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":"9caf178cae1cf728c51cd09d07cca97e0cae68df7564ad8a86103f5e3dfc74cf"} diff --git a/.agents/pm/history/pm-gh1598.jsonl b/.agents/pm/history/pm-gh1598.jsonl index 508444d520..6b52123d90 100644 --- a/.agents/pm/history/pm-gh1598.jsonl +++ b/.agents/pm/history/pm-gh1598.jsonl @@ -16,3 +16,11 @@ {"hash_algorithm":"sha256","ts":"2026-10-28T22:07:22.006Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/5","value":{"created_at":"2026-10-28T22:07:22.006Z","author":"harness:codex","text":"Final candidate validation: full sandboxed source coverage passed 11540 tests (3 platform skips), 880 passing files and 1 skipped file, with exact 71421/71421 statements, 55025/55025 branches, 14707/14707 functions and 67487/67487 lines. Linked recovery 65/65 and SDK/semantic-preview 49/49 passed, along with typecheck, ESLint, duplicate checks, generated contracts/surface/catalogs, docs links, graph composition and record integrity. Bounded mutation lane: 345 killed and 7 equivalent of 352, no failures. Final packed npm tarball passed Node and Bun batch/replay/retirement/replacement and unsafe-preview bootstrap controls. Local transport performance also failed unchanged base; thresholds remain unchanged and the initial PR head passed both hosted performance gates. Final revised head must pass hosted checks before merge. New APIs are not yet claimed as published."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:07:22.006Z"}],"before_hash":"4a27cd36289577bfee3c89157d2a2d99d58f4f84e0b3cf4ae5b09695327e68b7","after_hash":"90444480833a3bef07493c8a63930ce369e3eda69bf8afac86fe6daf70524227","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":"3586366a7baf07d05c01160e95241e83a7a61f075a979fdf19cc7ec640ed8164"} {"hash_algorithm":"sha256","ts":"2026-10-28T22:07:25.052Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"release-operator","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]},"topic":{"value":"pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]}},"op":"close","patch":[{"op":"replace","path":"/metadata/expected_result","value":"Packages can use SDK-owned normalized preview records and bound identity while preserving read-only preview and replay safety."},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:07:25.052Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-10-28T22:07:25.021Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-10-28T22:07:25.021Z"},{"op":"add","path":"/metadata/resolution","value":"Implemented host-bound preview and commit methods with canonical final staged records, applied/adopted state, commit-time clock pointers and explicit replay constraints. Configuration-only bootstrap protects preview/status from optional-schema FIFO reads before staging."},{"op":"add","path":"/metadata/actual_result","value":"49/49 linked SDK/semantic-preview tests and full 11540-test exact-coverage run passed. Native unsafe-storage negative controls, type surface and Node/Bun packed artifact passed. Reviewed delivery is PR #1621; publication remains separate."},{"op":"add","path":"/metadata/close_reason","value":"Implementation and regression evidence complete; closure travels with the reviewed delivery."}],"before_hash":"90444480833a3bef07493c8a63930ce369e3eda69bf8afac86fe6daf70524227","after_hash":"abcaa5f8dc4695f7c4328239fd75389dc106ba2a940b287c4bdb629849346163","item_hash_version":3,"context":{"completion":{"timestamp":"2026-10-28T22:07:25.021Z","source":"close_time"},"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":"e75bcca6a77e76fee83bc466744ebb5f3e2ee2c6b231c741ed63e259797a7598"} {"hash_algorithm":"sha256","ts":"2026-10-28T22:07:25.991Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"release-operator","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]},"topic":{"value":"pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:07:25.991Z"}],"before_hash":"abcaa5f8dc4695f7c4328239fd75389dc106ba2a940b287c4bdb629849346163","after_hash":"e8f41c540cc2c192f998100df5b6578951f0ff3ebf9f29546e3e88d1c530a788","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":"b6787d67cc3297565b43a41c47ecdb32fe6b27cd64a78a6672dcd932e29c14b2"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:23:03.067Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"pm-gh1597","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"reopen","patch":[{"op":"remove","path":"/metadata/close_reason"},{"op":"remove","path":"/metadata/actual_result"},{"op":"remove","path":"/metadata/expected_result"},{"op":"remove","path":"/metadata/resolution"},{"op":"remove","path":"/metadata/completed_at"},{"op":"remove","path":"/metadata/closed_at"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:23:03.067Z"},{"op":"replace","path":"/metadata/status","value":"open"}],"before_hash":"e8f41c540cc2c192f998100df5b6578951f0ff3ebf9f29546e3e88d1c530a788","after_hash":"9003c03cb7c680006a1e8ecf8babe0c25e061c10303eec20ba7124605a760f56","item_hash_version":3,"context":{"recurrence":{"reason":"PR #1621 review requests precise replay guarantee bounded by committed-journal retention.","from_status":"closed","to_status":"open","previous_terminal":{"close_reason":"Implementation and regression evidence complete; closure travels with the reviewed delivery.","resolution":"Implemented host-bound preview and commit methods with canonical final staged records, applied/adopted state, commit-time clock pointers and explicit replay constraints. Configuration-only bootstrap protects preview/status from optional-schema FIFO reads before staging.","expected_result":"Packages can use SDK-owned normalized preview records and bound identity while preserving read-only preview and replay safety.","actual_result":"49/49 linked SDK/semantic-preview tests and full 11540-test exact-coverage run passed. Native unsafe-storage negative controls, type surface and Node/Bun packed artifact passed. Reviewed delivery is PR #1621; publication remains separate."}},"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":"c27e6fee4e094f26af528144fe67cc89841ec24a101ea4da291105f74df67351"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:23:03.790Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"pm-gh1597","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:23:03.790Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#568692524ccbb719c2f222a0"}],"before_hash":"9003c03cb7c680006a1e8ecf8babe0c25e061c10303eec20ba7124605a760f56","after_hash":"8496818ea8db9556f972591b4221c6cab4c535d2b269ed5111bbf324919ccec6","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":"d647ff31f9f3f21e4d2c6f5cb4fa98e5ebe77ef77a113634528ce9de7bf2a88e"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:23:03.934Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:23:03.934Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"8496818ea8db9556f972591b4221c6cab4c535d2b269ed5111bbf324919ccec6","after_hash":"9a89d066a4cbb42f3853107ebe50b6c183688d472c861f845747b6440fc94ad4","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":"f54ae973d58fea4a1c908dfb0cd43b8dc6b77989c16423c940782338f4a560b4"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:24:15.477Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/6","value":{"created_at":"2026-10-28T22:24:15.477Z","author":"harness:codex","text":"Second review cycle on PR #1621 clarified that identical-plan replay and changed-plan mismatch guarantees require retention of the committed journal. Existing GC may remove old committed receipts and the identity can then be treated as new; explicitly abandoned receipts remain protected. Documentation now states the boundary. Linked tests and full coverage are being rerun before reviewed closure."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:24:15.477Z"}],"before_hash":"9a89d066a4cbb42f3853107ebe50b6c183688d472c861f845747b6440fc94ad4","after_hash":"7cdc208ece60aa7df93d0b8547df28f21f79ea9d218774ffc47f03b79a845f05","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":"3a2beabe515981391ba6eae95c6fcd9e4e4ecbaf5ddd5411563bd75d3353f32c"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:25:04.785Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"test_run_track","patch":[{"op":"add","path":"/metadata/test_runs/2","value":{"run_id":"test-local-mvson46t-8nw20g","kind":"test","status":"passed","started_at":"2026-10-28T22:24:17.796Z","finished_at":"2026-10-28T22:25:04.757Z","recorded_at":"2026-10-28T22:25:04.757Z","passed":1,"failed":0,"skipped":0,"executions":[{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/integration/transactions/semantic-preview.integration.spec.ts","requested_pm_context_mode":"schema","pm_context_mode":"schema","workspace_context_mode":"source","trust_reason":"local_source_ref"}]}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:25:04.785Z"}],"before_hash":"7cdc208ece60aa7df93d0b8547df28f21f79ea9d218774ffc47f03b79a845f05","after_hash":"278c026365f343abdffd1f181acf081ed97113933e580897477c61c4a779a3ba","item_hash_version":3,"message":"Track test run summary (test-local-mvson46t-8nw20g)","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":"3c79b35f398cda5eaac3536ac7cf7d59264d4dd94a025e79b01e0153455a3f1d"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:52:52.366Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"release-operator","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]},"topic":{"value":"pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/7","value":{"created_at":"2026-10-28T22:52:52.365Z","author":"harness:codex","text":"Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:52:52.366Z"}],"before_hash":"278c026365f343abdffd1f181acf081ed97113933e580897477c61c4a779a3ba","after_hash":"8221de59ddededa20a4bc6ec9ece0dc6cc288d1d460ba63217987d5c90c08544","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":"8d961caa5a76e313f94b1d00fde84fc478af656c0d2e3897a409853696c5800f"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:52:53.286Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"release-operator","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]},"topic":{"value":"pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:52:53.286Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-10-28T22:52:53.234Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-10-28T22:52:53.234Z"},{"op":"add","path":"/metadata/resolution","value":"Delivered bound batch preview and commit with canonical staged records and safe preview bootstrap.Replay guarantees explicitly depend on retaining committed journals; GC removal can admit the identity as new."},{"op":"add","path":"/metadata/expected_result","value":"Packages can perform host-bound atomic batches and compare normalized intents using SDK-owned records instead of re-deriving roots or duplicating normalization."},{"op":"add","path":"/metadata/actual_result","value":"Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge."},{"op":"add","path":"/metadata/close_reason","value":"Implementation and review remediation verified; closure included in PR #1621."}],"before_hash":"8221de59ddededa20a4bc6ec9ece0dc6cc288d1d460ba63217987d5c90c08544","after_hash":"a452f017a15ec223d381f12b659b7d6c1a98a58bea689e05bf41608dc459e3f7","item_hash_version":3,"context":{"completion":{"timestamp":"2026-10-28T22:52:53.234Z","source":"close_time"},"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":"9657721859684138b02f804ae94c17787d18e0bc0b7c75d2b9b2cff7e777463d"} +{"hash_algorithm":"sha256","ts":"2026-10-28T22:52:54.188Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"release-operator","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]},"topic":{"value":"pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1598","release:pm-gh1597"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:52:54.188Z"}],"before_hash":"a452f017a15ec223d381f12b659b7d6c1a98a58bea689e05bf41608dc459e3f7","after_hash":"04a084ea3da6df364b4705a3ab817112f9f9a246d9a4b04c878e9472d42dc660","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":"44ac6d0967bc6d45945fd8705802aca0b90440c94e8084e7304a127e47270b97"} diff --git a/docs/SDK.md b/docs/SDK.md index 47087494c1..1432d3f93f 100644 --- a/docs/SDK.md +++ b/docs/SDK.md @@ -1676,9 +1676,12 @@ regenerated clocks, conservatively including existing or explicitly supplied clocks. These preview values are observations, not reserved commit values. Compare normalized intent separately from those clocks; commit still evaluates current state, attribution, extension policy and concurrency. A committed replay returns an empty -`records` array, not a reconstruction of its original write values. Replaying -the identical committed plan performs no item write; changing its ordered -payload under the same id refuses with `transaction_plan_mismatch`. +`records` array, not a reconstruction of its original write values. While the +committed journal is retained, replaying the identical plan performs no item +write; changing its ordered payload under the same id refuses with +`transaction_plan_mismatch`. If transaction GC removes that committed journal, +the coordinator can treat its id as new; replay guarantees do not survive that +removal. The workspace transaction lock serializes transaction coordinators. Ordinary SDK and CLI item writers can still interleave between a step's read and write; diff --git a/src/sdk/workspace-transaction.ts b/src/sdk/workspace-transaction.ts index 7bfb44ddc8..6f068a6c10 100644 --- a/src/sdk/workspace-transaction.ts +++ b/src/sdk/workspace-transaction.ts @@ -378,9 +378,9 @@ function journalPlanMismatch(transactionId: string): PmCliError { ); } -/** Status reads omit a requested plan; fully compensated attempts can be replanned. */ -function matchesJournalSteps(status: string, recorded: readonly string[], requested: readonly string[] | undefined): boolean { - return requested === undefined || status === "compensated" || +/** Status reads omit a plan; retired ids reach their dedicated refusal and compensated attempts can be replanned. */ +function matchesJournalSteps(journal: Partial, recorded: readonly string[], requested: readonly string[] | undefined): boolean { + return requested === undefined || journal.abandonment !== undefined || journal.status === "compensated" || (recorded.length === requested.length && recorded.every((id, index) => id === requested[index])); } @@ -413,8 +413,9 @@ function parseJournal( ) throw invalidJournal(transactionId, "invalid lifecycle, metadata, status or step ids"); // A compensated attempt was rolled back step by step and holds nothing to // resume, so a re-planned document may start a fresh attempt under the same - // id; every other status must replay the exact plan it recorded. - const stepsMatch = matchesJournalSteps(journal.status, recordedStepIds, stepIds); + // id. Retired ids must instead reach the permanent retirement refusal, + // regardless of the requested plan; all other attempts replay the exact plan. + const stepsMatch = matchesJournalSteps(journal, recordedStepIds, stepIds); if (!stepsMatch) throw journalPlanMismatch(transactionId); return { ...(journal as WorkspaceTransactionJournal), diff --git a/tests/unit/sdk/transactions/host-bound.spec.ts b/tests/unit/sdk/transactions/host-bound.spec.ts index 3192dcdc9c..d4eaea4c1d 100644 --- a/tests/unit/sdk/transactions/host-bound.spec.ts +++ b/tests/unit/sdk/transactions/host-bound.spec.ts @@ -55,6 +55,8 @@ describe("host-bound item batches and recovery (pm-gh1597, pm-gh1598)", () => { await client.itemTransactions.supersede("retired", "replacement", { reason: "Retry request" }); expect(await readFile(path.join(pmPath, "transactions", "sdk", "retired.json"), "utf8")).toBe(journalBytes); await expect(client.commitItemMutations(options)).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); + await expect(client.commitItemMutations({ ...options, mutations: [{ op: "update", id: original.id, options: { title: "Forbidden replan" } }] })).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); + expect((await client.get(original.id)).item.title).toBe("Original"); await expect(client.itemTransactions.abandon("retired", { reason: "Different replacement" })).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); await client.commitItemMutations({ ...options, transactionId: "replacement", mutations: [{ op: "update", id: original.id, options: { title: "Replanned" } }] }); expect((await client.get(original.id)).item.title).toBe("Replanned"); @@ -131,7 +133,7 @@ describe("host-bound item batches and recovery (pm-gh1597, pm-gh1598)", () => { vi.restoreAllMocks(); expect((await client.itemTransactions.status("compensation"))?.journal.schemaVersion).toBe(2); if (createCompensation === "close") await client.reopen("compensated", "Peer reopens after completed compensation"); - await expect(client.commitItemMutations(options)).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); + await expect(client.commitItemMutations({ ...options, mutations: [{ op: "create", id: "compensated", options: { title: "Forbidden replan", type: "Task" } }] })).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); expect((await client.itemTransactions.abandon("compensation", { reason: "Resume retirement" })).journal.status).toBe("abandoned"); if (createCompensation === "close") expect((await client.get("compensated")).item.status).toBe("open"); await client.create({ id: "later", title: "Later", type: "Task" }); From f340350271d5e686ffdb52ac01336121a5a59c75 Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Thu, 29 Oct 2026 00:20:08 +0100 Subject: [PATCH 4/5] docs(pm): retain Windows benchmark failure and unchanged retry evidence Attach the observed scale-manifest timeout and product-budget failures to the existing runner-qualification diagnosis. Record the preceding green head and the single successful failed-jobs retry on the same commit without inferring causation or changing source, timeouts, qualification or performance budgets. Preserve the failed admission as historical evidence and keep the canonical diagnosis open and unclaimed. Tracker history and storage integrity pass. --- .agents/pm/history/pm-bj7rq0.jsonl | 1 + .agents/pm/issues/pm-bj7rq0.toon | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.agents/pm/history/pm-bj7rq0.jsonl b/.agents/pm/history/pm-bj7rq0.jsonl index f3b04e1e7d..8f24c18ae6 100644 --- a/.agents/pm/history/pm-bj7rq0.jsonl +++ b/.agents/pm/history/pm-bj7rq0.jsonl @@ -179,3 +179,4 @@ {"hash_algorithm":"sha256","ts":"2026-10-28T16:28:14.541Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"738f7d9b84aae278517b105a","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1603","claim:pm-gh1617","lineage:pm-gh1603","lineage:pm-mpbb","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1603+pm-gh1617","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1603","claim:pm-gh1617","lineage:pm-gh1603","lineage:pm-mpbb","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/115","value":{"created_at":"2026-10-28T16:28:14.540Z","author":"harness:codex","text":"2026-10-28 validation evidence on Node 26.12.1: full coverage reached 11520 passing tests but failed packed continuation because npm/package.json was not resolvable and scale benchmark at unchanged 30-second timeout. Focused rerun with NODE_PATH set to npm root -g passed both (packed Node/Bun continuation and 28.465-second benchmark). No test timeout or gate threshold changed; this does not claim a successful full coverage run."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T16:28:14.541Z"}],"before_hash":"16296cc3fcdd077579552298fddfbe63ae5840eacae3844215fd773742fe9403","after_hash":"9efbb61564cad16f2299de8edcbd36f5799133955a7766e67af463bd839a25da","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":"ce6cadff4bddf2dadb4bbe4a8793d3b75c4e99cffce81d68d2817024faed9e75"} {"hash_algorithm":"sha256","ts":"2026-10-28T16:47:40.865Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"738f7d9b84aae278517b105a","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/116","value":{"created_at":"2026-10-28T16:47:40.865Z","author":"harness:codex","text":"Current branch local static checks reached the unchanged CLI transport-floor gate and failed on a qualified Node 26.12.1 runner (best list 471ms vs 419ms, context 466ms vs 433ms, next 480ms vs 440ms, create 448ms vs 398ms, claim 557ms vs 415ms). Do not interpret earlier focused test success as admission. Comparing untouched main separately; required hosted Node 24 static admission remains authoritative for this delivery."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T16:47:40.865Z"}],"before_hash":"9efbb61564cad16f2299de8edcbd36f5799133955a7766e67af463bd839a25da","after_hash":"ca29e59a6efe0a7e1d7529bae8b90b21c8d45215fed0dd3f876c7bb3dca20d8f","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":"ea0e3c687afe9642248aa22836f5c7f1e3163ae35518e43b1e4e8752bca54a6e"} {"hash_algorithm":"sha256","ts":"2026-10-28T16:49:31.727Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"738f7d9b84aae278517b105a","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/117","value":{"created_at":"2026-10-28T16:49:31.726Z","author":"harness:codex","text":"Untouched-main comparison completed from git archive of 0194b37689531155b105a614874cc26131e36a60 in an isolated build using the same dependencies/runtime. The unchanged transport-floor also fails on a qualified runner: get 407ms > 362ms, context 454ms > 433ms, next 475ms > 440ms, create 455ms > 398ms, claim 487ms > 415ms. This confirms an existing local admission failure, not a green baseline; thresholds remain unchanged and exact-head hosted gates must pass."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T16:49:31.727Z"}],"before_hash":"ca29e59a6efe0a7e1d7529bae8b90b21c8d45215fed0dd3f876c7bb3dca20d8f","after_hash":"88eee0755fdadecd9c182afd56fa7603933e971167ac1cc283dabef12b9ca6f1","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":"827226d9bc9272c6914baa9494bb4fb6bd058738c7a4d540fa0d529775b30dcc"} +{"hash_algorithm":"sha256","ts":"2026-10-28T23:19:03.932Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/118","value":{"created_at":"2026-10-28T23:19:03.931Z","author":"harness:codex","text":"PR #1621 validation recurrence: head 4d2a20af11734e3eddc41a6cf5b7fc25375af195 initially failed Windows script cohort 2/2 in CI run 40783675212, job 123152027862. The unchanged scale-benchmark custom-manifest keeper exceeded its 30000ms timeout and fixed product targets (SDK create p95 2367ms and claim 3051ms, each ceiling 1000ms). The benchmark, test and workflow have no diff from preceding head 512184eb9, where all required checks passed. After the complete run finished, one failed-jobs retry on the same head passed all required checks with no source, timeout, qualification or budget changes. Preserve the first failed admission; retry success does not establish its cause. Current local transport also failed on candidate and untouched base f8ca152d, while both tested PR heads passed hosted static/performance admission. This existing diagnosis remains open and unclaimed; no duplicate issue or performance fix is claimed. Evidence: https://github.com/unbraind/pm-cli/actions/runs/40783675212"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T23:19:03.932Z"}],"before_hash":"88eee0755fdadecd9c182afd56fa7603933e971167ac1cc283dabef12b9ca6f1","after_hash":"7c84c062fe813be7b33db26aaaf0c008f211aee99b03ef24a113a6bfb01458d3","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":"28c810db0003efab65189cd40efa08bcc2a52cff2bd27e1b0a0d676afb3e6a78"} diff --git a/.agents/pm/issues/pm-bj7rq0.toon b/.agents/pm/issues/pm-bj7rq0.toon index 6ede14f5a7..8cea2d5adb 100644 --- a/.agents/pm/issues/pm-bj7rq0.toon +++ b/.agents/pm/issues/pm-bj7rq0.toon @@ -6,7 +6,7 @@ status: open priority: 2 tags: [] created_at: "2026-09-28T06:20:35.648Z" -updated_at: "2026-10-28T16:49:31.727Z" +updated_at: "2026-10-28T23:19:03.932Z" author: "harness:codex" estimated_minutes: 240 acceptance_criteria: Reproduce with recorded runtime and runner-pressure evidence on an isolated supported environment and compare the unchanged base revision; Classify runner qualification separately from product admission without treating failed or unavailable measurements as passes; Fix only the demonstrated cause and preserve every latency and RSS ratchet unless an explicitly reviewed platform correction is supported; Add positive and negative regression controls proving real command regressions still fail and any runner refusal is explicit @@ -22,7 +22,7 @@ dependencies[6]{id,kind,created_at,author,source_kind,author_source}: pm-jm7m3o,related,"2026-10-19T13:23:49.412Z","harness:codex","cli:update:dep",detected pm-58zon0,related,"2026-10-19T14:07:58.070Z","harness:codex","cli:update:dep",detected pm-2zjs0g,related,"2026-10-20T16:26:25.937Z","harness:codex","cli:update:dep",detected -comments[118]: +comments[119]: - created_at: "2026-09-28T06:20:35.648Z" author: "harness:codex" text: "text: Duplicate check 2026-09-28: inspected the complete all-status corpus for startup, latency, entrypoint and benchmark owners and ran the live all-status CLI startup budget search. The completed transport-floor owner pm-yse5dt remains closed: its ten-sample implementation is present. The completed SDK cold-cache sampling fix is a different admission boundary and does not establish this failure mechanism. No active individual issue owns the repeated transport admission failures observed in this review. The existing scale outcome pm-o87av6 remains the parent." @@ -379,6 +379,9 @@ comments[118]: - created_at: "2026-10-28T16:49:31.726Z" author: "harness:codex" text: "Untouched-main comparison completed from git archive of 0194b37689531155b105a614874cc26131e36a60 in an isolated build using the same dependencies/runtime. The unchanged transport-floor also fails on a qualified runner: get 407ms > 362ms, context 454ms > 433ms, next 475ms > 440ms, create 455ms > 398ms, claim 487ms > 415ms. This confirms an existing local admission failure, not a green baseline; thresholds remain unchanged and exact-head hosted gates must pass." + - created_at: "2026-10-28T23:19:03.931Z" + author: "harness:codex" + text: "PR #1621 validation recurrence: head 4d2a20af11734e3eddc41a6cf5b7fc25375af195 initially failed Windows script cohort 2/2 in CI run 40783675212, job 123152027862. The unchanged scale-benchmark custom-manifest keeper exceeded its 30000ms timeout and fixed product targets (SDK create p95 2367ms and claim 3051ms, each ceiling 1000ms). The benchmark, test and workflow have no diff from preceding head 512184eb9, where all required checks passed. After the complete run finished, one failed-jobs retry on the same head passed all required checks with no source, timeout, qualification or budget changes. Preserve the first failed admission; retry success does not establish its cause. Current local transport also failed on candidate and untouched base f8ca152d, while both tested PR heads passed hosted static/performance admission. This existing diagnosis remains open and unclaimed; no duplicate issue or performance fix is claimed. Evidence: https://github.com/unbraind/pm-cli/actions/runs/40783675212" files[12]: - path: .github/workflows/ci.yml scope: project From 8a14dfc644855a9f40e40473de1322244b55a3e4 Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Thu, 29 Oct 2026 01:14:02 +0100 Subject: [PATCH 5/5] fix(sdk): distinguish pending retirement in recovery refusals Build retirement errors from the validated journal so incomplete retirement reports its durable replacement identity and the exact retry constraint. Keep the transaction_abandoned code and existing terminal-abandonment behavior. Use the same guidance for forward replay and mismatched abandonment retries. Describe pending retirement accurately both during compensation and after compensation when final journal publication is interrupted. Add native negative controls for replacement and non-replacement intents, and verify that a wrong retry preserves the pending receipt. Validation: 11540 tests passed with exact 100% statements, branches, functions and lines; linked recovery, types, lint, generated contracts and packed Node/Bun pending-retirement controls passed. Include reviewed PM closure and generated changelog with the implementation. --- .../pm/extensions/.managed-extensions.json | 2 +- .agents/pm/features/pm-gh1597.toon | 31 +++++++++++++------ .agents/pm/history/pm-gh1597.jsonl | 8 +++++ CHANGELOG.md | 2 +- docs/SDK.md | 6 +++- src/sdk/workspace-transaction.ts | 20 +++++++----- .../unit/sdk/transactions/host-bound.spec.ts | 8 +++-- 7 files changed, 56 insertions(+), 21 deletions(-) diff --git a/.agents/pm/extensions/.managed-extensions.json b/.agents/pm/extensions/.managed-extensions.json index 4c9354968d..ac40b3d1e1 100644 --- a/.agents/pm/extensions/.managed-extensions.json +++ b/.agents/pm/extensions/.managed-extensions.json @@ -1,6 +1,6 @@ { "version": 1, - "updated_at": "2026-10-28T22:53:52.778Z", + "updated_at": "2026-10-29T00:12:02.978Z", "entries": [ { "name": "builtin-calendar", diff --git a/.agents/pm/features/pm-gh1597.toon b/.agents/pm/features/pm-gh1597.toon index 16d7b5ad1c..60a7a4fa64 100644 --- a/.agents/pm/features/pm-gh1597.toon +++ b/.agents/pm/features/pm-gh1597.toon @@ -6,22 +6,22 @@ status: closed priority: 1 tags: [] created_at: "2026-10-26T04:54:49.262Z" -updated_at: "2026-10-28T22:52:51.392Z" -closed_at: "2026-10-28T22:52:50.315Z" -completed_at: "2026-10-28T22:52:50.315Z" +updated_at: "2026-10-29T00:11:06.604Z" +closed_at: "2026-10-29T00:11:05.226Z" +completed_at: "2026-10-29T00:11:05.226Z" author: "harness:codex" estimated_minutes: 300 acceptance_criteria: Expose typed host-bound journal state and applied/compensated step receipts with plan identity; Provide safe abandonment and supersession using proven apply markers and existing guarded compensation; never overwrite later peer edits or silently compensate committed work; Name executable public recovery in transaction-plan-mismatch guidance and verify non-Git crash/retry/peer-edit controls plus SDK contract documentation parent: pm-9rgaal risk: high confidence: high -resolution: Delivered host-bound transaction recovery with durable retirement and peer-safe compensation. Retired identities return actionable retirement guidance before plan comparison. -expected_result: Extensions can inspect and recover interrupted batches through a supported root-bound API without reading private paths or recreating journal and compensation rules. -actual_result: "Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge." +resolution: "Delivered bound transaction status, safe abandonment and supersession using retained original plans, durable versioned retirement intent, normalized identities, idempotent audit and locked compensation ownership. Retired IDs return their dedicated refusal before plan comparison; pending retirement reports the persisted replacement and accurate retry guidance. Committed work and peer edits are protected." +expected_result: Packages can inspect and safely retire interrupted item batches through their configured client without rebuilding private journal rules. +actual_result: "Pending-retirement guidance validation complete: 11540 passing tests, three platform skips and exact 100/100/100/100 coverage (statements 71424/71424; branches 55038/55038; functions 14707/14707; lines 67490/67490). The linked 65-test recovery run, typecheck, lint, generated contracts/catalog/surface and docs checks pass. Packed npm consumers passed under Node and Bun, including actual pending retirement after a peer edit and its persisted replacement guidance. Three pre-fix native cases reproduced inaccurate terminal wording; the fix distinguishes pending retirement during compensation or final journal publication and preserves terminal behavior. Final revised-head CI and renewed review remain required before merge; publication is separate." dependencies[2]{id,kind,created_at,author,source_kind,author_source}: pm-9rgaal,implements,"2026-10-26T04:54:49.262Z","harness:codex","cli:create:dep",detected pm-y9hq,discovered_from,"2026-10-26T04:54:49.262Z","harness:codex","cli:create:dep",detected -comments[10]{created_at,author,text}: +comments[12]{created_at,author,text}: "2026-10-26T04:54:49.262Z","harness:codex","Duplicate check: complete strict all-status corpus plus live request-specific searches and full terminal-lineage reads found no exact active owner. Existing SDK promotion and transaction/preview delivery remain completed; this item owns the newly requested public surface." "2026-10-28T19:44:07.695Z","harness:codex","Implementation scope: retain original item plans in coordinator journals, expose read-only status and host-bound guarded abandonment/supersession, refuse committed and peer-edited work, preserve append-only compensation and audit evidence. Complete strict 3148-item all-status census has no omissions; 38 open GitHub issues each already have a canonical PM link comment. No open PRs or GitHub dependency/code/secret alerts at intake." "2026-10-28T20:16:18.094Z","harness:codex","Native late-peer recovery oracle initially exposed a delete-store gap: the existing scoped item precondition was checked by update/close but not by locked deletion. Isolated candidate adds the same assertion before deletion policy/hooks and centralizes create compensation ownership checks. Close and delete both preserve a peer edit injected immediately before item-lock acquisition. Isolated focused proof passes51 tests; original checkout remains frozen for the in-flight full coverage run. Retirement intent is additionally retained before compensation to fence forward replay across recovery crashes." @@ -32,6 +32,8 @@ comments[10]{created_at,author,text}: "2026-10-28T22:07:21.136Z","harness:codex","Final candidate validation: full sandboxed source coverage passed 11540 tests (3 platform skips), 880 passing files and 1 skipped file, with exact 71421/71421 statements, 55025/55025 branches, 14707/14707 functions and 67487/67487 lines. Linked recovery 65/65 and SDK/semantic-preview 49/49 passed, along with typecheck, ESLint, duplicate checks, generated contracts/surface/catalogs, docs links, graph composition and record integrity. Bounded mutation lane: 345 killed and 7 equivalent of 352, no failures. Final packed npm tarball passed Node and Bun batch/replay/retirement/replacement and unsafe-preview bootstrap controls. Local transport performance also failed unchanged base; thresholds remain unchanged and the initial PR head passed both hosted performance gates. Final revised head must pass hosted checks before merge. New APIs are not yet claimed as published." "2026-10-28T22:24:14.492Z","harness:codex","Second review cycle on PR #1621: five native recovery cases reproduced the retired-ID precedence defect, returning transaction_plan_mismatch for changed payloads after durable retirement or during interrupted compensation. Journal validation now preserves structural checks but defers plan comparison for valid retirement metadata so the coordinator returns transaction_abandoned before any forward step. Existing crash tables exercise unchanged items after refusal. Linked tests and exact full coverage are being rerun; this item is actively claimed only for this review remediation." "2026-10-28T22:52:49.339Z","harness:codex","Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge." + "2026-10-28T23:45:51.485Z","harness:codex","Final review refinement: three pre-fix native cases reproduced inaccurate fully-abandoned wording for incomplete retirement. The same transaction_abandoned code now distinguishes pending retirement and supplies the persisted superseded_by identity (or null for abandonment without replacement) with retry guidance. The message is accurate both during compensation and after compensation when final journal publication remains incomplete; it does not incorrectly assert compensation must still be running. Commit replay and abandonment mismatch share the validated-journal helper; terminal abandoned behavior is preserved. Focused linked tests, typecheck, lint, contracts/catalog/surface and docs checks pass. Full coverage and packed Node/Bun consumer controls are running before final closure." + "2026-10-29T00:11:03.879Z","harness:codex","Pending-retirement guidance validation complete: 11540 passing tests, three platform skips and exact 100/100/100/100 coverage (statements 71424/71424; branches 55038/55038; functions 14707/14707; lines 67490/67490). The linked 65-test recovery run, typecheck, lint, generated contracts/catalog/surface and docs checks pass. Packed npm consumers passed under Node and Bun, including actual pending retirement after a peer edit and its persisted replacement guidance. Three pre-fix native cases reproduced inaccurate terminal wording; the fix distinguishes pending retirement during compensation or final journal publication and preserves terminal behavior. Final revised-head CI and renewed review remain required before merge; publication is separate." learnings[2]{created_at,author,text}: "2026-10-28T20:16:19.379Z","harness:codex","Retiring an interrupted batch requires a durable intent before compensation, not only a terminal status afterward. Every destructive compensation must recheck ownership under the target item lock; a pre-lock history comparison alone does not protect a late peer edit." "2026-10-28T21:55:42.128Z","harness:codex",Normalize transaction identity before building both durable effects and journal receipts. Normalizing only the coordinator key can make recovery miss its own apply markers and falsely report compensation. @@ -51,7 +53,7 @@ files[13]{path,scope}: tests/unit/sdk/workspace-transaction.spec.ts,project tests[1]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts,project,300,"harness:codex","2026-10-28T19:50:40.616Z",local_mutation,feat/host-bound-item-transactions -test_runs[3]: +test_runs[4]: - run_id: test-local-mvskr61r-dyaj7d kind: test status: passed @@ -85,8 +87,19 @@ test_runs[3]: skipped: 0 executions[1]{command,requested_pm_context_mode,pm_context_mode,workspace_context_mode,trust_reason}: node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts,schema,schema,source,local_source_ref + - run_id: test-local-mvsrgsli-lir0lf + kind: test + status: passed + started_at: "2026-10-28T23:43:44.636Z" + finished_at: "2026-10-28T23:44:08.646Z" + recorded_at: "2026-10-28T23:44:08.646Z" + passed: 1 + failed: 0 + skipped: 0 + executions[1]{command,requested_pm_context_mode,pm_context_mode,workspace_context_mode,trust_reason}: + node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts,schema,schema,source,local_source_ref docs[2]{path,scope}: docs/generated/REFUSAL_CLOSURE_CENSUS.md,project docs/SDK.md,project -close_reason: Implementation and review remediation verified; closure included in PR #1621. +close_reason: Host-bound recovery and all reviewed refinements are implemented and regression-verified; closure travels with PR #1621. body: "" diff --git a/.agents/pm/history/pm-gh1597.jsonl b/.agents/pm/history/pm-gh1597.jsonl index 6b9b7287fd..f2dce03be6 100644 --- a/.agents/pm/history/pm-gh1597.jsonl +++ b/.agents/pm/history/pm-gh1597.jsonl @@ -28,3 +28,11 @@ {"hash_algorithm":"sha256","ts":"2026-10-28T22:52:49.339Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/9","value":{"created_at":"2026-10-28T22:52:49.339Z","author":"harness:codex","text":"Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:52:49.339Z"}],"before_hash":"b60d0b25ba9d0271f632b7457c96414266cae998b14184dbf493dbaac0be593e","after_hash":"189b7e49b26b2c4810b887bd40a6662fd7b3514759d242ac4474196e327cd653","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":"1e5db91c798318078a8611301ea88f317dc7c7d9ba08a524c84ceb3e57cc9591"} {"hash_algorithm":"sha256","ts":"2026-10-28T22:52:50.348Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:52:50.348Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-10-28T22:52:50.315Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-10-28T22:52:50.315Z"},{"op":"add","path":"/metadata/resolution","value":"Delivered host-bound transaction recovery with durable retirement and peer-safe compensation. Retired identities return actionable retirement guidance before plan comparison."},{"op":"add","path":"/metadata/expected_result","value":"Extensions can inspect and recover interrupted batches through a supported root-bound API without reading private paths or recreating journal and compensation rules."},{"op":"add","path":"/metadata/actual_result","value":"Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge."},{"op":"add","path":"/metadata/close_reason","value":"Implementation and review remediation verified; closure included in PR #1621."}],"before_hash":"189b7e49b26b2c4810b887bd40a6662fd7b3514759d242ac4474196e327cd653","after_hash":"b07b1f2a2c6e69986c70e833637755f6cccaea5df34bb0b20db859fe91f2b1f1","item_hash_version":3,"context":{"completion":{"timestamp":"2026-10-28T22:52:50.315Z","source":"close_time"},"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":"3f73d9c2ff2dd39e9250dafbedd378932a697023c2a1161c2c0ce7e112a6be99"} {"hash_algorithm":"sha256","ts":"2026-10-28T22:52:51.392Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"workset:pm-gh1597+pm-gh1598","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","claim:pm-gh1598","lineage:pm-gh1598","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T22:52:51.392Z"}],"before_hash":"b07b1f2a2c6e69986c70e833637755f6cccaea5df34bb0b20db859fe91f2b1f1","after_hash":"dd677c322e8c8a1cb005908f3510b3c2fb95c4129d975f1bbec9c53834b4cc41","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":"9caf178cae1cf728c51cd09d07cca97e0cae68df7564ad8a86103f5e3dfc74cf"} +{"hash_algorithm":"sha256","ts":"2026-10-28T23:42:21.559Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"reopen","patch":[{"op":"remove","path":"/metadata/close_reason"},{"op":"remove","path":"/metadata/actual_result"},{"op":"remove","path":"/metadata/expected_result"},{"op":"remove","path":"/metadata/resolution"},{"op":"remove","path":"/metadata/completed_at"},{"op":"remove","path":"/metadata/closed_at"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T23:42:21.559Z"},{"op":"replace","path":"/metadata/status","value":"open"}],"before_hash":"dd677c322e8c8a1cb005908f3510b3c2fb95c4129d975f1bbec9c53834b4cc41","after_hash":"869456138d2ffd76899c68b6bf8e24eade1ad5a246a2a8934ba29a01e6f47ddd","item_hash_version":3,"context":{"recurrence":{"reason":"PR #1621 final review found that pending-retirement mismatches need accurate state and persisted replacement guidance.","from_status":"closed","to_status":"open","previous_terminal":{"close_reason":"Implementation and review remediation verified; closure included in PR #1621.","resolution":"Delivered host-bound transaction recovery with durable retirement and peer-safe compensation. Retired identities return actionable retirement guidance before plan comparison.","expected_result":"Extensions can inspect and recover interrupted batches through a supported root-bound API without reading private paths or recreating journal and compensation rules.","actual_result":"Final review remediation validation: full suite passed with exact 100/100/100/100 source coverage (statements 71421/71421; branches 55026/55026; functions 14707/14707; lines 67487/67487). Linked recovery 65/65 and SDK/semantic-preview 49/49 passed again, as did build, typecheck, ESLint, contracts, SDK surface and docs links. Final packed artifact passed Node and Bun including changed-plan refusal for retired identities. Five pre-fix native cases returned the wrong plan-mismatch code; the fixed cases return transaction_abandoned and preserve state. Previous reviewed head 512184eb9 passed every required GitHub check including macOS and both performance gates; this revision still requires its own hosted checks and renewed review before merge."}},"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":"6748a3b3433290462fa047b149c0365e78affafc664fae9fec55ef0433a3a59a"} +{"hash_algorithm":"sha256","ts":"2026-10-28T23:42:22.386Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","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-28T23:42:22.386Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#568692524ccbb719c2f222a0"}],"before_hash":"869456138d2ffd76899c68b6bf8e24eade1ad5a246a2a8934ba29a01e6f47ddd","after_hash":"ebab3d8957cbcac78ec6705c7e70d4fd176a839abbab19f9ee99a992d0ee51ca","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":"e1ea04db8f001e621cea8466de31ffbec80d6b0829a97bab03dfc16999b4ce5e"} +{"hash_algorithm":"sha256","ts":"2026-10-28T23:42:22.666Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"pm-gh1597","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T23:42:22.666Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"ebab3d8957cbcac78ec6705c7e70d4fd176a839abbab19f9ee99a992d0ee51ca","after_hash":"bd70ebc0c6d07218267f09d7445930fc26031f04ddc07417bec02028b6851fb6","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":"b4550a01b4f92f2307519ae0fb4df2769d1e4d1150eacb6350020e17f364b1b0"} +{"hash_algorithm":"sha256","ts":"2026-10-28T23:44:08.681Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"pm-gh1597","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"test_run_track","patch":[{"op":"add","path":"/metadata/test_runs/3","value":{"run_id":"test-local-mvsrgsli-lir0lf","kind":"test","status":"passed","started_at":"2026-10-28T23:43:44.636Z","finished_at":"2026-10-28T23:44:08.646Z","recorded_at":"2026-10-28T23:44:08.646Z","passed":1,"failed":0,"skipped":0,"executions":[{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/transactions/host-bound.spec.ts tests/unit/sdk/item-transaction.spec.ts tests/unit/sdk/workspace-transaction.spec.ts","requested_pm_context_mode":"schema","pm_context_mode":"schema","workspace_context_mode":"source","trust_reason":"local_source_ref"}]}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T23:44:08.681Z"}],"before_hash":"bd70ebc0c6d07218267f09d7445930fc26031f04ddc07417bec02028b6851fb6","after_hash":"1b4c5746bf506db37ebef7ad01b4e3bd5d3381aa1507e8bc1625b4a764284072","item_hash_version":3,"message":"Track test run summary (test-local-mvsrgsli-lir0lf)","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":"817e133b8e90466ae85d9087c4d11c7a7903232ad79d0c5825320ef984de2e71"} +{"hash_algorithm":"sha256","ts":"2026-10-28T23:45:51.485Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"pm-gh1597","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/10","value":{"created_at":"2026-10-28T23:45:51.485Z","author":"harness:codex","text":"Final review refinement: three pre-fix native cases reproduced inaccurate fully-abandoned wording for incomplete retirement. The same transaction_abandoned code now distinguishes pending retirement and supplies the persisted superseded_by identity (or null for abandonment without replacement) with retry guidance. The message is accurate both during compensation and after compensation when final journal publication remains incomplete; it does not incorrectly assert compensation must still be running. Commit replay and abandonment mismatch share the validated-journal helper; terminal abandoned behavior is preserved. Focused linked tests, typecheck, lint, contracts/catalog/surface and docs checks pass. Full coverage and packed Node/Bun consumer controls are running before final closure."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-28T23:45:51.485Z"}],"before_hash":"1b4c5746bf506db37ebef7ad01b4e3bd5d3381aa1507e8bc1625b4a764284072","after_hash":"18e126652be4b2b69a0321918a7184478cb4873def31908f36e997e894846b7d","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":"70a6832357271d3bd0e87bfdc1b40b4c851b8f492c50fc78c0a4ef6c18bce5ec"} +{"hash_algorithm":"sha256","ts":"2026-10-29T00:11:03.879Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"pm-gh1597","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/11","value":{"created_at":"2026-10-29T00:11:03.879Z","author":"harness:codex","text":"Pending-retirement guidance validation complete: 11540 passing tests, three platform skips and exact 100/100/100/100 coverage (statements 71424/71424; branches 55038/55038; functions 14707/14707; lines 67490/67490). The linked 65-test recovery run, typecheck, lint, generated contracts/catalog/surface and docs checks pass. Packed npm consumers passed under Node and Bun, including actual pending retirement after a peer edit and its persisted replacement guidance. Three pre-fix native cases reproduced inaccurate terminal wording; the fix distinguishes pending retirement during compensation or final journal publication and preserves terminal behavior. Final revised-head CI and renewed review remain required before merge; publication is separate."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-29T00:11:03.879Z"}],"before_hash":"18e126652be4b2b69a0321918a7184478cb4873def31908f36e997e894846b7d","after_hash":"138b89be17bb45dc4ab84a330a0f68fc5914902248da639d03c2b0aaf4209632","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":"d55621f3566b3fd47fe70c31dead5eaee03915578c4e530cd193eb7fd57e5eb5"} +{"hash_algorithm":"sha256","ts":"2026-10-29T00:11:05.287Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"pm-gh1597","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-29T00:11:05.287Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-10-29T00:11:05.226Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-10-29T00:11:05.226Z"},{"op":"add","path":"/metadata/resolution","value":"Delivered bound transaction status, safe abandonment and supersession using retained original plans, durable versioned retirement intent, normalized identities, idempotent audit and locked compensation ownership. Retired IDs return their dedicated refusal before plan comparison; pending retirement reports the persisted replacement and accurate retry guidance. Committed work and peer edits are protected."},{"op":"add","path":"/metadata/expected_result","value":"Packages can inspect and safely retire interrupted item batches through their configured client without rebuilding private journal rules."},{"op":"add","path":"/metadata/actual_result","value":"Pending-retirement guidance validation complete: 11540 passing tests, three platform skips and exact 100/100/100/100 coverage (statements 71424/71424; branches 55038/55038; functions 14707/14707; lines 67490/67490). The linked 65-test recovery run, typecheck, lint, generated contracts/catalog/surface and docs checks pass. Packed npm consumers passed under Node and Bun, including actual pending retirement after a peer edit and its persisted replacement guidance. Three pre-fix native cases reproduced inaccurate terminal wording; the fix distinguishes pending retirement during compensation or final journal publication and preserves terminal behavior. Final revised-head CI and renewed review remain required before merge; publication is separate."},{"op":"add","path":"/metadata/close_reason","value":"Host-bound recovery and all reviewed refinements are implemented and regression-verified; closure travels with PR #1621."}],"before_hash":"138b89be17bb45dc4ab84a330a0f68fc5914902248da639d03c2b0aaf4209632","after_hash":"b2669d8d147e0c19668813a62c83d54bceba051968003571e10f77059698505a","item_hash_version":3,"context":{"completion":{"timestamp":"2026-10-29T00:11:05.226Z","source":"close_time"},"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":"b0f1664c5acc7cec72c04afb59fea3f9200bea70827bb0aa833d96096f89a5a0"} +{"hash_algorithm":"sha256","ts":"2026-10-29T00:11:06.604Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_model":"gpt-6-astra","agent_model_source":"probe","agent_instance":"568692524ccbb719c2f222a0","agent_provenance":{"model":{"value":"gpt-6-astra","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]},"topic":{"value":"pm-gh1597","source":"inferred","confidence":"medium","rule_version":"v2","evidence":["claim:pm-gh1597","lineage:pm-gh1597","lineage:pm-9rgaal","lineage:pm-doxj"]}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-29T00:11:06.604Z"}],"before_hash":"b2669d8d147e0c19668813a62c83d54bceba051968003571e10f77059698505a","after_hash":"6c55f6affd2111bc4bfaf5245345e883fc3fc70253aa68f429ed6bf15b54ef02","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":"5584144627610ee99690ac83d37b5e0268d0388e10e63cae019489393e1f4ef5"} diff --git a/CHANGELOG.md b/CHANGELOG.md index 62f28543c9..e84c83cd4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,8 @@ ### Added -- GH-1598: bind batch mutation APIs to PmClient and expose canonical staged preview records ([pm-gh1598](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/features/pm-gh1598.toon)) - GH-1597: expose host-bound item transaction status and safe abandonment or supersession ([pm-gh1597](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/features/pm-gh1597.toon)) +- GH-1598: bind batch mutation APIs to PmClient and expose canonical staged preview records ([pm-gh1598](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/features/pm-gh1598.toon)) ### Fixed diff --git a/docs/SDK.md b/docs/SDK.md index 1432d3f93f..a92eef7dd7 100644 --- a/docs/SDK.md +++ b/docs/SDK.md @@ -1714,7 +1714,11 @@ intent instead of silently resuming it. `supersede(id, newId, { reason })` performs that retirement and records the replacement identity; it does not atomically commit the replacement plan or reserve its id. Repeating the same retirement is idempotent. Committed journals -cannot be abandoned. During compensation, a later peer edit refuses with +cannot be abandoned. A pending-retirement refusal keeps the +`transaction_abandoned` code, reports `retirement.state: "pending"` and the +recorded `superseded_by` value (`null` for abandonment without a replacement), +and explains how to retry the original intent. Finish that retirement before +re-planning. During compensation, a later peer edit refuses with `transaction_partial_mutation` and retains recovery data; it is never silently overwritten. Legacy journals without a retained item plan require the original plan and adapter for replay. Abandoned receipts remain retained by transaction diff --git a/src/sdk/workspace-transaction.ts b/src/sdk/workspace-transaction.ts index 6f068a6c10..be4d1977db 100644 --- a/src/sdk/workspace-transaction.ts +++ b/src/sdk/workspace-transaction.ts @@ -696,7 +696,7 @@ export async function commitWorkspaceTransaction( ); try { const existing = await loadJournal(pmRoot, transactionId, stepIds); - if (existing?.status === "abandoned" || existing?.abandonment !== undefined) throw retiredTransaction(transactionId); + if (existing?.status === "abandoned" || existing?.abandonment !== undefined) throw retiredTransaction(existing); const recovered = existing !== undefined; if (existing?.status === "committed") return { @@ -722,11 +722,17 @@ export async function commitWorkspaceTransaction( } } -/** Reject replay of a retired id without applying a new plan under that identity. */ -function retiredTransaction(transactionId: string): PmCliError { - return new PmCliError(`Transaction ${transactionId} has been abandoned`, EXIT_CODE.CONFLICT, { - code: "transaction_abandoned", required: "Use a new transactionId for the replacement plan.", - why: "An explicitly retired transaction identity cannot be resumed.", +/** Explain a validated retirement fence, preserving the recorded replacement while retirement is incomplete. */ +function retiredTransaction(journal: WorkspaceTransactionJournal): PmCliError { + const pending = journal.status !== "abandoned"; + const supersededBy = journal.abandonment!.supersededBy; + const retry = supersededBy === undefined + ? `Retry abandonment without supersededBy to finish retirement of ${JSON.stringify(journal.transactionId)}.` + : `Retry abandonment with supersededBy ${JSON.stringify(supersededBy)} to finish retirement of ${JSON.stringify(journal.transactionId)}.`; + return new PmCliError(pending ? `Transaction ${journal.transactionId} retirement is incomplete` : `Transaction ${journal.transactionId} has been abandoned`, EXIT_CODE.CONFLICT, { + code: "transaction_abandoned", required: pending ? retry : "Use a new transactionId for the replacement plan.", + why: pending ? "Forward replay is fenced, but the recorded retirement has not finished. Preserve its replacement identity." : "An explicitly retired transaction identity cannot be resumed.", + ...(pending ? { retirement: { state: "pending", superseded_by: supersededBy ?? null }, nextSteps: [retry] } : {}), }); } @@ -764,7 +770,7 @@ export async function abandonWorkspaceTransaction(options: AbandonWorkspaceTrans const journal = await loadJournal(identity.pmRoot, identity.transactionId); if (journal === undefined) throw new PmCliError(`Transaction ${identity.transactionId} was not found`, EXIT_CODE.NOT_FOUND); if (journal.status === "committed") throw new PmCliError(`Transaction ${identity.transactionId} is committed and cannot be abandoned`, EXIT_CODE.CONFLICT, { code: "transaction_committed", required: "Plan a separate explicit corrective mutation.", why: "Recovery cannot silently undo committed work." }); - if (journal.abandonment !== undefined && journal.abandonment.supersededBy !== supersededBy) throw retiredTransaction(identity.transactionId); + if (journal.abandonment !== undefined && journal.abandonment.supersededBy !== supersededBy) throw retiredTransaction(journal); if (journal.status === "abandoned") return journal; const steps = options.resolveSteps(structuredClone(journal)); if (JSON.stringify(steps.map(step => step.id)) !== JSON.stringify(journal.stepIds)) throw journalPlanMismatch(identity.transactionId); diff --git a/tests/unit/sdk/transactions/host-bound.spec.ts b/tests/unit/sdk/transactions/host-bound.spec.ts index d4eaea4c1d..0ef9f00ed9 100644 --- a/tests/unit/sdk/transactions/host-bound.spec.ts +++ b/tests/unit/sdk/transactions/host-bound.spec.ts @@ -54,7 +54,7 @@ describe("host-bound item batches and recovery (pm-gh1597, pm-gh1598)", () => { const journalBytes = await readFile(path.join(pmPath, "transactions", "sdk", "retired.json"), "utf8"); await client.itemTransactions.supersede("retired", "replacement", { reason: "Retry request" }); expect(await readFile(path.join(pmPath, "transactions", "sdk", "retired.json"), "utf8")).toBe(journalBytes); - await expect(client.commitItemMutations(options)).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); + await expect(client.commitItemMutations(options)).rejects.toMatchObject({ message: "Transaction retired has been abandoned", context: { code: "transaction_abandoned", required: "Use a new transactionId for the replacement plan." } }); await expect(client.commitItemMutations({ ...options, mutations: [{ op: "update", id: original.id, options: { title: "Forbidden replan" } }] })).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); expect((await client.get(original.id)).item.title).toBe("Original"); await expect(client.itemTransactions.abandon("retired", { reason: "Different replacement" })).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); @@ -132,8 +132,9 @@ describe("host-bound item batches and recovery (pm-gh1597, pm-gh1598)", () => { await expect(client.itemTransactions.abandon("compensation", { reason: "Retire" })).rejects.toThrow("Stop compensation"); vi.restoreAllMocks(); expect((await client.itemTransactions.status("compensation"))?.journal.schemaVersion).toBe(2); + await expect(client.itemTransactions.supersede("compensation", "wrong-replacement", { reason: "Wrong retry" })).rejects.toMatchObject({ message: "Transaction compensation retirement is incomplete", context: { code: "transaction_abandoned", required: expect.stringContaining("without supersededBy"), retirement: { state: "pending", superseded_by: null } } }); if (createCompensation === "close") await client.reopen("compensated", "Peer reopens after completed compensation"); - await expect(client.commitItemMutations({ ...options, mutations: [{ op: "create", id: "compensated", options: { title: "Forbidden replan", type: "Task" } }] })).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); + await expect(client.commitItemMutations({ ...options, mutations: [{ op: "create", id: "compensated", options: { title: "Forbidden replan", type: "Task" } }] })).rejects.toMatchObject({ context: { code: "transaction_abandoned", retirement: { state: "pending", superseded_by: null } } }); expect((await client.itemTransactions.abandon("compensation", { reason: "Resume retirement" })).journal.status).toBe("abandoned"); if (createCompensation === "close") expect((await client.get("compensated")).item.status).toBe("open"); await client.create({ id: "later", title: "Later", type: "Task" }); @@ -164,6 +165,9 @@ describe("host-bound item batches and recovery (pm-gh1597, pm-gh1598)", () => { vi.restoreAllMocks(); const auditPath = path.join(pmPath, "history", "_workspace.jsonl"); const audit = await readFile(auditPath, "utf8"); + const pendingJournal = await readFile(file, "utf8"); + await expect(client.itemTransactions.abandon("audit", { reason: "Wrong retry" })).rejects.toMatchObject({ message: "Transaction audit retirement is incomplete", context: { code: "transaction_abandoned", required: expect.stringContaining('supersededBy "audit-replacement"'), retirement: { state: "pending", superseded_by: "audit-replacement" } } }); + expect(await readFile(file, "utf8")).toBe(pendingJournal); await expect(client.commitItemMutations({ transactionId: "audit", mutations: [{ op: "update", id: "audit", options: { title: "Forward" } }] })).rejects.toMatchObject({ context: { code: "transaction_abandoned" } }); const collected = await runWorkspaceTransactionGc(pmPath, { dryRun: true, retentionDays: 0, now: Date.now() + 86400000 }); expect(collected.retained).toContain("transactions/sdk/audit.json");