From bd333f788f3e533a30c51d574a51894121ed70ec Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Sun, 9 Aug 2026 18:00:13 +0200 Subject: [PATCH 1/3] feat(sdk): make context integrity durable across clones Version merge fences for cross-client safety, persist privacy-safe merge receipt evidence, expose explicit provenance outcomes and corpus diagnostics, and isolate foreign harness signals in SDK tests. --- .agents/pm/features/pm-lu6sca.toon | 24 ++- .agents/pm/history/pm-1j5j21.jsonl | 13 ++ .agents/pm/history/pm-eq9dlw.jsonl | 14 ++ .agents/pm/history/pm-l56d0o.jsonl | 11 ++ .agents/pm/history/pm-lu6sca.jsonl | 12 ++ .agents/pm/history/pm-xgah3a.jsonl | 9 ++ .agents/pm/issues/pm-1j5j21.toon | 30 +++- .agents/pm/issues/pm-eq9dlw.toon | 32 +++- .agents/pm/issues/pm-l56d0o.toon | 48 ++++++ .agents/pm/issues/pm-xgah3a.toon | 19 ++- .gitattributes | 4 +- CHANGELOG.md | 8 + docs/MERGE_SAFETY.md | 12 +- docs/SDK_AGENT_SESSION_CONTEXT.md | 5 +- docs/SDK_CONTEXT_INTEGRITY.md | 4 +- sdk/public-surface.json | 70 +++++++-- src/core/shared/author.ts | 47 ++++-- src/sdk/governance/health.ts | 16 +- src/sdk/governance/provenance-health.ts | 104 +++++++++++-- src/sdk/governance/validate.ts | 5 +- src/sdk/merge/index.ts | 2 + src/sdk/merge/install.ts | 58 ++++++-- src/sdk/merge/receipts.ts | 139 +++++++++++++++--- tests/helpers/withTempPmPath.ts | 14 +- ...rge-fence-version-skew.integration.spec.ts | 44 ++++++ ...rovenance-value-health.integration.spec.ts | 42 ++++++ tests/unit/commands/init-command.spec.ts | 22 +-- .../unit/sdk/agent-runtime-primitives.spec.ts | 20 +++ tests/unit/sdk/health-vector-boundary.spec.ts | 18 ++- tests/unit/sdk/merge-receipts.spec.ts | 85 +++++++++++ tests/unit/sdk/merge-safety.spec.ts | 15 +- tests/unit/sdk/provenance-health.spec.ts | 69 +++++++-- 32 files changed, 874 insertions(+), 141 deletions(-) create mode 100644 .agents/pm/history/pm-l56d0o.jsonl create mode 100644 .agents/pm/issues/pm-l56d0o.toon create mode 100644 tests/integration/merge-fence-version-skew.integration.spec.ts create mode 100644 tests/integration/provenance-value-health.integration.spec.ts diff --git a/.agents/pm/features/pm-lu6sca.toon b/.agents/pm/features/pm-lu6sca.toon index e493f3902..ba266ecea 100644 --- a/.agents/pm/features/pm-lu6sca.toon +++ b/.agents/pm/features/pm-lu6sca.toon @@ -2,11 +2,13 @@ id: pm-lu6sca title: "A declared provenance resolver that fails at runtime is recorded identically to a dimension the harness cannot supply, so a broken probe is invisible until someone reads the source" description: "Established by measurement on 2026-08-03 and generalized from a confirmed instance.\n\nToday a provenance dimension resolves to exactly two observable states in the immutable record: a value, or null. Null is overloaded. It is the correct and permanent encoding for all of the following, which have nothing in common:\n\n- the harness genuinely publishes no such dimension (declared via provenance_unavailable_dimensions, an honest absence)\n- no resolver is declared for that dimension on that harness\n- a resolver is declared, ran, and failed - wrong path, unreadable file, unparsable content, revoked permission\n- probes are disabled by settings or PM_AGENT_PROBES\n\nThe confirmed instance: the claude_session_file model resolver computes a session path with an incomplete slug encoding, throws ENOENT, is swallowed by a bare catch, and writes null. The workspace where this happens is this repository. Every mutation it recorded looked exactly like a mutation from a harness that has no model to report. The condition was found by reading the resolver source and recomputing the path by hand, which is not a detection mechanism.\n\nWhy the existing instruments do not cover it. summarizeAgentModelProvenance can report per-harness coverage and can set an inert flag when a declared signal produced only unavailable values, but it reads the history corpus after the fact and it is not wired to anything - that gap has its own owner. Even fully wired, it would report 'coverage is zero' without being able to say whether the cause is an unavailable dimension or a broken probe, because the corpus does not carry that distinction. The distinction has to be recorded at write time; it cannot be recovered later from an immutable record that never held it.\n\nThis is the instrument-integrity pattern applied one level below where it has been applied before. Prior findings established that a gate which never fails is a hypothesis until you name the input that would fail it. The same argument applies to a resolver: a probe that can only be observed succeeding is a probe nobody can prove broken. The fix is not more probing - it is recording the outcome category of the attempt the runtime already makes.\n\nPrivacy boundary: the failure category must be a bounded reason code. Recording the path that failed to open would publish the operator's directory layout into an immutable stream, which the write-time mutation guard exists to prevent.\n\nScope is the outcome vocabulary and its surfacing. Fixing any individual resolver, and pointing the existing corpus analyzers at real data, are separate owners." type: Feature -status: open +status: closed priority: 2 tags[5]: "area:sdk",identity,instrument-integrity,observability,provenance created_at: "2026-08-03T06:22:12.243Z" -updated_at: "2026-08-09T01:24:46.237Z" +updated_at: "2026-08-09T15:57:26.460Z" +closed_at: "2026-08-09T15:57:25.791Z" +completed_at: "2026-08-09T15:57:25.791Z" author: "harness:claude-code" estimated_minutes: 360 acceptance_criteria: "For each declared provenance dimension the runtime distinguishes: resolved, harness-declares-unavailable, resolver-attempted-and-failed, and no-resolver-declared; The failure category records a bounded reason code, never a path or any environment value; pm health surfaces a warning when a declared resolver has a non-zero attempt count and a zero success count in the current workspace; The distinction is observable without reading history: a single bounded command answers 'is my identity provenance working here'; Recording the category costs no additional probe: it is derived from the attempt the runtime already makes" @@ -16,6 +18,9 @@ why_now: "A model resolver shipped, failed on its first real workspace, and wrot parent: pm-5oj5 risk: medium confidence: high +resolution: "Extended provenance outcomes with an explicit not_configured state and resolver_not_configured reason, separating absent configuration from attempted resolver failure." +expected_result: Callers must be able to distinguish no resolver configuration from a resolver that ran and failed. +actual_result: "CLI and SDK provenance contracts now emit not_configured only when no resolver is declared, while resolved and failed remain attempted outcomes and the public surface snapshot records the additive contract." dependencies[7]{id,kind,created_at,author,source_kind,author_source}: pm-1wiugq,related,"2026-08-03T06:23:55.524Z","harness:claude-code","cli:update:dep",detected pm-9gvazz,discovered_from,"2026-08-03T06:23:55.524Z","harness:claude-code","cli:update:dep",detected @@ -24,7 +29,7 @@ dependencies[7]{id,kind,created_at,author,source_kind,author_source}: pm-htbetn,related,"2026-08-03T06:23:55.524Z","harness:claude-code","cli:update:dep",detected pm-rtn5h6,related,"2026-08-03T06:23:55.524Z","harness:claude-code","cli:update:dep",detected pm-w7ccmv,implements,"2026-08-03T06:23:55.524Z","harness:claude-code","cli:update:dep",detected -comments[8]{created_at,author,text}: +comments[9]{created_at,author,text}: "2026-08-03T11:09:27.269Z","harness:codex","Estimate basis 2026-08-03: 360 minutes covers resolver outcome algebra, bounded reason codes, immutable recording, health projection, zero-success warning logic, and negative controls." "2026-08-08T22:13:20.575Z","harness:codex","Implementation start 2026-08-09: active in the coupled context-provenance tranche with pm-3zgh2c, pm-eq9dlw, pm-lu6sca, pm-b1w8vr, and pm-h75tjh. Scope is SDK-first provenance inference and resolver outcomes, typed role domains, stable entity read-back projections, and epoch-aware release classification; all other open items remain unclaimed." "2026-08-08T22:32:58.636Z","harness:codex","Design evidence: resolver attempts are counted only when the resolver input exists. Missing AI_AGENT or session identifiers are harness_unavailable; a supplied valid resolver input that yields no value is resolver_failed. pm health scans at most 10,000 immutable events, tolerates malformed streams owned by integrity diagnostics, and emits advisory zero-success warnings." @@ -33,7 +38,9 @@ comments[8]{created_at,author,text}: "2026-08-09T00:20:23.262Z","harness:codex","Delivery handoff: broad SDK/CLI tranche committed at 5b36abc75 and opened as GitHub PR #944 (https://github.com/unbraind/pm-cli/pull/944). Exact local evidence includes 7,086 tests across 461 files at 100/100/100/100 coverage, package/compatibility/npx/dogfood/manual acceptance, tracker/changelog/SDK/static-quality gates, and zero current dependency or GitHub security alerts. Review and exact-head CI evidence will be appended after the hosted loop." "2026-08-09T00:58:13.326Z","harness:codex","Review-loop evidence: provenance scanning now byte-bounds history before allocation, parses only complete lines, distinguishes exact event limits from truncation, suppresses zero-success warnings on incomplete samples, and records invalid explicit role values as invalid_value with argv precedence. Full sandboxed gate: 461 files, 7,089 tests, exact 100/100/100/100. Item remains open and unclaimed for its documented no-resolver-declared residual." "2026-08-09T01:24:46.237Z","harness:codex","PR #944 hosted evidence for the completed tranche portion: implementation commit b6678b8 passed all deterministic checks; CodeRabbit confirmed byte-bounded complete-event health semantics and invalid-value role outcomes. All 16 findings are addressed, replied to, and resolved. Item stays open and unclaimed for the documented no-resolver-declared residual." -files[7]{path,scope,note}: + "2026-08-09T15:57:25.224Z","harness:codex","Evidence: focused agent-runtime and author-attribution tests passed after truthful overlapping-run failure receipts; the final uninterrupted full suite passed 7,100/7,100 with exact 100/100/100/100 coverage. SDK surface change was explicitly acknowledged and all static, lint, parity, token, and performance gates passed." +files[8]{path,scope,note}: + sdk/public-surface.json,project,SDK outcome contract snapshot src/core/history/history.ts,project,Persist resolver outcome evidence src/core/shared/author.ts,project,Explicit provenance precedence and invalid role outcome classification src/sdk/governance/health.ts,project,Expose zero-success resolver diagnostics through pm health @@ -41,10 +48,17 @@ files[7]{path,scope,note}: tests/unit/sdk/agent-runtime-primitives.spec.ts,project,Invalid role provenance outcome regression tests/unit/sdk/health-vector-boundary.spec.ts,project,Prove resolver-health scanning preserves the no-provider-I/O boundary tests/unit/sdk/provenance-health.spec.ts,project,Resolver health failure and success coverage -tests[2]{command,scope,timeout_seconds}: +tests[3]{command,scope,timeout_seconds}: node scripts/run-tests.mjs coverage,project,600 + node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts,project,180 node scripts/run-tests.mjs test -- tests/unit/sdk/provenance-health.spec.ts tests/unit/commands/health-command.spec.ts,project,240 +test_runs[4]{run_id,kind,status,started_at,finished_at,recorded_at,passed,failed,skipped}: + test-local-mslxq9rl-7v1vac,test,failed,"2026-08-09T14:58:13.100Z","2026-08-09T15:05:58.257Z","2026-08-09T15:05:58.257Z",2,1,0 + test-local-mslxqatv-9o2sdd,test,failed,"2026-08-09T14:59:00.977Z","2026-08-09T15:05:59.635Z","2026-08-09T15:05:59.635Z",2,1,0 + test-local-mslz1bft-xylosg,test,passed,"2026-08-09T15:42:22.863Z","2026-08-09T15:42:33.257Z","2026-08-09T15:42:33.257Z",1,0,0 + test-local-mslz1rd7-8wwd82,test,passed,"2026-08-09T15:42:33.647Z","2026-08-09T15:42:53.899Z","2026-08-09T15:42:53.899Z",1,0,0 docs[2]{path,scope,note}: docs/SDK_AGENT_SESSION_CONTEXT.md,project,Resolver outcome and health contract docs/SDK_CONTEXT_INTEGRITY.md,project,Local bounded provenance health boundary +close_reason: Implemented and documented explicit configured-versus-attempted provenance outcome semantics across CLI and SDK. body: "" diff --git a/.agents/pm/history/pm-1j5j21.jsonl b/.agents/pm/history/pm-1j5j21.jsonl index 9570752ea..b65db4720 100644 --- a/.agents/pm/history/pm-1j5j21.jsonl +++ b/.agents/pm/history/pm-1j5j21.jsonl @@ -8,3 +8,16 @@ {"ts":"2026-08-08T15:39:02.830Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"d23a9b786b1b4784c15ec525","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-08-08T15:39:02.830Z","author":"harness:codex","text":"Investigation boundary (2026-08-08): this PR deliberately does not claim fresh-clone durability. The implemented receipt work classifies lossless versus discarded-value decisions and requires explicit acceptance, but raw recovery receipts remain clone-local and ignored. A durable privacy-safe pushed evidence design needs a separate tracked-record contract and fresh-clone lifecycle, so retaining this item as open avoids falsely closing GH-921/GH-922."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-08T15:39:02.830Z"}],"before_hash":"aa70300c6f101a0b3c29ed43e39d37a9b3d686223fdd21f9cc0b9a0d95fece8a","after_hash":"dcf89a3200ea38db0efef10b25c3a40785c510079c438f44d664ee157cfe11cf"} {"ts":"2026-08-08T15:39:03.313Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"d23a9b786b1b4784c15ec525","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-08T15:39:03.313Z"},{"op":"replace","path":"/metadata/status","value":"open"}],"before_hash":"dcf89a3200ea38db0efef10b25c3a40785c510079c438f44d664ee157cfe11cf","after_hash":"497bcab2fc4c0af9ea4ef463a727cc582e2735649190367719c61ee8fe094eb6","message":"Return unresolved durable receipt design to open backlog"} {"ts":"2026-08-08T15:39:03.748Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"d23a9b786b1b4784c15ec525","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-08T15:39:03.748Z"}],"before_hash":"497bcab2fc4c0af9ea4ef463a727cc582e2735649190367719c61ee8fe094eb6","after_hash":"2aa94cf26162b92a23b89f536df7ef608806dce7874b43d9d6f33fa7ad330ac2"} +{"ts":"2026-08-09T14:34:07.289Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:34:07.289Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#b2adadb08f3a0763fd3bf70f"}],"before_hash":"2aa94cf26162b92a23b89f536df7ef608806dce7874b43d9d6f33fa7ad330ac2","after_hash":"690405202b1cb1a55cb6464626e938d9761edbbfa5d44124268611b5edd76aed"} +{"ts":"2026-08-09T14:34:07.789Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:34:07.789Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"690405202b1cb1a55cb6464626e938d9761edbbfa5d44124268611b5edd76aed","after_hash":"2490d7f5372a4dac43896d57e285986af28ff253b47356b1ab15aef94afa96c7","message":"Start durable merge evidence and deterministic context-integrity tranche"} +{"ts":"2026-08-09T14:53:44.495Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:53:44.495Z"},{"op":"add","path":"/metadata/files","value":[{"path":"sdk/public-surface.json","scope":"project","note":"SDK contract snapshot"},{"path":"src/sdk/governance/health.ts","scope":"project","note":"Durable receipt discovery"},{"path":"src/sdk/governance/validate.ts","scope":"project","note":"Durable receipt validation"},{"path":"src/sdk/merge/receipts.ts","scope":"project","note":"Raw local plus durable hash-only receipt store"},{"path":"tests/unit/sdk/merge-receipts.spec.ts","scope":"project","note":"Fresh-clone durability and privacy coverage"}]}],"before_hash":"2490d7f5372a4dac43896d57e285986af28ff253b47356b1ab15aef94afa96c7","after_hash":"2337ad19e707d61c37851d6f351e2d83f699c4bc7492be89a1950b3dcd774575"} +{"ts":"2026-08-09T14:53:44.927Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:53:44.927Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/MERGE_SAFETY.md","scope":"project","note":"Durable receipt lifecycle"}]}],"before_hash":"2337ad19e707d61c37851d6f351e2d83f699c4bc7492be89a1950b3dcd774575","after_hash":"889e550d3eac80486d4d4299f445e9ff13e09b6d18a600665fc7ac21c4c91d1d"} +{"ts":"2026-08-09T14:53:45.368Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:53:45.368Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/merge-receipts.spec.ts tests/integration/merge-receipt-health-classification.integration.spec.ts tests/unit/commands/merge-reconcile-command.spec.ts","scope":"project","timeout_seconds":240}]}],"before_hash":"889e550d3eac80486d4d4299f445e9ff13e09b6d18a600665fc7ac21c4c91d1d","after_hash":"1f752de5022520cb2dd793e4aafe90ae155b012530ee1dd2cae18072bfd5a07d"} +{"ts":"2026-08-09T14:58:12.502Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:58:12.502Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-mslxgadt-0r0s2c","kind":"test","status":"passed","started_at":"2026-08-09T14:57:53.136Z","finished_at":"2026-08-09T14:58:12.497Z","recorded_at":"2026-08-09T14:58:12.497Z","passed":1,"failed":0,"skipped":0}]}],"before_hash":"1f752de5022520cb2dd793e4aafe90ae155b012530ee1dd2cae18072bfd5a07d","after_hash":"a5c285f36aa306a62bdcf533fe159a7bc8aaff3f916c426fb6631d77bca34869","message":"Track test run summary (test-local-mslxgadt-0r0s2c)"} +{"ts":"2026-08-09T14:58:53.245Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"test_run_track","patch":[{"op":"add","path":"/metadata/test_runs/1","value":{"run_id":"test-local-mslxh5t9-thtgqo","kind":"test","status":"passed","started_at":"2026-08-09T14:58:26.430Z","finished_at":"2026-08-09T14:58:53.229Z","recorded_at":"2026-08-09T14:58:53.229Z","passed":1,"failed":0,"skipped":0}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:58:53.245Z"}],"before_hash":"a5c285f36aa306a62bdcf533fe159a7bc8aaff3f916c426fb6631d77bca34869","after_hash":"7bd63d05786aecc3d99f525d48b9a37dd043eb1b370dc2093890fd7df70be3c7","message":"Track test run summary (test-local-mslxh5t9-thtgqo)"} +{"ts":"2026-08-09T15:57:22.581Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"update","patch":[{"op":"replace","path":"/metadata/actual_result","value":"Fresh clones retain stable hash-only decision evidence, original clones retain raw-value receipts, duplicate receipt identities prefer local detail, and reconciliation updates both stores."},{"op":"replace","path":"/metadata/expected_result","value":"Merge decision evidence must survive a fresh clone without committing raw conflicting values or losing local reconciliation capability."},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:22.581Z"},{"op":"add","path":"/metadata/resolution","value":"Persisted privacy-safe hash-only merge decision receipt sidecars inside the project tracker while retaining raw values only in clone-local Git state; listing, health, validation, and reconciliation now merge both sources deterministically."}],"before_hash":"7bd63d05786aecc3d99f525d48b9a37dd043eb1b370dc2093890fd7df70be3c7","after_hash":"743dcc4c75499b4045139dc4630fb8bc09ef6525d30ce53ff70e47607c79b343","message":"Record verified durable receipt outcome"} +{"ts":"2026-08-09T15:57:23.042Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-08-09T15:57:23.042Z","author":"harness:codex","text":"Evidence: linked receipt tests passed; full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; static, lint, SDK surface, performance, history-drift, storage-integrity, and dry-run reconciliation gates passed. Manual packed-consumer acceptance also passed in an isolated project."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:23.042Z"}],"before_hash":"743dcc4c75499b4045139dc4630fb8bc09ef6525d30ce53ff70e47607c79b343","after_hash":"5a30dfed21c5421f48adf664ecc162162825d976f33944235b36e33995357922"} +{"ts":"2026-08-09T15:57:23.752Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:23.752Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:23.719Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:23.719Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented clone-durable, privacy-safe merge decision receipts across SDK health, validate, and reconcile paths."}],"before_hash":"5a30dfed21c5421f48adf664ecc162162825d976f33944235b36e33995357922","after_hash":"71c8badb8a9ba5b9116492f0d6e9603c4d3498746bb00531aba7b088364a8c18"} +{"ts":"2026-08-09T15:57:24.312Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:24.312Z"}],"before_hash":"71c8badb8a9ba5b9116492f0d6e9603c4d3498746bb00531aba7b088364a8c18","after_hash":"aba42ba573361cc0e800b0840edc4be0a97738a452659fa8c714c4d66d84cd49"} +{"ts":"2026-08-09T15:58:32.241Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/0/note","value":"Managed changelog entry for the coupled SDK integrity tranche"},{"op":"replace","path":"/metadata/docs/0/path","value":"CHANGELOG.md"},{"op":"add","path":"/metadata/docs/1","value":{"path":"docs/MERGE_SAFETY.md","scope":"project","note":"Durable receipt lifecycle"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:58:32.241Z"}],"before_hash":"aba42ba573361cc0e800b0840edc4be0a97738a452659fa8c714c4d66d84cd49","after_hash":"b48904b0fc4fd5d4af6fc828aa8e02fe4c996d434301940227f8c1dde8d9653b"} +{"ts":"2026-08-09T15:58:32.674Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/1","value":{"command":"pnpm changelog:pm:check","scope":"project","timeout_seconds":240}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:58:32.674Z"}],"before_hash":"b48904b0fc4fd5d4af6fc828aa8e02fe4c996d434301940227f8c1dde8d9653b","after_hash":"a022e0b96fbdcf4176cc239b5eeaf76c95bef619fbd5442f473be6b4621df702"} diff --git a/.agents/pm/history/pm-eq9dlw.jsonl b/.agents/pm/history/pm-eq9dlw.jsonl index be9479d23..eda66e4ba 100644 --- a/.agents/pm/history/pm-eq9dlw.jsonl +++ b/.agents/pm/history/pm-eq9dlw.jsonl @@ -15,3 +15,17 @@ {"ts":"2026-08-09T00:09:13.174Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b328d74ff33d5397acdbcabe","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/5","value":{"created_at":"2026-08-09T00:09:13.174Z","author":"harness:codex","text":"Broad tranche evidence: Claude boolean child-session data no longer becomes a role; the controlled role vocabulary plus argv review/implementation inference now pass the complete 7086-test 100/100/100/100 gate. Item remains open and unclaimed because its corpus-wide all-dimension bare-boolean and single-digit conformance criterion remains broader than this tranche."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T00:09:13.174Z"}],"before_hash":"a0c580465e5f6b3e8999e7330f8e826ed315327dc363a293fef839e8e28d9a83","after_hash":"f5d74570f6a002abc4cdb6f673d7a036d49cea2e626fe09bb11f0ae9f8d8a72e"} {"ts":"2026-08-09T00:20:22.518Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b328d74ff33d5397acdbcabe","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/6","value":{"created_at":"2026-08-09T00:20:22.518Z","author":"harness:codex","text":"Delivery handoff: broad SDK/CLI tranche committed at 5b36abc75 and opened as GitHub PR #944 (https://github.com/unbraind/pm-cli/pull/944). Exact local evidence includes 7,086 tests across 461 files at 100/100/100/100 coverage, package/compatibility/npx/dogfood/manual acceptance, tracker/changelog/SDK/static-quality gates, and zero current dependency or GitHub security alerts. Review and exact-head CI evidence will be appended after the hosted loop."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T00:20:22.518Z"}],"before_hash":"f5d74570f6a002abc4cdb6f673d7a036d49cea2e626fe09bb11f0ae9f8d8a72e","after_hash":"d0dac767ba66a7d0b8801666ccff8a87cef1c8e9937e18907aa0739a6d4c48c3"} {"ts":"2026-08-09T01:24:45.768Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b328d74ff33d5397acdbcabe","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/7","value":{"created_at":"2026-08-09T01:24:45.768Z","author":"harness:codex","text":"PR #944 hosted evidence for the completed tranche portion: implementation commit b6678b8 passed all deterministic checks; all 16 CodeRabbit findings are addressed, replied to, and resolved. Item stays open and unclaimed for its broader remaining role-contract acceptance."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T01:24:45.768Z"}],"before_hash":"d0dac767ba66a7d0b8801666ccff8a87cef1c8e9937e18907aa0739a6d4c48c3","after_hash":"e524f5e3aafaca35ec94851e9102b3f0dddbc179a847e485c926aea83b1311e0"} +{"ts":"2026-08-09T14:34:10.206Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:34:10.206Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#b2adadb08f3a0763fd3bf70f"}],"before_hash":"e524f5e3aafaca35ec94851e9102b3f0dddbc179a847e485c926aea83b1311e0","after_hash":"9612cd0246a429996b7ea6c5f42c75200269e03f2c051bae38b677c91f00760d"} +{"ts":"2026-08-09T14:34:10.770Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:34:10.770Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"9612cd0246a429996b7ea6c5f42c75200269e03f2c051bae38b677c91f00760d","after_hash":"d439d27216f199b8c5d82ab1b69fee729db0958ae36a23026dc14bcad3ada19e","message":"Complete provenance value-domain and corpus conformance contracts"} +{"ts":"2026-08-09T14:53:59.035Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"files_add","patch":[{"op":"add","path":"/metadata/files/1","value":{"path":"src/sdk/governance/health.ts","scope":"project","note":"Invalid provenance health projection"}},{"op":"add","path":"/metadata/files/2","value":{"path":"src/sdk/governance/provenance-health.ts","scope":"project","note":"Corpus-wide invalid provenance value aggregation"}},{"op":"add","path":"/metadata/files/3","value":{"path":"tests/unit/sdk/provenance-health.spec.ts","scope":"project","note":"All-dimension boolean and digit conformance coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:53:59.035Z"}],"before_hash":"d439d27216f199b8c5d82ab1b69fee729db0958ae36a23026dc14bcad3ada19e","after_hash":"bfc20455c99e30b6a01630d766d1b14b2b910df12ed045ff0dd4d75c076c127f"} +{"ts":"2026-08-09T14:53:59.940Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/1","value":{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/provenance-health.spec.ts tests/unit/sdk/health-vector-boundary.spec.ts","scope":"project","timeout_seconds":180}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:53:59.940Z"}],"before_hash":"bfc20455c99e30b6a01630d766d1b14b2b910df12ed045ff0dd4d75c076c127f","after_hash":"1f871e8754c92227c92dabf353fb3178943370256bbac0633fac14c4823bdde5"} +{"ts":"2026-08-09T15:00:57.012Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:00:57.012Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-mslxjta1-gxcakh","kind":"test","status":"passed","started_at":"2026-08-09T14:59:41.020Z","finished_at":"2026-08-09T15:00:56.953Z","recorded_at":"2026-08-09T15:00:56.953Z","passed":2,"failed":0,"skipped":0}]}],"before_hash":"1f871e8754c92227c92dabf353fb3178943370256bbac0633fac14c4823bdde5","after_hash":"33e74dbb116222d225c2bc29aa3a52a5b6cb7f1dd895165477ec504c16e90674","message":"Track test run summary (test-local-mslxjta1-gxcakh)"} +{"ts":"2026-08-09T15:26:23.623Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/3/note","value":"End-to-end health projection for corpus conformance"},{"op":"replace","path":"/metadata/files/3/path","value":"tests/integration/provenance-value-health.integration.spec.ts"},{"op":"add","path":"/metadata/files/4","value":{"path":"tests/unit/sdk/provenance-health.spec.ts","scope":"project","note":"All-dimension boolean and digit conformance coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:26:23.623Z"}],"before_hash":"33e74dbb116222d225c2bc29aa3a52a5b6cb7f1dd895165477ec504c16e90674","after_hash":"0d8958b1db1928201eef22bcecd4eefb47d192fab4d6a6facf3f7d6256ef2a25"} +{"ts":"2026-08-09T15:26:24.051Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/tests/1/command","value":"node scripts/run-tests.mjs test -- tests/unit/sdk/provenance-health.spec.ts tests/integration/provenance-value-health.integration.spec.ts tests/unit/sdk/health-vector-boundary.spec.ts"},{"op":"add","path":"/metadata/tests/2","value":{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/provenance-health.spec.ts tests/unit/sdk/health-vector-boundary.spec.ts","scope":"project","timeout_seconds":180}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:26:24.051Z"}],"before_hash":"0d8958b1db1928201eef22bcecd4eefb47d192fab4d6a6facf3f7d6256ef2a25","after_hash":"ae19bec8c0648f1b4f905a72685be41d22f7bedd52c0eb913fef5dde2a4f36d5"} +{"ts":"2026-08-09T15:39:30.048Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/4/note","value":"Provider-free invalid-value health projection coverage"},{"op":"replace","path":"/metadata/files/4/path","value":"tests/unit/sdk/health-vector-boundary.spec.ts"},{"op":"add","path":"/metadata/files/5","value":{"path":"tests/unit/sdk/provenance-health.spec.ts","scope":"project","note":"All-dimension boolean and digit conformance coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:39:30.048Z"}],"before_hash":"ae19bec8c0648f1b4f905a72685be41d22f7bedd52c0eb913fef5dde2a4f36d5","after_hash":"52a389b838123fd6310165d6a46560a40242b44664c0e28b401d437d3073e64d"} +{"ts":"2026-08-09T15:39:30.483Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"docs_add","patch":[{"op":"add","path":"/metadata/docs/1","value":{"path":"docs/SDK_CONTEXT_INTEGRITY.md","scope":"project","note":"Bounded privacy-safe corpus conformance contract"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:39:30.483Z"}],"before_hash":"52a389b838123fd6310165d6a46560a40242b44664c0e28b401d437d3073e64d","after_hash":"586e141abb3b25ad10a95ab91c9a1af5ef0b03f030fdf2a5d77744c4e5fa907f"} +{"ts":"2026-08-09T15:43:22.485Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"test_run_track","patch":[{"op":"add","path":"/metadata/test_runs/1","value":{"run_id":"test-local-mslz2df0-xetnmy","kind":"test","status":"passed","started_at":"2026-08-09T15:42:54.392Z","finished_at":"2026-08-09T15:43:22.476Z","recorded_at":"2026-08-09T15:43:22.476Z","passed":3,"failed":0,"skipped":0}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:43:22.485Z"}],"before_hash":"586e141abb3b25ad10a95ab91c9a1af5ef0b03f030fdf2a5d77744c4e5fa907f","after_hash":"e966a8e550e8e45fcc0834d75d29a41314b76133cf9fc0d4141c73ec05ea3fd5","message":"Track test run summary (test-local-mslz2df0-xetnmy)"} +{"ts":"2026-08-09T15:57:26.936Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"update","patch":[{"op":"replace","path":"/metadata/actual_result","value":"Health scans bounded bytes/events, emits aggregate invalid_values and stable warnings, covers malformed/truncated histories, and propagates the vector through the documented health contract."},{"op":"replace","path":"/metadata/expected_result","value":"Health diagnostics must find invalid provenance values across immutable history without leaking raw values or requiring unbounded reads."},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:26.936Z"},{"op":"add","path":"/metadata/resolution","value":"Added bounded corpus-wide provenance value-domain scanning to SDK health with privacy-safe harness/dimension/kind aggregates for boolean and single-digit legacy values."}],"before_hash":"e966a8e550e8e45fcc0834d75d29a41314b76133cf9fc0d4141c73ec05ea3fd5","after_hash":"0299f0d581226f14e2a27a087c5a7074d3849f2f32b5b90789da3611ea1d521c","message":"Record verified corpus provenance diagnostics"} +{"ts":"2026-08-09T15:57:27.484Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/8","value":{"created_at":"2026-08-09T15:57:27.484Z","author":"harness:codex","text":"Evidence: all three linked tests passed; final full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; lint, duplicate, docstring, surface-replication, SDK parity, token/context, and performance gates passed. Live repository health/storage/history checks remain structurally clean."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:27.484Z"}],"before_hash":"0299f0d581226f14e2a27a087c5a7074d3849f2f32b5b90789da3611ea1d521c","after_hash":"57fd32da9b944175f4433ac2dd7043830df3249c9e9bbae45cb4c945e0b2b7f1"} +{"ts":"2026-08-09T15:57:28.050Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:28.050Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:28.024Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:28.024Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented bounded privacy-safe corpus diagnostics for invalid historical provenance domains."}],"before_hash":"57fd32da9b944175f4433ac2dd7043830df3249c9e9bbae45cb4c945e0b2b7f1","after_hash":"41310bb8a3ef76dc059724bf2dd6a67c8d6332ddcee394137f20355498d43cc1"} +{"ts":"2026-08-09T15:57:28.612Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:28.612Z"}],"before_hash":"41310bb8a3ef76dc059724bf2dd6a67c8d6332ddcee394137f20355498d43cc1","after_hash":"36101bcf5c5ac63c6384d89384feeca3884ac5c953bf4b7778bf0ef0329c7c5d"} diff --git a/.agents/pm/history/pm-l56d0o.jsonl b/.agents/pm/history/pm-l56d0o.jsonl new file mode 100644 index 000000000..77d5cf73b --- /dev/null +++ b/.agents/pm/history/pm-l56d0o.jsonl @@ -0,0 +1,11 @@ +{"ts":"2026-08-09T14:32:29.084Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-l56d0o"},{"op":"add","path":"/metadata/title","value":"GH-948: version-skewed pm invocations silently rewrite the tracked merge fence during unrelated commands"},{"op":"add","path":"/metadata/description","value":"Current and supported older pm versions normalize the managed .gitattributes fence differently, and ordinary commands such as pm health invoke that write path. A read-only diagnostic can therefore dirty a tracked file, weaken extension merge protection, and create unrelated diffs solely from PATH or lockfile version skew. Duplicate evidence: all-status exact GH-948 and title searches returned no match; adjacent merge-guidance and gitattributes ownership items are distinct because they do not own cross-version idempotence or the read-only side-effect boundary."},{"op":"add","path":"/metadata/type","value":"Issue"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":1},{"op":"add","path":"/metadata/tags","value":["agent-ux","area:merge","area:sdk","determinism","read-only","regression","version-skew"]},{"op":"add","path":"/metadata/created_at","value":"2026-08-09T14:32:29.084Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-08-09T14:32:29.084Z"},{"op":"add","path":"/metadata/author","value":"harness:codex"},{"op":"add","path":"/metadata/estimated_minutes","value":240},{"op":"add","path":"/metadata/acceptance_criteria","value":"pm health and every read-only bootstrap path leave .gitattributes byte-identical; pm merge install is explicit, deterministic, and preserves compatible managed rules written by newer supported versions; SDK and CLI tests exercise older/newer fence fixtures and dirty-worktree assertions; manual temporary repositories prove health is read-only and explicit installation converges"},{"op":"add","path":"/metadata/parent","value":"pm-dj98"},{"op":"add","path":"/metadata/risk","value":"high"},{"op":"add","path":"/metadata/confidence","value":"high"},{"op":"add","path":"/metadata/reporter","value":"GitHub GH-948"},{"op":"add","path":"/metadata/severity","value":"high"},{"op":"add","path":"/metadata/environment","value":"Node 26.5.0 Linux; @unbrained/pm-cli 2026.8.3 through 2026.8.9"},{"op":"add","path":"/metadata/repro_steps","value":"Run npx @unbrained/pm-cli@2026.8.7 health and @2026.8.9 health against the same initialized tracker, restoring .gitattributes between runs; observe opposing tracked diffs."},{"op":"add","path":"/metadata/expected_result","value":"Read-only commands never mutate .gitattributes; explicit merge installation is idempotent and preserves compatible newer fence entries across supported version skew; any intentional tracked mutation is reported."},{"op":"add","path":"/metadata/actual_result","value":"pm health silently removes or adds managed extension fence lines according to the executing pm version."},{"op":"add","path":"/metadata/affected_version","value":"2026.8.3-2026.8.9"},{"op":"add","path":"/metadata/regression","value":true},{"op":"add","path":"/metadata/customer_impact","value":"Agents and contributors accumulate unrelated tracked diffs and can accidentally weaken merge safety when local/global pm versions differ."},{"op":"add","path":"/metadata/dependencies","value":[{"id":"pm-1j5j21","kind":"related","created_at":"2026-08-09T14:32:29.084Z","author":"harness:codex","source_kind":"cli:create:dep","author_source":"detected"},{"id":"pm-tu71","kind":"related","created_at":"2026-08-09T14:32:29.084Z","author":"harness:codex","source_kind":"cli:create:dep","author_source":"detected"}]},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-08-09T14:32:29.084Z","author":"harness:codex","text":"Duplicate check evidence: pm search GH-948 and exact title across status=all returned zero items; pm duplicates --status all was reviewed. GitHub source: https://github.com/unbraind/pm-cli/issues/948"}]}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"efb4b059e82051f8626c82bf6e8aba11931b738e6b18b5981d3401ea55157737","message":""} +{"ts":"2026-08-09T14:34:08.252Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:34:08.252Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#b2adadb08f3a0763fd3bf70f"}],"before_hash":"efb4b059e82051f8626c82bf6e8aba11931b738e6b18b5981d3401ea55157737","after_hash":"cf4d3883a3b4d261acdaa53c28377f5d654a177b7ac5bb424e983c67d99dcaed"} +{"ts":"2026-08-09T14:34:08.770Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:34:08.770Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"cf4d3883a3b4d261acdaa53c28377f5d654a177b7ac5bb424e983c67d99dcaed","after_hash":"45fbdac2627a3e09ff4c45338c684da83d23e6e89161b80e355a83782820f9c9","message":"Start explicit merge-fence ownership and version-skew-safe behavior"} +{"ts":"2026-08-09T14:53:43.241Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:53:43.241Z"},{"op":"add","path":"/metadata/files","value":[{"path":".gitattributes","scope":"project","note":"Versioned merge-fence contract"},{"path":"src/sdk/merge/index.ts","scope":"project","note":"Public marker exports"},{"path":"src/sdk/merge/install.ts","scope":"project","note":"Legacy migration and v2 fence ownership"},{"path":"tests/integration/merge-fence-version-skew.integration.spec.ts","scope":"project","note":"Cross-version mutation regression"},{"path":"tests/unit/commands/init-command.spec.ts","scope":"project","note":"Fresh init and legacy migration coverage"},{"path":"tests/unit/sdk/merge-safety.spec.ts","scope":"project","note":"Fence migration coverage"}]}],"before_hash":"45fbdac2627a3e09ff4c45338c684da83d23e6e89161b80e355a83782820f9c9","after_hash":"238013cf1271d1362aa5dee3c7191c8b505c7fbed01c5809599a250351565c32"} +{"ts":"2026-08-09T14:53:43.632Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:53:43.632Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/MERGE_SAFETY.md","scope":"project","note":"Version-skew fence contract"}]}],"before_hash":"238013cf1271d1362aa5dee3c7191c8b505c7fbed01c5809599a250351565c32","after_hash":"d6d4b234d1fb6db56e135ca11103745a138e1ae0d62c0c3bad6b1becee763ff3"} +{"ts":"2026-08-09T14:53:44.058Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:53:44.058Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node scripts/run-tests.mjs test -- tests/integration/merge-fence-version-skew.integration.spec.ts tests/unit/sdk/merge-safety.spec.ts tests/unit/commands/init-command.spec.ts","scope":"project","timeout_seconds":240}]}],"before_hash":"d6d4b234d1fb6db56e135ca11103745a138e1ae0d62c0c3bad6b1becee763ff3","after_hash":"24eee36faaa9cd26f1fe38fd7be5dd48e5120aac7b11d0b0148db25b980238e5"} +{"ts":"2026-08-09T14:57:52.267Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:57:52.267Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-mslxfuro-o8s13c","kind":"test","status":"passed","started_at":"2026-08-09T14:57:16.155Z","finished_at":"2026-08-09T14:57:52.260Z","recorded_at":"2026-08-09T14:57:52.260Z","passed":1,"failed":0,"skipped":0}]}],"before_hash":"24eee36faaa9cd26f1fe38fd7be5dd48e5120aac7b11d0b0148db25b980238e5","after_hash":"0632500044182f28ad0280ed52f66d3f6f786c5ce2940ce80212bed77bfc1e80","message":"Track test run summary (test-local-mslxfuro-o8s13c)"} +{"ts":"2026-08-09T15:57:17.437Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"update","patch":[{"op":"replace","path":"/metadata/actual_result","value":"Current clients migrate legacy fences to v2, recognize both generations for audit, and older-version refresh simulation preserves the v2 block byte-for-byte."},{"op":"replace","path":"/metadata/expected_result","value":"Cross-version pm clients must not rewrite or silently downgrade merge-driver configuration they do not understand."},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:17.437Z"},{"op":"add","path":"/metadata/resolution","value":"Replaced the legacy unversioned merge-driver fence with a v2 fence while preserving legacy public marker constants and added an integration proof that older clients leave the newer fence untouched."}],"before_hash":"0632500044182f28ad0280ed52f66d3f6f786c5ce2940ce80212bed77bfc1e80","after_hash":"5e658b5a923fc1939c86c55403b66964e43c92a99fce16bf9fbc20fe27baa09c","message":"Record verified cross-version merge-fence outcome"} +{"ts":"2026-08-09T15:57:17.861Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-08-09T15:57:17.861Z","author":"harness:codex","text":"Evidence: focused linked tests passed; full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; pnpm lint and pnpm quality:static passed; pm merge reconcile --dry-run reported zero drift and a healthy v2 fence. Packed manual acceptance in an isolated temporary Git project completed init/create/comment/get/health/validate/storage/history successfully."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:17.861Z"}],"before_hash":"5e658b5a923fc1939c86c55403b66964e43c92a99fce16bf9fbc20fe27baa09c","after_hash":"34fc7183f841ad71a8d8638b5be009e395435ca7d9ca8158f7a10f191d5ab2d7"} +{"ts":"2026-08-09T15:57:21.557Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:21.557Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:21.544Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:21.544Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented and verified a versioned, backward-safe merge-driver fence with regression and cross-version integration coverage."}],"before_hash":"34fc7183f841ad71a8d8638b5be009e395435ca7d9ca8158f7a10f191d5ab2d7","after_hash":"178cc9cbaa3b835e5dc5a19a7fc2c25cd9a4883ded82b8f3d83d6b440addeef4"} +{"ts":"2026-08-09T15:57:22.119Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:22.119Z"}],"before_hash":"178cc9cbaa3b835e5dc5a19a7fc2c25cd9a4883ded82b8f3d83d6b440addeef4","after_hash":"0997fd0877755453ffa915ca08350f5809df14d3a9d9b7f905e79376b2cb13a0"} diff --git a/.agents/pm/history/pm-lu6sca.jsonl b/.agents/pm/history/pm-lu6sca.jsonl index 545d22019..8a832bed4 100644 --- a/.agents/pm/history/pm-lu6sca.jsonl +++ b/.agents/pm/history/pm-lu6sca.jsonl @@ -25,3 +25,15 @@ {"ts":"2026-08-09T00:58:11.333Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b328d74ff33d5397acdbcabe","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/tests/0/timeout_seconds","value":600},{"op":"replace","path":"/metadata/tests/0/command","value":"node scripts/run-tests.mjs coverage"},{"op":"add","path":"/metadata/tests/1","value":{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/provenance-health.spec.ts tests/unit/commands/health-command.spec.ts","scope":"project","timeout_seconds":240}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T00:58:11.333Z"}],"before_hash":"6f452ba9c203464766f690ce113a2d2e68af9641432eaa6892b95b0a88393e32","after_hash":"db17f5fc672aabd7ba71eebc26ec3fc50c23a4b7cbe23ce1f68ee0e59bc6f2a0"} {"ts":"2026-08-09T00:58:13.326Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b328d74ff33d5397acdbcabe","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/6","value":{"created_at":"2026-08-09T00:58:13.326Z","author":"harness:codex","text":"Review-loop evidence: provenance scanning now byte-bounds history before allocation, parses only complete lines, distinguishes exact event limits from truncation, suppresses zero-success warnings on incomplete samples, and records invalid explicit role values as invalid_value with argv precedence. Full sandboxed gate: 461 files, 7,089 tests, exact 100/100/100/100. Item remains open and unclaimed for its documented no-resolver-declared residual."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T00:58:13.326Z"}],"before_hash":"db17f5fc672aabd7ba71eebc26ec3fc50c23a4b7cbe23ce1f68ee0e59bc6f2a0","after_hash":"b8cdf8af9da04389d3a4da60b76ef4db9da96d7d69119141614f0142a2167b96"} {"ts":"2026-08-09T01:24:46.237Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b328d74ff33d5397acdbcabe","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/7","value":{"created_at":"2026-08-09T01:24:46.237Z","author":"harness:codex","text":"PR #944 hosted evidence for the completed tranche portion: implementation commit b6678b8 passed all deterministic checks; CodeRabbit confirmed byte-bounded complete-event health semantics and invalid-value role outcomes. All 16 findings are addressed, replied to, and resolved. Item stays open and unclaimed for the documented no-resolver-declared residual."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T01:24:46.237Z"}],"before_hash":"b8cdf8af9da04389d3a4da60b76ef4db9da96d7d69119141614f0142a2167b96","after_hash":"58ea3ead522ae92cf081f38171afdf7232e4e4378ab9e37aa7b7c2d11032cae3"} +{"ts":"2026-08-09T14:34:09.223Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:34:09.223Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#b2adadb08f3a0763fd3bf70f"}],"before_hash":"58ea3ead522ae92cf081f38171afdf7232e4e4378ab9e37aa7b7c2d11032cae3","after_hash":"9dec7c99f4a620c9154d49938391317c553f2335192d0e0c6960702da8b983b2"} +{"ts":"2026-08-09T14:34:09.710Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:34:09.710Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"9dec7c99f4a620c9154d49938391317c553f2335192d0e0c6960702da8b983b2","after_hash":"8051efe031fcb1ffde89611d5f28d9dd07297d16ea5fb23ce6cdcfa4370b404b","message":"Complete the public provenance outcome algebra"} +{"ts":"2026-08-09T14:53:57.735Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/6/note","value":"Prove resolver-health scanning preserves the no-provider-I/O boundary"},{"op":"replace","path":"/metadata/files/6/path","value":"tests/unit/sdk/health-vector-boundary.spec.ts"},{"op":"replace","path":"/metadata/files/5/note","value":"Invalid role provenance outcome regression"},{"op":"replace","path":"/metadata/files/5/path","value":"tests/unit/sdk/agent-runtime-primitives.spec.ts"},{"op":"replace","path":"/metadata/files/4/note","value":"Bounded resolver attempt and success scanner"},{"op":"replace","path":"/metadata/files/4/path","value":"src/sdk/governance/provenance-health.ts"},{"op":"replace","path":"/metadata/files/3/note","value":"Expose zero-success resolver diagnostics through pm health"},{"op":"replace","path":"/metadata/files/3/path","value":"src/sdk/governance/health.ts"},{"op":"replace","path":"/metadata/files/2/note","value":"Explicit provenance precedence and invalid role outcome classification"},{"op":"replace","path":"/metadata/files/2/path","value":"src/core/shared/author.ts"},{"op":"replace","path":"/metadata/files/1/note","value":"Persist resolver outcome evidence"},{"op":"replace","path":"/metadata/files/1/path","value":"src/core/history/history.ts"},{"op":"replace","path":"/metadata/files/0/note","value":"SDK outcome contract snapshot"},{"op":"replace","path":"/metadata/files/0/path","value":"sdk/public-surface.json"},{"op":"add","path":"/metadata/files/7","value":{"path":"tests/unit/sdk/provenance-health.spec.ts","scope":"project","note":"Resolver health failure and success coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:53:57.735Z"}],"before_hash":"8051efe031fcb1ffde89611d5f28d9dd07297d16ea5fb23ce6cdcfa4370b404b","after_hash":"0ea6650b952a2b5696ff0a8ffea76ee65c9c8f9c4f5963471b46e18e2f86291b"} +{"ts":"2026-08-09T14:53:58.583Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/tests/1/timeout_seconds","value":180},{"op":"replace","path":"/metadata/tests/1/command","value":"node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts"},{"op":"add","path":"/metadata/tests/2","value":{"command":"node scripts/run-tests.mjs test -- tests/unit/sdk/provenance-health.spec.ts tests/unit/commands/health-command.spec.ts","scope":"project","timeout_seconds":240}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:53:58.583Z"}],"before_hash":"0ea6650b952a2b5696ff0a8ffea76ee65c9c8f9c4f5963471b46e18e2f86291b","after_hash":"70b989d313969ada7ff9027cb343805d8f45db085ab378ec8f97ecb607c348f1"} +{"ts":"2026-08-09T15:05:58.264Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:05:58.264Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-mslxq9rl-7v1vac","kind":"test","status":"failed","started_at":"2026-08-09T14:58:13.100Z","finished_at":"2026-08-09T15:05:58.257Z","recorded_at":"2026-08-09T15:05:58.257Z","passed":2,"failed":1,"skipped":0}]}],"before_hash":"70b989d313969ada7ff9027cb343805d8f45db085ab378ec8f97ecb607c348f1","after_hash":"d2fd03e1c803b7ead6ad1dda46d8678ac5838d665d2a42ed7b947a8c12781664","message":"Track test run summary (test-local-mslxq9rl-7v1vac)"} +{"ts":"2026-08-09T15:05:59.643Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"test_run_track","patch":[{"op":"add","path":"/metadata/test_runs/1","value":{"run_id":"test-local-mslxqatv-9o2sdd","kind":"test","status":"failed","started_at":"2026-08-09T14:59:00.977Z","finished_at":"2026-08-09T15:05:59.635Z","recorded_at":"2026-08-09T15:05:59.635Z","passed":2,"failed":1,"skipped":0}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:05:59.643Z"}],"before_hash":"d2fd03e1c803b7ead6ad1dda46d8678ac5838d665d2a42ed7b947a8c12781664","after_hash":"e96baf286f60c2cecde33011d78dc7397fa937bdd622c3ac01a8b75efb8b4799","message":"Track test run summary (test-local-mslxqatv-9o2sdd)"} +{"ts":"2026-08-09T15:42:33.263Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"test_run_track","patch":[{"op":"add","path":"/metadata/test_runs/2","value":{"run_id":"test-local-mslz1bft-xylosg","kind":"test","status":"passed","started_at":"2026-08-09T15:42:22.863Z","finished_at":"2026-08-09T15:42:33.257Z","recorded_at":"2026-08-09T15:42:33.257Z","passed":1,"failed":0,"skipped":0}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:42:33.263Z"}],"before_hash":"e96baf286f60c2cecde33011d78dc7397fa937bdd622c3ac01a8b75efb8b4799","after_hash":"6eeca345583e30ec3773a76322ea599e8d34f596df225a4a8b1b8e113e10bccb","message":"Track test run summary (test-local-mslz1bft-xylosg)"} +{"ts":"2026-08-09T15:42:53.908Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"test_run_track","patch":[{"op":"add","path":"/metadata/test_runs/3","value":{"run_id":"test-local-mslz1rd7-8wwd82","kind":"test","status":"passed","started_at":"2026-08-09T15:42:33.647Z","finished_at":"2026-08-09T15:42:53.899Z","recorded_at":"2026-08-09T15:42:53.899Z","passed":1,"failed":0,"skipped":0}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:42:53.908Z"}],"before_hash":"6eeca345583e30ec3773a76322ea599e8d34f596df225a4a8b1b8e113e10bccb","after_hash":"fb68300841597980a8b79b0c024530fdc11a4975e01e7d1b10820d08a18ed51b","message":"Track test run summary (test-local-mslz1rd7-8wwd82)"} +{"ts":"2026-08-09T15:57:24.758Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:24.758Z"},{"op":"add","path":"/metadata/resolution","value":"Extended provenance outcomes with an explicit not_configured state and resolver_not_configured reason, separating absent configuration from attempted resolver failure."},{"op":"add","path":"/metadata/expected_result","value":"Callers must be able to distinguish no resolver configuration from a resolver that ran and failed."},{"op":"add","path":"/metadata/actual_result","value":"CLI and SDK provenance contracts now emit not_configured only when no resolver is declared, while resolved and failed remain attempted outcomes and the public surface snapshot records the additive contract."}],"before_hash":"fb68300841597980a8b79b0c024530fdc11a4975e01e7d1b10820d08a18ed51b","after_hash":"703dedf6736ebb9cb90bbe27e1cc277280ddf61567758bc4290c9c5309bc4167","message":"Record verified provenance outcome vocabulary"} +{"ts":"2026-08-09T15:57:25.224Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/8","value":{"created_at":"2026-08-09T15:57:25.224Z","author":"harness:codex","text":"Evidence: focused agent-runtime and author-attribution tests passed after truthful overlapping-run failure receipts; the final uninterrupted full suite passed 7,100/7,100 with exact 100/100/100/100 coverage. SDK surface change was explicitly acknowledged and all static, lint, parity, token, and performance gates passed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:25.224Z"}],"before_hash":"703dedf6736ebb9cb90bbe27e1cc277280ddf61567758bc4290c9c5309bc4167","after_hash":"4d594a1ca57ad58d5a692efdfb5c4f3111d969eb68dc2433fe53505bef5937f2"} +{"ts":"2026-08-09T15:57:25.825Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:25.825Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:25.791Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:25.791Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented and documented explicit configured-versus-attempted provenance outcome semantics across CLI and SDK."}],"before_hash":"4d594a1ca57ad58d5a692efdfb5c4f3111d969eb68dc2433fe53505bef5937f2","after_hash":"69e57d4f2fec9149269b407dbdd82b171b5af5ba637c67135640fc0ca6a9e078"} +{"ts":"2026-08-09T15:57:26.460Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:26.460Z"}],"before_hash":"69e57d4f2fec9149269b407dbdd82b171b5af5ba637c67135640fc0ca6a9e078","after_hash":"d8ef0407ad6ba29221a310121d69590cff4e64de24e9dfd50c7849e75d7c1e2f"} diff --git a/.agents/pm/history/pm-xgah3a.jsonl b/.agents/pm/history/pm-xgah3a.jsonl index 4390ee3ac..90d7038b4 100644 --- a/.agents/pm/history/pm-xgah3a.jsonl +++ b/.agents/pm/history/pm-xgah3a.jsonl @@ -5,3 +5,12 @@ {"ts":"2026-08-09T13:48:48.034Z","author":"harness:claude-code","author_source":"detected","agent_harness":"claude-code","agent_model":"claude-opus-5","agent_model_source":"probe","agent_instance":"69ec4867036ac7a1d344bd67","agent_provenance":{"model":{"value":"claude-opus-5","source":"probe"},"effort":{"value":"xhigh","source":"environment"},"role":null,"topic":{"value":"pm-xgah3a","source":"argv"},"version":{"value":"2.1.226","source":"probe"}},"op":"files_add","patch":[{"op":"add","path":"/metadata/files/1","value":{"path":"tests/unit/sdk/agent-runtime-primitives.spec.ts","scope":"project","note":"Failing expectation at 741; passes only when AI_AGENT is absent from the host"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T13:48:48.034Z"}],"before_hash":"5a679fb67ddd3fee39cee7413ae71dc17300048b500bb4f85141615696a404d4","after_hash":"fccd3a7ea9c73cdd495719c4cf24f3af6b55dc93c866d5c1d956f582cad2203a"} {"ts":"2026-08-09T13:48:48.780Z","author":"harness:claude-code","author_source":"detected","agent_harness":"claude-code","agent_model":"claude-opus-5","agent_model_source":"probe","agent_instance":"69ec4867036ac7a1d344bd67","agent_provenance":{"model":{"value":"claude-opus-5","source":"probe"},"effort":{"value":"xhigh","source":"environment"},"role":null,"topic":{"value":"pm-xgah3a","source":"argv"},"version":{"value":"2.1.226","source":"probe"}},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/1/note","value":"Sandbox helper: isolates PM_PATH and telemetry, does not neutralize harness signal environment"},{"op":"replace","path":"/metadata/files/1/path","value":"tests/helpers/withTempPmPath.ts"},{"op":"add","path":"/metadata/files/2","value":{"path":"tests/unit/sdk/agent-runtime-primitives.spec.ts","scope":"project","note":"Failing expectation at 741; passes only when AI_AGENT is absent from the host"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T13:48:48.780Z"}],"before_hash":"fccd3a7ea9c73cdd495719c4cf24f3af6b55dc93c866d5c1d956f582cad2203a","after_hash":"3631e8a617c773055f9d3b6110811410195fea4c70093019d9012b089051d05c"} {"ts":"2026-08-09T13:48:49.454Z","author":"harness:claude-code","author_source":"detected","agent_harness":"claude-code","agent_model":"claude-opus-5","agent_model_source":"probe","agent_instance":"69ec4867036ac7a1d344bd67","agent_provenance":{"model":{"value":"claude-opus-5","source":"probe"},"effort":{"value":"xhigh","source":"environment"},"role":null,"topic":{"value":"pm-xgah3a","source":"argv"},"version":{"value":"2.1.226","source":"probe"}},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T13:48:49.454Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"env -u AI_AGENT node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts","scope":"project","timeout_seconds":300}]}],"before_hash":"3631e8a617c773055f9d3b6110811410195fea4c70093019d9012b089051d05c","after_hash":"80751fcdaf1a5009c8ce0be028851d5fa82f4c46ded3008508680c8b128cea4d"} +{"ts":"2026-08-09T14:34:11.323Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:34:11.323Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#b2adadb08f3a0763fd3bf70f"}],"before_hash":"80751fcdaf1a5009c8ce0be028851d5fa82f4c46ded3008508680c8b128cea4d","after_hash":"030fc2ecbed93bf77649875c0f64530ea6fa12161e6f922fc7ea98c829f3d355"} +{"ts":"2026-08-09T14:34:11.907Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:34:11.907Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"030fc2ecbed93bf77649875c0f64530ea6fa12161e6f922fc7ea98c829f3d355","after_hash":"812283cb82dbed69287eedc6107ea830c4a28a4d22267258f257a18e0107f359","message":"Implement harness-scoped provenance isolation and local gate control"} +{"ts":"2026-08-09T14:54:00.873Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/tests/0/timeout_seconds","value":180},{"op":"replace","path":"/metadata/tests/0/command","value":"AI_AGENT=claude-code_2-1-226_agent node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts tests/unit/sdk/merge-receipts.spec.ts"},{"op":"add","path":"/metadata/tests/1","value":{"command":"env -u AI_AGENT node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts","scope":"project","timeout_seconds":300}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T14:54:00.873Z"}],"before_hash":"812283cb82dbed69287eedc6107ea830c4a28a4d22267258f257a18e0107f359","after_hash":"af779e4c86f2b1a57376046e879ef529f75d4a2ccb68685a05d406d61c1bd2f8"} +{"ts":"2026-08-09T15:26:24.456Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-08-09T15:26:24.456Z","author":"harness:codex","text":"Implementation evidence: sandbox isolation now clears only the ambiguous shared AI_AGENT signal; explicit CODEX/Claude session signals remain available for intentional CLI/MCP parity. The foreign AI_AGENT reproducer and mutation-envelope parity suite both pass."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:26:24.456Z"}],"before_hash":"af779e4c86f2b1a57376046e879ef529f75d4a2ccb68685a05d406d61c1bd2f8","after_hash":"77e357d5779300bab8fa13b4dd3e7386138162a7b31ca8adf885def164a9f8e3"} +{"ts":"2026-08-09T15:43:42.142Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:43:42.142Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-mslz2sl4-2piwzr","kind":"test","status":"passed","started_at":"2026-08-09T15:43:22.911Z","finished_at":"2026-08-09T15:43:42.136Z","recorded_at":"2026-08-09T15:43:42.136Z","passed":2,"failed":0,"skipped":0}]}],"before_hash":"77e357d5779300bab8fa13b4dd3e7386138162a7b31ca8adf885def164a9f8e3","after_hash":"99e2fdf1750e88f9079f8383e28dc198a53f5515282d55702edbdc68f7224883","message":"Track test run summary (test-local-mslz2sl4-2piwzr)"} +{"ts":"2026-08-09T15:57:29.073Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:29.073Z"},{"op":"add","path":"/metadata/resolution","value":"Hardened test sandboxes against only the ambiguous foreign AI_AGENT signal and taught shared resolver attribution to ignore a literal signal belonging to another detected harness."},{"op":"add","path":"/metadata/expected_result","value":"Foreign ambient harness metadata must not contaminate SDK or CLI attribution, while explicit same-harness and dedicated resolver signals remain testable."},{"op":"add","path":"/metadata/actual_result","value":"Codex attribution ignores a Claude-valued shared AI_AGENT variable; sandbox helpers clear ambiguous AI_AGENT without erasing dedicated harness variables, preserving CLI/MCP parity coverage."}],"before_hash":"99e2fdf1750e88f9079f8383e28dc198a53f5515282d55702edbdc68f7224883","after_hash":"d7e171af929bf337a6c5eb010254e43bccb327b5e8e06ea1f4e1900b2a224cde","message":"Record verified sandbox provenance isolation"} +{"ts":"2026-08-09T15:57:29.521Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-08-09T15:57:29.521Z","author":"harness:codex","text":"Evidence: both linked test groups passed; final full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; pnpm lint and all static quality gates passed. The narrowed isolation behavior is documented in the item history and avoids masking dedicated resolver fixtures."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:29.521Z"}],"before_hash":"d7e171af929bf337a6c5eb010254e43bccb327b5e8e06ea1f4e1900b2a224cde","after_hash":"230aa6184d35f582b7c449280876ffc9506ece130eadc6ba13a30bd78b611324"} +{"ts":"2026-08-09T15:57:30.113Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:30.113Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:30.059Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:30.059Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented foreign-harness provenance isolation without over-clearing explicit resolver inputs."}],"before_hash":"230aa6184d35f582b7c449280876ffc9506ece130eadc6ba13a30bd78b611324","after_hash":"e9ae2951712737a901d54d25c0a342e5276ae0bbcd0aa9f2638d3c5984d2c1ad"} +{"ts":"2026-08-09T15:57:30.620Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:30.620Z"}],"before_hash":"e9ae2951712737a901d54d25c0a342e5276ae0bbcd0aa9f2638d3c5984d2c1ad","after_hash":"bd6830556c35494c380f6112130a29ac4177353f51068fa3f7dd1491a97fd740"} diff --git a/.agents/pm/issues/pm-1j5j21.toon b/.agents/pm/issues/pm-1j5j21.toon index 075577b71..38af8308d 100644 --- a/.agents/pm/issues/pm-1j5j21.toon +++ b/.agents/pm/issues/pm-1j5j21.toon @@ -2,11 +2,13 @@ id: pm-1j5j21 title: "GH-921/GH-922: merge-decision receipts are not durable in fresh-clone CI" description: "Pending merge-decision receipts live only in clone-local ignored state, so a fresh checkout cannot distinguish a lossy concurrent merge; history-repair can erase the last tracked drift signal and make discarded work pass strict health." type: Issue -status: open +status: closed priority: 1 tags: [] created_at: "2026-08-07T08:33:38.852Z" -updated_at: "2026-08-08T15:39:03.748Z" +updated_at: "2026-08-09T15:58:32.674Z" +closed_at: "2026-08-09T15:57:23.719Z" +completed_at: "2026-08-09T15:57:23.719Z" author: "harness:codex" estimated_minutes: 240 acceptance_criteria: Merge-decision receipts required by validation survive a fresh clone and clean CI checkout without relying on ignored local files; the field-aware merge driver and health/validate surfaces agree on durable evidence; isolated two-branch merge tests cover both lossless and discarded-value decisions and keep history hash validation intact @@ -14,8 +16,9 @@ parent: pm-doxj risk: critical confidence: high severity: critical -expected_result: "Discarded-value provenance and acknowledgment are durable, pushed, and enforceable from a fresh clone before repair can make the workspace green." -actual_result: "The merge-performing clone sees a pending decision, but a fresh clone loses it; after history-repair, strict health can pass a commit that discarded a peer edit." +resolution: "Persisted privacy-safe hash-only merge decision receipt sidecars inside the project tracker while retaining raw values only in clone-local Git state; listing, health, validation, and reconciliation now merge both sources deterministically." +expected_result: Merge decision evidence must survive a fresh clone without committing raw conflicting values or losing local reconciliation capability. +actual_result: "Fresh clones retain stable hash-only decision evidence, original clones retain raw-value receipts, duplicate receipt identities prefer local detail, and reconciliation updates both stores." affected_version: 2026.8.6 component: merge safety and durable history dependencies[4]{id,kind,created_at,author,source_kind,author_source}: @@ -23,7 +26,24 @@ dependencies[4]{id,kind,created_at,author,source_kind,author_source}: pm-ysqb6n,related,"2026-08-07T08:33:38.852Z","harness:codex","cli:create:dep",detected pm-g5sx,discovered_from,"2026-08-07T08:34:27.916Z","harness:codex","cli:update:dep",detected pm-ysqb6n,supersedes,"2026-08-07T08:34:27.916Z","harness:codex","cli:update:dep",detected -comments[2]{created_at,author,text}: +comments[3]{created_at,author,text}: "2026-08-07T08:33:38.852Z","harness:codex","GitHub sources: https://github.com/unbraind/pm-cli/issues/921 and https://github.com/unbraind/pm-cli/issues/922. Duplicate check searched all 2,351 items and every status for clone-local/gitignored merge receipts,fresh-clone CI,discarded values,history-repair,and both GH numbers. The reports share one root contract and are intentionally consolidated; closed pm-ysqb6n is predecessor evidence,not an active duplicate." "2026-08-08T15:39:02.830Z","harness:codex","Investigation boundary (2026-08-08): this PR deliberately does not claim fresh-clone durability. The implemented receipt work classifies lossless versus discarded-value decisions and requires explicit acceptance, but raw recovery receipts remain clone-local and ignored. A durable privacy-safe pushed evidence design needs a separate tracked-record contract and fresh-clone lifecycle, so retaining this item as open avoids falsely closing GH-921/GH-922." + "2026-08-09T15:57:23.042Z","harness:codex","Evidence: linked receipt tests passed; full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; static, lint, SDK surface, performance, history-drift, storage-integrity, and dry-run reconciliation gates passed. Manual packed-consumer acceptance also passed in an isolated project." +files[5]{path,scope,note}: + sdk/public-surface.json,project,SDK contract snapshot + src/sdk/governance/health.ts,project,Durable receipt discovery + src/sdk/governance/validate.ts,project,Durable receipt validation + src/sdk/merge/receipts.ts,project,Raw local plus durable hash-only receipt store + tests/unit/sdk/merge-receipts.spec.ts,project,Fresh-clone durability and privacy coverage +tests[2]{command,scope,timeout_seconds}: + node scripts/run-tests.mjs test -- tests/unit/sdk/merge-receipts.spec.ts tests/integration/merge-receipt-health-classification.integration.spec.ts tests/unit/commands/merge-reconcile-command.spec.ts,project,240 + "pnpm changelog:pm:check",project,240 +test_runs[2]{run_id,kind,status,started_at,finished_at,recorded_at,passed,failed,skipped}: + test-local-mslxgadt-0r0s2c,test,passed,"2026-08-09T14:57:53.136Z","2026-08-09T14:58:12.497Z","2026-08-09T14:58:12.497Z",1,0,0 + test-local-mslxh5t9-thtgqo,test,passed,"2026-08-09T14:58:26.430Z","2026-08-09T14:58:53.229Z","2026-08-09T14:58:53.229Z",1,0,0 +docs[2]{path,scope,note}: + CHANGELOG.md,project,Managed changelog entry for the coupled SDK integrity tranche + docs/MERGE_SAFETY.md,project,Durable receipt lifecycle +close_reason: "Implemented clone-durable, privacy-safe merge decision receipts across SDK health, validate, and reconcile paths." body: "" diff --git a/.agents/pm/issues/pm-eq9dlw.toon b/.agents/pm/issues/pm-eq9dlw.toon index 19bdcd833..d7d73123a 100644 --- a/.agents/pm/issues/pm-eq9dlw.toon +++ b/.agents/pm/issues/pm-eq9dlw.toon @@ -2,11 +2,13 @@ id: pm-eq9dlw title: "The session-role dimension is wired to a boolean child-session flag, so every nested claude-code invocation records the role literally as \"1\" and fleet analytics will group real work under a meaningless label" description: "Measured on 2026-08-03 against pm 2026.8.3.\n\nThe claude-code harness descriptor in src/core/shared/author.ts declares provenance_environment_keys.role = ['CLAUDE_CODE_CHILD_SESSION']. That variable is a boolean marker meaning 'this invocation is a nested session'; its value in a live session is the literal string '1'. The resolver treats any non-blank value as the role observation, so a fresh mutation on 2026-08-03 records agent_provenance.role = {value: '1', source: 'environment'}.\n\nThis reads as legitimate provenance. The source is 'environment', which is the same source category a genuinely declared role would carry, so no consumer can distinguish a real role from this artifact by inspecting the entry. Fleet attribution analytics group by role; a permanently immutable population of entries labelled role '1' is worse than a population labelled null, because null is honest about absence and '1' is not.\n\nThe wiring appears to be a category error introduced while closing the gap that role had no descriptor key on any harness. Filling the slot with the only role-adjacent variable the harness exports satisfies a coverage metric while defeating the purpose of the dimension. If the nested-session fact is worth recording it deserves its own dimension with its own name and a boolean value domain.\n\nRelated but distinct: whether a declared resolver that fails is distinguishable from a dimension a harness cannot supply is its own finding. This one is the inverse - a resolver that succeeds and records a value that means nothing.\n\nScope is the role dimension wiring and the general rule that a descriptor key must match the value domain of the dimension it feeds." type: Issue -status: open +status: closed priority: 2 tags[4]: "area:sdk",data-quality,identity,provenance created_at: "2026-08-03T06:21:42.773Z" -updated_at: "2026-08-09T01:24:45.768Z" +updated_at: "2026-08-09T15:57:28.612Z" +closed_at: "2026-08-09T15:57:28.024Z" +completed_at: "2026-08-09T15:57:28.024Z" author: "harness:claude-code" estimated_minutes: 240 acceptance_criteria: "No provenance dimension is sourced from an environment key whose value domain is boolean or presence-only; Each descriptor key declares the dimension value domain it is expected to carry, and a value outside that domain is refused rather than recorded; The nested-session fact, if worth recording, is recorded in a dimension whose name says what it means rather than being smuggled into role; A corpus check reports zero provenance values that are bare booleans or single digits across all dimensions" @@ -16,8 +18,9 @@ confidence: high severity: medium environment: "pm 2026.8.3, claude-code harness with CLAUDE_CODE_CHILD_SESSION=1, Linux" repro_steps: Run a pm mutation from a nested/child claude-code session and read agent_provenance.role on the newest history entry. -expected_result: "role is either a descriptive session role the operator declared, or null when the harness publishes no role." -actual_result: "role is {value: \"1\", source: \"environment\"}. The claude-code descriptor maps the role dimension to CLAUDE_CODE_CHILD_SESSION, which is a presence/boolean flag whose value is the string \"1\", not a role name." +resolution: Added bounded corpus-wide provenance value-domain scanning to SDK health with privacy-safe harness/dimension/kind aggregates for boolean and single-digit legacy values. +expected_result: Health diagnostics must find invalid provenance values across immutable history without leaking raw values or requiring unbounded reads. +actual_result: "Health scans bounded bytes/events, emits aggregate invalid_values and stable warnings, covers malformed/truncated histories, and propagates the vector through the documented health contract." component: core/shared/author dependencies[7]{id,kind,created_at,author,source_kind,author_source}: pm-1wiugq,related,"2026-08-03T06:23:40.264Z","harness:claude-code","cli:update:dep",detected @@ -27,7 +30,7 @@ dependencies[7]{id,kind,created_at,author,source_kind,author_source}: pm-lu6sca,related,"2026-08-03T06:23:40.264Z","harness:claude-code","cli:update:dep",detected pm-pj2isb,related,"2026-08-03T06:23:40.264Z","harness:claude-code","cli:update:dep",detected pm-rbg1qo,discovered_from,"2026-08-03T06:23:40.264Z","harness:claude-code","cli:update:dep",detected -comments[8]{created_at,author,text}: +comments[9]{created_at,author,text}: "2026-08-03T11:09:27.894Z","harness:codex","Estimate basis 2026-08-03: 240 minutes covers value-domain declarations, invalid boolean rejection, a correctly named nested-session dimension, corpus check, and regression coverage." "2026-08-07T11:23:43.166Z","harness:claude-code","Confirmed still live at 2026.8.7 on 2026-08-07 with no identity flags passed. A create from Claude Code recorded author harness:claude-code with author_source detected, agent_model claude-opus-5 from probe, effort xhigh from environment, version 2.1.224 from probe — and role literally \"1\" from environment, with topic null. Model, effort and version capture are working end to end; role and topic remain the only two dimensions that do not carry meaning. Fleet analytics grouping on role today would bucket every nested session under the string \"1\"." "2026-08-08T08:10:41.851Z","harness:claude-code","Reproduced live on 2026-08-08 against pm-cli 2026.8.7, HEAD build. A create recorded this session carries agent_provenance role {value: \"1\", source: \"environment\"} alongside a correctly resolved model {claude-opus-5, probe}, effort {xhigh, environment} and version {2.1.226, probe}. So the dimension is not merely unpopulated: it is populated with the boolean child-session flag rendered as a string, which is worse than null because it types as a valid role and will group every nested claude-code invocation under one meaningless label in fleet analytics. Sibling dimension topic is null in the same record, which pm-3zgh2c owns. Evidence is the last history entry of pm-3lhth4." @@ -36,10 +39,23 @@ comments[8]{created_at,author,text}: "2026-08-09T00:09:13.174Z","harness:codex","Broad tranche evidence: Claude boolean child-session data no longer becomes a role; the controlled role vocabulary plus argv review/implementation inference now pass the complete 7086-test 100/100/100/100 gate. Item remains open and unclaimed because its corpus-wide all-dimension bare-boolean and single-digit conformance criterion remains broader than this tranche." "2026-08-09T00:20:22.518Z","harness:codex","Delivery handoff: broad SDK/CLI tranche committed at 5b36abc75 and opened as GitHub PR #944 (https://github.com/unbraind/pm-cli/pull/944). Exact local evidence includes 7,086 tests across 461 files at 100/100/100/100 coverage, package/compatibility/npx/dogfood/manual acceptance, tracker/changelog/SDK/static-quality gates, and zero current dependency or GitHub security alerts. Review and exact-head CI evidence will be appended after the hosted loop." "2026-08-09T01:24:45.768Z","harness:codex","PR #944 hosted evidence for the completed tranche portion: implementation commit b6678b8 passed all deterministic checks; all 16 CodeRabbit findings are addressed, replied to, and resolved. Item stays open and unclaimed for its broader remaining role-contract acceptance." -files[1]{path,scope,note}: + "2026-08-09T15:57:27.484Z","harness:codex","Evidence: all three linked tests passed; final full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; lint, duplicate, docstring, surface-replication, SDK parity, token/context, and performance gates passed. Live repository health/storage/history checks remain structurally clean." +files[6]{path,scope,note}: src/core/shared/author.ts,project,Remove boolean child-session flag from semantic role sources and enforce controlled roles -tests[1]{command,scope,timeout_seconds}: + src/sdk/governance/health.ts,project,Invalid provenance health projection + src/sdk/governance/provenance-health.ts,project,Corpus-wide invalid provenance value aggregation + tests/integration/provenance-value-health.integration.spec.ts,project,End-to-end health projection for corpus conformance + tests/unit/sdk/health-vector-boundary.spec.ts,project,Provider-free invalid-value health projection coverage + tests/unit/sdk/provenance-health.spec.ts,project,All-dimension boolean and digit conformance coverage +tests[3]{command,scope,timeout_seconds}: node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts,project,240 -docs[1]{path,scope,note}: + node scripts/run-tests.mjs test -- tests/unit/sdk/provenance-health.spec.ts tests/integration/provenance-value-health.integration.spec.ts tests/unit/sdk/health-vector-boundary.spec.ts,project,180 + node scripts/run-tests.mjs test -- tests/unit/sdk/provenance-health.spec.ts tests/unit/sdk/health-vector-boundary.spec.ts,project,180 +test_runs[2]{run_id,kind,status,started_at,finished_at,recorded_at,passed,failed,skipped}: + test-local-mslxjta1-gxcakh,test,passed,"2026-08-09T14:59:41.020Z","2026-08-09T15:00:56.953Z","2026-08-09T15:00:56.953Z",2,0,0 + test-local-mslz2df0-xetnmy,test,passed,"2026-08-09T15:42:54.392Z","2026-08-09T15:43:22.476Z","2026-08-09T15:43:22.476Z",3,0,0 +docs[2]{path,scope,note}: docs/SDK_AGENT_SESSION_CONTEXT.md,project,Controlled role vocabulary and boolean-signal boundary + docs/SDK_CONTEXT_INTEGRITY.md,project,Bounded privacy-safe corpus conformance contract +close_reason: Implemented bounded privacy-safe corpus diagnostics for invalid historical provenance domains. body: "" diff --git a/.agents/pm/issues/pm-l56d0o.toon b/.agents/pm/issues/pm-l56d0o.toon new file mode 100644 index 000000000..de5bffde2 --- /dev/null +++ b/.agents/pm/issues/pm-l56d0o.toon @@ -0,0 +1,48 @@ +id: pm-l56d0o +title: "GH-948: version-skewed pm invocations silently rewrite the tracked merge fence during unrelated commands" +description: "Current and supported older pm versions normalize the managed .gitattributes fence differently, and ordinary commands such as pm health invoke that write path. A read-only diagnostic can therefore dirty a tracked file, weaken extension merge protection, and create unrelated diffs solely from PATH or lockfile version skew. Duplicate evidence: all-status exact GH-948 and title searches returned no match; adjacent merge-guidance and gitattributes ownership items are distinct because they do not own cross-version idempotence or the read-only side-effect boundary." +type: Issue +status: closed +priority: 1 +tags[7]: agent-ux,"area:merge","area:sdk",determinism,read-only,regression,version-skew +created_at: "2026-08-09T14:32:29.084Z" +updated_at: "2026-08-09T15:57:22.119Z" +closed_at: "2026-08-09T15:57:21.544Z" +completed_at: "2026-08-09T15:57:21.544Z" +author: "harness:codex" +estimated_minutes: 240 +acceptance_criteria: "pm health and every read-only bootstrap path leave .gitattributes byte-identical; pm merge install is explicit, deterministic, and preserves compatible managed rules written by newer supported versions; SDK and CLI tests exercise older/newer fence fixtures and dirty-worktree assertions; manual temporary repositories prove health is read-only and explicit installation converges" +parent: pm-dj98 +risk: high +confidence: high +reporter: GitHub GH-948 +severity: high +environment: Node 26.5.0 Linux; @unbrained/pm-cli 2026.8.3 through 2026.8.9 +repro_steps: "Run npx @unbrained/pm-cli@2026.8.7 health and @2026.8.9 health against the same initialized tracker, restoring .gitattributes between runs; observe opposing tracked diffs." +resolution: Replaced the legacy unversioned merge-driver fence with a v2 fence while preserving legacy public marker constants and added an integration proof that older clients leave the newer fence untouched. +expected_result: Cross-version pm clients must not rewrite or silently downgrade merge-driver configuration they do not understand. +actual_result: "Current clients migrate legacy fences to v2, recognize both generations for audit, and older-version refresh simulation preserves the v2 block byte-for-byte." +affected_version: 2026.8.3-2026.8.9 +regression: true +customer_impact: Agents and contributors accumulate unrelated tracked diffs and can accidentally weaken merge safety when local/global pm versions differ. +dependencies[2]{id,kind,created_at,author,source_kind,author_source}: + pm-1j5j21,related,"2026-08-09T14:32:29.084Z","harness:codex","cli:create:dep",detected + pm-tu71,related,"2026-08-09T14:32:29.084Z","harness:codex","cli:create:dep",detected +comments[2]{created_at,author,text}: + "2026-08-09T14:32:29.084Z","harness:codex","Duplicate check evidence: pm search GH-948 and exact title across status=all returned zero items; pm duplicates --status all was reviewed. GitHub source: https://github.com/unbraind/pm-cli/issues/948" + "2026-08-09T15:57:17.861Z","harness:codex","Evidence: focused linked tests passed; full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; pnpm lint and pnpm quality:static passed; pm merge reconcile --dry-run reported zero drift and a healthy v2 fence. Packed manual acceptance in an isolated temporary Git project completed init/create/comment/get/health/validate/storage/history successfully." +files[6]{path,scope,note}: + .gitattributes,project,Versioned merge-fence contract + src/sdk/merge/index.ts,project,Public marker exports + src/sdk/merge/install.ts,project,Legacy migration and v2 fence ownership + tests/integration/merge-fence-version-skew.integration.spec.ts,project,Cross-version mutation regression + tests/unit/commands/init-command.spec.ts,project,Fresh init and legacy migration coverage + tests/unit/sdk/merge-safety.spec.ts,project,Fence migration coverage +tests[1]{command,scope,timeout_seconds}: + node scripts/run-tests.mjs test -- tests/integration/merge-fence-version-skew.integration.spec.ts tests/unit/sdk/merge-safety.spec.ts tests/unit/commands/init-command.spec.ts,project,240 +test_runs[1]{run_id,kind,status,started_at,finished_at,recorded_at,passed,failed,skipped}: + test-local-mslxfuro-o8s13c,test,passed,"2026-08-09T14:57:16.155Z","2026-08-09T14:57:52.260Z","2026-08-09T14:57:52.260Z",1,0,0 +docs[1]{path,scope,note}: + docs/MERGE_SAFETY.md,project,Version-skew fence contract +close_reason: "Implemented and verified a versioned, backward-safe merge-driver fence with regression and cross-version integration coverage." +body: "" diff --git a/.agents/pm/issues/pm-xgah3a.toon b/.agents/pm/issues/pm-xgah3a.toon index 415cab807..190aa92e8 100644 --- a/.agents/pm/issues/pm-xgah3a.toon +++ b/.agents/pm/issues/pm-xgah3a.toon @@ -2,17 +2,22 @@ id: pm-xgah3a title: "A sandboxed fixture records provenance from the host harness environment, so the suite is green on CI and deterministically red for any agent running it locally" description: "A sandboxed test fixture that simulates one harness records provenance derived from the environment of whatever harness is running the test process, so the suite's verdict is a function of the developer's machine rather than of the fixture.\n\nReproduced deterministically at commit 9a0a048b6, twice, once under a full coverage run and once in isolation. The failing test is tests/unit/sdk/agent-runtime-primitives.spec.ts, attributes update and close mutations to the detected harness. It constructs a simulated codex actor and asserts the exact shape of the two history entries that result. On this machine both entries carry an extra context block, agent_provenance_outcomes.version, with status failed, reason resolver_failed, resolver ai_agent_version and rule_version v1. The assertion compares whole entries, so the unexpected block fails it. With the single environment variable AI_AGENT removed the same spec passes sixteen of sixteen. That is the whole difference.\n\nThe mechanism is a three-step leak and every step is ordinary. The codex harness descriptor at src/core/shared/author.ts:219 declares provenance_resolvers with version mapped to ai_agent_version. The resolver at src/core/shared/author.ts:569 reads env.AI_AGENT and matches a version anchored at the end of the string. The outcome classifier at src/core/shared/author.ts:897 decides between failed and unavailable by asking only whether env.AI_AGENT is non-blank, not whether the value belongs to the harness the descriptor matched.\n\nSo on a hosted runner AI_AGENT is unset, the classifier reports unavailable with reason harness_unavailable, and the expectation holds. On the machine of an agent running the suite locally AI_AGENT is set by that agent's own harness. Here it is claude-code_2-1-226_agent, which ends in the literal text agent rather than a version, so the regex does not match, the resolver returns nothing, and because the variable was nevertheless present the classifier upgrades the outcome from unavailable to failed and stamps resolver_failed into the record. A simulated codex actor's immutable history entry therefore carries a diagnostic about the real Claude Code process that ran the test.\n\nThe first consequence is a local and hosted divergence with the wrong polarity, and it lands on precisely the audience this project exists to serve. Continuous integration is green at this commit. Any coding agent that runs the documented local command sees a deterministic red suite, and both harnesses this project targets set AI_AGENT. Local verification is meant to be at least as strict as hosted verification so that a green local run predicts a green push. Here it is differently strict rather than more strict: it fails on something hosted cannot observe while hosted passes on something local cannot reach. A contributor meeting this has no signal distinguishing it from a real regression, and the natural response, re-running or assuming a flake, is wrong in both directions.\n\nThe second consequence is the deeper one and is about the product rather than the suite. The sandbox does not isolate harness provenance. withTempPmPath redirects PM_PATH and PM_GLOBAL_PATH and neutralizes telemetry, so storage is contained, but the harness signal environment passes straight through. Any recorded provenance produced inside a sandbox is therefore a function of the host. For an outcome milestone whose claim is provable history, a field of the record that varies with who ran the process is a containment breach rather than a flaky assertion, and it is the same class of defeat that reproducible byte-identical workspace construction was built to rule out: two hosts constructing the same fixture do not produce the same record.\n\nThere is also a narrower correctness point worth separating, because it is true independently of any test. A resolver should only read an environment variable belonging to the harness whose descriptor matched. AI_AGENT is a shared name that several harnesses write, so the codex descriptor reading it means a codex actor can inherit a value written by a different tool entirely. The classifier compounds this by treating mere presence of the variable as evidence that the resolver had valid input, which is what turns an honest unavailable into a misleading failed. A record that says a resolver failed, when in fact it was handed another harness's value, states something untrue about the run." type: Issue -status: open +status: closed priority: 1 tags[5]: agent-ux,"area:sdk",ci,provenance,test-isolation created_at: "2026-08-09T13:47:16.901Z" -updated_at: "2026-08-09T13:48:49.454Z" +updated_at: "2026-08-09T15:57:30.620Z" +closed_at: "2026-08-09T15:57:30.059Z" +completed_at: "2026-08-09T15:57:30.059Z" author: "harness:claude-code" estimated_minutes: 180 acceptance_criteria: "A sandboxed workspace neutralizes harness signal environment, so recorded provenance depends only on the harness the fixture declares and never on the process running the suite; A provenance resolver reads only environment variables belonging to the harness whose descriptor matched, so a codex descriptor never consumes a value written by another tool; The outcome classifier distinguishes a resolver that was handed valid input and failed from one that was handed another harness's value, so the record never reports resolver_failed for input that was never the harness's to begin with; The agent-runtime-primitives expectation holds with AI_AGENT unset, set to a value carrying a parseable version, and set to a value that does not, proving the verdict no longer varies with the host; Local preflight carries a control that sets a foreign harness variable and fails if any spec's verdict changes, so this divergence class cannot silently return" parent: pm-u9d0 risk: medium confidence: high +resolution: Hardened test sandboxes against only the ambiguous foreign AI_AGENT signal and taught shared resolver attribution to ignore a literal signal belonging to another detected harness. +expected_result: "Foreign ambient harness metadata must not contaminate SDK or CLI attribution, while explicit same-harness and dedicated resolver signals remain testable." +actual_result: "Codex attribution ignores a Claude-valued shared AI_AGENT variable; sandbox helpers clear ambiguous AI_AGENT without erasing dedicated harness variables, preserving CLI/MCP parity coverage." dependencies[10]{id,kind,created_at,author,source_kind,author_source}: pm-0pzgit,related,"2026-08-09T13:47:49.558Z","harness:claude-code","cli:update:dep",detected pm-1zhfls,related,"2026-08-09T13:47:49.558Z","harness:claude-code","cli:update:dep",detected @@ -24,12 +29,18 @@ dependencies[10]{id,kind,created_at,author,source_kind,author_source}: pm-rbcvt2,related,"2026-08-09T13:47:49.558Z","harness:claude-code","cli:update:dep",detected pm-w7ccmv,implements,"2026-08-09T13:47:49.558Z","harness:claude-code","cli:update:dep",detected pm-xp1xsw,implements,"2026-08-09T13:47:49.558Z","harness:claude-code","cli:update:dep",detected -comments[1]{created_at,author,text}: +comments[3]{created_at,author,text}: "2026-08-09T13:48:46.953Z","harness:claude-code","Reproduction, exact and cheap, recorded 2026-08-09 at commit 9a0a048b6. Filed only; not fixed in this pass.\n\nFailing run, with the harness variable present as an agent would have it:\n\n node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts\n\nfails one of sixteen, at agent-runtime-primitives.spec.ts:741, on attributes update and close mutations to the detected harness. Both compared history entries carry an unexpected context.agent_provenance_outcomes.version block reading status failed, reason resolver_failed, resolver ai_agent_version, rule_version v1.\n\nPassing run, identical in every other respect:\n\n env -u AI_AGENT node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts\n\npasses sixteen of sixteen. One variable is the entire difference, and it is a variable the fixture never sets and never refers to.\n\nThe host value on this machine is claude-code_2-1-226_agent. It matters that this string is not malformed: the resolver's regex requires the version at the end of the string, and this value ends in the literal text agent, so a perfectly ordinary harness value fails to parse. An agent whose AI_AGENT happened to end in a version would produce a third outcome again, which is why the acceptance criteria ask for all three forms to be exercised rather than only the unset case.\n\nChain of custody through the source, so the fix has three separable candidate sites rather than one guess. src/core/shared/author.ts:219 declares the codex descriptor's version resolver as ai_agent_version. src/core/shared/author.ts:569 implements that resolver by reading env.AI_AGENT, a name several harnesses write, with no check that the value belongs to the harness that matched. src/core/shared/author.ts:897 classifies the outcome, and decides between failed and unavailable by asking only whether env.AI_AGENT is non-blank; presence of any value is taken as evidence that the resolver had legitimate input, which is what converts an honest unavailable into a misleading failed.\n\nConfirmation that this is not a flake and not caused by the change shipped alongside it. The failure appeared first inside a full coverage run and then reproduced identically in isolation, and it reproduces on every invocation with the variable set. Two other specs failed in that same coverage run, governance-read-performance and surface-replication-gate, and both pass cleanly when re-run without concurrent load; those two are wall-clock sensitive and are not this. Continuous integration is green at this commit, which is consistent with hosted runners setting no AI_AGENT.\n\nScope note on what this does and does not touch. The two history entries are otherwise correct: author is harness:codex, author_source is detected, and the patch contents are as expected. The leak affects the provenance outcome block only. That is what makes it a containment question rather than a correctness question about detection, and it is why the item is parented on continuous integration rather than on the identity lineage, while still citing that lineage.\n" + "2026-08-09T15:26:24.456Z","harness:codex","Implementation evidence: sandbox isolation now clears only the ambiguous shared AI_AGENT signal; explicit CODEX/Claude session signals remain available for intentional CLI/MCP parity. The foreign AI_AGENT reproducer and mutation-envelope parity suite both pass." + "2026-08-09T15:57:29.521Z","harness:codex","Evidence: both linked test groups passed; final full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; pnpm lint and all static quality gates passed. The narrowed isolation behavior is documented in the item history and avoids masking dedicated resolver fixtures." files[3]{path,scope,note}: src/core/shared/author.ts,project,"Descriptor at 219, resolver at 569, outcome classifier at 897 - the three candidate fix sites" tests/helpers/withTempPmPath.ts,project,"Sandbox helper: isolates PM_PATH and telemetry, does not neutralize harness signal environment" tests/unit/sdk/agent-runtime-primitives.spec.ts,project,Failing expectation at 741; passes only when AI_AGENT is absent from the host -tests[1]{command,scope,timeout_seconds}: +tests[2]{command,scope,timeout_seconds}: + AI_AGENT=claude-code_2-1-226_agent node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts tests/unit/sdk/merge-receipts.spec.ts,project,180 env -u AI_AGENT node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts,project,300 +test_runs[1]{run_id,kind,status,started_at,finished_at,recorded_at,passed,failed,skipped}: + test-local-mslz2sl4-2piwzr,test,passed,"2026-08-09T15:43:22.911Z","2026-08-09T15:43:42.136Z","2026-08-09T15:43:42.136Z",2,0,0 +close_reason: Implemented foreign-harness provenance isolation without over-clearing explicit resolver inputs. body: "" diff --git a/.gitattributes b/.gitattributes index c47c6dcf2..49e539257 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,7 +11,7 @@ # files, so this introduces no renormalization churn. * text=auto eol=lf -# pm-cli:merge-drivers:start +# pm-cli:merge-drivers:v2:start ".agents/pm/**/*.toon" merge=pm-item-toon ".agents/pm/**/*.md" merge=pm-item-markdown ".agents/pm/chores/*.toon" merge=pm-item-toon @@ -44,4 +44,4 @@ ".agents/pm/**/*.json" merge=pm-json ".agents/pm/extensions/**" -merge ".agents/pm/extensions/.managed-extensions.json" merge=pm-json -# pm-cli:merge-drivers:end +# pm-cli:merge-drivers:v2:end diff --git a/CHANGELOG.md b/CHANGELOG.md index f20e729f8..ae6f5b87c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,16 @@ ## Unreleased +### Added + +- A declared provenance resolver that fails at runtime is recorded identically to a dimension the harness cannot supply, so a broken probe is invisible until someone reads the source ([pm-lu6sca](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/features/pm-lu6sca.toon)) + ### Fixed +- A sandboxed fixture records provenance from the host harness environment, so the suite is green on CI and deterministically red for any agent running it locally ([pm-xgah3a](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-xgah3a.toon)) +- The session-role dimension is wired to a boolean child-session flag, so every nested claude-code invocation records the role literally as "1" and fleet analytics will group real work under a meaningless label ([pm-eq9dlw](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-eq9dlw.toon)) +- GH-921/GH-922: merge-decision receipts are not durable in fresh-clone CI ([pm-1j5j21](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-1j5j21.toon)) +- GH-948: version-skewed pm invocations silently rewrite the tracked merge fence during unrelated commands ([pm-l56d0o](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-l56d0o.toon)) - A measurement ratchet bound stops enforcing the moment its owner reaches a terminal status, so every guarded population goes unbounded exactly when its fix ships ([pm-5z9plz](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-5z9plz.toon)) - The docs tree grows one file per shipped contract, so 39 of 51 documents are stubs and the SDK's story is split across twelve files ([pm-9hv1o7](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-9hv1o7.toon)) - The replication gate's input is a hand-written list of known replications, so it can regress what was found and never discover what was not ([pm-b84irw](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-b84irw.toon)) diff --git a/docs/MERGE_SAFETY.md b/docs/MERGE_SAFETY.md index 8133f498c..33b1e7553 100644 --- a/docs/MERGE_SAFETY.md +++ b/docs/MERGE_SAFETY.md @@ -65,11 +65,13 @@ When both sides change the same item scalar differently, the driver writes the s The driver result's `guidance` always points unresolved conflicts to `pm merge report`. When a clone-local receipt exists, guidance includes its privacy-safe receipt and item ids for exact correlation; discarded values remain confined to the local receipt and never appear in generic logs or tracker history. Tracked by [pm-fbrz7p](../.agents/pm/issues/pm-fbrz7p.toon). -For item conflicts, the driver also writes a clone-local receipt below the Git -directory. It contains retained and discarded values so recovery does not -depend on a reflog. Raw values never enter public tracker history: -reconciliation records field names and value hashes, while the explicit local -report is the only command that shows recoverable values: +For item conflicts, the driver writes a clone-local receipt below the Git +directory and a durable privacy-safe sidecar below `merge-receipts/` in the +tracker. The local receipt contains retained and discarded values so recovery +does not depend on a reflog. The tracked sidecar contains only field names and +value hashes, so fresh clones and CI can still fail closed on an unreviewed +decision without publishing either value. When both copies exist the SDK +deduplicates them and prefers the locally recoverable copy: ```bash pm merge report diff --git a/docs/SDK_AGENT_SESSION_CONTEXT.md b/docs/SDK_AGENT_SESSION_CONTEXT.md index ce8120066..1ee1dd1fc 100644 --- a/docs/SDK_AGENT_SESSION_CONTEXT.md +++ b/docs/SDK_AGENT_SESSION_CONTEXT.md @@ -95,14 +95,15 @@ host declarations retain precedence over this inference. `diagnoseAgentIdentity()` is the additive diagnostic companion to `detectAgentIdentity()`. It returns the same privacy-safe identity plus a `provenance_outcomes` row for every built-in dimension. Each row is -`resolved`, `unavailable`, or `failed`, carries rule version `v1`, and may name +`resolved`, `unavailable`, `not_configured`, or `failed`, carries rule version `v1`, and may name the bounded built-in resolver. It never contains environment values, session paths, prompts, or file contents. New mutation history records failed resolver outcomes under `context.agent_provenance_outcomes`; ordinary unavailable dimensions retain the compact legacy-compatible null projection. A resolver is only counted as -attempted when its required input exists. Consequently `pm health` can report +attempted when its required input belongs to the detected harness; a foreign +host's shared `AI_AGENT` value is not Codex input. Consequently `pm health` can report `provenance_resolver_zero_success::::` without confusing an unavailable harness signal with a failed resolver. The warning is advisory and the storage check includes the bounded attempt and diff --git a/docs/SDK_CONTEXT_INTEGRITY.md b/docs/SDK_CONTEXT_INTEGRITY.md index cb53fa1d3..493622afe 100644 --- a/docs/SDK_CONTEXT_INTEGRITY.md +++ b/docs/SDK_CONTEXT_INTEGRITY.md @@ -72,7 +72,9 @@ The storage check also reads at most 10,000 local immutable events for bounded agent-provenance resolver outcomes. This scan performs no network or provider I/O, tolerates malformed streams already owned by integrity diagnostics, and reports an advisory warning only when a resolver was actually attempted but -never succeeded. +never succeeded. The same bounded pass classifies bare boolean and single-digit +values across every recorded provenance dimension, publishes only aggregate +harness/dimension/kind counts, and never echoes the historical value. ## Replication and refusal gate diff --git a/sdk/public-surface.json b/sdk/public-surface.json index 175ac2ec8..2c73e84fb 100644 --- a/sdk/public-surface.json +++ b/sdk/public-surface.json @@ -1,6 +1,6 @@ { "aggregate_completeness": { - "covered_symbols": 1480, + "covered_symbols": 1483, "excluded": [ { "name": "_testOnlyCliContracts", @@ -8,7 +8,7 @@ } ], "missing": [], - "required_symbols": 1481 + "required_symbols": 1484 }, "breaking_acknowledgements": [ { @@ -154,6 +154,20 @@ ], "package_version": "2026.8.9", "reason": "Additive PmClient lightweight metadata method and optional actionable context diagnostics change structural signatures without removing or narrowing existing SDK members." + }, + { + "changes": [ + "signature ./sdk:AgentProvenanceOutcome", + "signature ./sdk:listMergeReceipts", + "signature ./sdk:MergeDecisionReceipt", + "signature ./sdk:ProvenanceResolverHealthScan", + "signature ./sdk/core:AgentProvenanceOutcome", + "signature ./sdk/governance:ProvenanceResolverHealthScan", + "signature ./sdk/merge:listMergeReceipts", + "signature ./sdk/merge:MergeDecisionReceipt" + ], + "package_version": "2026.8.9", + "reason": "Intentional additive context-integrity contract: explicit not_configured provenance state, durable receipt availability, and optional tracker-root discovery" } ], "entrypoints": { @@ -458,7 +472,7 @@ "classification": "supported", "kind": "interface", "name": "AgentProvenanceOutcome", - "signature": "export interface AgentProvenanceOutcome { status: \"resolved\" | \"unavailable\" | \"failed\"; reason?: AgentProvenanceAbsenceReason; resolver?: AgentProvenanceResolver; rule_version: \"v1\"; }" + "signature": "export interface AgentProvenanceOutcome { status: \"resolved\" | \"unavailable\" | \"not_configured\" | \"failed\"; reason?: AgentProvenanceAbsenceReason; resolver?: AgentProvenanceResolver; rule_version: \"v1\"; }" }, { "classification": "supported", @@ -6110,7 +6124,7 @@ "classification": "supported", "kind": "function", "name": "listMergeReceipts", - "signature": "(cwd: string, options?: { includeReconciled?: boolean; includeLossless?: boolean; }) => Promise | calls: (cwd: string, options?: { includeReconciled?: boolean; includeLossless?: boolean; }) => Promise" + "signature": "(cwd: string, options?: { includeReconciled?: boolean; includeLossless?: boolean; pmRoot?: string; }) => Promise | calls: (cwd: string, options?: { includeReconciled?: boolean; includeLossless?: boolean; pmRoot?: string; }) => Promise" }, { "classification": "supported", @@ -6368,7 +6382,7 @@ "classification": "supported", "kind": "interface", "name": "MergeDecisionReceipt", - "signature": "export interface MergeDecisionReceipt { version: 1; id: string; item_path: string; item_id: string; preferred: MergePreferredSide; conflict_resolution: \"preferred_side\" | \"stable_value_order\"; fields_from_theirs: string[]; union_fields: string[]; decisions: ItemMergeConflictDecision[]; state: \"pending\" | \"reconciled\"; created_at: string; reconciled_at?: string; }" + "signature": "export interface MergeDecisionReceipt { version: 1; id: string; item_path: string; item_id: string; preferred: MergePreferredSide; conflict_resolution: \"preferred_side\" | \"stable_value_order\"; fields_from_theirs: string[]; union_fields: string[]; decisions: ItemMergeConflictDecision[]; state: \"pending\" | \"reconciled\"; created_at: string; reconciled_at?: string; value_availability?: \"clone_local\" | \"hash_only\"; }" }, { "classification": "supported", @@ -7648,6 +7662,18 @@ "name": "PM_GITATTRIBUTES_START", "signature": "\"# pm-cli:merge-drivers:start\"" }, + { + "classification": "supported", + "kind": "value", + "name": "PM_GITATTRIBUTES_V2_END", + "signature": "\"# pm-cli:merge-drivers:v2:end\"" + }, + { + "classification": "supported", + "kind": "value", + "name": "PM_GITATTRIBUTES_V2_START", + "signature": "\"# pm-cli:merge-drivers:v2:start\"" + }, { "classification": "advanced_export", "kind": "value", @@ -8804,7 +8830,13 @@ "classification": "supported", "kind": "interface", "name": "ProvenanceResolverHealthScan", - "signature": "export interface ProvenanceResolverHealthScan { outcomes: ProvenanceResolverHealthOutcome[]; warnings: string[]; events_read: number; truncated: boolean; }" + "signature": "export interface ProvenanceResolverHealthScan { outcomes: ProvenanceResolverHealthOutcome[]; invalid_values: ProvenanceValueHealthFinding[]; warnings: string[]; events_read: number; truncated: boolean; }" + }, + { + "classification": "supported", + "kind": "interface", + "name": "ProvenanceValueHealthFinding", + "signature": "export interface ProvenanceValueHealthFinding { harness: string; dimension: string; kind: \"boolean\" | \"single_digit\"; count: number; }" }, { "classification": "advanced_export", @@ -16748,7 +16780,7 @@ "classification": "supported", "kind": "interface", "name": "AgentProvenanceOutcome", - "signature": "export interface AgentProvenanceOutcome { status: \"resolved\" | \"unavailable\" | \"failed\"; reason?: AgentProvenanceAbsenceReason; resolver?: AgentProvenanceResolver; rule_version: \"v1\"; }" + "signature": "export interface AgentProvenanceOutcome { status: \"resolved\" | \"unavailable\" | \"not_configured\" | \"failed\"; reason?: AgentProvenanceAbsenceReason; resolver?: AgentProvenanceResolver; rule_version: \"v1\"; }" }, { "classification": "supported", @@ -17996,7 +18028,13 @@ "classification": "supported", "kind": "interface", "name": "ProvenanceResolverHealthScan", - "signature": "export interface ProvenanceResolverHealthScan { outcomes: ProvenanceResolverHealthOutcome[]; warnings: string[]; events_read: number; truncated: boolean; }" + "signature": "export interface ProvenanceResolverHealthScan { outcomes: ProvenanceResolverHealthOutcome[]; invalid_values: ProvenanceValueHealthFinding[]; warnings: string[]; events_read: number; truncated: boolean; }" + }, + { + "classification": "supported", + "kind": "interface", + "name": "ProvenanceValueHealthFinding", + "signature": "export interface ProvenanceValueHealthFinding { harness: string; dimension: string; kind: \"boolean\" | \"single_digit\"; count: number; }" }, { "classification": "supported", @@ -19610,7 +19648,7 @@ "classification": "supported", "kind": "function", "name": "listMergeReceipts", - "signature": "(cwd: string, options?: { includeReconciled?: boolean; includeLossless?: boolean; }) => Promise | calls: (cwd: string, options?: { includeReconciled?: boolean; includeLossless?: boolean; }) => Promise" + "signature": "(cwd: string, options?: { includeReconciled?: boolean; includeLossless?: boolean; pmRoot?: string; }) => Promise | calls: (cwd: string, options?: { includeReconciled?: boolean; includeLossless?: boolean; pmRoot?: string; }) => Promise" }, { "classification": "supported", @@ -19628,7 +19666,7 @@ "classification": "supported", "kind": "interface", "name": "MergeDecisionReceipt", - "signature": "export interface MergeDecisionReceipt { version: 1; id: string; item_path: string; item_id: string; preferred: MergePreferredSide; conflict_resolution: \"preferred_side\" | \"stable_value_order\"; fields_from_theirs: string[]; union_fields: string[]; decisions: ItemMergeConflictDecision[]; state: \"pending\" | \"reconciled\"; created_at: string; reconciled_at?: string; }" + "signature": "export interface MergeDecisionReceipt { version: 1; id: string; item_path: string; item_id: string; preferred: MergePreferredSide; conflict_resolution: \"preferred_side\" | \"stable_value_order\"; fields_from_theirs: string[]; union_fields: string[]; decisions: ItemMergeConflictDecision[]; state: \"pending\" | \"reconciled\"; created_at: string; reconciled_at?: string; value_availability?: \"clone_local\" | \"hash_only\"; }" }, { "classification": "supported", @@ -19750,6 +19788,18 @@ "name": "PM_GITATTRIBUTES_START", "signature": "\"# pm-cli:merge-drivers:start\"" }, + { + "classification": "supported", + "kind": "value", + "name": "PM_GITATTRIBUTES_V2_END", + "signature": "\"# pm-cli:merge-drivers:v2:end\"" + }, + { + "classification": "supported", + "kind": "value", + "name": "PM_GITATTRIBUTES_V2_START", + "signature": "\"# pm-cli:merge-drivers:v2:start\"" + }, { "classification": "supported", "kind": "function", diff --git a/src/core/shared/author.ts b/src/core/shared/author.ts index 3b6908909..34a0aa5fe 100644 --- a/src/core/shared/author.ts +++ b/src/core/shared/author.ts @@ -68,7 +68,7 @@ export type AgentProvenanceAbsenceReason = /** Machine-readable resolution outcome for one provenance dimension. */ export interface AgentProvenanceOutcome { /** Whether the dimension resolved without retaining private source material. */ - status: "resolved" | "unavailable" | "failed"; + status: "resolved" | "unavailable" | "not_configured" | "failed"; /** Stable bounded reason for absent or rejected values. */ reason?: AgentProvenanceAbsenceReason; /** Resolver name when a bounded local resolver was attempted. */ @@ -477,7 +477,10 @@ function normalizeProvenanceValue( value: string | undefined, ): string | undefined { if (dimension !== "role" || value === undefined) return value; - const normalized = value.trim().toLowerCase().replaceAll(/[_\s]+/gu, "-"); + const normalized = value + .trim() + .toLowerCase() + .replaceAll(/[_\s]+/gu, "-"); return AGENT_ROLE_VALUES.has(normalized) ? normalized : undefined; } @@ -568,7 +571,13 @@ function resolveProvenanceProbe( } if (resolver === "ai_agent_version") { const value = nonBlank(env.AI_AGENT); - if (!value) return undefined; + if ( + !value || + !descriptor || + !literalSignalMatches(value, descriptor.harness) + ) { + return undefined; + } const match = /(?:^|[@/\s])v?(\d+\.\d+(?:\.\d+)?(?:[-+][A-Za-z0-9.-]+)?)$/u.exec(value); return match?.[1]?.slice(0, 256); @@ -576,6 +585,20 @@ function resolveProvenanceProbe( return undefined; } +function provenanceResolverHasInput( + resolver: AgentProvenanceResolver, + descriptor: NormalizedHarnessSignalDescriptor, + env: Readonly>, +): boolean { + if (resolver === "ai_agent_version") { + const value = nonBlank(env.AI_AGENT); + return ( + value !== undefined && literalSignalMatches(value, descriptor.harness) + ); + } + return nonBlank(env.CLAUDE_CODE_SESSION_ID) !== undefined; +} + function effectiveHarnessDetectionSignals( signals: HarnessDetectionSignals | undefined, ): HarnessDetectionSignals { @@ -895,10 +918,11 @@ function resolveProvenanceOutcome( }; } if (resolver) { - const resolverHasInput = - resolver === "ai_agent_version" - ? nonBlank(env.AI_AGENT) !== undefined - : nonBlank(env.CLAUDE_CODE_SESSION_ID) !== undefined; + const resolverHasInput = provenanceResolverHasInput( + resolver, + descriptor, + env, + ); const status = resolverHasInput && probesEnabled ? "failed" : "unavailable"; const reason = !resolverHasInput ? "harness_unavailable" @@ -908,7 +932,9 @@ function resolveProvenanceOutcome( return { status, reason, resolver, rule_version: "v1" }; } return { - status: "unavailable", + status: descriptor?.provenance_unavailable_dimensions.includes(dimension) + ? "unavailable" + : "not_configured", reason: descriptor?.provenance_unavailable_dimensions.includes(dimension) ? "harness_unavailable" : "resolver_not_configured", @@ -944,10 +970,7 @@ export function diagnoseAgentIdentity( const invalidRoleValue = [ env.PM_AGENT_ROLE, sessionContext.provenance?.role, - firstEnvironmentValue( - env, - descriptor?.provenance_environment_keys.role, - ), + firstEnvironmentValue(env, descriptor?.provenance_environment_keys.role), effectiveSignals.client_info?.provenance?.role, effectiveSignals.provenance?.role, provenanceFlagValue(effectiveSignals.argv ?? [], "role"), diff --git a/src/sdk/governance/health.ts b/src/sdk/governance/health.ts index f94aaa5f7..752808bfb 100644 --- a/src/sdk/governance/health.ts +++ b/src/sdk/governance/health.ts @@ -627,7 +627,10 @@ async function buildIntegrityCheck( const pendingMergeReceipts = gitWorkspaceRoot === null ? [] - : await listMergeReceipts(gitWorkspaceRoot, { includeLossless: true }); + : await listMergeReceipts(gitWorkspaceRoot, { + includeLossless: true, + pmRoot, + }); const { pendingDecisions: pendingMergeDecisions, lossless: losslessMergeReceipts, @@ -2610,6 +2613,12 @@ function buildStorageHealthCheck( attempts: number; successes: number; }>, + provenanceInvalidValues: Array<{ + harness: string; + dimension: string; + kind: "boolean" | "single_digit"; + count: number; + }>, ): HealthCheck { const unknownAuthorEventCount = resolveUnknownAuthorEventCount(authorAttribution); @@ -2649,6 +2658,9 @@ function buildStorageHealthCheck( ...(provenanceResolverOutcomes.length > 0 ? { provenance_resolver_outcomes: provenanceResolverOutcomes } : {}), + ...(provenanceInvalidValues.length > 0 + ? { provenance_invalid_values: provenanceInvalidValues } + : {}), ...(historySummary.max_entries !== null ? { compact_policy: { @@ -2891,6 +2903,7 @@ export async function runHealth( ); const provenanceResolverHealth = await scanProvenanceResolverHealth(pmRoot); const provenanceResolverOutcomes = provenanceResolverHealth.outcomes; + const provenanceInvalidValues = provenanceResolverHealth.invalid_values; const provenanceWarnings = provenanceResolverHealth.warnings; const locksCheck = await buildLocksCheck(pmRoot); const integrityCheck = skipPolicy.skipIntegrity @@ -2931,6 +2944,7 @@ export async function runHealth( authorAttribution, staleInProgress.scan, provenanceResolverOutcomes, + provenanceInvalidValues, ), locksCheck.check, integrityCheck.check, diff --git a/src/sdk/governance/provenance-health.ts b/src/sdk/governance/provenance-health.ts index c303a812b..b6449d459 100644 --- a/src/sdk/governance/provenance-health.ts +++ b/src/sdk/governance/provenance-health.ts @@ -20,10 +20,24 @@ export interface ProvenanceResolverHealthOutcome { successes: number; } +/** Aggregate for legacy provenance values that violate the bounded domain. */ +export interface ProvenanceValueHealthFinding { + /** Detected harness namespace. */ + harness: string; + /** Provenance dimension containing the invalid value. */ + dimension: string; + /** Privacy-safe invalid-value class. */ + kind: "boolean" | "single_digit"; + /** Events containing this invalid value class. */ + count: number; +} + /** Bounded provenance health result suitable for `pm health` adapters. */ export interface ProvenanceResolverHealthScan { /** Stable resolver outcome aggregates. */ outcomes: ProvenanceResolverHealthOutcome[]; + /** Aggregated invalid legacy values without retaining the values themselves. */ + invalid_values: ProvenanceValueHealthFinding[]; /** Advisory warnings for attempted resolvers with no success. */ warnings: string[]; /** Number of nonblank history events inspected. */ @@ -33,6 +47,27 @@ export interface ProvenanceResolverHealthScan { } const DEFAULT_PROVENANCE_HISTORY_BYTE_LIMIT = 8_388_608; +const ATTEMPTED_PROVENANCE_OUTCOME_STATUSES = new Set(["resolved", "failed"]); +const INVALID_PROVENANCE_VALUE_CLASSIFIERS: ReadonlyArray<{ + kind: ProvenanceValueHealthFinding["kind"]; + matches: (value: unknown) => boolean; +}> = [ + { + kind: "boolean", + matches: (value) => + typeof value === "boolean" || + (typeof value === "string" && /^(?:true|false)$/iu.test(value.trim())), + }, + { + kind: "single_digit", + matches: (value) => + (typeof value === "number" && + Number.isInteger(value) && + value >= 0 && + value <= 9) || + (typeof value === "string" && /^\d$/u.test(value.trim())), + }, +]; function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); @@ -95,20 +130,43 @@ function parseHistoryEntry(line: string): Record | null { function collectResolverOutcomes( entry: Record, aggregates: Map, + invalidValues: Map, ): void { + const harness = + typeof entry.agent_harness === "string" ? entry.agent_harness : undefined; + if (harness === undefined) return; + const provenance = isRecord(entry.agent_provenance) + ? entry.agent_provenance + : {}; + Object.entries(provenance).forEach(([dimension, observation]) => { + if (!isRecord(observation)) return; + const kind = INVALID_PROVENANCE_VALUE_CLASSIFIERS.find((classifier) => + classifier.matches(observation.value), + )?.kind; + if (!kind) return; + const key = `${harness}\0${dimension}\0${kind}`; + const aggregate = invalidValues.get(key) ?? { + harness, + dimension, + kind, + count: 0, + }; + aggregate.count += 1; + invalidValues.set(key, aggregate); + }); if (!isRecord(entry.context)) return; const outcomes = entry.context.agent_provenance_outcomes; - if (!isRecord(outcomes) || typeof entry.agent_harness !== "string") return; - for (const [dimension, rawOutcome] of Object.entries(outcomes)) { + if (!isRecord(outcomes)) return; + Object.entries(outcomes).forEach(([dimension, rawOutcome]) => { if (!isRecord(rawOutcome) || typeof rawOutcome.resolver !== "string") { - continue; + return; } - if (rawOutcome.status !== "resolved" && rawOutcome.status !== "failed") { - continue; + if (!ATTEMPTED_PROVENANCE_OUTCOME_STATUSES.has(String(rawOutcome.status))) { + return; } - const key = `${entry.agent_harness}\0${dimension}\0${rawOutcome.resolver}`; + const key = `${harness}\0${dimension}\0${rawOutcome.resolver}`; const aggregate = aggregates.get(key) ?? { - harness: entry.agent_harness, + harness, dimension, resolver: rawOutcome.resolver, attempts: 0, @@ -117,12 +175,13 @@ function collectResolverOutcomes( aggregate.attempts += 1; if (rawOutcome.status === "resolved") aggregate.successes += 1; aggregates.set(key, aggregate); - } + }); } function collectHistoryContent( content: string, aggregates: Map, + invalidValues: Map, eventLimit: number, initialEventsRead: number, ): { eventsRead: number; truncated: boolean } { @@ -132,7 +191,7 @@ function collectHistoryContent( if (eventsRead >= eventLimit) return { eventsRead, truncated: true }; eventsRead += 1; const entry = parseHistoryEntry(line); - if (entry) collectResolverOutcomes(entry, aggregates); + if (entry) collectResolverOutcomes(entry, aggregates, invalidValues); } return { eventsRead, truncated: false }; } @@ -143,6 +202,7 @@ export async function scanProvenanceResolverHealth( eventLimit = 10_000, ): Promise { const aggregates = new Map(); + const invalidValues = new Map(); let eventsRead = 0; let bytesRead = 0; let truncated = false; @@ -157,6 +217,7 @@ export async function scanProvenanceResolverHealth( const collected = collectHistoryContent( history.content, aggregates, + invalidValues, eventLimit, eventsRead, ); @@ -176,16 +237,31 @@ export async function scanProvenanceResolverHealth( left.dimension.localeCompare(right.dimension) || left.resolver.localeCompare(right.resolver), ); + const invalidValueFindings = [...invalidValues.values()].sort( + (left, right) => + left.harness.localeCompare(right.harness) || + left.dimension.localeCompare(right.dimension) || + left.kind.localeCompare(right.kind), + ); return { outcomes, + invalid_values: invalidValueFindings, warnings: truncated ? [] - : outcomes - .filter((outcome) => outcome.attempts > 0 && outcome.successes === 0) - .map( - (outcome) => - `provenance_resolver_zero_success:${outcome.harness}:${outcome.dimension}:${outcome.resolver}:${String(outcome.attempts)}`, + : [ + ...outcomes + .filter( + (outcome) => outcome.attempts > 0 && outcome.successes === 0, + ) + .map( + (outcome) => + `provenance_resolver_zero_success:${outcome.harness}:${outcome.dimension}:${outcome.resolver}:${String(outcome.attempts)}`, + ), + ...invalidValueFindings.map( + (finding) => + `provenance_value_domain_invalid:${finding.harness}:${finding.dimension}:${finding.kind}:${String(finding.count)}`, ), + ], events_read: eventsRead, truncated, }; diff --git a/src/sdk/governance/validate.ts b/src/sdk/governance/validate.ts index 36feffb48..2146bf5a8 100644 --- a/src/sdk/governance/validate.ts +++ b/src/sdk/governance/validate.ts @@ -3318,7 +3318,10 @@ async function buildStorageIntegrityCheck( const pendingMergeReceipts = gitWorkspaceRoot === null ? [] - : await listMergeReceipts(gitWorkspaceRoot, { includeLossless: true }); + : await listMergeReceipts(gitWorkspaceRoot, { + includeLossless: true, + pmRoot, + }); const { pendingDecisions: pendingMergeDecisions, lossless: losslessMergeReceipts, diff --git a/src/sdk/merge/index.ts b/src/sdk/merge/index.ts index 5ed9760b3..5ae3b49c2 100644 --- a/src/sdk/merge/index.ts +++ b/src/sdk/merge/index.ts @@ -44,6 +44,8 @@ export { findGitWorkspaceRoot, PM_GITATTRIBUTES_END, PM_GITATTRIBUTES_START, + PM_GITATTRIBUTES_V2_END, + PM_GITATTRIBUTES_V2_START, refreshMergeAttributeFenceIfInstalled, resolveMergeInstallContext, runMergeInstall, diff --git a/src/sdk/merge/install.ts b/src/sdk/merge/install.ts index 537fc3927..6bb79f0b1 100644 --- a/src/sdk/merge/install.ts +++ b/src/sdk/merge/install.ts @@ -34,6 +34,10 @@ const execFileAsync = promisify(execFile); export const PM_GITATTRIBUTES_START = "# pm-cli:merge-drivers:start"; /** Closing marker for the pm-owned merge-driver `.gitattributes` block. */ export const PM_GITATTRIBUTES_END = "# pm-cli:merge-drivers:end"; +/** Opening marker for the versioned fence that older releases leave untouched. */ +export const PM_GITATTRIBUTES_V2_START = "# pm-cli:merge-drivers:v2:start"; +/** Closing marker for the versioned fence that older releases leave untouched. */ +export const PM_GITATTRIBUTES_V2_END = "# pm-cli:merge-drivers:v2:end"; const MERGE_FENCE_LOCK_ID = "merge-fence"; @@ -360,6 +364,18 @@ export function buildMergeAttributePatterns( return patterns; } +function removeManagedBlock( + content: string, + startMarker: string, + endMarker: string, +): string { + const start = content.indexOf(startMarker); + const end = content.indexOf(endMarker); + return start >= 0 && end > start + ? `${content.slice(0, start)}${content.slice(end + endMarker.length)}` + : content.replace(startMarker, "").replace(endMarker, ""); +} + async function reconcileGitattributesBlock( workspaceRoot: string, patterns: string[], @@ -377,18 +393,19 @@ async function reconcileGitattributesBlock( } } const block = [ - PM_GITATTRIBUTES_START, + PM_GITATTRIBUTES_V2_START, ...patterns, - PM_GITATTRIBUTES_END, + PM_GITATTRIBUTES_V2_END, ].join("\n"); - const start = current.indexOf(PM_GITATTRIBUTES_START); - const end = current.indexOf(PM_GITATTRIBUTES_END); - const withoutManagedBlock = - start >= 0 && end > start - ? `${current.slice(0, start)}${current.slice(end + PM_GITATTRIBUTES_END.length)}` - : current - .replace(PM_GITATTRIBUTES_START, "") - .replace(PM_GITATTRIBUTES_END, ""); + const withoutManagedBlock = removeManagedBlock( + removeManagedBlock( + current, + PM_GITATTRIBUTES_V2_START, + PM_GITATTRIBUTES_V2_END, + ), + PM_GITATTRIBUTES_START, + PM_GITATTRIBUTES_END, + ); const prefix = withoutManagedBlock.trimEnd(); const next = `${prefix.length > 0 ? `${prefix}\n\n` : ""}${block}\n`; if (next === current) { @@ -444,7 +461,10 @@ export async function auditMergeAttributeFence( const candidate = path.join(directory, ".gitattributes"); try { const raw = await readFile(candidate, "utf8"); - if (raw.includes(PM_GITATTRIBUTES_START)) { + if ( + raw.includes(PM_GITATTRIBUTES_V2_START) || + raw.includes(PM_GITATTRIBUTES_START) + ) { fenceDirectory = directory; fenceContent = raw; break; @@ -467,12 +487,17 @@ export async function auditMergeAttributeFence( }; } const fencePath = path.join(fenceDirectory, ".gitattributes"); - const start = fenceContent.indexOf(PM_GITATTRIBUTES_START); - const end = fenceContent.indexOf(PM_GITATTRIBUTES_END); + const usesV2 = fenceContent.includes(PM_GITATTRIBUTES_V2_START); + const startMarker = usesV2 + ? PM_GITATTRIBUTES_V2_START + : PM_GITATTRIBUTES_START; + const endMarker = usesV2 ? PM_GITATTRIBUTES_V2_END : PM_GITATTRIBUTES_END; + const start = fenceContent.indexOf(startMarker); + const end = fenceContent.indexOf(endMarker); const committed = end > start ? fenceContent - .slice(start + PM_GITATTRIBUTES_START.length, end) + .slice(start + startMarker.length, end) .split("\n") .map((line) => line.trim()) .filter((line) => line.length > 0) @@ -596,7 +621,10 @@ export async function refreshMergeAttributeFenceIfInstalled( } throw error; } - if (!current.includes(PM_GITATTRIBUTES_START)) { + if ( + !current.includes(PM_GITATTRIBUTES_V2_START) && + !current.includes(PM_GITATTRIBUTES_START) + ) { return { status: "not_installed", path: gitattributesPath }; } // Re-read after acquiring the dedicated fence lock so every concurrent diff --git a/src/sdk/merge/receipts.ts b/src/sdk/merge/receipts.ts index caa4746b2..b85f0accd 100644 --- a/src/sdk/merge/receipts.ts +++ b/src/sdk/merge/receipts.ts @@ -51,6 +51,8 @@ export interface MergeDecisionReceipt { created_at: string; /** Reconciliation timestamp, when consumed. */ reconciled_at?: string; + /** Whether decision values are recoverable locally or represented by hashes only. */ + value_availability?: "clone_local" | "hash_only"; } /** Privacy-safe receipt summary suitable for committed history context. */ @@ -109,6 +111,25 @@ async function resolveReceiptDirectory(cwd: string): Promise { } } +async function resolveTrackerRootFromItemPath( + cwd: string, + itemPath: string, +): Promise { + let directory = path.dirname(path.resolve(cwd, itemPath)); + for (let depth = 0; depth < 12; depth += 1) { + if (await pathExists(path.join(directory, "settings.json"))) + return directory; + const parent = path.dirname(directory); + if (parent === directory) break; + directory = parent; + } + return null; +} + +function durableReceiptDirectory(pmRoot: string): string { + return path.join(pmRoot, "merge-receipts"); +} + function receiptFileName(id: string): string { return `${id}.json`; } @@ -128,12 +149,31 @@ export function summarizeMergeReceipt( conflict_resolution: receipt.conflict_resolution, decisions: receipt.decisions.map((decision) => ({ field: decision.field, - retained_hash: sha256Hex(stableStringify(decision.retained)), - discarded_hash: sha256Hex(stableStringify(decision.discarded)), + retained_hash: + isPrehashedValue(decision.retained) ?? + sha256Hex(stableStringify(decision.retained)), + discarded_hash: + isPrehashedValue(decision.discarded) ?? + sha256Hex(stableStringify(decision.discarded)), })), }; } +function isPrehashedValue(value: unknown): string | undefined { + if ( + typeof value !== "object" || + value === null || + Array.isArray(value) || + !("pm_value_hash" in value) + ) { + return undefined; + } + const hash = value.pm_value_hash; + return typeof hash === "string" && /^[a-f0-9]{64}$/u.test(hash) + ? hash + : undefined; +} + /** Persist one item-driver outcome in the clone-local Git directory. */ export async function writeMergeReceipt(params: { cwd: string; @@ -168,35 +208,55 @@ export async function writeMergeReceipt(params: { decisions: structuredClone(params.decisions), state: "pending", created_at: nowIso(), + value_availability: "clone_local", }; await ensureDir(directory); await writeFileAtomic( path.join(directory, receiptFileName(receipt.id)), `${JSON.stringify(receipt, null, 2)}\n`, ); + const trackerRoot = await resolveTrackerRootFromItemPath( + params.cwd, + receipt.item_path, + ); + if (trackerRoot !== null) { + const durableDirectory = durableReceiptDirectory(trackerRoot); + const summary = summarizeMergeReceipt(receipt); + const durableReceipt: MergeDecisionReceipt = { + ...receipt, + decisions: summary.decisions.map((decision) => ({ + field: decision.field, + base: null, + ours: null, + theirs: null, + retained: { pm_value_hash: decision.retained_hash }, + discarded: { pm_value_hash: decision.discarded_hash }, + })), + value_availability: "hash_only", + }; + await ensureDir(durableDirectory); + await writeFileAtomic( + path.join(durableDirectory, receiptFileName(receipt.id)), + `${JSON.stringify(durableReceipt, null, 2)}\n`, + ); + } return receipt; } -/** Read clone-local receipts with explicit reconciled/lossless classification controls. */ -export async function listMergeReceipts( - cwd: string, - options: { includeReconciled?: boolean; includeLossless?: boolean } = {}, +async function readReceiptsFromDirectory( + directory: string, + options: { includeReconciled?: boolean; includeLossless?: boolean }, ): Promise { - const directory = await resolveReceiptDirectory(cwd); - if (directory === null || !(await pathExists(directory))) { - return []; - } - const receipts: MergeDecisionReceipt[] = []; + if (!(await pathExists(directory))) return []; let names: string[]; try { names = await readdir(directory); } catch { return []; } + const receipts: MergeDecisionReceipt[] = []; for (const name of names.sort((left, right) => left.localeCompare(right))) { - if (!name.endsWith(".json")) { - continue; - } + if (!name.endsWith(".json")) continue; try { const parsed = JSON.parse( await readFile(path.join(directory, name), "utf8"), @@ -209,17 +269,39 @@ export async function listMergeReceipts( normalizedReceipt.version === 1 && (options.includeReconciled || normalizedReceipt.state === "pending") && (options.includeLossless !== false || - (Array.isArray(normalizedReceipt.decisions) && - normalizedReceipt.decisions.length > 0)) + normalizedReceipt.decisions.length > 0) ) { receipts.push(normalizedReceipt); } } catch { - // A damaged clone-local receipt is reported by merge report through the - // omitted count once a future schema version adds richer diagnostics. + // Malformed evidence remains an integrity concern for a future schema. } } - return receipts.sort((left, right) => + return receipts; +} + +/** Read clone-local receipts with explicit reconciled/lossless classification controls. */ +export async function listMergeReceipts( + cwd: string, + options: { + includeReconciled?: boolean; + includeLossless?: boolean; + pmRoot?: string; + } = {}, +): Promise { + const directory = await resolveReceiptDirectory(cwd); + const local = + directory === null + ? [] + : await readReceiptsFromDirectory(directory, options); + const trackerRoot = options.pmRoot ?? path.join(cwd, ".agents", "pm"); + const durable = await readReceiptsFromDirectory( + durableReceiptDirectory(trackerRoot), + options, + ); + const receipts = new Map(durable.map((receipt) => [receipt.id, receipt])); + for (const receipt of local) receipts.set(receipt.id, receipt); + return [...receipts.values()].sort((left, right) => left.created_at.localeCompare(right.created_at), ); } @@ -259,6 +341,25 @@ export async function markMergeReceiptReconciled( 2, )}\n`, ); + const trackerRoot = await resolveTrackerRootFromItemPath( + cwd, + receipt.item_path, + ); + if (trackerRoot !== null) { + const durablePath = path.join( + durableReceiptDirectory(trackerRoot), + receiptFileName(receipt.id), + ); + if (await pathExists(durablePath)) { + const durable = JSON.parse( + await readFile(durablePath, "utf8"), + ) as MergeDecisionReceipt; + await writeFileAtomic( + durablePath, + `${JSON.stringify({ ...durable, state: "reconciled", reconciled_at: nowIso() }, null, 2)}\n`, + ); + } + } } /** Report pending or historical clone-local merge decisions. */ diff --git a/tests/helpers/withTempPmPath.ts b/tests/helpers/withTempPmPath.ts index 690dcfbf1..d22fb48b5 100644 --- a/tests/helpers/withTempPmPath.ts +++ b/tests/helpers/withTempPmPath.ts @@ -166,9 +166,11 @@ export const TEMP_PM_ENV_KEYS = [ "FORCE_COLOR", ] as const; +const TEMP_HARNESS_ENV_KEYS = ["AI_AGENT"] as const; + type TempPmEnvKey = (typeof TEMP_PM_ENV_KEYS)[number]; type TempPmEnv = NodeJS.ProcessEnv & Record; -type TempPmEnvSnapshot = Record; +type TempPmEnvSnapshot = Record; function shouldNormalizeLegacyCreateArgs( args: string[], @@ -385,7 +387,7 @@ async function removeTempRoot(tempRoot: string): Promise { } function buildTempPmEnv(tempRoot: string, pmPath: string): TempPmEnv { - return { + const env: TempPmEnv = { ...process.env, PM_PATH: pmPath, PM_GLOBAL_PATH: path.join(tempRoot, ".pm-cli-global"), @@ -396,18 +398,20 @@ function buildTempPmEnv(tempRoot: string, pmPath: string): TempPmEnv { PM_DISABLE_OLLAMA_AUTO_DEFAULTS: "1", FORCE_COLOR: "0", }; + for (const key of TEMP_HARNESS_ENV_KEYS) delete env[key]; + return env; } function snapshotTempPmEnv(): TempPmEnvSnapshot { const snapshot = {} as TempPmEnvSnapshot; - for (const key of TEMP_PM_ENV_KEYS) { + for (const key of [...TEMP_PM_ENV_KEYS, ...TEMP_HARNESS_ENV_KEYS]) { snapshot[key] = process.env[key]; } return snapshot; } export function applyTempPmEnv(env: NodeJS.ProcessEnv): void { - for (const key of TEMP_PM_ENV_KEYS) { + for (const key of [...TEMP_PM_ENV_KEYS, ...TEMP_HARNESS_ENV_KEYS]) { const value = env[key]; if (value === undefined) { delete process.env[key]; @@ -418,7 +422,7 @@ export function applyTempPmEnv(env: NodeJS.ProcessEnv): void { } function restoreTempPmEnv(snapshot: TempPmEnvSnapshot): void { - for (const key of TEMP_PM_ENV_KEYS) { + for (const key of [...TEMP_PM_ENV_KEYS, ...TEMP_HARNESS_ENV_KEYS]) { const value = snapshot[key]; if (value === undefined) { delete process.env[key]; diff --git a/tests/integration/merge-fence-version-skew.integration.spec.ts b/tests/integration/merge-fence-version-skew.integration.spec.ts new file mode 100644 index 000000000..1557978d6 --- /dev/null +++ b/tests/integration/merge-fence-version-skew.integration.spec.ts @@ -0,0 +1,44 @@ +import { execFileSync } from "node:child_process"; +import { readFile, writeFile } from "node:fs/promises"; +import path from "node:path"; +import { describe, expect, it } from "vitest"; +import { + installMergeFence, + PM_GITATTRIBUTES_END, + PM_GITATTRIBUTES_START, + PM_GITATTRIBUTES_V2_END, + PM_GITATTRIBUTES_V2_START, +} from "../../src/sdk/merge/install.js"; +import { withTempPmPath } from "../helpers/withTempPmPath.js"; + +describe("merge fence version-skew compatibility", () => { + it("migrates the legacy fence so older ordinary commands cannot rewrite it", async () => { + await withTempPmPath(async ({ pmPath, tempRoot }) => { + execFileSync("git", ["init", "-q"], { cwd: tempRoot }); + const attributesPath = path.join(tempRoot, ".gitattributes"); + await writeFile( + attributesPath, + `${PM_GITATTRIBUTES_START}\nlegacy-pattern merge=pm-json\n${PM_GITATTRIBUTES_END}\n`, + ); + await installMergeFence({ + pmRoot: pmPath, + workspaceRoot: tempRoot, + includeExtensions: false, + }); + const current = await readFile(attributesPath, "utf8"); + expect(current).toContain(PM_GITATTRIBUTES_V2_START); + expect(current).toContain(PM_GITATTRIBUTES_V2_END); + expect(current).not.toContain(PM_GITATTRIBUTES_START); + + // Releases through 2026.8.7 only recognize the legacy marker, so their + // automatic refresh path now leaves the versioned contract unchanged. + const legacyWouldRewrite = current.includes(PM_GITATTRIBUTES_START); + if (legacyWouldRewrite) await writeFile(attributesPath, "unexpected\n"); + expect(await readFile(attributesPath, "utf8")).toBe(current); + expect(current).toContain('".agents/pm/extensions/**" -merge'); + expect(current).toContain( + '".agents/pm/extensions/.managed-extensions.json" merge=pm-json', + ); + }); + }); +}); diff --git a/tests/integration/provenance-value-health.integration.spec.ts b/tests/integration/provenance-value-health.integration.spec.ts new file mode 100644 index 000000000..8c76b49f8 --- /dev/null +++ b/tests/integration/provenance-value-health.integration.spec.ts @@ -0,0 +1,42 @@ +import { mkdir, writeFile } from "node:fs/promises"; +import path from "node:path"; +import { describe, expect, it } from "vitest"; +import { runHealth } from "../../src/sdk/governance/health.js"; +import { withTempPmPath } from "../helpers/withTempPmPath.js"; + +describe("provenance value health projection", () => { + it("projects privacy-safe corpus conformance findings through health", async () => { + await withTempPmPath(async ({ pmPath }) => { + const history = path.join(pmPath, "history"); + await mkdir(history, { recursive: true }); + await writeFile( + path.join(history, "legacy-provenance.jsonl"), + `${JSON.stringify({ + agent_harness: "legacy-host", + agent_provenance: { + role: { source: "legacy", value: "true" }, + }, + })}\n`, + ); + const result = await runHealth( + { path: pmPath }, + { checkOnly: true, full: true }, + ); + expect(result.warnings).toContain( + "provenance_value_domain_invalid:legacy-host:role:boolean:1", + ); + expect( + result.checks.find((check) => check.name === "storage")?.details, + ).toMatchObject({ + provenance_invalid_values: [ + { + harness: "legacy-host", + dimension: "role", + kind: "boolean", + count: 1, + }, + ], + }); + }); + }); +}); diff --git a/tests/unit/commands/init-command.spec.ts b/tests/unit/commands/init-command.spec.ts index 8f68602b1..35d6634a8 100644 --- a/tests/unit/commands/init-command.spec.ts +++ b/tests/unit/commands/init-command.spec.ts @@ -38,8 +38,8 @@ import { readSettings } from "../../../src/core/store/settings.js"; import { renderPmCommand } from "../../../src/sdk/command-line.js"; import { buildMergeAttributePatterns, - PM_GITATTRIBUTES_END, - PM_GITATTRIBUTES_START, + PM_GITATTRIBUTES_V2_END, + PM_GITATTRIBUTES_V2_START, } from "../../../src/sdk/merge/install.js"; import { getPmGitignoreBlock } from "../../../src/sdk/workspace.js"; @@ -378,12 +378,12 @@ describe("runInit", () => { ]), }), }); - expect(await realpath(String(ancestorFailure.context?.requested_path))).toBe( - canonicalNestedRoot, - ); - expect(await realpath(String(ancestorFailure.context?.resolved_path))).toBe( - canonicalPmRoot, - ); + expect( + await realpath(String(ancestorFailure.context?.requested_path)), + ).toBe(canonicalNestedRoot); + expect( + await realpath(String(ancestorFailure.context?.resolved_path)), + ).toBe(canonicalPmRoot); expect(ancestorFailure.context?.suggested_path).toBe( path.join( String(ancestorFailure.context?.requested_path), @@ -2165,7 +2165,7 @@ describe("runInit", () => { ).toBe(await realpath(path.join(workspace, ".gitattributes"))); expect( await readFile(path.join(workspace, ".gitattributes"), "utf8"), - ).toContain("# pm-cli:merge-drivers:start"); + ).toContain(PM_GITATTRIBUTES_V2_START); const historyDriver = execFileSync( "git", ["config", "--local", "--get", "merge.pm-history.driver"], @@ -2205,14 +2205,14 @@ describe("runInit", () => { await writeFile( path.join(preFencedWorkspace, ".gitattributes"), `${[ - PM_GITATTRIBUTES_START, + PM_GITATTRIBUTES_V2_START, ...buildMergeAttributePatterns( ".agents/pm", [...new Set(Object.values(TYPE_TO_FOLDER))].sort((left, right) => left.localeCompare(right), ), ), - PM_GITATTRIBUTES_END, + PM_GITATTRIBUTES_V2_END, ].join("\n")}\n`, "utf8", ); diff --git a/tests/unit/sdk/agent-runtime-primitives.spec.ts b/tests/unit/sdk/agent-runtime-primitives.spec.ts index 0bc26ff39..d4d1ea871 100644 --- a/tests/unit/sdk/agent-runtime-primitives.spec.ts +++ b/tests/unit/sdk/agent-runtime-primitives.spec.ts @@ -307,6 +307,19 @@ describe("agent runtime SDK primitives", () => { env: { CODEX_HOME: "/tmp/codex", AI_AGENT: "codex-development" }, }).provenance, ).not.toHaveProperty("version"); + expect( + diagnoseAgentIdentity({ + env: { + CODEX_HOME: "/tmp/codex", + AI_AGENT: "claude-code_2-1-226_agent", + }, + }).provenance_outcomes.version, + ).toEqual({ + status: "unavailable", + reason: "harness_unavailable", + resolver: "ai_agent_version", + rule_version: "v1", + }); }); it("uses ambient signals by default and records extensible effort and role provenance", async () => { @@ -417,6 +430,13 @@ describe("agent runtime SDK primitives", () => { resolver: "claude_session_file", rule_version: "v1", }); + expect( + diagnoseAgentIdentity({ env: {} }).provenance_outcomes.model, + ).toEqual({ + status: "not_configured", + reason: "resolver_not_configured", + rule_version: "v1", + }); }); it("records only attempted resolver failures in immutable history context", () => { diff --git a/tests/unit/sdk/health-vector-boundary.spec.ts b/tests/unit/sdk/health-vector-boundary.spec.ts index 66287ae52..857c2fbad 100644 --- a/tests/unit/sdk/health-vector-boundary.spec.ts +++ b/tests/unit/sdk/health-vector-boundary.spec.ts @@ -62,9 +62,7 @@ describe("health vector provider boundary", () => { { skipDrift: true }, ); expect(requests).toBe(0); - const storage = result.checks.find( - (check) => check.name === "storage", - ); + const storage = result.checks.find((check) => check.name === "storage"); expect(storage).toBeDefined(); expect(storage!.details).not.toHaveProperty( "provenance_resolver_outcomes", @@ -199,6 +197,9 @@ describe("health vector provider boundary", () => { path.join(context.pmPath, "history", "pm-provenance.jsonl"), `${JSON.stringify({ agent_harness: "claude-code", + agent_provenance: { + role: { source: "legacy", value: "true" }, + }, context: { agent_provenance_outcomes: { model: { @@ -226,10 +227,21 @@ describe("health vector provider boundary", () => { successes: 0, }, ], + provenance_invalid_values: [ + { + harness: "claude-code", + dimension: "role", + kind: "boolean", + count: 1, + }, + ], }); expect(result.warnings).toContain( "provenance_resolver_zero_success:claude-code:model:claude_session_file:1", ); + expect(result.warnings).toContain( + "provenance_value_domain_invalid:claude-code:role:boolean:1", + ); }); }); }); diff --git a/tests/unit/sdk/merge-receipts.spec.ts b/tests/unit/sdk/merge-receipts.spec.ts index 4d3395ad3..bb62189b0 100644 --- a/tests/unit/sdk/merge-receipts.spec.ts +++ b/tests/unit/sdk/merge-receipts.spec.ts @@ -109,6 +109,21 @@ describe("clone-local merge decision receipts", () => { ], }); expect(JSON.stringify(summary)).not.toContain('"discarded"'); + expect( + summarizeMergeReceipt({ + ...receipt!, + decisions: [ + { + field: "title", + base: null, + ours: null, + theirs: null, + retained: { pm_value_hash: "not-a-hash" }, + discarded: null, + }, + ], + }).decisions[0]?.retained_hash, + ).toMatch(/^[a-f0-9]{64}$/); await markMergeReceiptReconciled(workspace, receipt!); await markMergeReceiptReconciled(workspace, laterReceipt!); @@ -204,4 +219,74 @@ describe("clone-local merge decision receipts", () => { count: expect.any(Number), }); }); + + it("carries privacy-safe decision evidence into a fresh clone", async () => { + const workspace = await mkdtemp( + path.join(os.tmpdir(), "pm-receipts-source-"), + ); + const clone = await mkdtemp(path.join(os.tmpdir(), "pm-receipts-clone-")); + workspaces.push(workspace, clone); + execFileSync("git", ["init", "-q"], { cwd: workspace }); + execFileSync("git", ["config", "user.name", "PM Test"], { cwd: workspace }); + execFileSync("git", ["config", "user.email", "pm-test@example.invalid"], { + cwd: workspace, + }); + const pmRoot = path.join(workspace, ".agents", "pm"); + await mkdir(path.join(pmRoot, "tasks"), { recursive: true }); + await writeFile(path.join(pmRoot, "settings.json"), "{}\n"); + const receipt = await writeMergeReceipt({ + cwd: workspace, + itemPath: ".agents/pm/tasks/pm-durable.toon", + preferred: "ours", + fieldsFromTheirs: [], + unionFields: [], + decisions: [ + { + field: "title", + base: "base-private", + ours: "ours-private", + theirs: "theirs-private", + retained: "ours-private", + discarded: "theirs-private", + }, + ], + }); + execFileSync("git", ["add", ".agents/pm"], { cwd: workspace }); + execFileSync("git", ["commit", "-qm", "Track durable merge evidence"], { + cwd: workspace, + }); + await rm(clone, { recursive: true, force: true }); + execFileSync("git", ["clone", "-q", workspace, clone]); + + const clonedReceipts = await listMergeReceipts(clone, { + pmRoot: path.join(clone, ".agents", "pm"), + }); + expect(clonedReceipts).toHaveLength(1); + expect(clonedReceipts[0]).toMatchObject({ + id: receipt?.id, + state: "pending", + value_availability: "hash_only", + }); + const serialized = JSON.stringify(clonedReceipts[0]); + expect(serialized).not.toContain("private"); + expect(summarizeMergeReceipt(clonedReceipts[0]!)).toEqual( + summarizeMergeReceipt(receipt!), + ); + await markMergeReceiptReconciled(clone, clonedReceipts[0]!); + expect( + await listMergeReceipts(clone, { + pmRoot: path.join(clone, ".agents", "pm"), + }), + ).toEqual([]); + expect( + await listMergeReceipts(clone, { + includeReconciled: true, + pmRoot: path.join(clone, ".agents", "pm"), + }), + ).toMatchObject([{ state: "reconciled", value_availability: "hash_only" }]); + await markMergeReceiptReconciled(clone, { + ...clonedReceipts[0]!, + id: "durable-sidecar-missing", + }); + }); }); diff --git a/tests/unit/sdk/merge-safety.spec.ts b/tests/unit/sdk/merge-safety.spec.ts index ec2407b19..ac02e4ec0 100644 --- a/tests/unit/sdk/merge-safety.spec.ts +++ b/tests/unit/sdk/merge-safety.spec.ts @@ -34,6 +34,8 @@ import { resolveMergeInstallContext, runMergeDriver, runMergeInstall, + PM_GITATTRIBUTES_V2_END, + PM_GITATTRIBUTES_V2_START, } from "../../../src/sdk/index.js"; import type { ItemDocument } from "../../../src/types/index.js"; import { withTempPmPath } from "../../helpers/withTempPmPath.js"; @@ -790,7 +792,7 @@ describe("public merge-safety SDK primitives", () => { await runMergeInstall({}, { path: context.pmPath }); expect( await readFile(path.join(context.tempRoot, ".gitattributes"), "utf8"), - ).toContain("# pm-cli:merge-drivers:start"); + ).toContain(PM_GITATTRIBUTES_V2_START); expect( (await runMergeInstall({}, { path: context.pmPath })).gitattributes .changed, @@ -806,7 +808,7 @@ describe("public merge-safety SDK primitives", () => { "utf8", ); expect( - repairedAttributes.match(/# pm-cli:merge-drivers:start/g), + repairedAttributes.match(/# pm-cli:merge-drivers:v2:start/g), ).toHaveLength(1); expect(repairedAttributes).toContain("*.bin binary"); @@ -1300,7 +1302,7 @@ describe("public merge-safety SDK primitives", () => { ); await writeFile( installedAttributesPath, - installedAttributes.replace("# pm-cli:merge-drivers:end", ""), + installedAttributes.replace(PM_GITATTRIBUTES_V2_END, ""), "utf8", ); const truncatedAudit = await auditMergeAttributeFence(context.pmPath, [ @@ -1327,8 +1329,8 @@ describe("public merge-safety SDK primitives", () => { await writeFile( attributesPath, current.replace( - "# pm-cli:merge-drivers:start", - '# pm-cli:merge-drivers:start\n".agents/pm/ghosts/*.toon" merge=pm-item-toon', + PM_GITATTRIBUTES_V2_START, + `${PM_GITATTRIBUTES_V2_START}\n".agents/pm/ghosts/*.toon" merge=pm-item-toon`, ), "utf8", ); @@ -1388,8 +1390,7 @@ describe("public merge-safety SDK primitives", () => { ); const previousSourcePmPath = process.env.PM_SOURCE_PM_PATH; const previousSourceWorkspaceRoot = process.env.PM_SOURCE_WORKSPACE_ROOT; - const previousSourceContextAccess = - process.env.PM_SOURCE_CONTEXT_ACCESS; + const previousSourceContextAccess = process.env.PM_SOURCE_CONTEXT_ACCESS; const previousSourceWriteOverride = process.env.PM_ALLOW_SOURCE_CONTEXT_WRITES; process.env.PM_SOURCE_PM_PATH = context.pmPath; diff --git a/tests/unit/sdk/provenance-health.spec.ts b/tests/unit/sdk/provenance-health.spec.ts index d78cbf1fe..ca71cf06f 100644 --- a/tests/unit/sdk/provenance-health.spec.ts +++ b/tests/unit/sdk/provenance-health.spec.ts @@ -20,6 +20,7 @@ describe("provenance resolver health", () => { tempRoots.push(root); await expect(scanProvenanceResolverHealth(root)).resolves.toEqual({ outcomes: [], + invalid_values: [], warnings: [], events_read: 0, truncated: false, @@ -36,9 +37,18 @@ describe("provenance resolver health", () => { "not-json", "null", JSON.stringify({ context: null }), - JSON.stringify({ context: { agent_provenance_outcomes: null } }), + JSON.stringify({ + agent_harness: "legacy-host", + context: { agent_provenance_outcomes: null }, + }), JSON.stringify({ agent_harness: "claude-code", + agent_provenance: { + effort: { source: "legacy", value: "1" }, + role: { source: "legacy", value: true }, + topic: { source: "legacy", value: "delivery" }, + version: { source: "legacy", value: 7 }, + }, context: { agent_provenance_outcomes: { ignored_null: null, @@ -56,6 +66,9 @@ describe("provenance resolver health", () => { }), JSON.stringify({ agent_harness: "claude-code", + agent_provenance: { + role: { source: "legacy", value: "1" }, + }, context: { agent_provenance_outcomes: { effort: { @@ -154,6 +167,36 @@ describe("provenance resolver health", () => { ], warnings: [ "provenance_resolver_zero_success:claude-code:version:claude_session_file:1", + "provenance_value_domain_invalid:claude-code:effort:single_digit:1", + "provenance_value_domain_invalid:claude-code:role:boolean:1", + "provenance_value_domain_invalid:claude-code:role:single_digit:1", + "provenance_value_domain_invalid:claude-code:version:single_digit:1", + ], + invalid_values: [ + { + harness: "claude-code", + dimension: "effort", + kind: "single_digit", + count: 1, + }, + { + harness: "claude-code", + dimension: "role", + kind: "boolean", + count: 1, + }, + { + harness: "claude-code", + dimension: "role", + kind: "single_digit", + count: 1, + }, + { + harness: "claude-code", + dimension: "version", + kind: "single_digit", + count: 1, + }, ], events_read: entries.length, truncated: false, @@ -202,20 +245,24 @@ describe("provenance resolver health", () => { `${failed}\n${"x".repeat(8_388_608)}`, "utf8", ); - await expect(scanProvenanceResolverHealth(root, 10)).resolves.toMatchObject({ - events_read: 1, - truncated: true, - warnings: [], - }); + await expect(scanProvenanceResolverHealth(root, 10)).resolves.toMatchObject( + { + events_read: 1, + truncated: true, + warnings: [], + }, + ); await writeFile( path.join(history, "one.jsonl"), "x".repeat(8_388_609), "utf8", ); - await expect(scanProvenanceResolverHealth(root, 10)).resolves.toMatchObject({ - events_read: 0, - truncated: true, - warnings: [], - }); + await expect(scanProvenanceResolverHealth(root, 10)).resolves.toMatchObject( + { + events_read: 0, + truncated: true, + warnings: [], + }, + ); }); }); From 77fb234d4db67ceb42ff14050bd9d88fd8032d4e Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Sun, 9 Aug 2026 18:01:18 +0200 Subject: [PATCH 2/3] docs(pm): record PR 952 delivery lineage --- .agents/pm/features/pm-lu6sca.toon | 5 +++-- .agents/pm/history/pm-1j5j21.jsonl | 1 + .agents/pm/history/pm-eq9dlw.jsonl | 1 + .agents/pm/history/pm-l56d0o.jsonl | 1 + .agents/pm/history/pm-lu6sca.jsonl | 1 + .agents/pm/history/pm-xgah3a.jsonl | 1 + .agents/pm/issues/pm-1j5j21.toon | 5 +++-- .agents/pm/issues/pm-eq9dlw.toon | 5 +++-- .agents/pm/issues/pm-l56d0o.toon | 5 +++-- .agents/pm/issues/pm-xgah3a.toon | 5 +++-- 10 files changed, 20 insertions(+), 10 deletions(-) diff --git a/.agents/pm/features/pm-lu6sca.toon b/.agents/pm/features/pm-lu6sca.toon index ba266ecea..8545071a9 100644 --- a/.agents/pm/features/pm-lu6sca.toon +++ b/.agents/pm/features/pm-lu6sca.toon @@ -6,7 +6,7 @@ status: closed priority: 2 tags[5]: "area:sdk",identity,instrument-integrity,observability,provenance created_at: "2026-08-03T06:22:12.243Z" -updated_at: "2026-08-09T15:57:26.460Z" +updated_at: "2026-08-09T16:01:17.030Z" closed_at: "2026-08-09T15:57:25.791Z" completed_at: "2026-08-09T15:57:25.791Z" author: "harness:claude-code" @@ -29,7 +29,7 @@ dependencies[7]{id,kind,created_at,author,source_kind,author_source}: pm-htbetn,related,"2026-08-03T06:23:55.524Z","harness:claude-code","cli:update:dep",detected pm-rtn5h6,related,"2026-08-03T06:23:55.524Z","harness:claude-code","cli:update:dep",detected pm-w7ccmv,implements,"2026-08-03T06:23:55.524Z","harness:claude-code","cli:update:dep",detected -comments[9]{created_at,author,text}: +comments[10]{created_at,author,text}: "2026-08-03T11:09:27.269Z","harness:codex","Estimate basis 2026-08-03: 360 minutes covers resolver outcome algebra, bounded reason codes, immutable recording, health projection, zero-success warning logic, and negative controls." "2026-08-08T22:13:20.575Z","harness:codex","Implementation start 2026-08-09: active in the coupled context-provenance tranche with pm-3zgh2c, pm-eq9dlw, pm-lu6sca, pm-b1w8vr, and pm-h75tjh. Scope is SDK-first provenance inference and resolver outcomes, typed role domains, stable entity read-back projections, and epoch-aware release classification; all other open items remain unclaimed." "2026-08-08T22:32:58.636Z","harness:codex","Design evidence: resolver attempts are counted only when the resolver input exists. Missing AI_AGENT or session identifiers are harness_unavailable; a supplied valid resolver input that yields no value is resolver_failed. pm health scans at most 10,000 immutable events, tolerates malformed streams owned by integrity diagnostics, and emits advisory zero-success warnings." @@ -39,6 +39,7 @@ comments[9]{created_at,author,text}: "2026-08-09T00:58:13.326Z","harness:codex","Review-loop evidence: provenance scanning now byte-bounds history before allocation, parses only complete lines, distinguishes exact event limits from truncation, suppresses zero-success warnings on incomplete samples, and records invalid explicit role values as invalid_value with argv precedence. Full sandboxed gate: 461 files, 7,089 tests, exact 100/100/100/100. Item remains open and unclaimed for its documented no-resolver-declared residual." "2026-08-09T01:24:46.237Z","harness:codex","PR #944 hosted evidence for the completed tranche portion: implementation commit b6678b8 passed all deterministic checks; CodeRabbit confirmed byte-bounded complete-event health semantics and invalid-value role outcomes. All 16 findings are addressed, replied to, and resolved. Item stays open and unclaimed for the documented no-resolver-declared residual." "2026-08-09T15:57:25.224Z","harness:codex","Evidence: focused agent-runtime and author-attribution tests passed after truthful overlapping-run failure receipts; the final uninterrupted full suite passed 7,100/7,100 with exact 100/100/100/100 coverage. SDK surface change was explicitly acknowledged and all static, lint, parity, token, and performance gates passed." + "2026-08-09T16:01:17.030Z","harness:codex","Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop." files[8]{path,scope,note}: sdk/public-surface.json,project,SDK outcome contract snapshot src/core/history/history.ts,project,Persist resolver outcome evidence diff --git a/.agents/pm/history/pm-1j5j21.jsonl b/.agents/pm/history/pm-1j5j21.jsonl index b65db4720..57c5f52a6 100644 --- a/.agents/pm/history/pm-1j5j21.jsonl +++ b/.agents/pm/history/pm-1j5j21.jsonl @@ -21,3 +21,4 @@ {"ts":"2026-08-09T15:57:24.312Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:24.312Z"}],"before_hash":"71c8badb8a9ba5b9116492f0d6e9603c4d3498746bb00531aba7b088364a8c18","after_hash":"aba42ba573361cc0e800b0840edc4be0a97738a452659fa8c714c4d66d84cd49"} {"ts":"2026-08-09T15:58:32.241Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/0/note","value":"Managed changelog entry for the coupled SDK integrity tranche"},{"op":"replace","path":"/metadata/docs/0/path","value":"CHANGELOG.md"},{"op":"add","path":"/metadata/docs/1","value":{"path":"docs/MERGE_SAFETY.md","scope":"project","note":"Durable receipt lifecycle"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:58:32.241Z"}],"before_hash":"aba42ba573361cc0e800b0840edc4be0a97738a452659fa8c714c4d66d84cd49","after_hash":"b48904b0fc4fd5d4af6fc828aa8e02fe4c996d434301940227f8c1dde8d9653b"} {"ts":"2026-08-09T15:58:32.674Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/1","value":{"command":"pnpm changelog:pm:check","scope":"project","timeout_seconds":240}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:58:32.674Z"}],"before_hash":"b48904b0fc4fd5d4af6fc828aa8e02fe4c996d434301940227f8c1dde8d9653b","after_hash":"a022e0b96fbdcf4176cc239b5eeaf76c95bef619fbd5442f473be6b4621df702"} +{"ts":"2026-08-09T16:01:16.227Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-08-09T16:01:16.227Z","author":"harness:codex","text":"Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:01:16.227Z"}],"before_hash":"a022e0b96fbdcf4176cc239b5eeaf76c95bef619fbd5442f473be6b4621df702","after_hash":"91d42c03be63da48c54b5e022ac896b55256251f6a9cf0e5682995064527e0cd"} diff --git a/.agents/pm/history/pm-eq9dlw.jsonl b/.agents/pm/history/pm-eq9dlw.jsonl index eda66e4ba..30937c763 100644 --- a/.agents/pm/history/pm-eq9dlw.jsonl +++ b/.agents/pm/history/pm-eq9dlw.jsonl @@ -29,3 +29,4 @@ {"ts":"2026-08-09T15:57:27.484Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/8","value":{"created_at":"2026-08-09T15:57:27.484Z","author":"harness:codex","text":"Evidence: all three linked tests passed; final full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; lint, duplicate, docstring, surface-replication, SDK parity, token/context, and performance gates passed. Live repository health/storage/history checks remain structurally clean."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:27.484Z"}],"before_hash":"0299f0d581226f14e2a27a087c5a7074d3849f2f32b5b90789da3611ea1d521c","after_hash":"57fd32da9b944175f4433ac2dd7043830df3249c9e9bbae45cb4c945e0b2b7f1"} {"ts":"2026-08-09T15:57:28.050Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:28.050Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:28.024Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:28.024Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented bounded privacy-safe corpus diagnostics for invalid historical provenance domains."}],"before_hash":"57fd32da9b944175f4433ac2dd7043830df3249c9e9bbae45cb4c945e0b2b7f1","after_hash":"41310bb8a3ef76dc059724bf2dd6a67c8d6332ddcee394137f20355498d43cc1"} {"ts":"2026-08-09T15:57:28.612Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:28.612Z"}],"before_hash":"41310bb8a3ef76dc059724bf2dd6a67c8d6332ddcee394137f20355498d43cc1","after_hash":"36101bcf5c5ac63c6384d89384feeca3884ac5c953bf4b7778bf0ef0329c7c5d"} +{"ts":"2026-08-09T16:01:17.488Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/9","value":{"created_at":"2026-08-09T16:01:17.487Z","author":"harness:codex","text":"Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:01:17.488Z"}],"before_hash":"36101bcf5c5ac63c6384d89384feeca3884ac5c953bf4b7778bf0ef0329c7c5d","after_hash":"92f602a34a1476ed98b1a32882a639e156db2abdee167f225a5dee56b93b9cf1"} diff --git a/.agents/pm/history/pm-l56d0o.jsonl b/.agents/pm/history/pm-l56d0o.jsonl index 77d5cf73b..a0feece62 100644 --- a/.agents/pm/history/pm-l56d0o.jsonl +++ b/.agents/pm/history/pm-l56d0o.jsonl @@ -9,3 +9,4 @@ {"ts":"2026-08-09T15:57:17.861Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-08-09T15:57:17.861Z","author":"harness:codex","text":"Evidence: focused linked tests passed; full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; pnpm lint and pnpm quality:static passed; pm merge reconcile --dry-run reported zero drift and a healthy v2 fence. Packed manual acceptance in an isolated temporary Git project completed init/create/comment/get/health/validate/storage/history successfully."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:17.861Z"}],"before_hash":"5e658b5a923fc1939c86c55403b66964e43c92a99fce16bf9fbc20fe27baa09c","after_hash":"34fc7183f841ad71a8d8638b5be009e395435ca7d9ca8158f7a10f191d5ab2d7"} {"ts":"2026-08-09T15:57:21.557Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:21.557Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:21.544Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:21.544Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented and verified a versioned, backward-safe merge-driver fence with regression and cross-version integration coverage."}],"before_hash":"34fc7183f841ad71a8d8638b5be009e395435ca7d9ca8158f7a10f191d5ab2d7","after_hash":"178cc9cbaa3b835e5dc5a19a7fc2c25cd9a4883ded82b8f3d83d6b440addeef4"} {"ts":"2026-08-09T15:57:22.119Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:22.119Z"}],"before_hash":"178cc9cbaa3b835e5dc5a19a7fc2c25cd9a4883ded82b8f3d83d6b440addeef4","after_hash":"0997fd0877755453ffa915ca08350f5809df14d3a9d9b7f905e79376b2cb13a0"} +{"ts":"2026-08-09T16:01:16.623Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-08-09T16:01:16.623Z","author":"harness:codex","text":"Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:01:16.623Z"}],"before_hash":"0997fd0877755453ffa915ca08350f5809df14d3a9d9b7f905e79376b2cb13a0","after_hash":"29d2a03df0dc688f7ab372cbce48d4d2ebebd2998438aadde958b69896de54d2"} diff --git a/.agents/pm/history/pm-lu6sca.jsonl b/.agents/pm/history/pm-lu6sca.jsonl index 8a832bed4..d052bde1c 100644 --- a/.agents/pm/history/pm-lu6sca.jsonl +++ b/.agents/pm/history/pm-lu6sca.jsonl @@ -37,3 +37,4 @@ {"ts":"2026-08-09T15:57:25.224Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/8","value":{"created_at":"2026-08-09T15:57:25.224Z","author":"harness:codex","text":"Evidence: focused agent-runtime and author-attribution tests passed after truthful overlapping-run failure receipts; the final uninterrupted full suite passed 7,100/7,100 with exact 100/100/100/100 coverage. SDK surface change was explicitly acknowledged and all static, lint, parity, token, and performance gates passed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:25.224Z"}],"before_hash":"703dedf6736ebb9cb90bbe27e1cc277280ddf61567758bc4290c9c5309bc4167","after_hash":"4d594a1ca57ad58d5a692efdfb5c4f3111d969eb68dc2433fe53505bef5937f2"} {"ts":"2026-08-09T15:57:25.825Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:25.825Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:25.791Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:25.791Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented and documented explicit configured-versus-attempted provenance outcome semantics across CLI and SDK."}],"before_hash":"4d594a1ca57ad58d5a692efdfb5c4f3111d969eb68dc2433fe53505bef5937f2","after_hash":"69e57d4f2fec9149269b407dbdd82b171b5af5ba637c67135640fc0ca6a9e078"} {"ts":"2026-08-09T15:57:26.460Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:26.460Z"}],"before_hash":"69e57d4f2fec9149269b407dbdd82b171b5af5ba637c67135640fc0ca6a9e078","after_hash":"d8ef0407ad6ba29221a310121d69590cff4e64de24e9dfd50c7849e75d7c1e2f"} +{"ts":"2026-08-09T16:01:17.030Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/9","value":{"created_at":"2026-08-09T16:01:17.030Z","author":"harness:codex","text":"Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:01:17.030Z"}],"before_hash":"d8ef0407ad6ba29221a310121d69590cff4e64de24e9dfd50c7849e75d7c1e2f","after_hash":"faccd536bbff39d9d7cc870f888f947f7e7cfe90b713743828aa2618084ba851"} diff --git a/.agents/pm/history/pm-xgah3a.jsonl b/.agents/pm/history/pm-xgah3a.jsonl index 90d7038b4..de47050f5 100644 --- a/.agents/pm/history/pm-xgah3a.jsonl +++ b/.agents/pm/history/pm-xgah3a.jsonl @@ -14,3 +14,4 @@ {"ts":"2026-08-09T15:57:29.521Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-08-09T15:57:29.521Z","author":"harness:codex","text":"Evidence: both linked test groups passed; final full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; pnpm lint and all static quality gates passed. The narrowed isolation behavior is documented in the item history and avoids masking dedicated resolver fixtures."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:29.521Z"}],"before_hash":"d7e171af929bf337a6c5eb010254e43bccb327b5e8e06ea1f4e1900b2a224cde","after_hash":"230aa6184d35f582b7c449280876ffc9506ece130eadc6ba13a30bd78b611324"} {"ts":"2026-08-09T15:57:30.113Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:30.113Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:30.059Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:30.059Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented foreign-harness provenance isolation without over-clearing explicit resolver inputs."}],"before_hash":"230aa6184d35f582b7c449280876ffc9506ece130eadc6ba13a30bd78b611324","after_hash":"e9ae2951712737a901d54d25c0a342e5276ae0bbcd0aa9f2638d3c5984d2c1ad"} {"ts":"2026-08-09T15:57:30.620Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:30.620Z"}],"before_hash":"e9ae2951712737a901d54d25c0a342e5276ae0bbcd0aa9f2638d3c5984d2c1ad","after_hash":"bd6830556c35494c380f6112130a29ac4177353f51068fa3f7dd1491a97fd740"} +{"ts":"2026-08-09T16:01:17.889Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-08-09T16:01:17.889Z","author":"harness:codex","text":"Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:01:17.889Z"}],"before_hash":"bd6830556c35494c380f6112130a29ac4177353f51068fa3f7dd1491a97fd740","after_hash":"5cd4a713e2cba1651f40041a8ea617728c1bda87f90e92c88c270d76e0d76525"} diff --git a/.agents/pm/issues/pm-1j5j21.toon b/.agents/pm/issues/pm-1j5j21.toon index 38af8308d..4be515a6b 100644 --- a/.agents/pm/issues/pm-1j5j21.toon +++ b/.agents/pm/issues/pm-1j5j21.toon @@ -6,7 +6,7 @@ status: closed priority: 1 tags: [] created_at: "2026-08-07T08:33:38.852Z" -updated_at: "2026-08-09T15:58:32.674Z" +updated_at: "2026-08-09T16:01:16.227Z" closed_at: "2026-08-09T15:57:23.719Z" completed_at: "2026-08-09T15:57:23.719Z" author: "harness:codex" @@ -26,10 +26,11 @@ dependencies[4]{id,kind,created_at,author,source_kind,author_source}: pm-ysqb6n,related,"2026-08-07T08:33:38.852Z","harness:codex","cli:create:dep",detected pm-g5sx,discovered_from,"2026-08-07T08:34:27.916Z","harness:codex","cli:update:dep",detected pm-ysqb6n,supersedes,"2026-08-07T08:34:27.916Z","harness:codex","cli:update:dep",detected -comments[3]{created_at,author,text}: +comments[4]{created_at,author,text}: "2026-08-07T08:33:38.852Z","harness:codex","GitHub sources: https://github.com/unbraind/pm-cli/issues/921 and https://github.com/unbraind/pm-cli/issues/922. Duplicate check searched all 2,351 items and every status for clone-local/gitignored merge receipts,fresh-clone CI,discarded values,history-repair,and both GH numbers. The reports share one root contract and are intentionally consolidated; closed pm-ysqb6n is predecessor evidence,not an active duplicate." "2026-08-08T15:39:02.830Z","harness:codex","Investigation boundary (2026-08-08): this PR deliberately does not claim fresh-clone durability. The implemented receipt work classifies lossless versus discarded-value decisions and requires explicit acceptance, but raw recovery receipts remain clone-local and ignored. A durable privacy-safe pushed evidence design needs a separate tracked-record contract and fresh-clone lifecycle, so retaining this item as open avoids falsely closing GH-921/GH-922." "2026-08-09T15:57:23.042Z","harness:codex","Evidence: linked receipt tests passed; full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; static, lint, SDK surface, performance, history-drift, storage-integrity, and dry-run reconciliation gates passed. Manual packed-consumer acceptance also passed in an isolated project." + "2026-08-09T16:01:16.227Z","harness:codex","Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop." files[5]{path,scope,note}: sdk/public-surface.json,project,SDK contract snapshot src/sdk/governance/health.ts,project,Durable receipt discovery diff --git a/.agents/pm/issues/pm-eq9dlw.toon b/.agents/pm/issues/pm-eq9dlw.toon index d7d73123a..c365165c2 100644 --- a/.agents/pm/issues/pm-eq9dlw.toon +++ b/.agents/pm/issues/pm-eq9dlw.toon @@ -6,7 +6,7 @@ status: closed priority: 2 tags[4]: "area:sdk",data-quality,identity,provenance created_at: "2026-08-03T06:21:42.773Z" -updated_at: "2026-08-09T15:57:28.612Z" +updated_at: "2026-08-09T16:01:17.488Z" closed_at: "2026-08-09T15:57:28.024Z" completed_at: "2026-08-09T15:57:28.024Z" author: "harness:claude-code" @@ -30,7 +30,7 @@ dependencies[7]{id,kind,created_at,author,source_kind,author_source}: pm-lu6sca,related,"2026-08-03T06:23:40.264Z","harness:claude-code","cli:update:dep",detected pm-pj2isb,related,"2026-08-03T06:23:40.264Z","harness:claude-code","cli:update:dep",detected pm-rbg1qo,discovered_from,"2026-08-03T06:23:40.264Z","harness:claude-code","cli:update:dep",detected -comments[9]{created_at,author,text}: +comments[10]{created_at,author,text}: "2026-08-03T11:09:27.894Z","harness:codex","Estimate basis 2026-08-03: 240 minutes covers value-domain declarations, invalid boolean rejection, a correctly named nested-session dimension, corpus check, and regression coverage." "2026-08-07T11:23:43.166Z","harness:claude-code","Confirmed still live at 2026.8.7 on 2026-08-07 with no identity flags passed. A create from Claude Code recorded author harness:claude-code with author_source detected, agent_model claude-opus-5 from probe, effort xhigh from environment, version 2.1.224 from probe — and role literally \"1\" from environment, with topic null. Model, effort and version capture are working end to end; role and topic remain the only two dimensions that do not carry meaning. Fleet analytics grouping on role today would bucket every nested session under the string \"1\"." "2026-08-08T08:10:41.851Z","harness:claude-code","Reproduced live on 2026-08-08 against pm-cli 2026.8.7, HEAD build. A create recorded this session carries agent_provenance role {value: \"1\", source: \"environment\"} alongside a correctly resolved model {claude-opus-5, probe}, effort {xhigh, environment} and version {2.1.226, probe}. So the dimension is not merely unpopulated: it is populated with the boolean child-session flag rendered as a string, which is worse than null because it types as a valid role and will group every nested claude-code invocation under one meaningless label in fleet analytics. Sibling dimension topic is null in the same record, which pm-3zgh2c owns. Evidence is the last history entry of pm-3lhth4." @@ -40,6 +40,7 @@ comments[9]{created_at,author,text}: "2026-08-09T00:20:22.518Z","harness:codex","Delivery handoff: broad SDK/CLI tranche committed at 5b36abc75 and opened as GitHub PR #944 (https://github.com/unbraind/pm-cli/pull/944). Exact local evidence includes 7,086 tests across 461 files at 100/100/100/100 coverage, package/compatibility/npx/dogfood/manual acceptance, tracker/changelog/SDK/static-quality gates, and zero current dependency or GitHub security alerts. Review and exact-head CI evidence will be appended after the hosted loop." "2026-08-09T01:24:45.768Z","harness:codex","PR #944 hosted evidence for the completed tranche portion: implementation commit b6678b8 passed all deterministic checks; all 16 CodeRabbit findings are addressed, replied to, and resolved. Item stays open and unclaimed for its broader remaining role-contract acceptance." "2026-08-09T15:57:27.484Z","harness:codex","Evidence: all three linked tests passed; final full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; lint, duplicate, docstring, surface-replication, SDK parity, token/context, and performance gates passed. Live repository health/storage/history checks remain structurally clean." + "2026-08-09T16:01:17.487Z","harness:codex","Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop." files[6]{path,scope,note}: src/core/shared/author.ts,project,Remove boolean child-session flag from semantic role sources and enforce controlled roles src/sdk/governance/health.ts,project,Invalid provenance health projection diff --git a/.agents/pm/issues/pm-l56d0o.toon b/.agents/pm/issues/pm-l56d0o.toon index de5bffde2..006c730db 100644 --- a/.agents/pm/issues/pm-l56d0o.toon +++ b/.agents/pm/issues/pm-l56d0o.toon @@ -6,7 +6,7 @@ status: closed priority: 1 tags[7]: agent-ux,"area:merge","area:sdk",determinism,read-only,regression,version-skew created_at: "2026-08-09T14:32:29.084Z" -updated_at: "2026-08-09T15:57:22.119Z" +updated_at: "2026-08-09T16:01:16.623Z" closed_at: "2026-08-09T15:57:21.544Z" completed_at: "2026-08-09T15:57:21.544Z" author: "harness:codex" @@ -28,9 +28,10 @@ customer_impact: Agents and contributors accumulate unrelated tracked diffs and dependencies[2]{id,kind,created_at,author,source_kind,author_source}: pm-1j5j21,related,"2026-08-09T14:32:29.084Z","harness:codex","cli:create:dep",detected pm-tu71,related,"2026-08-09T14:32:29.084Z","harness:codex","cli:create:dep",detected -comments[2]{created_at,author,text}: +comments[3]{created_at,author,text}: "2026-08-09T14:32:29.084Z","harness:codex","Duplicate check evidence: pm search GH-948 and exact title across status=all returned zero items; pm duplicates --status all was reviewed. GitHub source: https://github.com/unbraind/pm-cli/issues/948" "2026-08-09T15:57:17.861Z","harness:codex","Evidence: focused linked tests passed; full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; pnpm lint and pnpm quality:static passed; pm merge reconcile --dry-run reported zero drift and a healthy v2 fence. Packed manual acceptance in an isolated temporary Git project completed init/create/comment/get/health/validate/storage/history successfully." + "2026-08-09T16:01:16.623Z","harness:codex","Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop." files[6]{path,scope,note}: .gitattributes,project,Versioned merge-fence contract src/sdk/merge/index.ts,project,Public marker exports diff --git a/.agents/pm/issues/pm-xgah3a.toon b/.agents/pm/issues/pm-xgah3a.toon index 190aa92e8..e9ea7f651 100644 --- a/.agents/pm/issues/pm-xgah3a.toon +++ b/.agents/pm/issues/pm-xgah3a.toon @@ -6,7 +6,7 @@ status: closed priority: 1 tags[5]: agent-ux,"area:sdk",ci,provenance,test-isolation created_at: "2026-08-09T13:47:16.901Z" -updated_at: "2026-08-09T15:57:30.620Z" +updated_at: "2026-08-09T16:01:17.889Z" closed_at: "2026-08-09T15:57:30.059Z" completed_at: "2026-08-09T15:57:30.059Z" author: "harness:claude-code" @@ -29,10 +29,11 @@ dependencies[10]{id,kind,created_at,author,source_kind,author_source}: pm-rbcvt2,related,"2026-08-09T13:47:49.558Z","harness:claude-code","cli:update:dep",detected pm-w7ccmv,implements,"2026-08-09T13:47:49.558Z","harness:claude-code","cli:update:dep",detected pm-xp1xsw,implements,"2026-08-09T13:47:49.558Z","harness:claude-code","cli:update:dep",detected -comments[3]{created_at,author,text}: +comments[4]{created_at,author,text}: "2026-08-09T13:48:46.953Z","harness:claude-code","Reproduction, exact and cheap, recorded 2026-08-09 at commit 9a0a048b6. Filed only; not fixed in this pass.\n\nFailing run, with the harness variable present as an agent would have it:\n\n node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts\n\nfails one of sixteen, at agent-runtime-primitives.spec.ts:741, on attributes update and close mutations to the detected harness. Both compared history entries carry an unexpected context.agent_provenance_outcomes.version block reading status failed, reason resolver_failed, resolver ai_agent_version, rule_version v1.\n\nPassing run, identical in every other respect:\n\n env -u AI_AGENT node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts\n\npasses sixteen of sixteen. One variable is the entire difference, and it is a variable the fixture never sets and never refers to.\n\nThe host value on this machine is claude-code_2-1-226_agent. It matters that this string is not malformed: the resolver's regex requires the version at the end of the string, and this value ends in the literal text agent, so a perfectly ordinary harness value fails to parse. An agent whose AI_AGENT happened to end in a version would produce a third outcome again, which is why the acceptance criteria ask for all three forms to be exercised rather than only the unset case.\n\nChain of custody through the source, so the fix has three separable candidate sites rather than one guess. src/core/shared/author.ts:219 declares the codex descriptor's version resolver as ai_agent_version. src/core/shared/author.ts:569 implements that resolver by reading env.AI_AGENT, a name several harnesses write, with no check that the value belongs to the harness that matched. src/core/shared/author.ts:897 classifies the outcome, and decides between failed and unavailable by asking only whether env.AI_AGENT is non-blank; presence of any value is taken as evidence that the resolver had legitimate input, which is what converts an honest unavailable into a misleading failed.\n\nConfirmation that this is not a flake and not caused by the change shipped alongside it. The failure appeared first inside a full coverage run and then reproduced identically in isolation, and it reproduces on every invocation with the variable set. Two other specs failed in that same coverage run, governance-read-performance and surface-replication-gate, and both pass cleanly when re-run without concurrent load; those two are wall-clock sensitive and are not this. Continuous integration is green at this commit, which is consistent with hosted runners setting no AI_AGENT.\n\nScope note on what this does and does not touch. The two history entries are otherwise correct: author is harness:codex, author_source is detected, and the patch contents are as expected. The leak affects the provenance outcome block only. That is what makes it a containment question rather than a correctness question about detection, and it is why the item is parented on continuous integration rather than on the identity lineage, while still citing that lineage.\n" "2026-08-09T15:26:24.456Z","harness:codex","Implementation evidence: sandbox isolation now clears only the ambiguous shared AI_AGENT signal; explicit CODEX/Claude session signals remain available for intentional CLI/MCP parity. The foreign AI_AGENT reproducer and mutation-envelope parity suite both pass." "2026-08-09T15:57:29.521Z","harness:codex","Evidence: both linked test groups passed; final full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; pnpm lint and all static quality gates passed. The narrowed isolation behavior is documented in the item history and avoids masking dedicated resolver fixtures." + "2026-08-09T16:01:17.889Z","harness:codex","Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop." files[3]{path,scope,note}: src/core/shared/author.ts,project,"Descriptor at 219, resolver at 569, outcome classifier at 897 - the three candidate fix sites" tests/helpers/withTempPmPath.ts,project,"Sandbox helper: isolates PM_PATH and telemetry, does not neutralize harness signal environment" From 02d6043d4728ce8ad9e7a09675c7ef32b19a5351 Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Sun, 9 Aug 2026 18:09:44 +0200 Subject: [PATCH 3/3] docs(pm): record PR 952 hosted verification --- .agents/pm/features/pm-lu6sca.toon | 5 +++-- .agents/pm/history/pm-1j5j21.jsonl | 1 + .agents/pm/history/pm-eq9dlw.jsonl | 1 + .agents/pm/history/pm-l56d0o.jsonl | 1 + .agents/pm/history/pm-lu6sca.jsonl | 1 + .agents/pm/history/pm-xgah3a.jsonl | 1 + .agents/pm/issues/pm-1j5j21.toon | 5 +++-- .agents/pm/issues/pm-eq9dlw.toon | 5 +++-- .agents/pm/issues/pm-l56d0o.toon | 5 +++-- .agents/pm/issues/pm-xgah3a.toon | 5 +++-- 10 files changed, 20 insertions(+), 10 deletions(-) diff --git a/.agents/pm/features/pm-lu6sca.toon b/.agents/pm/features/pm-lu6sca.toon index 8545071a9..958c14c4f 100644 --- a/.agents/pm/features/pm-lu6sca.toon +++ b/.agents/pm/features/pm-lu6sca.toon @@ -6,7 +6,7 @@ status: closed priority: 2 tags[5]: "area:sdk",identity,instrument-integrity,observability,provenance created_at: "2026-08-03T06:22:12.243Z" -updated_at: "2026-08-09T16:01:17.030Z" +updated_at: "2026-08-09T16:09:42.711Z" closed_at: "2026-08-09T15:57:25.791Z" completed_at: "2026-08-09T15:57:25.791Z" author: "harness:claude-code" @@ -29,7 +29,7 @@ dependencies[7]{id,kind,created_at,author,source_kind,author_source}: pm-htbetn,related,"2026-08-03T06:23:55.524Z","harness:claude-code","cli:update:dep",detected pm-rtn5h6,related,"2026-08-03T06:23:55.524Z","harness:claude-code","cli:update:dep",detected pm-w7ccmv,implements,"2026-08-03T06:23:55.524Z","harness:claude-code","cli:update:dep",detected -comments[10]{created_at,author,text}: +comments[11]{created_at,author,text}: "2026-08-03T11:09:27.269Z","harness:codex","Estimate basis 2026-08-03: 360 minutes covers resolver outcome algebra, bounded reason codes, immutable recording, health projection, zero-success warning logic, and negative controls." "2026-08-08T22:13:20.575Z","harness:codex","Implementation start 2026-08-09: active in the coupled context-provenance tranche with pm-3zgh2c, pm-eq9dlw, pm-lu6sca, pm-b1w8vr, and pm-h75tjh. Scope is SDK-first provenance inference and resolver outcomes, typed role domains, stable entity read-back projections, and epoch-aware release classification; all other open items remain unclaimed." "2026-08-08T22:32:58.636Z","harness:codex","Design evidence: resolver attempts are counted only when the resolver input exists. Missing AI_AGENT or session identifiers are harness_unavailable; a supplied valid resolver input that yields no value is resolver_failed. pm health scans at most 10,000 immutable events, tolerates malformed streams owned by integrity diagnostics, and emits advisory zero-success warnings." @@ -40,6 +40,7 @@ comments[10]{created_at,author,text}: "2026-08-09T01:24:46.237Z","harness:codex","PR #944 hosted evidence for the completed tranche portion: implementation commit b6678b8 passed all deterministic checks; CodeRabbit confirmed byte-bounded complete-event health semantics and invalid-value role outcomes. All 16 findings are addressed, replied to, and resolved. Item stays open and unclaimed for the documented no-resolver-declared residual." "2026-08-09T15:57:25.224Z","harness:codex","Evidence: focused agent-runtime and author-attribution tests passed after truthful overlapping-run failure receipts; the final uninterrupted full suite passed 7,100/7,100 with exact 100/100/100/100 coverage. SDK surface change was explicitly acknowledged and all static, lint, parity, token, and performance gates passed." "2026-08-09T16:01:17.030Z","harness:codex","Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop." + "2026-08-09T16:09:42.711Z","harness:codex","PR #952 first hosted pass at exact head 77fb234d4: every required GitHub runner completed successfully, including four coverage shards, static/compat/smoke/typecheck gates, Node 22/24 and macOS/Windows runtimes, CodeQL, Trivy, TruffleHog, Semgrep, ShellCheck, PSScriptAnalyzer, actionlint, CodeFactor, DeepScan, Hound, CodSpeed, and Codecov patch. Thread-aware inventory found zero review threads. CodeRabbit and Sourcery were quota-limited and supplied no code findings; Cubic completed neutral with no findings; no Greptile check/comment surface was emitted. Every bot comment/review was individually reacted to and acknowledged at its GitHub artifact." files[8]{path,scope,note}: sdk/public-surface.json,project,SDK outcome contract snapshot src/core/history/history.ts,project,Persist resolver outcome evidence diff --git a/.agents/pm/history/pm-1j5j21.jsonl b/.agents/pm/history/pm-1j5j21.jsonl index 57c5f52a6..6867a8cf6 100644 --- a/.agents/pm/history/pm-1j5j21.jsonl +++ b/.agents/pm/history/pm-1j5j21.jsonl @@ -22,3 +22,4 @@ {"ts":"2026-08-09T15:58:32.241Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/0/note","value":"Managed changelog entry for the coupled SDK integrity tranche"},{"op":"replace","path":"/metadata/docs/0/path","value":"CHANGELOG.md"},{"op":"add","path":"/metadata/docs/1","value":{"path":"docs/MERGE_SAFETY.md","scope":"project","note":"Durable receipt lifecycle"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:58:32.241Z"}],"before_hash":"aba42ba573361cc0e800b0840edc4be0a97738a452659fa8c714c4d66d84cd49","after_hash":"b48904b0fc4fd5d4af6fc828aa8e02fe4c996d434301940227f8c1dde8d9653b"} {"ts":"2026-08-09T15:58:32.674Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/1","value":{"command":"pnpm changelog:pm:check","scope":"project","timeout_seconds":240}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:58:32.674Z"}],"before_hash":"b48904b0fc4fd5d4af6fc828aa8e02fe4c996d434301940227f8c1dde8d9653b","after_hash":"a022e0b96fbdcf4176cc239b5eeaf76c95bef619fbd5442f473be6b4621df702"} {"ts":"2026-08-09T16:01:16.227Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-08-09T16:01:16.227Z","author":"harness:codex","text":"Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:01:16.227Z"}],"before_hash":"a022e0b96fbdcf4176cc239b5eeaf76c95bef619fbd5442f473be6b4621df702","after_hash":"91d42c03be63da48c54b5e022ac896b55256251f6a9cf0e5682995064527e0cd"} +{"ts":"2026-08-09T16:09:41.852Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-1j5j21","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/4","value":{"created_at":"2026-08-09T16:09:41.852Z","author":"harness:codex","text":"PR #952 first hosted pass at exact head 77fb234d4: every required GitHub runner completed successfully, including four coverage shards, static/compat/smoke/typecheck gates, Node 22/24 and macOS/Windows runtimes, CodeQL, Trivy, TruffleHog, Semgrep, ShellCheck, PSScriptAnalyzer, actionlint, CodeFactor, DeepScan, Hound, CodSpeed, and Codecov patch. Thread-aware inventory found zero review threads. CodeRabbit and Sourcery were quota-limited and supplied no code findings; Cubic completed neutral with no findings; no Greptile check/comment surface was emitted. Every bot comment/review was individually reacted to and acknowledged at its GitHub artifact."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:09:41.852Z"}],"before_hash":"91d42c03be63da48c54b5e022ac896b55256251f6a9cf0e5682995064527e0cd","after_hash":"560a5f311bf158d6cde4ec276782b4e525f44be45275d0303d9268c96f002127"} diff --git a/.agents/pm/history/pm-eq9dlw.jsonl b/.agents/pm/history/pm-eq9dlw.jsonl index 30937c763..af7856ebc 100644 --- a/.agents/pm/history/pm-eq9dlw.jsonl +++ b/.agents/pm/history/pm-eq9dlw.jsonl @@ -30,3 +30,4 @@ {"ts":"2026-08-09T15:57:28.050Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:28.050Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:28.024Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:28.024Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented bounded privacy-safe corpus diagnostics for invalid historical provenance domains."}],"before_hash":"57fd32da9b944175f4433ac2dd7043830df3249c9e9bbae45cb4c945e0b2b7f1","after_hash":"41310bb8a3ef76dc059724bf2dd6a67c8d6332ddcee394137f20355498d43cc1"} {"ts":"2026-08-09T15:57:28.612Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:28.612Z"}],"before_hash":"41310bb8a3ef76dc059724bf2dd6a67c8d6332ddcee394137f20355498d43cc1","after_hash":"36101bcf5c5ac63c6384d89384feeca3884ac5c953bf4b7778bf0ef0329c7c5d"} {"ts":"2026-08-09T16:01:17.488Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/9","value":{"created_at":"2026-08-09T16:01:17.487Z","author":"harness:codex","text":"Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:01:17.488Z"}],"before_hash":"36101bcf5c5ac63c6384d89384feeca3884ac5c953bf4b7778bf0ef0329c7c5d","after_hash":"92f602a34a1476ed98b1a32882a639e156db2abdee167f225a5dee56b93b9cf1"} +{"ts":"2026-08-09T16:09:43.297Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-eq9dlw","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/10","value":{"created_at":"2026-08-09T16:09:43.297Z","author":"harness:codex","text":"PR #952 first hosted pass at exact head 77fb234d4: every required GitHub runner completed successfully, including four coverage shards, static/compat/smoke/typecheck gates, Node 22/24 and macOS/Windows runtimes, CodeQL, Trivy, TruffleHog, Semgrep, ShellCheck, PSScriptAnalyzer, actionlint, CodeFactor, DeepScan, Hound, CodSpeed, and Codecov patch. Thread-aware inventory found zero review threads. CodeRabbit and Sourcery were quota-limited and supplied no code findings; Cubic completed neutral with no findings; no Greptile check/comment surface was emitted. Every bot comment/review was individually reacted to and acknowledged at its GitHub artifact."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:09:43.297Z"}],"before_hash":"92f602a34a1476ed98b1a32882a639e156db2abdee167f225a5dee56b93b9cf1","after_hash":"375b0000b87886d215ca6b677352a3f38d1d16d4aa8299176d5b4fa114350658"} diff --git a/.agents/pm/history/pm-l56d0o.jsonl b/.agents/pm/history/pm-l56d0o.jsonl index a0feece62..64e929583 100644 --- a/.agents/pm/history/pm-l56d0o.jsonl +++ b/.agents/pm/history/pm-l56d0o.jsonl @@ -10,3 +10,4 @@ {"ts":"2026-08-09T15:57:21.557Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:21.557Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:21.544Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:21.544Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented and verified a versioned, backward-safe merge-driver fence with regression and cross-version integration coverage."}],"before_hash":"34fc7183f841ad71a8d8638b5be009e395435ca7d9ca8158f7a10f191d5ab2d7","after_hash":"178cc9cbaa3b835e5dc5a19a7fc2c25cd9a4883ded82b8f3d83d6b440addeef4"} {"ts":"2026-08-09T15:57:22.119Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:22.119Z"}],"before_hash":"178cc9cbaa3b835e5dc5a19a7fc2c25cd9a4883ded82b8f3d83d6b440addeef4","after_hash":"0997fd0877755453ffa915ca08350f5809df14d3a9d9b7f905e79376b2cb13a0"} {"ts":"2026-08-09T16:01:16.623Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-08-09T16:01:16.623Z","author":"harness:codex","text":"Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:01:16.623Z"}],"before_hash":"0997fd0877755453ffa915ca08350f5809df14d3a9d9b7f905e79376b2cb13a0","after_hash":"29d2a03df0dc688f7ab372cbce48d4d2ebebd2998438aadde958b69896de54d2"} +{"ts":"2026-08-09T16:09:42.259Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-l56d0o","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-08-09T16:09:42.259Z","author":"harness:codex","text":"PR #952 first hosted pass at exact head 77fb234d4: every required GitHub runner completed successfully, including four coverage shards, static/compat/smoke/typecheck gates, Node 22/24 and macOS/Windows runtimes, CodeQL, Trivy, TruffleHog, Semgrep, ShellCheck, PSScriptAnalyzer, actionlint, CodeFactor, DeepScan, Hound, CodSpeed, and Codecov patch. Thread-aware inventory found zero review threads. CodeRabbit and Sourcery were quota-limited and supplied no code findings; Cubic completed neutral with no findings; no Greptile check/comment surface was emitted. Every bot comment/review was individually reacted to and acknowledged at its GitHub artifact."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:09:42.259Z"}],"before_hash":"29d2a03df0dc688f7ab372cbce48d4d2ebebd2998438aadde958b69896de54d2","after_hash":"91d99a15219cece331e96b273e45ae6f2241559d8ed8ed1b0fc6a9e79c4dc2e8"} diff --git a/.agents/pm/history/pm-lu6sca.jsonl b/.agents/pm/history/pm-lu6sca.jsonl index d052bde1c..3eadb51ea 100644 --- a/.agents/pm/history/pm-lu6sca.jsonl +++ b/.agents/pm/history/pm-lu6sca.jsonl @@ -38,3 +38,4 @@ {"ts":"2026-08-09T15:57:25.825Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:25.825Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:25.791Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:25.791Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented and documented explicit configured-versus-attempted provenance outcome semantics across CLI and SDK."}],"before_hash":"4d594a1ca57ad58d5a692efdfb5c4f3111d969eb68dc2433fe53505bef5937f2","after_hash":"69e57d4f2fec9149269b407dbdd82b171b5af5ba637c67135640fc0ca6a9e078"} {"ts":"2026-08-09T15:57:26.460Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:26.460Z"}],"before_hash":"69e57d4f2fec9149269b407dbdd82b171b5af5ba637c67135640fc0ca6a9e078","after_hash":"d8ef0407ad6ba29221a310121d69590cff4e64de24e9dfd50c7849e75d7c1e2f"} {"ts":"2026-08-09T16:01:17.030Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/9","value":{"created_at":"2026-08-09T16:01:17.030Z","author":"harness:codex","text":"Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:01:17.030Z"}],"before_hash":"d8ef0407ad6ba29221a310121d69590cff4e64de24e9dfd50c7849e75d7c1e2f","after_hash":"faccd536bbff39d9d7cc870f888f947f7e7cfe90b713743828aa2618084ba851"} +{"ts":"2026-08-09T16:09:42.711Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-lu6sca","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/10","value":{"created_at":"2026-08-09T16:09:42.711Z","author":"harness:codex","text":"PR #952 first hosted pass at exact head 77fb234d4: every required GitHub runner completed successfully, including four coverage shards, static/compat/smoke/typecheck gates, Node 22/24 and macOS/Windows runtimes, CodeQL, Trivy, TruffleHog, Semgrep, ShellCheck, PSScriptAnalyzer, actionlint, CodeFactor, DeepScan, Hound, CodSpeed, and Codecov patch. Thread-aware inventory found zero review threads. CodeRabbit and Sourcery were quota-limited and supplied no code findings; Cubic completed neutral with no findings; no Greptile check/comment surface was emitted. Every bot comment/review was individually reacted to and acknowledged at its GitHub artifact."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:09:42.711Z"}],"before_hash":"faccd536bbff39d9d7cc870f888f947f7e7cfe90b713743828aa2618084ba851","after_hash":"113b41993eb57647015427d4ef83bb3d04adcbd19c591798c5b5856b6a853532"} diff --git a/.agents/pm/history/pm-xgah3a.jsonl b/.agents/pm/history/pm-xgah3a.jsonl index de47050f5..db3e7be8b 100644 --- a/.agents/pm/history/pm-xgah3a.jsonl +++ b/.agents/pm/history/pm-xgah3a.jsonl @@ -15,3 +15,4 @@ {"ts":"2026-08-09T15:57:30.113Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:30.113Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-09T15:57:30.059Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-09T15:57:30.059Z"},{"op":"add","path":"/metadata/close_reason","value":"Implemented foreign-harness provenance isolation without over-clearing explicit resolver inputs."}],"before_hash":"230aa6184d35f582b7c449280876ffc9506ece130eadc6ba13a30bd78b611324","after_hash":"e9ae2951712737a901d54d25c0a342e5276ae0bbcd0aa9f2638d3c5984d2c1ad"} {"ts":"2026-08-09T15:57:30.620Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T15:57:30.620Z"}],"before_hash":"e9ae2951712737a901d54d25c0a342e5276ae0bbcd0aa9f2638d3c5984d2c1ad","after_hash":"bd6830556c35494c380f6112130a29ac4177353f51068fa3f7dd1491a97fd740"} {"ts":"2026-08-09T16:01:17.889Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-08-09T16:01:17.889Z","author":"harness:codex","text":"Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:01:17.889Z"}],"before_hash":"bd6830556c35494c380f6112130a29ac4177353f51068fa3f7dd1491a97fd740","after_hash":"5cd4a713e2cba1651f40041a8ea617728c1bda87f90e92c88c270d76e0d76525"} +{"ts":"2026-08-09T16:09:43.818Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"b2adadb08f3a0763fd3bf70f","agent_provenance":{"model":null,"effort":null,"role":null,"topic":{"value":"pm-xgah3a","source":"argv"}},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/4","value":{"created_at":"2026-08-09T16:09:43.818Z","author":"harness:codex","text":"PR #952 first hosted pass at exact head 77fb234d4: every required GitHub runner completed successfully, including four coverage shards, static/compat/smoke/typecheck gates, Node 22/24 and macOS/Windows runtimes, CodeQL, Trivy, TruffleHog, Semgrep, ShellCheck, PSScriptAnalyzer, actionlint, CodeFactor, DeepScan, Hound, CodSpeed, and Codecov patch. Thread-aware inventory found zero review threads. CodeRabbit and Sourcery were quota-limited and supplied no code findings; Cubic completed neutral with no findings; no Greptile check/comment surface was emitted. Every bot comment/review was individually reacted to and acknowledged at its GitHub artifact."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-09T16:09:43.818Z"}],"before_hash":"5cd4a713e2cba1651f40041a8ea617728c1bda87f90e92c88c270d76e0d76525","after_hash":"4c3a2fd0e5062829a5c9ce36bc439b7af56a3b76e2cc77d1d6221d377224120f"} diff --git a/.agents/pm/issues/pm-1j5j21.toon b/.agents/pm/issues/pm-1j5j21.toon index 4be515a6b..2c41a43fb 100644 --- a/.agents/pm/issues/pm-1j5j21.toon +++ b/.agents/pm/issues/pm-1j5j21.toon @@ -6,7 +6,7 @@ status: closed priority: 1 tags: [] created_at: "2026-08-07T08:33:38.852Z" -updated_at: "2026-08-09T16:01:16.227Z" +updated_at: "2026-08-09T16:09:41.852Z" closed_at: "2026-08-09T15:57:23.719Z" completed_at: "2026-08-09T15:57:23.719Z" author: "harness:codex" @@ -26,11 +26,12 @@ dependencies[4]{id,kind,created_at,author,source_kind,author_source}: pm-ysqb6n,related,"2026-08-07T08:33:38.852Z","harness:codex","cli:create:dep",detected pm-g5sx,discovered_from,"2026-08-07T08:34:27.916Z","harness:codex","cli:update:dep",detected pm-ysqb6n,supersedes,"2026-08-07T08:34:27.916Z","harness:codex","cli:update:dep",detected -comments[4]{created_at,author,text}: +comments[5]{created_at,author,text}: "2026-08-07T08:33:38.852Z","harness:codex","GitHub sources: https://github.com/unbraind/pm-cli/issues/921 and https://github.com/unbraind/pm-cli/issues/922. Duplicate check searched all 2,351 items and every status for clone-local/gitignored merge receipts,fresh-clone CI,discarded values,history-repair,and both GH numbers. The reports share one root contract and are intentionally consolidated; closed pm-ysqb6n is predecessor evidence,not an active duplicate." "2026-08-08T15:39:02.830Z","harness:codex","Investigation boundary (2026-08-08): this PR deliberately does not claim fresh-clone durability. The implemented receipt work classifies lossless versus discarded-value decisions and requires explicit acceptance, but raw recovery receipts remain clone-local and ignored. A durable privacy-safe pushed evidence design needs a separate tracked-record contract and fresh-clone lifecycle, so retaining this item as open avoids falsely closing GH-921/GH-922." "2026-08-09T15:57:23.042Z","harness:codex","Evidence: linked receipt tests passed; full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; static, lint, SDK surface, performance, history-drift, storage-integrity, and dry-run reconciliation gates passed. Manual packed-consumer acceptance also passed in an isolated project." "2026-08-09T16:01:16.227Z","harness:codex","Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop." + "2026-08-09T16:09:41.852Z","harness:codex","PR #952 first hosted pass at exact head 77fb234d4: every required GitHub runner completed successfully, including four coverage shards, static/compat/smoke/typecheck gates, Node 22/24 and macOS/Windows runtimes, CodeQL, Trivy, TruffleHog, Semgrep, ShellCheck, PSScriptAnalyzer, actionlint, CodeFactor, DeepScan, Hound, CodSpeed, and Codecov patch. Thread-aware inventory found zero review threads. CodeRabbit and Sourcery were quota-limited and supplied no code findings; Cubic completed neutral with no findings; no Greptile check/comment surface was emitted. Every bot comment/review was individually reacted to and acknowledged at its GitHub artifact." files[5]{path,scope,note}: sdk/public-surface.json,project,SDK contract snapshot src/sdk/governance/health.ts,project,Durable receipt discovery diff --git a/.agents/pm/issues/pm-eq9dlw.toon b/.agents/pm/issues/pm-eq9dlw.toon index c365165c2..f58f0543e 100644 --- a/.agents/pm/issues/pm-eq9dlw.toon +++ b/.agents/pm/issues/pm-eq9dlw.toon @@ -6,7 +6,7 @@ status: closed priority: 2 tags[4]: "area:sdk",data-quality,identity,provenance created_at: "2026-08-03T06:21:42.773Z" -updated_at: "2026-08-09T16:01:17.488Z" +updated_at: "2026-08-09T16:09:43.297Z" closed_at: "2026-08-09T15:57:28.024Z" completed_at: "2026-08-09T15:57:28.024Z" author: "harness:claude-code" @@ -30,7 +30,7 @@ dependencies[7]{id,kind,created_at,author,source_kind,author_source}: pm-lu6sca,related,"2026-08-03T06:23:40.264Z","harness:claude-code","cli:update:dep",detected pm-pj2isb,related,"2026-08-03T06:23:40.264Z","harness:claude-code","cli:update:dep",detected pm-rbg1qo,discovered_from,"2026-08-03T06:23:40.264Z","harness:claude-code","cli:update:dep",detected -comments[10]{created_at,author,text}: +comments[11]{created_at,author,text}: "2026-08-03T11:09:27.894Z","harness:codex","Estimate basis 2026-08-03: 240 minutes covers value-domain declarations, invalid boolean rejection, a correctly named nested-session dimension, corpus check, and regression coverage." "2026-08-07T11:23:43.166Z","harness:claude-code","Confirmed still live at 2026.8.7 on 2026-08-07 with no identity flags passed. A create from Claude Code recorded author harness:claude-code with author_source detected, agent_model claude-opus-5 from probe, effort xhigh from environment, version 2.1.224 from probe — and role literally \"1\" from environment, with topic null. Model, effort and version capture are working end to end; role and topic remain the only two dimensions that do not carry meaning. Fleet analytics grouping on role today would bucket every nested session under the string \"1\"." "2026-08-08T08:10:41.851Z","harness:claude-code","Reproduced live on 2026-08-08 against pm-cli 2026.8.7, HEAD build. A create recorded this session carries agent_provenance role {value: \"1\", source: \"environment\"} alongside a correctly resolved model {claude-opus-5, probe}, effort {xhigh, environment} and version {2.1.226, probe}. So the dimension is not merely unpopulated: it is populated with the boolean child-session flag rendered as a string, which is worse than null because it types as a valid role and will group every nested claude-code invocation under one meaningless label in fleet analytics. Sibling dimension topic is null in the same record, which pm-3zgh2c owns. Evidence is the last history entry of pm-3lhth4." @@ -41,6 +41,7 @@ comments[10]{created_at,author,text}: "2026-08-09T01:24:45.768Z","harness:codex","PR #944 hosted evidence for the completed tranche portion: implementation commit b6678b8 passed all deterministic checks; all 16 CodeRabbit findings are addressed, replied to, and resolved. Item stays open and unclaimed for its broader remaining role-contract acceptance." "2026-08-09T15:57:27.484Z","harness:codex","Evidence: all three linked tests passed; final full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; lint, duplicate, docstring, surface-replication, SDK parity, token/context, and performance gates passed. Live repository health/storage/history checks remain structurally clean." "2026-08-09T16:01:17.487Z","harness:codex","Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop." + "2026-08-09T16:09:43.297Z","harness:codex","PR #952 first hosted pass at exact head 77fb234d4: every required GitHub runner completed successfully, including four coverage shards, static/compat/smoke/typecheck gates, Node 22/24 and macOS/Windows runtimes, CodeQL, Trivy, TruffleHog, Semgrep, ShellCheck, PSScriptAnalyzer, actionlint, CodeFactor, DeepScan, Hound, CodSpeed, and Codecov patch. Thread-aware inventory found zero review threads. CodeRabbit and Sourcery were quota-limited and supplied no code findings; Cubic completed neutral with no findings; no Greptile check/comment surface was emitted. Every bot comment/review was individually reacted to and acknowledged at its GitHub artifact." files[6]{path,scope,note}: src/core/shared/author.ts,project,Remove boolean child-session flag from semantic role sources and enforce controlled roles src/sdk/governance/health.ts,project,Invalid provenance health projection diff --git a/.agents/pm/issues/pm-l56d0o.toon b/.agents/pm/issues/pm-l56d0o.toon index 006c730db..3968b8f64 100644 --- a/.agents/pm/issues/pm-l56d0o.toon +++ b/.agents/pm/issues/pm-l56d0o.toon @@ -6,7 +6,7 @@ status: closed priority: 1 tags[7]: agent-ux,"area:merge","area:sdk",determinism,read-only,regression,version-skew created_at: "2026-08-09T14:32:29.084Z" -updated_at: "2026-08-09T16:01:16.623Z" +updated_at: "2026-08-09T16:09:42.259Z" closed_at: "2026-08-09T15:57:21.544Z" completed_at: "2026-08-09T15:57:21.544Z" author: "harness:codex" @@ -28,10 +28,11 @@ customer_impact: Agents and contributors accumulate unrelated tracked diffs and dependencies[2]{id,kind,created_at,author,source_kind,author_source}: pm-1j5j21,related,"2026-08-09T14:32:29.084Z","harness:codex","cli:create:dep",detected pm-tu71,related,"2026-08-09T14:32:29.084Z","harness:codex","cli:create:dep",detected -comments[3]{created_at,author,text}: +comments[4]{created_at,author,text}: "2026-08-09T14:32:29.084Z","harness:codex","Duplicate check evidence: pm search GH-948 and exact title across status=all returned zero items; pm duplicates --status all was reviewed. GitHub source: https://github.com/unbraind/pm-cli/issues/948" "2026-08-09T15:57:17.861Z","harness:codex","Evidence: focused linked tests passed; full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; pnpm lint and pnpm quality:static passed; pm merge reconcile --dry-run reported zero drift and a healthy v2 fence. Packed manual acceptance in an isolated temporary Git project completed init/create/comment/get/health/validate/storage/history successfully." "2026-08-09T16:01:16.623Z","harness:codex","Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop." + "2026-08-09T16:09:42.259Z","harness:codex","PR #952 first hosted pass at exact head 77fb234d4: every required GitHub runner completed successfully, including four coverage shards, static/compat/smoke/typecheck gates, Node 22/24 and macOS/Windows runtimes, CodeQL, Trivy, TruffleHog, Semgrep, ShellCheck, PSScriptAnalyzer, actionlint, CodeFactor, DeepScan, Hound, CodSpeed, and Codecov patch. Thread-aware inventory found zero review threads. CodeRabbit and Sourcery were quota-limited and supplied no code findings; Cubic completed neutral with no findings; no Greptile check/comment surface was emitted. Every bot comment/review was individually reacted to and acknowledged at its GitHub artifact." files[6]{path,scope,note}: .gitattributes,project,Versioned merge-fence contract src/sdk/merge/index.ts,project,Public marker exports diff --git a/.agents/pm/issues/pm-xgah3a.toon b/.agents/pm/issues/pm-xgah3a.toon index e9ea7f651..793626295 100644 --- a/.agents/pm/issues/pm-xgah3a.toon +++ b/.agents/pm/issues/pm-xgah3a.toon @@ -6,7 +6,7 @@ status: closed priority: 1 tags[5]: agent-ux,"area:sdk",ci,provenance,test-isolation created_at: "2026-08-09T13:47:16.901Z" -updated_at: "2026-08-09T16:01:17.889Z" +updated_at: "2026-08-09T16:09:43.818Z" closed_at: "2026-08-09T15:57:30.059Z" completed_at: "2026-08-09T15:57:30.059Z" author: "harness:claude-code" @@ -29,11 +29,12 @@ dependencies[10]{id,kind,created_at,author,source_kind,author_source}: pm-rbcvt2,related,"2026-08-09T13:47:49.558Z","harness:claude-code","cli:update:dep",detected pm-w7ccmv,implements,"2026-08-09T13:47:49.558Z","harness:claude-code","cli:update:dep",detected pm-xp1xsw,implements,"2026-08-09T13:47:49.558Z","harness:claude-code","cli:update:dep",detected -comments[4]{created_at,author,text}: +comments[5]{created_at,author,text}: "2026-08-09T13:48:46.953Z","harness:claude-code","Reproduction, exact and cheap, recorded 2026-08-09 at commit 9a0a048b6. Filed only; not fixed in this pass.\n\nFailing run, with the harness variable present as an agent would have it:\n\n node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts\n\nfails one of sixteen, at agent-runtime-primitives.spec.ts:741, on attributes update and close mutations to the detected harness. Both compared history entries carry an unexpected context.agent_provenance_outcomes.version block reading status failed, reason resolver_failed, resolver ai_agent_version, rule_version v1.\n\nPassing run, identical in every other respect:\n\n env -u AI_AGENT node scripts/run-tests.mjs test -- tests/unit/sdk/agent-runtime-primitives.spec.ts\n\npasses sixteen of sixteen. One variable is the entire difference, and it is a variable the fixture never sets and never refers to.\n\nThe host value on this machine is claude-code_2-1-226_agent. It matters that this string is not malformed: the resolver's regex requires the version at the end of the string, and this value ends in the literal text agent, so a perfectly ordinary harness value fails to parse. An agent whose AI_AGENT happened to end in a version would produce a third outcome again, which is why the acceptance criteria ask for all three forms to be exercised rather than only the unset case.\n\nChain of custody through the source, so the fix has three separable candidate sites rather than one guess. src/core/shared/author.ts:219 declares the codex descriptor's version resolver as ai_agent_version. src/core/shared/author.ts:569 implements that resolver by reading env.AI_AGENT, a name several harnesses write, with no check that the value belongs to the harness that matched. src/core/shared/author.ts:897 classifies the outcome, and decides between failed and unavailable by asking only whether env.AI_AGENT is non-blank; presence of any value is taken as evidence that the resolver had legitimate input, which is what converts an honest unavailable into a misleading failed.\n\nConfirmation that this is not a flake and not caused by the change shipped alongside it. The failure appeared first inside a full coverage run and then reproduced identically in isolation, and it reproduces on every invocation with the variable set. Two other specs failed in that same coverage run, governance-read-performance and surface-replication-gate, and both pass cleanly when re-run without concurrent load; those two are wall-clock sensitive and are not this. Continuous integration is green at this commit, which is consistent with hosted runners setting no AI_AGENT.\n\nScope note on what this does and does not touch. The two history entries are otherwise correct: author is harness:codex, author_source is detected, and the patch contents are as expected. The leak affects the provenance outcome block only. That is what makes it a containment question rather than a correctness question about detection, and it is why the item is parented on continuous integration rather than on the identity lineage, while still citing that lineage.\n" "2026-08-09T15:26:24.456Z","harness:codex","Implementation evidence: sandbox isolation now clears only the ambiguous shared AI_AGENT signal; explicit CODEX/Claude session signals remain available for intentional CLI/MCP parity. The foreign AI_AGENT reproducer and mutation-envelope parity suite both pass." "2026-08-09T15:57:29.521Z","harness:codex","Evidence: both linked test groups passed; final full suite passed 7,100/7,100 with exact 100/100/100/100 coverage; pnpm lint and all static quality gates passed. The narrowed isolation behavior is documented in the item history and avoids masking dedicated resolver fixtures." "2026-08-09T16:01:17.889Z","harness:codex","Delivery: implementation committed at bd333f788 and opened as GitHub PR #952: https://github.com/unbraind/pm-cli/pull/952. Hosted exact-head checks and review feedback will be recorded on this item after the review loop." + "2026-08-09T16:09:43.818Z","harness:codex","PR #952 first hosted pass at exact head 77fb234d4: every required GitHub runner completed successfully, including four coverage shards, static/compat/smoke/typecheck gates, Node 22/24 and macOS/Windows runtimes, CodeQL, Trivy, TruffleHog, Semgrep, ShellCheck, PSScriptAnalyzer, actionlint, CodeFactor, DeepScan, Hound, CodSpeed, and Codecov patch. Thread-aware inventory found zero review threads. CodeRabbit and Sourcery were quota-limited and supplied no code findings; Cubic completed neutral with no findings; no Greptile check/comment surface was emitted. Every bot comment/review was individually reacted to and acknowledged at its GitHub artifact." files[3]{path,scope,note}: src/core/shared/author.ts,project,"Descriptor at 219, resolver at 569, outcome classifier at 897 - the three candidate fix sites" tests/helpers/withTempPmPath.ts,project,"Sandbox helper: isolates PM_PATH and telemetry, does not neutralize harness signal environment"