Repository navigation
Description
The only artifact that records "agent A's edit was silently discarded by this merge" is a merge
receipt, and receipts live in the clone-local, gitignored .agents/pm/runtime/. They are never
pushed. A fresh checkout of the exact commit that lost the edit therefore reports zero pending
decisions and passes pm health --strict-exit, so merge safety cannot be enforced in CI at all.
Why this is not obvious
The lossy case is already invisible to normal review: the merged .toon has no conflict markers,
is valid TOON, and already holds the winning value, so pm validate returns ok:true. pm health
is the one surface that goes red — which makes it the natural CI gate. But it only goes red in the
clone that performed the merge.
Reproduction (pm CLI 2026.8.5)
Two branches each set a different title on the same item, then git merge, git add -A,
git commit (the marker-free file stages cleanly):
# in the clone that performed the merge
$ pm merge report --json | jq .count
1
$ pm health --strict-exit ; echo $?
1 # correctly red
# fresh clone of that very same commit
$ git clone <repo> fresh && cd fresh
$ pm merge report --json | jq .count
0 # receipt was never pushed
$ pm health --strict-exit ; echo $?
0 # PASSES - the discarded edit sails through CI
.agents/pm/runtime/ is in the gitignore block pm init itself writes, so this is the default and
intended state of every repo, not a misconfiguration.
The pushed history does not disambiguate it either
The merged history stream contains both writes, ordered by timestamp:
2026-...:26.423Z agent-a ["Renamed by agent A"]
2026-...:27.066Z agent-b ["Renamed by agent B"]
and the item holds agent-b's value, so pm history <id> --verify reports
current_matches_latest: true with matching hashes. From pushed state alone, "two concurrent branch
edits where one was discarded" is indistinguishable from "two sequential edits where the second
superseded the first". Every check is correct in isolation and the loss is still invisible.
pm merge reconcile publishes the evidence but does not make it gateable
pm merge reconcile appends a merge_reconcile event into the tracked history stream carrying the
full decision, including conflict_fields, retained_hash and discarded_hash. That evidence
is pushed and readable in a fresh clone — good. But:
- After reconcile,
pm health --strict-exitexits 0 in both the local and the fresh clone, so the
durable record of a discarded value produces no signal. - Reconcile is optional. A contributor who never runs it pushes a commit that looks clean
everywhere.
So there is no configuration in which CI can observe that an edit was discarded.
Suggested fix
Any one of these would close it:
- Make receipts durable by default — write pending merge decisions into the tracked tracker
(or require reconcile before the tree is considered clean), so the evidence travels with the
commit that caused it. - Give
pm healtha repository-scoped mode that inspects merge commits reachable in git rather
than only clone-local state — for a merge commit, compare each parent against the merge base and
report same-field divergences that the merged item resolved. This is the only signal that
genuinely exists in pushed state. - Surface reconciled-with-discarded-values as a distinct, gateable condition, so a
merge_reconcileevent whosedecisions[]contains adiscarded_hashcan fail a strict gate
until a human or agent explicitly acknowledges the loss.
Related: GH-920 (health counts lossless receipts identically to lossy ones), which compounds this —
the counter is simultaneously too noisy locally and entirely blind in CI.
Observed on pm CLI 2026.8.5. Found when rolling pm health --strict-exit out as a CI gate across a
20-package fleet; the gate was demonstrated to pass a commit that had silently dropped a peer
agent's edit.
Activity
coderabbitai commentedon Aug 6, 2026
🔗 Related PRs
#200 - Add validation self-repair and agent ergonomics primitives [closed]
#614 - SDK-first field-aware merge safety and storage integrity [merged]
#712 - SDK context integrity: atomic Plans, batch similarity, sparse settings, and tombstones [merged]
#758 - Make branch merge decisions recoverable, replayable, and CI-enforced [merged]
#783 - Harden SDK context integrity, merge safety, and agent-efficient output [merged]
📝 Issue Planner
Check the box below or use the
@coderabbitai plancommand to generate an implementation plan and prompts that you can use with your favorite coding assistant.🧪 Issue enrichment is currently in open beta.
You can configure auto-planning by selecting labels in the issue_enrichment configuration.
To disable automatic issue enrichment, add the following to your
.coderabbit.yaml:💬 Have feedback or questions? Drop into our discord!
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim: it does not catch discarded peer edits
Correct the gate's claim and regenerate the changelog in prepend mode
unbraind commentedon Aug 7, 2026
Canonical PM item: pm-1j5j21. This link preserves the implementation lineage, dependencies, decisions, and verification evidence in the project system of record.
docs(pm): connect open GitHub issues to canonical work
docs(pm): connect open GitHub issues to canonical work