Development record
Nothing tells an agent that a record it is about to fix has been claimed or resolved by another session until the resolution gate refuses the push. In one night a peer session re-fixed two issues a paused branch also fixed, and two of its open PRs duplicate merged work. The claim signal that worked in every published multi-agent run is the repository itself: a claim written into the open record (claimed_by: account and harness, branch) and pushed alone through the queue before any fix starts, so a losing race is a push rejection; plus a duplicate-guard required check that fails a PR whose Resolves trailer names a record already resolved on origin/main; plus capture resolve refusing a record that is already terminal on the fetched origin/main. Folder membership is already the status signal, so the claim extends the one canonical primitive rather than adding a lock file that rots. Refines iss-2608220750029993.
Nothing tells an agent that a record it is about to fix has been claimed or resolved by another session until the resolution gate refuses the push. In one night a peer session re-fixed two issues a paused branch also fixed, and two of its open PRs duplicate merged work. The claim signal that worked in every published multi-agent run is the repository itself: a claim written into the open record (claimed_by: account and harness, branch) and pushed alone through the queue before any fix starts, so a losing race is a push rejection; plus a duplicate-guard required check that fails a PR whose Resolves trailer names a record already resolved on origin/main; plus capture resolve refusing a record that is already terminal on the fetched origin/main. Folder membership is already the status signal, so the claim extends the one canonical primitive rather than adding a lock file that rots. Refines iss-2608220750029993.
Grounds
- pursued: we expect a session to be able to tell, before it starts work, that another session has already claimed or resolved the record it is about to fix, so the duplicated effort this record measured stops happening; a claim signal nobody reads, or one that goes stale and blocks a session from work nobody is doing, would show it wrong.
Corroboration (2026-09-18, Gropius managed-repo session gropiusllm-56, relayed
to abcd-17). The sibling-worktree half, split into itd-2609091416295622 on
2026-09-09, was met again at v0.9.0 in a second managed repository: the ledger
is per worktree and says so nowhere. A capture filed in one worktree was
invisible to capture resolve in another until the branch carrying it merged
main (recorded in that repository's own ledger), and an audit agent working from
a worktree that predated a merge reported three shipped intents as existing
nowhere. The session's ask is either of two things the draft intent already
weighs: resolve the store through git rev-parse --git-common-dir and warn, or
have every ledger verb print which checkout's ledger it addressed. Note the
same mechanism produced this batch's "not found in any bucket" diagnosis from
intent audit, which at v0.9.0 does distinguish a draft from a never-minted id
in the same checkout; what it cannot see is a record on another worktree.
Deferral 2026-09-29
Deferred past v0.11.1: Promoted to itd-2609091034175565 (draft), and a promoted issue keeps its folder until the intent ships. The product thinker's ruling M20 of 2026-09-23 plans it next cycle; the interview answers the draft's open questions. Owed: that interview, which opens on one question: where does the claim signal's stop sit, and how is an abandoned claim told from a live one?
Remedy grounds (2026-09-29)
- itd-2609221656373558 (shipped) answers how an abandoned claim is told from a live one inside one account: a lease that lapses and is logged; itd-2609091416295622 (shipped) is the sibling-worktree listing.
- The open question is only whether the stop must reach other machines, where the 2026-09-09 ruling dcn-2609090000000005 prices the pushed claim at a merge-queue pass per claim.
- Rejected: a lock file in the tree, which the record refuses as a primitive that rots.
Frontmatter
| id | iss-2609020716570699 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | major |
.abcd/work/issues/resolved/iss-2609020716570699-nothing-tells-an-agent-that-a-record-it.md
open on GitHub ↗ · commit history ↗
References3
- itd-2609091034175565Before an agent starts on an item, it reserves it on the shared remote, and everyone who works on the project sees the reservationrelated
- itd-2609091416295622A session sees the records its peers hold before it mints or fixes onerelated
- itd-2609091416304128capture resolve refuses a record the default branch has already closed, judged by the last fetchrelated
mentions7
- adr-2610031352212697Claims are branches on the shared remote; nothing kept on one computer is the register; claim text is data
- dcn-26090900000000052026-09-09 — itd-2609091034175565, the claim intent, is split into three records (maintainer, ruling after two adversarial reviews of the widened draft, design/feasibility and record-discipline). The reviews found the expensive parts unsound as drafted: a `claimed_by` stamp on an issue record is invisible to any peer on an older binary, because `issueschema.Known` is a closed allow-list whose reader refuses and skips a record carrying an unknown key and `record_schema` mirrors the refusal into the gate, and version skew is the steady state here (five plugin-cache vintages beside a `go run` checkout); the write-verb refusals fire after the fix is written, because `AGENTS.md` puts `capture resolve` in the same change as the fix; no staleness threshold is safe in both directions for two sessions in one worktree, since the worktree-exists and branch-merged tests are identical for both and a host may fire session-end on a context clear with the human still present; and the pushed half costs a merge-queue pass per claim, measured at fifteen to sixteen minutes on this repository's merge-group `ci` leg. Every collision on record is one of two claim-free shapes. The ruling: itd-2609091416295622 carries the read-only sibling-worktree ledger diff over `git worktree list --porcelain` (no claim, no lease, no hook, no threshold; the piece that ships soonest); itd-2609091416304128 carries `capture resolve` and `capture wontfix` refusing a record terminal at the local `origin/main` ref as last fetched, stating the ref's age and fetching nothing, with the same judgement rendered read-only on `abcd <record-id>`; itd-2609091034175565 keeps the claim, the lease and the refusals as a draft marked not ready, carrying the refusal-surface, liveness and pushed-price questions as open questions and the two-release stamp migration as a hard constraint. The existing record stays the claim so the `promoted_from` trail from iss-2609020716570699 — whose remedy is the claim and the pushed half — stays true rather than being retitled onto a listing the issue never proposed; the two new records reach the issue through `related_intents` on the issue and on themselves, and every relation the schema cannot type is stated in prose as a prose cross-reference (iss-2609091256264547). All three sit in `drafts/`; adoption is the interview's. Rejected: re-scoping the existing record to the listing, which keeps the trail mechanically and breaks it semantically; a fifth relation word for "split from", which is the vague form the decomposition principle forbids.
- iss-2608220750029993Session-presence detection for shared checkouts: each live session leases a marker (session id, intended branch, started-at) in the checkout, and the pre-commit gate warns when another live session's lease is present — the armed-detector rung of the AGENTS.md concurrent-session conventions, which are vigilance-only until this ships. Lease home needs thought: the local tier is per-worktree by design, and the hazard is precisely two sessions in ONE worktree, so the lease belongs to the checkout, not the branch.
- iss-2609202053570475Every ledger verb should name which checkout's ledger it addressed. The ledger is per worktree and says so nowhere: a capture filed in one worktree is invisible to capture resolve in another, and the verb's refusal reads "not found" with no hint that another checkout holds the record. The cheapest always-on remedy, asked for in the 2026-09-18 corroboration on iss-2609020716570699 and routed out of the peer-listing intent by its record-discipline review on 2026-09-20 as a cross-cutting change: one line from every ledger verb (capture, resolve, wontfix, promote, list, the record dispatcher, intent audit) naming the checkout root and branch whose ledger it read or wrote, on stderr in the text render and as a member in --json. Distinct from the peer listing (itd-2609091416295622), which reads other checkouts; this is the verb saying which one it is in.
- itd-2609221656373558Two sessions share one run, and the run measures which way of dividing the work is best
- itd-2610031259176838Outside contributors reserve work through a draft pull request that abcd honours
- spc-2610031753359849Reservations on the shared remote: `abcd reserve`, one liveness judgement, and the build, drain and land integration