docs(backlog): file the shared-scratchpad commit-message hazard (BACKLOG #1440) - #849
Conversation
…LOG #1440) A session wrote a commit message to <scratchpad>/msg1.txt and ran `git commit -F` against it. A concurrent agent overwrote the file in between, so the commit would have carried another item's subject. The claim gate refused it, catching a defect it was not built for. The original framing said concurrent SESSIONS share the directory. They do not: the UUID segment partitions top-level sessions, one slug carrying 209 of them. What shares it is a session and every subagent it spawns -- confirmed by spawning one, which quoted this session's exact path from its own system prompt and read back a marker only the parent had written. The isolation is asymmetric: subagents get their own worktree, branch and .venv, so every cheap signal says isolated while the shared directory is the one advertised as private. CLAUDE.md sec. 5 now says to write the message inside your own worktree, names the scratchpad as the wrong place, and gives the reason. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A peer seat reviewing the row listed three candidate sharing conditions. Two were already measured and named: same-worktree sessions cannot collide because the UUID partitions them, and subagents inheriting the parent path is the measured cause. The third, a resumed session reusing its UUID, was not measured and is now recorded as an open candidate. It cannot produce the observed failure, since a session is not concurrent with itself. Also records how to reproduce, because the first framing did not. A reader who lists their own project directory finds one UUID and correctly concludes nothing is shared between seats; that is not a refutation, because the collision is inside one session. The reproduction is to write a marker and spawn a subagent to list the same directory. States why the two colliding paths are not published: they carry a host account name and worktree slugs, which the forbidden-content gate blocks and which its own message says to remove rather than allowlist. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…o #1440 A peer manager seat observed the same sharing from the parent side, without running an experiment: it listed its own scratchpad after four hours of ordinary work and found 22 files, one of which it had written. At least five agents it had spawned deposited the rest. Two things that adds. Those builders each ran in their own git worktree on their own branch and still wrote into the parent's scratchpad, so the row's asymmetry claim is now observed at n=5 rather than inferred at n=1. And a near miss on a generic filename that is not a commit message: one fullsuite.log existed while at least two builders reported running full suites. Whether one overwrote the other is not established and is not claimed; the collision surface is. Also records this as the reproduction most readers should use. Measurement A needs a subagent spawned deliberately. This needs ls. The peer's measured/inferred boundary is preserved: the listing and mtimes are measured, the per-agent attribution is inferred from filenames. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
main took ten commits touching docs/BACKLOG.md while this branch was held, and both sides append at the tail, so the file conflicted. Resolved by taking main's file whole and re-appending the #1440 block after #1439. No existing item was edited and no line above #1440 differs from main. CLAUDE.md merged without conflict: main has not touched that file since this branch's base. Verified after resolution: no conflict markers remain, backlog_status_check reports 429 items in the live ledger each declaring exactly one status, and the leak, dangling-citation and claude-section gates pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Resolved by the Lander. The ledger tail serialising: this branch appends its item, main appended another. Different items, so both sides stand, with main's block in the position it holds on main. Set-difference control over item numbers: nothing lost, nothing invented, no duplicate headings. #1069 is absent because main archived it at 7f97202, not because this merge dropped it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
This pull request is green and nobody has marked it read. Every check that has reported is passing and the To clear it, IN THIS ORDER:
DO NOT TRIAGE THIS FROM A seat can find every pull request in this state in one call: The |
Files one backlog item and narrows one existing CLAUDE.md bullet. No engine code, no test file, no workflow change.
What went wrong
A session wrote a commit message to
<scratchpad>/msg1.txt, then rangit commit -F <scratchpad>/msg1.txt. Between those two steps another agent overwrote that file with its own message, for a different backlog item. The commit would have carried another item's subject and body. The substitution is invisible ingit commit -Foutput.The ledger claim gate refused the commit, because the substituted subject cited a number this worktree did not hold. That gate exists for an unrelated reason, and it is the only reader in the chain that compares the message's content against something the session independently knows about itself.
The original framing was wrong, and the row corrects it
The finding was filed as "concurrent sessions in the same project resolve to one directory". They do not. The session-UUID segment partitions top-level sessions correctly. What it does not partition is a session from its own subagents and background tasks, all of which are handed the same path and told it is "session-specific, isolated".
Three measurements, in the row:
A peer manager seat corroborated this independently at n=5 by listing its own scratchpad after four hours of ordinary work: 22 files, one of them its own, the rest deposited by five agents it had spawned. That is the reproduction most readers should use, because it needs
lsrather than a deliberately spawned subagent.The isolation is asymmetric, which is why the mistake is easy
A subagent gets its own git worktree, branch and
.venv. Every cheap signal it can consult says isolated. The one directory that is actually shared is the one it is told is private.Remedy
Write any file whose content is later fed to a command into your own worktree, under a name that cannot collide, and delete it after. The CLAUDE.md bullet already said "inside the project"; it now says which directory, names the scratchpad as the wrong place, and gives the reason.
The per-worktree git directory looks like the ideal home and is not: it sits under the primary checkout's path, so
worktree_gate.ps1refuses aWritethere. That was found by trying it, after a first draft of both the row and the CLAUDE.md line recommended it.The scratchpad mechanism itself is untouched. It is harness behaviour, not repository behaviour.
Checks run
Run here and passing:
backlog_status_check(429 live items, each declaring exactly one status),forbidden-contentleak scan,dangling_citation_check,backlog_citation_check,claude_section_check,ledger_check, plus the full pre-commit hook set on every commit. Targeted pytest: 143 passed acrosstest_backlog_status_check,test_backlog_citation_check,test_ledger_check,test_link_resolution,test_cp1252_console_safety.Not run here, and needing a reader: every hosted-runner leg. This worktree has no
.venv, so the tests above ran on a sibling interpreter and the extras-gated modules (fhir,dicom,x12,xml,webauthn) were never collected. That is fine for a documentation change and is stated rather than implied.verdict_divergence_checkexits 1 on this branch. It also exits 1 onmain: the three divergent items are #340, #1003 and #1266, all present onmainand untouched here, and this item carries no prose re-score. The script is neither a pre-commit hook nor referenced by any workflow.Conflict resolution
maintook ten commits touchingdocs/BACKLOG.mdwhile this branch was held, and both sides append at the tail. Resolved by takingmain's file whole and re-appending the #1440 block after #1439. No existing item was edited; the diff againstmainisCLAUDE.mdand the new item only.Notes for the reviewer
scripts/coord/alloc.ps1and is claimed by this worktree.🤖 Generated with Claude Code