Repository navigation
Description
pm delete correctly retains the item's history ledger as a tombstone, but nothing in the tooling can tell you that tombstone exists. No command enumerates it, no diagnostic reports it, and no pm gc scope reclaims it. The only way to discover one is to ls .agents/pm/history/ and diff the basenames against the item directories by hand.
Verified on 2026.7.25 in a clean throwaway workspace.
Reproduction
mkdir /tmp/tomb && cd /tmp/tomb && git init -q .
pm init --pm-path .agents/pm
pm create --title "Residue probe" --type Chore --author probe --pm-path .agents/pm
# -> pm-ladp
pm delete pm-ladp --pm-path .agents/pm --forceThe item file is gone and the ledger remains, with a correctly appended delete op:
$ ls .agents/pm/chores/ .agents/pm/history/
.agents/pm/chores/: # (empty)
.agents/pm/history/: pm-ladp.jsonl _workspace.jsonl
$ python3 -c "import json;[print(json.loads(l)['op']) for l in open('.agents/pm/history/pm-ladp.jsonl')]"
create
delete
So retention is clearly deliberate — that part is right, and this issue is not asking for the ledger to be deleted. The problem is everything else:
| probe | result |
|---|---|
pm show pm-ladp |
item_not_found |
pm history pm-ladp |
works — returns the full create + delete stream |
pm list --status all |
does not include it (correct, but there is no alternative that does) |
pm health --json |
ok: true — every one of the 11 checks passes, no mention |
pm validate --json |
ok: true, no mention |
pm gc --dry-run |
no scope matches; scopes are index, embeddings, runtime, locks, checkpoints, transactions |
pm health output does contain orphaned_paths / orphaned_path_rows keys, but those belong to the vectorization/index check and never populate for a tombstoned history stream — which makes the situation more confusing, not less: an agent that greps health output for "orphan" finds the vocabulary present and concludes the check covers this case.
Why this matters for agents
-
Undiscoverable state. An agent has no supported way to answer "does this workspace contain tombstoned streams?"
pm showdenies the id exists whilepm historyhappily serves it. Two built-in commands disagree about whetherpm-ladpis a thing, and neither mentions the tombstone concept. -
It breaks the documented commit convention. Every pm-CLI-based workflow we run enforces "a
.toonmust be committed together with itshistory/<id>.jsonlsibling". After a delete,git statusshows an untrackedhistory/<id>.jsonlwith no.toon— the inverse case the convention has no answer for. Agents either commit a ledger for an item that does not exist, or delete an intentional audit record. Both are wrong and the tooling gives no signal which is intended. -
Silent unbounded accumulation under multi-agent merge. Tombstone ledgers are append-only files with unique names, so they merge cleanly by construction and never conflict. Across many agents and branches they accumulate indefinitely with no command to list them, no check to count them, and no
gcscope to reclaim them. This is precisely the class of driftpm healthexists to surface. -
pm deletegives no hint. Its output (previous_status,changed_field_count: 1) does not mention that a ledger was retained, so the residue ingit statusreads as a bug in the caller rather than intended behaviour.
Requested
Any one of these would close the discoverability gap; the first is the most useful:
- A
pm healthcheck (or a field on the existingstorage/integritycheck) that counts history streams with no corresponding item file and lists them up to a cap —status: okwith an informational count is fine, since this is legitimate state, not corruption. - A way to enumerate them, e.g.
pm list --tombstonedor atombstonessection inpm health --detail deep. - A
pm gc --scope tombstones(opt-in, never in the default set) for workspaces that do not want to retain deleted-item audit trails, plus aretention_dayssetting alongside the existingcheckpoints.retention_days. - Mention the retained ledger in
pm delete's own output (e.g.history_retained: ".agents/pm/history/<id>.jsonl") so the caller knows the file is intentional and must be committed.
Documenting the tombstone contract in pm delete --help would help regardless of which of the above is chosen: right now the help text says only "Delete an item and record the change in history", which does not convey that the ledger file survives the item.
Activity
coderabbitai commentedon Jul 25, 2026
🔗 Related PRs
#51 - Polish CLI ergonomics, delete safety, and templates dedup [closed]
#200 - Add validation self-repair and agent ergonomics primitives [closed]
#549 - feat(sdk): ship history time travel, rich reads, and runtime integrity [merged]
#568 - Promote SDK governance engines and harden cross-platform release reliability [merged]
#593 - SDK-first agent UX graph, ownership, and recovery contracts [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!
unbraind commentedon Jul 25, 2026
Tracked canonically by
pm-wdrkfr.The PM item records the all-status duplicate check and links the existing delete implementation, storage observability, history namespace, mutation completeness, merge-resurrection, retention-growth, and durability lineages. It remains open, not in progress; this delivery documented the newly surfaced UX gap but did not claim or implement it.
The CodeRabbit related-PR enrichment was useful and received a positive reaction; those historical PRs are context only and do not replace the new tombstone discoverability/retention owner.
chore(pm): track delete tombstone observability