Problem
The afx spawn duplicate-work guard treats ANY issue comment whose body contains the substring "on it" anywhere as a work claim. Verified at packages/codev/src/agent-farm/commands/spawn-worktree.ts:571-572:
const onItComments = issue.comments.filter((c) =>
c.body.toLowerCase().includes('on it'),
);
Two false positives on one adopter workspace within two days, independently found by two lanes:
- A guard refusal fired on an architect comment whose text read "...receipts before you spend ON IT" — ordinary prose; no assignee, no builder, no branch, no PR on the issue.
- A refusal fired on the spawning architect's OWN takeover comment posted minutes earlier, which the guard read as a competing claim.
Both spawns required --force past a guard protecting nothing.
Why it matters beyond noise
A guard that cries wolf gets --forced reflexively, and then it is no guard at all on the day it is right. (--force also bypasses the dirty-worktree check, so reflexive forcing is doubly corrosive.)
Fix shape (hypothesis, for the builder to validate)
Match a STRUCTURED claim rather than prose. A claim is one of:
Consider also exempting comments authored by the invoking identity (a self-claim is not a collision).
Keep in the fix: the refusal path's semantics are correct
Both field refusals half-created NOTHING — no worktree, no branch, no registration. That fail-closed behavior is the standard the crash-mid-spawn path in #1712 needs to match; do not regress it while reworking the matcher.
Problem
The
afx spawnduplicate-work guard treats ANY issue comment whose body contains the substring "on it" anywhere as a work claim. Verified atpackages/codev/src/agent-farm/commands/spawn-worktree.ts:571-572:Two false positives on one adopter workspace within two days, independently found by two lanes:
Both spawns required
--forcepast a guard protecting nothing.Why it matters beyond noise
A guard that cries wolf gets
--forced reflexively, and then it is no guard at all on the day it is right. (--forcealso bypasses the dirty-worktree check, so reflexive forcing is doubly corrosive.)Fix shape (hypothesis, for the builder to validate)
Match a STRUCTURED claim rather than prose. A claim is one of:
Consider also exempting comments authored by the invoking identity (a self-claim is not a collision).
Keep in the fix: the refusal path's semantics are correct
Both field refusals half-created NOTHING — no worktree, no branch, no registration. That fail-closed behavior is the standard the crash-mid-spawn path in #1712 needs to match; do not regress it while reworking the matcher.