Skip to content

Commit 2274ac0

Browse files
authored
chore(skills): make the work-issues claim protocol race-safe (#1447)
1 parent 18d90ac commit 2274ac0

1 file changed

Lines changed: 36 additions & 2 deletions

File tree

.claude/skills/work-issues/SKILL.md

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,39 @@ Claiming to avoid collision with parallel agents."
139139
(English only — committed/public artifacts are English.) This is mandatory and
140140
comes BEFORE the first edit. It is the issue-level twin of the worktree
141141
DISJOINT-FILE rule (see the "Claim a filed issue before working it" rule in
142-
`CLAUDE.md`). Re-check for a competing claim/PR right before you start; if one
143-
appeared, pick a different issue.
142+
`CLAUDE.md`).
143+
144+
**Claim at SHORTLIST time, not after the analysis.** Claim the moment an issue
145+
enters your candidate set — before the deep read of its body, before mapping
146+
which files it lands in. Retracting a claim you then decided against costs one
147+
comment; a collision costs a whole lane. The window this closes is the one that
148+
actually bites: two sessions can each spend minutes triaging in total mutual
149+
invisibility, because neither has posted anything yet.
150+
151+
**Then VERIFY the claim stuck (compare-and-swap).** Posting is not winning —
152+
another session may have posted seconds earlier. Immediately re-read the issue
153+
and check for a competing claim:
154+
155+
```bash
156+
gh issue view <n> --json comments \
157+
--jq '.comments[] | select(.body | test("Working on this")) | "\(.createdAt)\t\(.body[0:80])"'
158+
```
159+
160+
**Tie-break: the EARLIEST `createdAt` wins.** If someone else's claim predates
161+
yours, you are the loser of the race — post a short stand-down comment naming
162+
the winning branch, drop the lane, and pick a different issue. Do this without
163+
asking; the whole point is that both sessions independently reach the same
164+
answer from the same timestamps. Escalate to the maintainer only when the
165+
timestamps cannot settle it.
166+
167+
This exists because it has already failed once: two sessions claimed #1419 /
168+
#1435 twenty seconds apart (2026-08-09), both having followed every other rule
169+
in this skill, and it took the maintainer arbitrating to resolve. See #1446.
170+
171+
**Do not trust a handoff table — verify it live.** A "these issues are taken"
172+
note you were handed is a snapshot of the moment it was written; PRs merge and
173+
worktrees disappear. Re-derive occupancy from `gh pr list --state open`,
174+
`git worktree list`, and the issues' own comments before believing any of it.
144175

145176
## 5. One worktree per lane, then implement
146177

@@ -277,6 +308,9 @@ anything non-obvious you learned in memory.
277308

278309
- **Claim before editing, always** — the whole point. An unclaimed lane races a
279310
parallel agent onto the same cross-cutting file.
311+
- **Claiming is not winning.** Posting the comment does not end the race — read
312+
it back and yield to an earlier `createdAt` (§4). Claiming late, after the
313+
triage, is what makes the race winnable in the first place.
280314
- **One lane per cross-cutting file.** `deploy-engine.ts` / `intrinsic-function-resolver.ts`
281315
/ `dag-builder.ts` / `register-providers.ts` absorb most non-trivial fixes; you
282316
cannot parallelize two issues that both land there. Per-provider fixes ARE

0 commit comments

Comments
 (0)