From d00956b9d4bb45458dd0cd6cb74216e3c646ae24 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Thu, 6 Aug 2026 23:04:18 +0200 Subject: [PATCH 1/5] Gate CI on pm health so a silently discarded peer edit cannot merge Add a 'Verify pm project integrity and merge safety' step to ci.yml immediately after Install dependencies. It runs ./node_modules/.bin/pm health --strict-exit. This closes a hole in multi-agent branch merging: when two agents edit the same scalar field of one item on two branches, the field-aware merge driver picks a winner and records the loser in a clone-local receipt. The resulting .toon has no conflict markers and already holds the winning value, so the naive resolution idiom (git add the marker-free file, commit) succeeds and the peer edit is gone with no trace in any pushed artifact. pm validate returns ok:true on that corrupted result because the file is valid TOON. Only pm health goes red, via integrity.counts.pending_merge_decisions, naming the affected items in pending_merge_decision_items. --strict-exit is load-bearing because a bare pm health exits 0 even when ok:false. Verified green on this repo and proven to exit 1 on the hazard in a throwaway copy. --- .agents/pm/chores/pm-github-eh1h.toon | 15 +++++++++++++++ .agents/pm/history/pm-github-eh1h.jsonl | 2 ++ .github/workflows/ci.yml | 18 ++++++++++++++++++ CHANGELOG.md | 6 ++++++ 4 files changed, 41 insertions(+) create mode 100644 .agents/pm/chores/pm-github-eh1h.toon create mode 100644 .agents/pm/history/pm-github-eh1h.jsonl diff --git a/.agents/pm/chores/pm-github-eh1h.toon b/.agents/pm/chores/pm-github-eh1h.toon new file mode 100644 index 0000000..2227bdb --- /dev/null +++ b/.agents/pm/chores/pm-github-eh1h.toon @@ -0,0 +1,15 @@ +id: pm-github-eh1h +title: Gate CI on pm health so a silently discarded peer edit cannot merge +description: "" +type: Chore +status: closed +priority: 2 +tags: [] +created_at: "2026-08-06T20:44:51.948Z" +updated_at: "2026-08-06T20:44:52.365Z" +closed_at: "2026-08-06T20:44:52.355Z" +completed_at: "2026-08-06T20:44:52.355Z" +author: pi-agent +acceptance_criteria: "CI workflow runs ./node_modules/.bin/pm health --strict-exit in a step immediately after Install dependencies; the step fails non-zero when integrity.counts.pending_merge_decisions is non-zero; pm validate is NOT used because it returns ok:true on a marker-free field-aware merge that silently dropped a peer edit" +close_reason: "Inserted the Verify pm project integrity and merge safety step into .github/workflows/ci.yml right after Install dependencies, running ./node_modules/.bin/pm health --strict-exit. pm health --strict-exit exits 0 on this repo and was proven to exit 1 on a same-field merge hazard in a throwaway copy where pm validate stayed ok:true." +body: "" diff --git a/.agents/pm/history/pm-github-eh1h.jsonl b/.agents/pm/history/pm-github-eh1h.jsonl new file mode 100644 index 0000000..7dfb69c --- /dev/null +++ b/.agents/pm/history/pm-github-eh1h.jsonl @@ -0,0 +1,2 @@ +{"ts":"2026-08-06T20:44:51.948Z","author":"pi-agent","author_source":"asserted","agent_harness":"pi","agent_model":"glm-5.2:cloud","agent_model_source":"environment","agent_instance":"549ee0e9d5103407c0b3bd52","agent_provenance":{"model":{"value":"glm-5.2:cloud","source":"environment"},"effort":null,"role":null,"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-github-eh1h"},{"op":"add","path":"/metadata/title","value":"Gate CI on pm health so a silently discarded peer edit cannot merge"},{"op":"add","path":"/metadata/description","value":""},{"op":"add","path":"/metadata/type","value":"Chore"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":[]},{"op":"add","path":"/metadata/created_at","value":"2026-08-06T20:44:51.948Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-08-06T20:44:51.948Z"},{"op":"add","path":"/metadata/author","value":"pi-agent"},{"op":"add","path":"/metadata/acceptance_criteria","value":"CI workflow runs ./node_modules/.bin/pm health --strict-exit in a step immediately after Install dependencies; the step fails non-zero when integrity.counts.pending_merge_decisions is non-zero; pm validate is NOT used because it returns ok:true on a marker-free field-aware merge that silently dropped a peer edit"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"d755c81f334bcdf4c44d5d6294f6fce46e1ae2352050e5ac74ac56b9c182edbc","message":""} +{"ts":"2026-08-06T20:44:52.365Z","author":"pi-agent","author_source":"asserted","agent_harness":"pi","agent_model":"glm-5.2:cloud","agent_model_source":"environment","agent_instance":"549ee0e9d5103407c0b3bd52","agent_provenance":{"model":{"value":"glm-5.2:cloud","source":"environment"},"effort":null,"role":null,"topic":null},"op":"close","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T20:44:52.365Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-06T20:44:52.355Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-06T20:44:52.355Z"},{"op":"add","path":"/metadata/close_reason","value":"Inserted the Verify pm project integrity and merge safety step into .github/workflows/ci.yml right after Install dependencies, running ./node_modules/.bin/pm health --strict-exit. pm health --strict-exit exits 0 on this repo and was proven to exit 1 on a same-field merge hazard in a throwaway copy where pm validate stayed ok:true."}],"before_hash":"d755c81f334bcdf4c44d5d6294f6fce46e1ae2352050e5ac74ac56b9c182edbc","after_hash":"316537b59febb3cc3d3658d692dfc821f6cf8843f383642cb342f447f54870d9"} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6943671..f8f24f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,6 +43,24 @@ jobs: - name: Install dependencies run: npm ci + - name: Verify pm project integrity and merge safety + shell: bash + run: | + set -euo pipefail + # `pm validate` is deliberately NOT the command here. After a same-field merge + # conflict the field-aware driver writes a marker-free .toon that already holds + # the winning value and records the discarded peer value in a clone-local + # receipt. That file is valid TOON, so `pm validate` returns ok:true while + # another agent's edit has been silently dropped. `pm health` is the only + # surface that goes red, via integrity.counts.pending_merge_decisions. + # + # --strict-exit is load-bearing: a bare `pm health` exits 0 EVEN WHEN ok:false, + # so without this flag the step is a no-op that always passes. + # + # A fresh runner checkout has no merge drivers installed. That is a warn, not a + # failure (upstream GH-815), so this gate does not need `pm merge install`. + ./node_modules/.bin/pm health --strict-exit + - name: Type check run: npm run typecheck diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ecd08a..217f6e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Other + +- Gate CI on pm health so a silently discarded peer edit cannot merge ([pm-github-eh1h](https://github.com/unbraind/pm-github/blob/main/.agents/pm/chores/pm-github-eh1h.toon)) + ## 2026.8.4 - 2026-08-04 ### Fixed From 4916773195371f673a97c109bfc89ecd93cf9e70 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Thu, 6 Aug 2026 23:28:12 +0200 Subject: [PATCH 2/5] Correct the gate's claim: it does not catch discarded peer edits The step and its tracker item both said this gate blocks a merge that silently discarded a peer agent's edit. Verified today that it does not, and cannot as built: merge-decision receipts live in .agents/pm/runtime/, which pm init gitignores, so they are never pushed. On the same commit, the merge-performing clone reports one receipt and exits 1, while a fresh clone - which is what CI checks out - reports zero and exits 0. The pushed history does not disambiguate it either. Both writes are present in timestamp order and the item matches the latest, so history verification reports ok. Filed upstream as unbraind/pm-cli#922; flagged first by Greptile on every PR in this rollout. The step is kept, because what it does catch is real and CI-observable: conflict markers in item and history files, parse failures, invalid history JSON, hash drift, unknown-author events, stale in-progress work and tracked runtime cache files. Only the overstated claim is removed. A gate whose documentation promises more than it delivers is worse than no gate, because it stops people looking for the hazard it does not cover. --- .agents/pm/chores/pm-github-eh1h.toon | 6 ++++-- .agents/pm/history/pm-github-eh1h.jsonl | 2 ++ .github/workflows/ci.yml | 24 +++++++++++++++++------- CHANGELOG.md | 2 +- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/.agents/pm/chores/pm-github-eh1h.toon b/.agents/pm/chores/pm-github-eh1h.toon index 2227bdb..b045c9a 100644 --- a/.agents/pm/chores/pm-github-eh1h.toon +++ b/.agents/pm/chores/pm-github-eh1h.toon @@ -1,15 +1,17 @@ id: pm-github-eh1h -title: Gate CI on pm health so a silently discarded peer edit cannot merge +title: "Gate CI on pm health for tracker integrity (does not cover discarded peer edits, see pm-cli 922)" description: "" type: Chore status: closed priority: 2 tags: [] created_at: "2026-08-06T20:44:51.948Z" -updated_at: "2026-08-06T20:44:52.365Z" +updated_at: "2026-08-06T21:27:18.566Z" closed_at: "2026-08-06T20:44:52.355Z" completed_at: "2026-08-06T20:44:52.355Z" author: pi-agent acceptance_criteria: "CI workflow runs ./node_modules/.bin/pm health --strict-exit in a step immediately after Install dependencies; the step fails non-zero when integrity.counts.pending_merge_decisions is non-zero; pm validate is NOT used because it returns ok:true on a marker-free field-aware merge that silently dropped a peer edit" +notes[1]{created_at,author,text}: + "2026-08-06T21:27:18.017Z","harness:claude-code","CORRECTION 2026-08-06, verified directly rather than reasoned about. This item's original close reason overstated what the gate does, and the CI comment has been rewritten to match reality.\n\nWHAT WAS WRONG. The gate was described as blocking a silently discarded peer edit. It does not, and cannot as currently built. Merge-decision receipts are written to .agents/pm/runtime/, which pm init itself gitignores, so they are never pushed. Measured on the same commit: the clone that performed the merge reports 1 receipt and the strict health check exits 1, while a fresh clone of that exact commit reports 0 receipts and the strict health check exits 0. CI checks out the fresh state, so the discarded edit passes.\n\nTHE PUSHED HISTORY DOES NOT DISAMBIGUATE IT EITHER. The merged history stream contains both writes in timestamp order and the item matches the latest one, so history verification reports current_matches_latest true with matching hashes. From pushed state alone, two concurrent branch edits where one was discarded look exactly like two sequential edits where the second superseded the first.\n\nRECONCILE PUBLISHES THE EVIDENCE BUT DOES NOT MAKE IT GATEABLE. Running merge reconcile appends a merge_reconcile event into tracked history carrying conflict_fields, retained_hash and discarded_hash, so durable evidence can exist. But the strict health check then exits 0 in both clones, and reconcile is optional anyway. There is no configuration in which CI observes the loss.\n\nCREDIT. Greptile flagged this as P1 on every gate PR in the rollout before it merged. Verified independently and filed upstream as pm-cli 922.\n\nWHAT THE GATE ACTUALLY DOES, all observable in a fresh checkout and all worth gating on: conflict markers left in item or history files, item parse failures, invalid history JSON, history hash drift, unknown-author history events, stale in-progress work, and tracked runtime cache files. The strict-exit flag remains load-bearing because a bare health check exits 0 even when not ok.\n\nThe step is kept for that real value. Only the claim was wrong, and a gate whose documentation overstates its guarantee is worse than no gate because it stops people looking for the real hazard." close_reason: "Inserted the Verify pm project integrity and merge safety step into .github/workflows/ci.yml right after Install dependencies, running ./node_modules/.bin/pm health --strict-exit. pm health --strict-exit exits 0 on this repo and was proven to exit 1 on a same-field merge hazard in a throwaway copy where pm validate stayed ok:true." body: "" diff --git a/.agents/pm/history/pm-github-eh1h.jsonl b/.agents/pm/history/pm-github-eh1h.jsonl index 7dfb69c..af9fa31 100644 --- a/.agents/pm/history/pm-github-eh1h.jsonl +++ b/.agents/pm/history/pm-github-eh1h.jsonl @@ -1,2 +1,4 @@ {"ts":"2026-08-06T20:44:51.948Z","author":"pi-agent","author_source":"asserted","agent_harness":"pi","agent_model":"glm-5.2:cloud","agent_model_source":"environment","agent_instance":"549ee0e9d5103407c0b3bd52","agent_provenance":{"model":{"value":"glm-5.2:cloud","source":"environment"},"effort":null,"role":null,"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-github-eh1h"},{"op":"add","path":"/metadata/title","value":"Gate CI on pm health so a silently discarded peer edit cannot merge"},{"op":"add","path":"/metadata/description","value":""},{"op":"add","path":"/metadata/type","value":"Chore"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":[]},{"op":"add","path":"/metadata/created_at","value":"2026-08-06T20:44:51.948Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-08-06T20:44:51.948Z"},{"op":"add","path":"/metadata/author","value":"pi-agent"},{"op":"add","path":"/metadata/acceptance_criteria","value":"CI workflow runs ./node_modules/.bin/pm health --strict-exit in a step immediately after Install dependencies; the step fails non-zero when integrity.counts.pending_merge_decisions is non-zero; pm validate is NOT used because it returns ok:true on a marker-free field-aware merge that silently dropped a peer edit"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"d755c81f334bcdf4c44d5d6294f6fce46e1ae2352050e5ac74ac56b9c182edbc","message":""} {"ts":"2026-08-06T20:44:52.365Z","author":"pi-agent","author_source":"asserted","agent_harness":"pi","agent_model":"glm-5.2:cloud","agent_model_source":"environment","agent_instance":"549ee0e9d5103407c0b3bd52","agent_provenance":{"model":{"value":"glm-5.2:cloud","source":"environment"},"effort":null,"role":null,"topic":null},"op":"close","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T20:44:52.365Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-06T20:44:52.355Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-06T20:44:52.355Z"},{"op":"add","path":"/metadata/close_reason","value":"Inserted the Verify pm project integrity and merge safety step into .github/workflows/ci.yml right after Install dependencies, running ./node_modules/.bin/pm health --strict-exit. pm health --strict-exit exits 0 on this repo and was proven to exit 1 on a same-field merge hazard in a throwaway copy where pm validate stayed ok:true."}],"before_hash":"d755c81f334bcdf4c44d5d6294f6fce46e1ae2352050e5ac74ac56b9c182edbc","after_hash":"316537b59febb3cc3d3658d692dfc821f6cf8843f383642cb342f447f54870d9"} +{"ts":"2026-08-06T21:27:18.017Z","author":"harness:claude-code","author_source":"asserted","agent_harness":"claude-code","agent_instance":"db7a36e250bba74236c8424b","agent_provenance":{"model":null,"effort":{"value":"xhigh","source":"environment"},"role":{"value":"1","source":"environment"},"topic":null},"op":"note_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T21:27:18.017Z"},{"op":"add","path":"/metadata/notes","value":[{"created_at":"2026-08-06T21:27:18.017Z","author":"harness:claude-code","text":"CORRECTION 2026-08-06, verified directly rather than reasoned about. This item's original close reason overstated what the gate does, and the CI comment has been rewritten to match reality.\n\nWHAT WAS WRONG. The gate was described as blocking a silently discarded peer edit. It does not, and cannot as currently built. Merge-decision receipts are written to .agents/pm/runtime/, which pm init itself gitignores, so they are never pushed. Measured on the same commit: the clone that performed the merge reports 1 receipt and the strict health check exits 1, while a fresh clone of that exact commit reports 0 receipts and the strict health check exits 0. CI checks out the fresh state, so the discarded edit passes.\n\nTHE PUSHED HISTORY DOES NOT DISAMBIGUATE IT EITHER. The merged history stream contains both writes in timestamp order and the item matches the latest one, so history verification reports current_matches_latest true with matching hashes. From pushed state alone, two concurrent branch edits where one was discarded look exactly like two sequential edits where the second superseded the first.\n\nRECONCILE PUBLISHES THE EVIDENCE BUT DOES NOT MAKE IT GATEABLE. Running merge reconcile appends a merge_reconcile event into tracked history carrying conflict_fields, retained_hash and discarded_hash, so durable evidence can exist. But the strict health check then exits 0 in both clones, and reconcile is optional anyway. There is no configuration in which CI observes the loss.\n\nCREDIT. Greptile flagged this as P1 on every gate PR in the rollout before it merged. Verified independently and filed upstream as pm-cli 922.\n\nWHAT THE GATE ACTUALLY DOES, all observable in a fresh checkout and all worth gating on: conflict markers left in item or history files, item parse failures, invalid history JSON, history hash drift, unknown-author history events, stale in-progress work, and tracked runtime cache files. The strict-exit flag remains load-bearing because a bare health check exits 0 even when not ok.\n\nThe step is kept for that real value. Only the claim was wrong, and a gate whose documentation overstates its guarantee is worse than no gate because it stops people looking for the real hazard."}]}],"before_hash":"316537b59febb3cc3d3658d692dfc821f6cf8843f383642cb342f447f54870d9","after_hash":"72c2d363ab031ca653445a8e7e987b1828f02bbc3cec8d001914ff9db4653a97"} +{"ts":"2026-08-06T21:27:18.566Z","author":"harness:claude-code","author_source":"asserted","agent_harness":"claude-code","agent_instance":"db7a36e250bba74236c8424b","agent_provenance":{"model":null,"effort":{"value":"xhigh","source":"environment"},"role":{"value":"1","source":"environment"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T21:27:18.566Z"},{"op":"replace","path":"/metadata/title","value":"Gate CI on pm health for tracker integrity (does not cover discarded peer edits, see pm-cli 922)"}],"before_hash":"72c2d363ab031ca653445a8e7e987b1828f02bbc3cec8d001914ff9db4653a97","after_hash":"bf639dcf61fd5ed77bcca9b9604fd681e98e32f0623de285071ccc8403127f02"} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8f24f2..e992704 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,16 +43,26 @@ jobs: - name: Install dependencies run: npm ci - - name: Verify pm project integrity and merge safety + - name: Verify pm tracker integrity shell: bash run: | set -euo pipefail - # `pm validate` is deliberately NOT the command here. After a same-field merge - # conflict the field-aware driver writes a marker-free .toon that already holds - # the winning value and records the discarded peer value in a clone-local - # receipt. That file is valid TOON, so `pm validate` returns ok:true while - # another agent's edit has been silently dropped. `pm health` is the only - # surface that goes red, via integrity.counts.pending_merge_decisions. + # WHAT THIS CATCHES, all visible in a fresh checkout: conflict markers left in + # item or history files, item parse failures, invalid history JSON, history hash + # drift, unknown-author history events, stale in-progress work, and tracked + # runtime cache files. + # + # WHAT THIS DOES NOT CATCH - stated explicitly so nobody relies on it. It does + # NOT detect a merge that silently discarded a peer agent's edit. When two + # branches edit the same scalar field, the field-aware driver keeps one value and + # records the discarded one in a merge receipt under .agents/pm/runtime/, which + # `pm init` gitignores, so the receipt is never pushed. A fresh checkout of that + # commit reports zero pending decisions and this step exits 0 - verified + # directly, not assumed. The pushed history does not disambiguate it either: + # both writes are present in timestamp order and the item matches the latest, so + # `pm history --verify` reports ok too. Tracked upstream as + # unbraind/pm-cli#922. Do not add a comment here claiming merge safety until + # that is closed. # # --strict-exit is load-bearing: a bare `pm health` exits 0 EVEN WHEN ok:false, # so without this flag the step is a no-op that always passes. diff --git a/CHANGELOG.md b/CHANGELOG.md index 217f6e0..760613b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Other -- Gate CI on pm health so a silently discarded peer edit cannot merge ([pm-github-eh1h](https://github.com/unbraind/pm-github/blob/main/.agents/pm/chores/pm-github-eh1h.toon)) +- Gate CI on pm health for tracker integrity (does not cover discarded peer edits, see pm-cli 922) ([pm-github-eh1h](https://github.com/unbraind/pm-github/blob/main/.agents/pm/chores/pm-github-eh1h.toon)) ## 2026.8.4 - 2026-08-04 From 9cb20bce58d791f67303ddee99b775d168df92d1 Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Thu, 6 Aug 2026 23:52:08 +0200 Subject: [PATCH 3/5] fix(ci): scope pm health gate to durable tracker state --- .agents/pm/chores/pm-github-eh1h.toon | 23 ++++++++++++++++++----- .agents/pm/history/pm-github-eh1h.jsonl | 2 ++ .github/workflows/ci.yml | 21 +++++++++------------ CHANGELOG.md | 2 +- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/.agents/pm/chores/pm-github-eh1h.toon b/.agents/pm/chores/pm-github-eh1h.toon index 2227bdb..255c280 100644 --- a/.agents/pm/chores/pm-github-eh1h.toon +++ b/.agents/pm/chores/pm-github-eh1h.toon @@ -1,15 +1,28 @@ id: pm-github-eh1h -title: Gate CI on pm health so a silently discarded peer edit cannot merge -description: "" +title: Gate CI on strict tracked pm project health +description: "Run pm health --strict-exit in CI to reject durable tracker-health failures. The fresh runner cannot inspect clone-local merge receipts; pm-cli#921 tracks the remaining attestation gap, so receipt reconciliation stays a local pre-push responsibility." type: Chore status: closed priority: 2 tags: [] created_at: "2026-08-06T20:44:51.948Z" -updated_at: "2026-08-06T20:44:52.365Z" +updated_at: "2026-08-06T21:50:45.430Z" closed_at: "2026-08-06T20:44:52.355Z" completed_at: "2026-08-06T20:44:52.355Z" author: pi-agent -acceptance_criteria: "CI workflow runs ./node_modules/.bin/pm health --strict-exit in a step immediately after Install dependencies; the step fails non-zero when integrity.counts.pending_merge_decisions is non-zero; pm validate is NOT used because it returns ok:true on a marker-free field-aware merge that silently dropped a peer edit" -close_reason: "Inserted the Verify pm project integrity and merge safety step into .github/workflows/ci.yml right after Install dependencies, running ./node_modules/.bin/pm health --strict-exit. pm health --strict-exit exits 0 on this repo and was proven to exit 1 on a same-field merge hazard in a throwaway copy where pm validate stayed ok:true." +acceptance_criteria: "CI runs pm health --strict-exit immediately after dependency installation; clean durable repository state exits 0; tracked history, attribution, cache, extension, or available merge-evidence failures block CI; documentation does not claim fresh CI can inspect clone-local receipts" +resolution: Added a strict tracked-state health gate and corrected the merge-safety boundary after exact reviewer feedback. +expected_result: CI rejects durable pm project-health failures without overstating coverage of clone-local merge receipts. +actual_result: "Package health passes locally. Published pm 2026.8.6 black-box proof showed pending receipts disappear in a fresh clone, durable history drift blocks the unrepaired merge, and history-repair can erase that last CI signal; upstream pm-cli#921 records the gap." +notes[1]{created_at,author,text}: + "2026-08-06T21:21:14.406Z",codex,"Greptile P1 was valid as a scope correction: a fresh checkout cannot inspect .git-local receipts. The gate remains useful for durable health and catches unrepaired lossy merges through history drift,but it is not a complete no-loss guarantee." +tests[2]: + - command: "npm run release:check" + scope: project + - command: pm health --strict-exit + scope: project + timeout_seconds: 120 +docs[1]{path,scope,note}: + "https://github.com/unbraind/pm-cli/issues/921",global,upstream durable merge-attestation gap +close_reason: "Added the CI tracked-state health gate, corrected workflow and changelog language after Greptile identified the fresh-clone receipt boundary, retained local receipt reconciliation as a pre-push requirement, and filed pm-cli#921 with 2026.8.6 black-box evidence." body: "" diff --git a/.agents/pm/history/pm-github-eh1h.jsonl b/.agents/pm/history/pm-github-eh1h.jsonl index 7dfb69c..bed9b99 100644 --- a/.agents/pm/history/pm-github-eh1h.jsonl +++ b/.agents/pm/history/pm-github-eh1h.jsonl @@ -1,2 +1,4 @@ {"ts":"2026-08-06T20:44:51.948Z","author":"pi-agent","author_source":"asserted","agent_harness":"pi","agent_model":"glm-5.2:cloud","agent_model_source":"environment","agent_instance":"549ee0e9d5103407c0b3bd52","agent_provenance":{"model":{"value":"glm-5.2:cloud","source":"environment"},"effort":null,"role":null,"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-github-eh1h"},{"op":"add","path":"/metadata/title","value":"Gate CI on pm health so a silently discarded peer edit cannot merge"},{"op":"add","path":"/metadata/description","value":""},{"op":"add","path":"/metadata/type","value":"Chore"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":[]},{"op":"add","path":"/metadata/created_at","value":"2026-08-06T20:44:51.948Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-08-06T20:44:51.948Z"},{"op":"add","path":"/metadata/author","value":"pi-agent"},{"op":"add","path":"/metadata/acceptance_criteria","value":"CI workflow runs ./node_modules/.bin/pm health --strict-exit in a step immediately after Install dependencies; the step fails non-zero when integrity.counts.pending_merge_decisions is non-zero; pm validate is NOT used because it returns ok:true on a marker-free field-aware merge that silently dropped a peer edit"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"d755c81f334bcdf4c44d5d6294f6fce46e1ae2352050e5ac74ac56b9c182edbc","message":""} {"ts":"2026-08-06T20:44:52.365Z","author":"pi-agent","author_source":"asserted","agent_harness":"pi","agent_model":"glm-5.2:cloud","agent_model_source":"environment","agent_instance":"549ee0e9d5103407c0b3bd52","agent_provenance":{"model":{"value":"glm-5.2:cloud","source":"environment"},"effort":null,"role":null,"topic":null},"op":"close","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T20:44:52.365Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-06T20:44:52.355Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-06T20:44:52.355Z"},{"op":"add","path":"/metadata/close_reason","value":"Inserted the Verify pm project integrity and merge safety step into .github/workflows/ci.yml right after Install dependencies, running ./node_modules/.bin/pm health --strict-exit. pm health --strict-exit exits 0 on this repo and was proven to exit 1 on a same-field merge hazard in a throwaway copy where pm validate stayed ok:true."}],"before_hash":"d755c81f334bcdf4c44d5d6294f6fce46e1ae2352050e5ac74ac56b9c182edbc","after_hash":"316537b59febb3cc3d3658d692dfc821f6cf8843f383642cb342f447f54870d9"} +{"ts":"2026-08-06T21:21:14.430Z","author":"codex","author_source":"asserted","agent_harness":"codex","agent_instance":"f1530d70463641787965c6dc","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/close_reason","value":"Added the CI tracked-state health gate, corrected workflow and changelog language after Greptile identified the fresh-clone receipt boundary, retained local receipt reconciliation as a pre-push requirement, and filed pm-cli#921 with 2026.8.6 black-box evidence."},{"op":"replace","path":"/metadata/acceptance_criteria","value":"CI runs pm health --strict-exit immediately after dependency installation; clean durable repository state exits 0; tracked history, attribution, cache, extension, or available merge-evidence failures block CI; documentation does not claim fresh CI can inspect clone-local receipts"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T21:21:14.430Z"},{"op":"replace","path":"/metadata/description","value":"Run pm health --strict-exit in CI to reject durable tracker-health failures. The fresh runner cannot inspect clone-local merge receipts; pm-cli#921 tracks the remaining attestation gap, so receipt reconciliation stays a local pre-push responsibility."},{"op":"replace","path":"/metadata/title","value":"Gate CI on strict tracked pm project health"},{"op":"add","path":"/metadata/resolution","value":"Added a strict tracked-state health gate and corrected the merge-safety boundary after exact reviewer feedback."},{"op":"add","path":"/metadata/expected_result","value":"CI rejects durable pm project-health failures without overstating coverage of clone-local merge receipts."},{"op":"add","path":"/metadata/actual_result","value":"Package health passes locally. Published pm 2026.8.6 black-box proof showed pending receipts disappear in a fresh clone, durable history drift blocks the unrepaired merge, and history-repair can erase that last CI signal; upstream pm-cli#921 records the gap."},{"op":"add","path":"/metadata/notes","value":[{"created_at":"2026-08-06T21:21:14.406Z","author":"codex","text":"Greptile P1 was valid as a scope correction: a fresh checkout cannot inspect .git-local receipts. The gate remains useful for durable health and catches unrepaired lossy merges through history drift,but it is not a complete no-loss guarantee."}]},{"op":"add","path":"/metadata/tests","value":[{"command":"pm health --strict-exit","scope":"project","timeout_seconds":120}]},{"op":"add","path":"/metadata/docs","value":[{"path":"https://github.com/unbraind/pm-cli/issues/921","scope":"global","note":"upstream durable merge-attestation gap"}]}],"before_hash":"316537b59febb3cc3d3658d692dfc821f6cf8843f383642cb342f447f54870d9","after_hash":"3e6b669bdcb0212a18649daff0cc7b83812e45039ba9357e58964bf2147d4ad2","message":"Correct the CI gate contract after fresh-clone black-box proof"} +{"ts":"2026-08-06T21:50:45.430Z","author":"codex","author_source":"asserted","agent_harness":"codex","agent_instance":"f1530d70463641787965c6dc","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"remove","path":"/metadata/tests/0/timeout_seconds"},{"op":"replace","path":"/metadata/tests/0/command","value":"npm run release:check"},{"op":"add","path":"/metadata/tests/1","value":{"command":"pm health --strict-exit","scope":"project","timeout_seconds":120}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T21:50:45.430Z"}],"before_hash":"3e6b669bdcb0212a18649daff0cc7b83812e45039ba9357e58964bf2147d4ad2","after_hash":"451b8d76cf71c0640cc7a57ff5c8733120d36c9ce072618fd74343595a878ff2"} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8f24f2..5ef50c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,22 +43,19 @@ jobs: - name: Install dependencies run: npm ci - - name: Verify pm project integrity and merge safety + - name: Verify tracked pm project health shell: bash run: | set -euo pipefail - # `pm validate` is deliberately NOT the command here. After a same-field merge - # conflict the field-aware driver writes a marker-free .toon that already holds - # the winning value and records the discarded peer value in a clone-local - # receipt. That file is valid TOON, so `pm validate` returns ok:true while - # another agent's edit has been silently dropped. `pm health` is the only - # surface that goes red, via integrity.counts.pending_merge_decisions. + # Gate durable workspace health: history integrity, attribution, tracked caches, + # extension state, and any merge evidence that exists in this checkout. + # `--strict-exit` is required because non-strict health reports findings without + # necessarily failing the shell command. # - # --strict-exit is load-bearing: a bare `pm health` exits 0 EVEN WHEN ok:false, - # so without this flag the step is a no-op that always passes. - # - # A fresh runner checkout has no merge drivers installed. That is a warn, not a - # failure (upstream GH-815), so this gate does not need `pm merge install`. + # This fresh checkout cannot inspect clone-local merge receipts. It can catch an + # unreconciled lossy merge through tracked history drift, but pm-cli#921 documents + # a repair path that can erase that signal. Receipt reconciliation remains a local + # pre-push responsibility until pm provides durable CI-verifiable attestation. ./node_modules/.bin/pm health --strict-exit - name: Type check diff --git a/CHANGELOG.md b/CHANGELOG.md index 217f6e0..040585b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Other -- Gate CI on pm health so a silently discarded peer edit cannot merge ([pm-github-eh1h](https://github.com/unbraind/pm-github/blob/main/.agents/pm/chores/pm-github-eh1h.toon)) +- Gate CI on strict tracked pm project health ([pm-github-eh1h](https://github.com/unbraind/pm-github/blob/main/.agents/pm/chores/pm-github-eh1h.toon)) ## 2026.8.4 - 2026-08-04 From 707bc0c38adb87583eeeac8ff8fb93a140d3a80b Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Fri, 7 Aug 2026 00:04:57 +0200 Subject: [PATCH 4/5] chore(deps): validate gates with pm 2026.8.6 --- .agents/pm/chores/pm-github-eh1h.toon | 9 ++- .agents/pm/history/pm-github-eh1h.jsonl | 2 + package-lock.json | 102 +++++++++++++++++++----- package.json | 4 +- 4 files changed, 95 insertions(+), 22 deletions(-) diff --git a/.agents/pm/chores/pm-github-eh1h.toon b/.agents/pm/chores/pm-github-eh1h.toon index 255c280..9ee0d9c 100644 --- a/.agents/pm/chores/pm-github-eh1h.toon +++ b/.agents/pm/chores/pm-github-eh1h.toon @@ -6,7 +6,7 @@ status: closed priority: 2 tags: [] created_at: "2026-08-06T20:44:51.948Z" -updated_at: "2026-08-06T21:50:45.430Z" +updated_at: "2026-08-06T22:00:22.491Z" closed_at: "2026-08-06T20:44:52.355Z" completed_at: "2026-08-06T20:44:52.355Z" author: pi-agent @@ -14,8 +14,13 @@ acceptance_criteria: "CI runs pm health --strict-exit immediately after dependen resolution: Added a strict tracked-state health gate and corrected the merge-safety boundary after exact reviewer feedback. expected_result: CI rejects durable pm project-health failures without overstating coverage of clone-local merge receipts. actual_result: "Package health passes locally. Published pm 2026.8.6 black-box proof showed pending receipts disappear in a fresh clone, durable history drift blocks the unrepaired merge, and history-repair can erase that last CI signal; upstream pm-cli#921 records the gap." -notes[1]{created_at,author,text}: +notes[2]{created_at,author,text}: "2026-08-06T21:21:14.406Z",codex,"Greptile P1 was valid as a scope correction: a fresh checkout cannot inspect .git-local receipts. The gate remains useful for durable health and catches unrepaired lossy merges through history drift,but it is not a complete no-loss guarantee." + "2026-08-06T22:00:22.491Z",codex,"Refreshed the package's development/runtime lock projection to @unbrained/pm-cli 2026.8.6 and pm-changelog 2026.8.6 where applicable, so the health and changelog gates execute against the current published contracts. Existing peer minima remain compatibility claims, not the tested tool version." +files[3]{path,scope}: + .gitattributes,project + package-lock.json,project + package.json,project tests[2]: - command: "npm run release:check" scope: project diff --git a/.agents/pm/history/pm-github-eh1h.jsonl b/.agents/pm/history/pm-github-eh1h.jsonl index bed9b99..3c4e302 100644 --- a/.agents/pm/history/pm-github-eh1h.jsonl +++ b/.agents/pm/history/pm-github-eh1h.jsonl @@ -2,3 +2,5 @@ {"ts":"2026-08-06T20:44:52.365Z","author":"pi-agent","author_source":"asserted","agent_harness":"pi","agent_model":"glm-5.2:cloud","agent_model_source":"environment","agent_instance":"549ee0e9d5103407c0b3bd52","agent_provenance":{"model":{"value":"glm-5.2:cloud","source":"environment"},"effort":null,"role":null,"topic":null},"op":"close","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T20:44:52.365Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-06T20:44:52.355Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-06T20:44:52.355Z"},{"op":"add","path":"/metadata/close_reason","value":"Inserted the Verify pm project integrity and merge safety step into .github/workflows/ci.yml right after Install dependencies, running ./node_modules/.bin/pm health --strict-exit. pm health --strict-exit exits 0 on this repo and was proven to exit 1 on a same-field merge hazard in a throwaway copy where pm validate stayed ok:true."}],"before_hash":"d755c81f334bcdf4c44d5d6294f6fce46e1ae2352050e5ac74ac56b9c182edbc","after_hash":"316537b59febb3cc3d3658d692dfc821f6cf8843f383642cb342f447f54870d9"} {"ts":"2026-08-06T21:21:14.430Z","author":"codex","author_source":"asserted","agent_harness":"codex","agent_instance":"f1530d70463641787965c6dc","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/close_reason","value":"Added the CI tracked-state health gate, corrected workflow and changelog language after Greptile identified the fresh-clone receipt boundary, retained local receipt reconciliation as a pre-push requirement, and filed pm-cli#921 with 2026.8.6 black-box evidence."},{"op":"replace","path":"/metadata/acceptance_criteria","value":"CI runs pm health --strict-exit immediately after dependency installation; clean durable repository state exits 0; tracked history, attribution, cache, extension, or available merge-evidence failures block CI; documentation does not claim fresh CI can inspect clone-local receipts"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T21:21:14.430Z"},{"op":"replace","path":"/metadata/description","value":"Run pm health --strict-exit in CI to reject durable tracker-health failures. The fresh runner cannot inspect clone-local merge receipts; pm-cli#921 tracks the remaining attestation gap, so receipt reconciliation stays a local pre-push responsibility."},{"op":"replace","path":"/metadata/title","value":"Gate CI on strict tracked pm project health"},{"op":"add","path":"/metadata/resolution","value":"Added a strict tracked-state health gate and corrected the merge-safety boundary after exact reviewer feedback."},{"op":"add","path":"/metadata/expected_result","value":"CI rejects durable pm project-health failures without overstating coverage of clone-local merge receipts."},{"op":"add","path":"/metadata/actual_result","value":"Package health passes locally. Published pm 2026.8.6 black-box proof showed pending receipts disappear in a fresh clone, durable history drift blocks the unrepaired merge, and history-repair can erase that last CI signal; upstream pm-cli#921 records the gap."},{"op":"add","path":"/metadata/notes","value":[{"created_at":"2026-08-06T21:21:14.406Z","author":"codex","text":"Greptile P1 was valid as a scope correction: a fresh checkout cannot inspect .git-local receipts. The gate remains useful for durable health and catches unrepaired lossy merges through history drift,but it is not a complete no-loss guarantee."}]},{"op":"add","path":"/metadata/tests","value":[{"command":"pm health --strict-exit","scope":"project","timeout_seconds":120}]},{"op":"add","path":"/metadata/docs","value":[{"path":"https://github.com/unbraind/pm-cli/issues/921","scope":"global","note":"upstream durable merge-attestation gap"}]}],"before_hash":"316537b59febb3cc3d3658d692dfc821f6cf8843f383642cb342f447f54870d9","after_hash":"3e6b669bdcb0212a18649daff0cc7b83812e45039ba9357e58964bf2147d4ad2","message":"Correct the CI gate contract after fresh-clone black-box proof"} {"ts":"2026-08-06T21:50:45.430Z","author":"codex","author_source":"asserted","agent_harness":"codex","agent_instance":"f1530d70463641787965c6dc","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"remove","path":"/metadata/tests/0/timeout_seconds"},{"op":"replace","path":"/metadata/tests/0/command","value":"npm run release:check"},{"op":"add","path":"/metadata/tests/1","value":{"command":"pm health --strict-exit","scope":"project","timeout_seconds":120}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T21:50:45.430Z"}],"before_hash":"3e6b669bdcb0212a18649daff0cc7b83812e45039ba9357e58964bf2147d4ad2","after_hash":"451b8d76cf71c0640cc7a57ff5c8733120d36c9ce072618fd74343595a878ff2"} +{"ts":"2026-08-06T22:00:22.077Z","author":"codex","author_source":"asserted","agent_harness":"codex","agent_instance":"f1530d70463641787965c6dc","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T22:00:22.077Z"},{"op":"add","path":"/metadata/files","value":[{"path":".gitattributes","scope":"project"},{"path":"package-lock.json","scope":"project"},{"path":"package.json","scope":"project"}]}],"before_hash":"451b8d76cf71c0640cc7a57ff5c8733120d36c9ce072618fd74343595a878ff2","after_hash":"cfcdd831712049582db514417784e400458ce6d0b3cc46beb32584e74f909314"} +{"ts":"2026-08-06T22:00:22.491Z","author":"codex","author_source":"asserted","agent_harness":"codex","agent_instance":"f1530d70463641787965c6dc","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"note_add","patch":[{"op":"add","path":"/metadata/notes/1","value":{"created_at":"2026-08-06T22:00:22.491Z","author":"codex","text":"Refreshed the package's development/runtime lock projection to @unbrained/pm-cli 2026.8.6 and pm-changelog 2026.8.6 where applicable, so the health and changelog gates execute against the current published contracts. Existing peer minima remain compatibility claims, not the tested tool version."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T22:00:22.491Z"}],"before_hash":"cfcdd831712049582db514417784e400458ce6d0b3cc46beb32584e74f909314","after_hash":"88af9586c5efafa808b3cbf92371d1f522f028bcb9f4019eed1628823ebb4cc0"} diff --git a/package-lock.json b/package-lock.json index eadbb43..2ec3b9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,8 @@ "license": "MIT", "devDependencies": { "@types/node": "^26.1.1", - "@unbrained/pm-cli": "^2026.8.3", - "pm-changelog": "^2026.7.25", + "@unbrained/pm-cli": "^2026.8.6", + "pm-changelog": "^2026.8.6", "typescript": "^7.0.2" }, "engines": { @@ -67,6 +67,19 @@ "module-details-from-path": "^1.0.4" } }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -718,9 +731,9 @@ } }, "node_modules/@unbrained/pm-cli": { - "version": "2026.8.3", - "resolved": "https://registry.npmjs.org/@unbrained/pm-cli/-/pm-cli-2026.8.3.tgz", - "integrity": "sha512-Eh/oYOiWfrxdXGqu9AJqebLCyglrVKwp3yXKXOuANIUh2w48ycvwlUEx+leQPX8YjfyOYxX+LsRvkmeyrzSmvw==", + "version": "2026.8.6", + "resolved": "https://registry.npmjs.org/@unbrained/pm-cli/-/pm-cli-2026.8.6.tgz", + "integrity": "sha512-98pay0mtwwcWhc9dORhPo3wAmcXV1E5snPv/QMrSd9CXNhCUB3mwYRf194iYR29ttUSfMfGtrF/G8tjbC+fPKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -730,7 +743,8 @@ "commander": "^15.0.0", "fast-glob": "^3.3.3", "fast-json-patch": "^3.1.1", - "npm-package-arg": "^13.0.2" + "npm-package-arg": "^13.0.2", + "tar": "7.5.22" }, "bin": { "pm": "dist/cli.js", @@ -739,14 +753,6 @@ }, "engines": { "node": ">=22.18.0" - }, - "peerDependencies": { - "typebox": "*" - }, - "peerDependenciesMeta": { - "typebox": { - "optional": true - } } }, "node_modules/astring": { @@ -772,6 +778,16 @@ "node": ">=8" } }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/cjs-module-lexer": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", @@ -1012,6 +1028,29 @@ "node": ">=8.6" } }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/module-details-from-path": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", @@ -1056,9 +1095,9 @@ } }, "node_modules/pm-changelog": { - "version": "2026.8.3", - "resolved": "https://registry.npmjs.org/pm-changelog/-/pm-changelog-2026.8.3.tgz", - "integrity": "sha512-yDnkdHEm85q7Gx0sQpW7BV5AEB+dQ6vmRiHkEK1VYYsDHxLvHf4wzN695zy1XjKs23wo3buCpePQS5k0/zz1hQ==", + "version": "2026.8.6", + "resolved": "https://registry.npmjs.org/pm-changelog/-/pm-changelog-2026.8.6.tgz", + "integrity": "sha512-W9TPsz5PBuK7Uug2GifWmgvPojf3lsAKJAL9D6AAxg9ZuhvZz/2X49FfPzJmQbREzbE6f8TpnVGyk7+DKfgFIQ==", "dev": true, "license": "MIT", "bin": { @@ -1068,7 +1107,7 @@ "node": ">=22.18.0" }, "peerDependencies": { - "@unbrained/pm-cli": ">=2026.7.29" + "@unbrained/pm-cli": ">=2026.8.3" } }, "node_modules/proc-log": { @@ -1181,6 +1220,23 @@ "node": ">=0.10.0" } }, + "node_modules/tar": { + "version": "7.5.22", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1245,6 +1301,16 @@ "engines": { "node": "^20.17.0 || >=22.9.0" } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } } } } diff --git a/package.json b/package.json index 0b36523..1f8956e 100644 --- a/package.json +++ b/package.json @@ -43,8 +43,8 @@ }, "devDependencies": { "@types/node": "^26.1.1", - "@unbrained/pm-cli": "^2026.8.3", - "pm-changelog": "^2026.7.25", + "@unbrained/pm-cli": "^2026.8.6", + "pm-changelog": "^2026.8.6", "typescript": "^7.0.2" }, "keywords": [ From a590780c101cd63d0bcbd863ba86aec41dd2a407 Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Fri, 7 Aug 2026 00:33:32 +0200 Subject: [PATCH 5/5] docs(ci): resolve exact-head health-gate findings --- .agents/pm/chores/pm-github-eh1h.toon | 15 +++++++++------ .agents/pm/history/pm-github-eh1h.jsonl | 3 +++ .github/workflows/ci.yml | 4 ++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.agents/pm/chores/pm-github-eh1h.toon b/.agents/pm/chores/pm-github-eh1h.toon index 022f253..b09d6cf 100644 --- a/.agents/pm/chores/pm-github-eh1h.toon +++ b/.agents/pm/chores/pm-github-eh1h.toon @@ -1,25 +1,27 @@ id: pm-github-eh1h title: Gate CI on strict tracked pm project health -description: "Run pm health --strict-exit in CI to reject durable tracker-health failures. The fresh runner cannot inspect clone-local merge receipts; pm-cli#921 tracks the remaining attestation gap, so receipt reconciliation stays a local pre-push responsibility." +description: Run pm health --strict-exit in CI to reject durable tracker-health failures without claiming lossless merge attestation. pm-cli#921 covers history-repair erasing a durable drift signal; pm-cli#922 covers a lossy merge shape whose fresh clone is already green because receipts are local and tracked history resembles sequential edits. type: Chore status: closed priority: 2 tags: [] created_at: "2026-08-06T20:44:51.948Z" -updated_at: "2026-08-06T22:00:22.491Z" +updated_at: "2026-08-06T22:32:19.477Z" closed_at: "2026-08-06T20:44:52.355Z" completed_at: "2026-08-06T20:44:52.355Z" author: pi-agent acceptance_criteria: "CI runs pm health --strict-exit immediately after dependency installation; clean durable repository state exits 0; tracked history, attribution, cache, extension, or available merge-evidence failures block CI; documentation does not claim fresh CI can inspect clone-local receipts" resolution: Added a strict tracked-state health gate and corrected the merge-safety boundary after exact reviewer feedback. expected_result: CI rejects durable pm project-health failures without overstating coverage of clone-local merge receipts. -actual_result: "Package health passes locally. Published pm 2026.8.6 black-box proof showed pending receipts disappear in a fresh clone, durable history drift blocks the unrepaired merge, and history-repair can erase that last CI signal; upstream pm-cli#921 records the gap." +actual_result: "Package health and release checks pass with pm 2026.8.6. Black-box proofs establish two distinct blind spots: #921 shows repair can erase the last durable signal, while #922 shows a directly green fresh-clone shape; local receipt review remains mandatory." notes[3]{created_at,author,text}: "2026-08-06T21:21:14.406Z",codex,"Greptile P1 was valid as a scope correction: a fresh checkout cannot inspect .git-local receipts. The gate remains useful for durable health and catches unrepaired lossy merges through history drift,but it is not a complete no-loss guarantee." "2026-08-06T21:27:18.017Z","harness:claude-code","CORRECTION 2026-08-06, verified directly rather than reasoned about. This item's original close reason overstated what the gate does, and the CI comment has been rewritten to match reality.\n\nWHAT WAS WRONG. The gate was described as blocking a silently discarded peer edit. It does not, and cannot as currently built. Merge-decision receipts are written to .agents/pm/runtime/, which pm init itself gitignores, so they are never pushed. Measured on the same commit: the clone that performed the merge reports 1 receipt and the strict health check exits 1, while a fresh clone of that exact commit reports 0 receipts and the strict health check exits 0. CI checks out the fresh state, so the discarded edit passes.\n\nTHE PUSHED HISTORY DOES NOT DISAMBIGUATE IT EITHER. The merged history stream contains both writes in timestamp order and the item matches the latest one, so history verification reports current_matches_latest true with matching hashes. From pushed state alone, two concurrent branch edits where one was discarded look exactly like two sequential edits where the second superseded the first.\n\nRECONCILE PUBLISHES THE EVIDENCE BUT DOES NOT MAKE IT GATEABLE. Running merge reconcile appends a merge_reconcile event into tracked history carrying conflict_fields, retained_hash and discarded_hash, so durable evidence can exist. But the strict health check then exits 0 in both clones, and reconcile is optional anyway. There is no configuration in which CI observes the loss.\n\nCREDIT. Greptile flagged this as P1 on every gate PR in the rollout before it merged. Verified independently and filed upstream as pm-cli 922.\n\nWHAT THE GATE ACTUALLY DOES, all observable in a fresh checkout and all worth gating on: conflict markers left in item or history files, item parse failures, invalid history JSON, history hash drift, unknown-author history events, stale in-progress work, and tracked runtime cache files. The strict-exit flag remains load-bearing because a bare health check exits 0 even when not ok.\n\nThe step is kept for that real value. Only the claim was wrong, and a gate whose documentation overstates its guarantee is worse than no gate because it stops people looking for the real hazard." "2026-08-06T22:00:22.491Z",codex,"Refreshed the package's development/runtime lock projection to @unbrained/pm-cli 2026.8.6 and pm-changelog 2026.8.6 where applicable, so the health and changelog gates execute against the current published contracts. Existing peer minima remain compatibility claims, not the tested tool version." -files[3]{path,scope}: +files[5]{path,scope}: .gitattributes,project + .github/workflows/ci.yml,project + CHANGELOG.md,project package-lock.json,project package.json,project tests[2]: @@ -28,7 +30,8 @@ tests[2]: - command: pm health --strict-exit scope: project timeout_seconds: 120 -docs[1]{path,scope,note}: +docs[2]{path,scope,note}: "https://github.com/unbraind/pm-cli/issues/921",global,upstream durable merge-attestation gap -close_reason: "Added the CI tracked-state health gate, corrected workflow and changelog language after Greptile identified the fresh-clone receipt boundary, retained local receipt reconciliation as a pre-push requirement, and filed pm-cli#921 with 2026.8.6 black-box evidence." + "https://github.com/unbraind/pm-cli/issues/922",global,direct fresh-clone receipt and sequential-looking history shape +close_reason: "Added the tracked-state health gate, corrected its boundary after bot review, linked both distinct upstream blind spots (#921 repair bypass and #922 directly green fresh-clone shape), recorded every affected file, and retained local receipt reconciliation as a pre-push requirement." body: "" diff --git a/.agents/pm/history/pm-github-eh1h.jsonl b/.agents/pm/history/pm-github-eh1h.jsonl index 048f3b3..bbb20e5 100644 --- a/.agents/pm/history/pm-github-eh1h.jsonl +++ b/.agents/pm/history/pm-github-eh1h.jsonl @@ -7,3 +7,6 @@ {"ts":"2026-08-06T22:00:22.077Z","author":"codex","author_source":"asserted","agent_harness":"codex","agent_instance":"f1530d70463641787965c6dc","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T22:00:22.077Z"},{"op":"add","path":"/metadata/files","value":[{"path":".gitattributes","scope":"project"},{"path":"package-lock.json","scope":"project"},{"path":"package.json","scope":"project"}]}],"before_hash":"6e8af979cfc609ec230065ced31592dbf11faa3b40e0afda4b805856ed23ebb9","after_hash":"232b1622591d59e550a4b6be7a2a3e3c813e141358ffc7a57bf353007009bc49"} {"ts":"2026-08-06T22:00:22.491Z","author":"codex","author_source":"asserted","agent_harness":"codex","agent_instance":"f1530d70463641787965c6dc","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"note_add","patch":[{"op":"add","path":"/metadata/notes/1","value":{"created_at":"2026-08-06T22:00:22.491Z","author":"codex","text":"Refreshed the package's development/runtime lock projection to @unbrained/pm-cli 2026.8.6 and pm-changelog 2026.8.6 where applicable, so the health and changelog gates execute against the current published contracts. Existing peer minima remain compatibility claims, not the tested tool version."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T22:00:22.491Z"}],"before_hash":"232b1622591d59e550a4b6be7a2a3e3c813e141358ffc7a57bf353007009bc49","after_hash":"09425406cbb6a689f7f3326d60b590a44fc25c3f7689f59bcc196d433ab43ae6"} {"ts":"2026-08-06T22:22:02.721Z","author":"codex","op":"merge_reconcile","patch":[{"op":"replace","path":"/metadata/notes/1/text","value":"CORRECTION 2026-08-06, verified directly rather than reasoned about. This item's original close reason overstated what the gate does, and the CI comment has been rewritten to match reality.\n\nWHAT WAS WRONG. The gate was described as blocking a silently discarded peer edit. It does not, and cannot as currently built. Merge-decision receipts are written to .agents/pm/runtime/, which pm init itself gitignores, so they are never pushed. Measured on the same commit: the clone that performed the merge reports 1 receipt and the strict health check exits 1, while a fresh clone of that exact commit reports 0 receipts and the strict health check exits 0. CI checks out the fresh state, so the discarded edit passes.\n\nTHE PUSHED HISTORY DOES NOT DISAMBIGUATE IT EITHER. The merged history stream contains both writes in timestamp order and the item matches the latest one, so history verification reports current_matches_latest true with matching hashes. From pushed state alone, two concurrent branch edits where one was discarded look exactly like two sequential edits where the second superseded the first.\n\nRECONCILE PUBLISHES THE EVIDENCE BUT DOES NOT MAKE IT GATEABLE. Running merge reconcile appends a merge_reconcile event into tracked history carrying conflict_fields, retained_hash and discarded_hash, so durable evidence can exist. But the strict health check then exits 0 in both clones, and reconcile is optional anyway. There is no configuration in which CI observes the loss.\n\nCREDIT. Greptile flagged this as P1 on every gate PR in the rollout before it merged. Verified independently and filed upstream as pm-cli 922.\n\nWHAT THE GATE ACTUALLY DOES, all observable in a fresh checkout and all worth gating on: conflict markers left in item or history files, item parse failures, invalid history JSON, history hash drift, unknown-author history events, stale in-progress work, and tracked runtime cache files. The strict-exit flag remains load-bearing because a bare health check exits 0 even when not ok.\n\nThe step is kept for that real value. Only the claim was wrong, and a gate whose documentation overstates its guarantee is worse than no gate because it stops people looking for the real hazard."},{"op":"replace","path":"/metadata/notes/1/author","value":"harness:claude-code"},{"op":"replace","path":"/metadata/notes/1/created_at","value":"2026-08-06T21:27:18.017Z"},{"op":"replace","path":"/metadata/notes/0/text","value":"Greptile P1 was valid as a scope correction: a fresh checkout cannot inspect .git-local receipts. The gate remains useful for durable health and catches unrepaired lossy merges through history drift,but it is not a complete no-loss guarantee."},{"op":"replace","path":"/metadata/notes/0/author","value":"codex"},{"op":"replace","path":"/metadata/notes/0/created_at","value":"2026-08-06T21:21:14.406Z"},{"op":"add","path":"/metadata/notes/2","value":{"created_at":"2026-08-06T22:00:22.491Z","author":"codex","text":"Refreshed the package's development/runtime lock projection to @unbrained/pm-cli 2026.8.6 and pm-changelog 2026.8.6 where applicable, so the health and changelog gates execute against the current published contracts. Existing peer minima remain compatibility claims, not the tested tool version."}},{"op":"replace","path":"/metadata/title","value":"Gate CI on strict tracked pm project health"}],"before_hash":"09425406cbb6a689f7f3326d60b590a44fc25c3f7689f59bcc196d433ab43ae6","after_hash":"9b62a3b0297ff7982a01d9b0e216fc5497b20f5cb3809cd40678bf99c89d4796","message":"Reconcile concurrent CI health-gate corrections; retain the tracked-health title and preserve both verification notes.","context":{"merge":{"receipts":[{"receipt_id":"56a58997-ff7c-451b-bb06-1a7c10a76426","item_id":"pm-github-eh1h","item_path":".agents/pm/chores/pm-github-eh1h.toon","conflict_fields":["title"],"fields_from_theirs":[],"union_fields":["notes"],"preferred":"ours","decisions":[{"field":"title","retained_hash":"6e2cb795a02ef2c0855ea5d7fc45290809683f5d1f83a76377fcd99b3097a7b6","discarded_hash":"55081b31c9da7e54d0cc27e76fde64b73a7188ce3c2fce9f824ada324e5b8dcf"}]}]}}} +{"ts":"2026-08-06T22:32:18.584Z","author":"codex","author_source":"asserted","agent_harness":"codex","agent_instance":"f1530d70463641787965c6dc","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/2/path","value":"CHANGELOG.md"},{"op":"replace","path":"/metadata/files/1/path","value":".github/workflows/ci.yml"},{"op":"add","path":"/metadata/files/3","value":{"path":"package-lock.json","scope":"project"}},{"op":"add","path":"/metadata/files/4","value":{"path":"package.json","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T22:32:18.584Z"}],"before_hash":"9b62a3b0297ff7982a01d9b0e216fc5497b20f5cb3809cd40678bf99c89d4796","after_hash":"f121c27b9b1610ac89868e220684ec94cf579c62d507f92352931e855ecf4ec9"} +{"ts":"2026-08-06T22:32:19.039Z","author":"codex","author_source":"asserted","agent_harness":"codex","agent_instance":"f1530d70463641787965c6dc","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"docs_add","patch":[{"op":"add","path":"/metadata/docs/1","value":{"path":"https://github.com/unbraind/pm-cli/issues/922","scope":"global","note":"direct fresh-clone receipt and sequential-looking history shape"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T22:32:19.039Z"}],"before_hash":"f121c27b9b1610ac89868e220684ec94cf579c62d507f92352931e855ecf4ec9","after_hash":"de7756a4adddb71e59124adcc5a18853e6bb81bb1f66e645f650e7c0955758a8"} +{"ts":"2026-08-06T22:32:19.477Z","author":"codex","author_source":"asserted","agent_harness":"codex","agent_instance":"f1530d70463641787965c6dc","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/close_reason","value":"Added the tracked-state health gate, corrected its boundary after bot review, linked both distinct upstream blind spots (#921 repair bypass and #922 directly green fresh-clone shape), recorded every affected file, and retained local receipt reconciliation as a pre-push requirement."},{"op":"replace","path":"/metadata/actual_result","value":"Package health and release checks pass with pm 2026.8.6. Black-box proofs establish two distinct blind spots: #921 shows repair can erase the last durable signal, while #922 shows a directly green fresh-clone shape; local receipt review remains mandatory."},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-06T22:32:19.477Z"},{"op":"replace","path":"/metadata/description","value":"Run pm health --strict-exit in CI to reject durable tracker-health failures without claiming lossless merge attestation. pm-cli#921 covers history-repair erasing a durable drift signal; pm-cli#922 covers a lossy merge shape whose fresh clone is already green because receipts are local and tracked history resembles sequential edits."}],"before_hash":"de7756a4adddb71e59124adcc5a18853e6bb81bb1f66e645f650e7c0955758a8","after_hash":"55583649a5a7a1cf3908b4dea94205ea2030b1cf931eddb65a15344fdb7844aa","message":"Address exact-head bot findings about gate scope, upstream issue mapping, and affected-file evidence"} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fca90b2..3b0c6a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,8 +48,8 @@ jobs: run: | set -euo pipefail # Catch durable checkout-visible failures: conflict markers, parse failures, - # invalid or drifted history, attribution failures, tracked runtime caches, - # extension health, and any merge evidence present in this clone. + # invalid or drifted history, tracked runtime caches, extension health, + # stale in-progress work, and any merge evidence present in this clone. # # This is not a lossless-merge attestation. Merge receipts are clone-local and # absent from a fresh CI checkout. Some unreconciled loss shapes surface as