docs(agents): give the claim pre-check its right delimiter, so a card number cannot prefix-match - #18918
Conversation
… number cannot prefix-match The documented one-command pre-check read `git ls-remote --heads origin | grep issue-N` with no right delimiter, so a card number that is a prefix of a longer card number matched that longer card's branch. Measured on `origin` at 2026-09-18T05:43Z: card 186 answered 3 heads (`claude/issue-18612-…`, `-18652-…`, `-18699-…`), none of them card 186, exit 0; card 1811 answered `claude/issue-18116-turso-begintransaction-radius`, card 18116. After: both answer 0 heads and exit 1, while a card that does have a head still answers it (positive control, card 18831: 1 head, exit 0). The delimited grep was chosen over the anchored refspec `refs/heads/claude/issue-N-*` because the refspec form is measurably blind to in-flight heads that do not carry the `claude/issue-` shape: `copilot/fix-issue-1172` (card 1172) and `claude/github-issue-2801-ee86eb` (card 2801) each read 0 heads under the refspec and 1 head under the delimited grep. A pre-check that hides real in-flight work trades a false positive for a false negative, which is the worse direction for a discovery probe. The `(-|$)` alternation, not a bare trailing dash, is what keeps the slug-less spelling (`copilot/fix-issue-1172`) discoverable. Still one command, no second read, net 0 lines: AGENTS.md 1099 / 1099 (ceiling 1099, headroom 0), widest table row 768 / 768 untouched, one line changed at 93 bytes. Claude-Session: https://claude.ai/code/session_01BTeBejoPUvRHN8WdAJC6oF Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
维护者速读(终稿)— PR #18918 · 席位定稿 2026-09-18T06:12Z(草稿在正文,以本评论为准)改了什么: 为什么改:原写法是前缀匹配——查卡 186 会命中 18612 / 18652 / 18699 三张别的卡的分支,且退出码 0,读起来像「这卡有人在做」;板面到 18,9xx 后,凡号码是更新卡号前缀的卡都在暴露面里。危害方向是静默:读者拿到一个关于自己没问的卡的自信答案,活卡被跳过。 风险与代价(含回滚):只改人读的指令文本,不进构建与发布物( 席位意见:建议批准。 你要做的:确认这一行如实补上了分隔符,是则 APPROVE( Generated by Claude Code |
|
Landing record — ruling C, on an authorized APPROVED (skills seat, os-zhuang ( Generated by Claude Code |
Fixes #18830
Clause-②: no
The documented claim pre-check in
AGENTS.md(Multi-agent discipline, rule 2) had no rightdelimiter, so a card number that is a prefix of a longer card number matched that longer
card's branch — a confident hit about a card the reader never asked about, exit 0. One line
changed; the pre-check is still one command and still one read.
(
Nabove stands for the card-number placeholder the file spells with angle brackets; thelanded line carries that placeholder, not the letter N.)
The probe table — three commands, six readings, on
originRe-run live in the worktree at
625db0e85(base) ande252d0d41(head). Exit codes capturedbefore any pipe. Verbatim transcript:
The defect reproduced live at my base with a different head set than the card recorded
(the reaper has since removed some and new branches landed): 3 heads today where the card
measured 5. The shape, not the roster, is what the card named.
Why the delimited grep and not the anchored refspec
The card offered two shapes. I measured both, and they are not equivalent — the refspec form
git ls-remote --heads origin 'refs/heads/claude/issue-N-*'is blind to in-flight heads thatdo not carry the
claude/issue-shape:Both of those are real in-flight heads for a real card, and the refspec hides both. A
discovery probe that trades a false positive for a false negative moves the failure in
the worse direction: a wrong-card hit is loud and a reader can see it is the wrong number,
while a missing head is silent and ends in duplicate work — which is the failure this
pre-check exists to prevent. The refspec form also cannot say "no head" in its exit code
(no match still exits 0 without
--exit-code), while the delimited grep exits 1 — so thefix also adds a signal where the old spelling answered exit 0 either way.
Two further measured notes:
grep issue-1172-, triage's literal one-character minimum) answers0 heads, exit 1 for card 1172 — it drops the slug-less spelling. The
(-|$)alternation is load-bearing, not decoration.
did not hold.
git grep -n "refs/heads/claude/issue-" scripts/answers two hits, bothparser test fixtures (
scripts/pm/check-governed-queue-guard.mjs:2217,scripts/pm/check-half-states.mjs:25116). The only realls-remoterefspec in the loop isscripts/pm/check-governed-merges.mjs:2211, and it probes one fully known branch name(
refs/heads/plus the branch), never a card-number wildcard. No script models thepre-check, so the scripts cast no vote here.
Reader test: a dev pasting the pre-check for card 186 gets 0 heads and exit 1, and one
pasting it for card 18831 still gets that card's head.
Budget and gates
AGENTS.md1099 → 1099 lines. Gate's own line:check-skill-line-ratchet: AGENTS.md is 1099 lines (ceiling 1099; headroom 0); widest table row768 bytes (pin 768; headroom 0),untouched. The changed line is 93 bytes, under the 120-byte max-line-length rule. No
re-flow: the change fits the existing wrap, so no other line in the bullet moved and the
reading clause that landed earlier today is byte-identical.
dispatch-gates --ranreconciliation: 14derived, 14 run, 0 NOT-MEASURED, 0 UNRUN (a derived zero — every entry carries its exit
code).
check:published-list-mirrorswas run beyond the derived union becauseAGENTS.mdholds a mirrored block; it reports
1 published list mirror(s) match their constants line for line, so the pass is real rather than an empty scan.skip-changeset, measured rather than assumed:AGENTS.mdappears in no publishedpackage's
files[](positive control in the same scan: 70 published packages do declare adistentry), so nothing published moves.Acceptance notes
Out of scope for this PR, filed nowhere by me — reported to the seat for filing:
.github/workflows/duplicate-fix-guard.yml:85carriesthe same undelimited match in executable code:
branch.includes('issue-' + n). Probe: aPR declaring card 186 with head ref
claude/issue-18611-xproduces no warning(
warns=false), although the branch names card 18611 and not card 186 — the advisoryfires in the false-negative direction, so a genuinely misnamed fix branch passes silently.
Control:
claude/issue-186-realcorrectly produces no warning. The same file's comment atline 81 restates the pre-check in the old undelimited spelling, so it now drifts from the
rule this PR landed; a card for the matcher should carry the comment with it. Dedupe words:
duplicate-fix-guard branch includes prefix·issue-N substring false negative·branch names no declared issue advisory·guard matcher delimiter·workflow comment stale pre-check spelling. ⛔ Not touched here: it is a differentinstrument in a different file, and editing a workflow would add a verification surface
this claim does not declare.
.claude/skills/pm-dispatch/references/platform-readings.md:379mentions the pre-check abbreviated, with no card-number placeholder at all, as a warning
about the positive-hit direction rather than a command to paste — so it prescribes no
spelling and needs no delimiter. Checked and clean, not a finding. Carrier: the next PR
that edits that reference file; none is queued.
维护者速读(草稿)
改了什么 ——
AGENTS.md规则 2 里那条「一条命令的认领前置检查」补上了右侧分隔符:grep issue-N改成grep -E 'issue-N(-|$)'。一行改动,净增 0 行(1099 / 1099),检查仍然是一条命令、仍然只读一次,今天早些落地的「一次命中只是线索」那句一个字节都没动。
为什么改 —— 原来的写法没有右分隔符,卡号是前缀匹配:查卡 186 会命中
18612 / 18652 / 18699 三条别的卡的分支,而且退出码是 0,读起来像「这卡有人在做」。
板面已经到 18,8xx,凡是号码是更新卡号前缀的卡(整段 1–1,8xx 与 18–188 等)今天都在暴露面内。
危害的方向是静默:读者得到一个关于自己没问过的卡的、自信的答案,后果是活卡被跳过。
风险与代价(含回滚) —— 风险极低:改动只影响人读的指令文本,不进构建、不进发布物
(
AGENTS.md不在任何已发布包的files[]里,故skip-changeset)。新写法是严格更窄的:它能命中的一定是老写法也能命中的,只是去掉了错卡那部分,所以不会让任何真实在途分支变得不可见 ——
这一点是实测的,不是推断的(另一个候选写法「锚定 refspec」反而会漏掉两条真实在途分支,
故未采用,理由在英文正文)。回滚成本 = 还原一行。
席位意见 ——
你要做的 —— 这是受管规则层,按约定停在 draft 等你一句话。请确认两点:① 分隔符写法取
grep -E 'issue-N(-|$)'(可粘贴、不会前缀误命中、真未命中时退出码为 1),而不是锚定 refspec(它会漏掉
copilot/fix-issue-1172一类不守命名约定的在途分支);② 同一个缺陷类还活在duplicate-fix-guardworkflow 的可执行匹配里(见 Acceptance notes,有具名探针),那一处不在本 PR,需要另开一卡 —— 由席位代立,不由我立。
Generated by Claude Code