Skip to content

docs(agents): give the claim pre-check its right delimiter, so a card number cannot prefix-match - #18918

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-18830-precheck-delimiter
Sep 18, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-18830-precheck-delimiter

Conversation

@os-elon-musk

Copy link
Copy Markdown
Collaborator

Fixes #18830

Clause-②: no

The documented claim pre-check in AGENTS.md (Multi-agent discipline, rule 2) had no right
delimiter, 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.

-   origin | grep issue-N` is a one-command pre-check, and the Duplicate Fix Guard
+   origin | grep -E 'issue-N(-|$)'` is a one-command pre-check, and the Duplicate Fix Guard

(N above stands for the card-number placeholder the file spells with angle brackets; the
landed line carries that placeholder, not the letter N.)

The probe table — three commands, six readings, on origin

Re-run live in the worktree at 625db0e85 (base) and e252d0d41 (head). Exit codes captured
before any pipe. Verbatim transcript:

===== BEFORE — the spelling as documented =====
card 186     git ls-remote --heads origin | grep issue-186      2026-09-18T05:43:06Z  exit=0  heads=3
      99c4c03e07671e462f76b88d0d432c4bcda72675  refs/heads/claude/issue-18612-cubejoin-retire-sql-relationship
      aefbf59275282b9f277832d9f98fd67f058fc238  refs/heads/claude/issue-18652-changeset-anonymous-null-clause
      ea7d40f8e8c926e2c93d1351a81d7b0fe944def9  refs/heads/claude/issue-18699-os-dev-label-scope
card 1811    git ls-remote --heads origin | grep issue-1811     2026-09-18T05:43:06Z  exit=0  heads=1
      d93400f42ea69215b3de22bfe3ca057385ff0eea  refs/heads/claude/issue-18116-turso-begintransaction-radius
card 18831   git ls-remote --heads origin | grep issue-18831    2026-09-18T05:43:07Z  exit=0  heads=1
      c8d3f36c9e10c86a85f378a9ac1616b1ddf56851  refs/heads/claude/issue-18831-claim-near-miss-forms

===== AFTER — the delimited spelling that landed =====
card 186     ... | grep -E 'issue-186(-|$)'                     2026-09-18T05:43:21Z  exit=1  heads=0
card 1811    ... | grep -E 'issue-1811(-|$)'                    2026-09-18T05:43:21Z  exit=1  heads=0
card 18831   ... | grep -E 'issue-18831(-|$)'                   2026-09-18T05:43:22Z  exit=0  heads=1
      c8d3f36c9e10c86a85f378a9ac1616b1ddf56851  refs/heads/claude/issue-18831-claim-near-miss-forms
card before: heads / exit after: heads / exit reading
186 (no branch of its own) 3 / 0 0 / 1 three wrong-card hits gone; a true miss now says so in the exit code too
1811 (no branch of its own) 1 / 0 0 / 1 the card-18116 head no longer answers for card 1811
18831 (positive control, has a head) 1 / 0 1 / 0 unchanged — the pre-check still finds real in-flight work

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 that
do not carry the claude/issue- shape:

card 1172   delimited grep    exit=0  heads=1   refs/heads/copilot/fix-issue-1172
card 1172   anchored refspec  exit=0  heads=0
card 2801   delimited grep    exit=0  heads=1   refs/heads/claude/github-issue-2801-ee86eb
card 2801   anchored refspec  exit=0  heads=0

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 the
fix also adds a signal where the old spelling answered exit 0 either way.

Two further measured notes:

  • A bare trailing dash (grep issue-1172-, triage's literal one-character minimum) answers
    0 heads, exit 1 for card 1172 — it drops the slug-less spelling. The (-|$)
    alternation is load-bearing, not decoration.
  • The dispatch's assumption that the anchored refspec "is what this loop's own scripts use"
    did not hold. git grep -n "refs/heads/claude/issue-" scripts/ answers two hits, both
    parser test fixtures (scripts/pm/check-governed-queue-guard.mjs:2217,
    scripts/pm/check-half-states.mjs:25116). The only real ls-remote refspec in the loop is
    scripts/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 the
    pre-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.md 1099 → 1099 lines. Gate's own line: check-skill-line-ratchet: AGENTS.md is 1099 lines (ceiling 1099; headroom 0); widest table row 768 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.
  • 14 derived gate families run, all exit 0; dispatch-gates --ran reconciliation: 14
    derived, 14 run, 0 NOT-MEASURED, 0 UNRUN
    (a derived zero — every entry carries its exit
    code). check:published-list-mirrors was run beyond the derived union because AGENTS.md
    holds 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.md appears in no published
    package's files[] (positive control in the same scan: 70 published packages do declare a
    dist entry), so nothing published moves.

Acceptance notes

Out of scope for this PR, filed nowhere by me — reported to the seat for filing:

  • To file (defect, named probe). .github/workflows/duplicate-fix-guard.yml:85 carries
    the same undelimited match in executable code: branch.includes('issue-' + n). Probe: a
    PR declaring card 186 with head ref claude/issue-18611-x produces no warning
    (warns=false), although the branch names card 18611 and not card 186 — the advisory
    fires in the false-negative direction, so a genuinely misnamed fix branch passes silently.
    Control: claude/issue-186-real correctly produces no warning. The same file's comment at
    line 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 different
    instrument in a different file, and editing a workflow would add a verification surface
    this claim does not declare.
  • Noted, not filed. .claude/skills/pm-dispatch/references/platform-readings.md:379
    mentions 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-guard workflow 的可执行匹配里(见 Acceptance notes,有具名探针),
那一处不在本 PR,需要另开一卡 —— 由席位代立,不由我立。


Generated by Claude Code

… 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>
@os-elon-musk os-elon-musk added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 18, 2026 — with Claude
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: e252d0d41acbc49e9081fd213244e2323f82f0dd

① Derived judgments

  • Surface: AGENTS.md (+1 / −1, 1099 / 1099), the Multi-agent discipline rule-2 bullet's pre-check command and nothing else. No published package moves (AGENTS.md is in no package's files[]); no contract's accept/reject set moves; the public surface is unchanged. check-governed-merges.mjs --test AGENTS.md: GOVERNED, rules layer.
  • The rule as landed: git ls-remote --heads origin | grep -E 'issue-<n>(-|$)'. The card's defect — the undelimited grep issue-<n> prefix-matches every longer card number and exits 0 on a wrong-card hit — is closed by the right delimiter: a head claude/issue-18612-… no longer answers for card 186, and a true miss now exits 1. Seat readings on the head blob: line 462 is 93 bytes (120-byte rule), the four neighbouring lines are byte-identical to origin/main, and the 「A hit is a hint, not a claim」 clause that landed earlier today in the same bullet is unmoved.
  • Shape (the card offered two): the delimited grep over the anchored refspec refs/heads/claude/issue-<n>-*. The dev measured the refspec blind to two real in-flight heads that do not carry the claude/issue- shape (copilot/fix-issue-1172, claude/github-issue-2801-ee86eb) and unable to say "no head" in its exit code; the seat agrees — for a discovery pre-check the false negative is the silent direction and the worse one. The (-|$) alternation is load-bearing: a bare trailing dash drops the slug-less spelling (card 1172 reads 0 heads). The dispatch's assumption that the loop's own scripts use the refspec form was falsified by the dev (the two git grep hits are parser fixtures; check-governed-merges.mjs :2211 probes one fully known branch name) — no script models the pre-check, so nothing else has to move; the seat withdraws that assumption here.
  • Probe table (dev, live on origin, base 625db0e85): card 186 before 3 heads / exit 0 → after 0 / 1; card 1811 1 / 0 → 0 / 1; card 18831 (positive control) 1 / 0 → 1 / 0. The seat's own fifth reading with the landed spelling, card 18830: 1 head, exit 0 (refs/heads/claude/issue-18830-precheck-delimiter) — the positive direction holds.
  • Machine side: none — one line of instruction prose that no script reads.
  • Residue (⛔ not this PR's): the same undelimited match lives in executable code, .github/workflows/duplicate-fix-guard.yml :85 (branch.includes('issue-' + n) in spirit; a template literal in the file), in the false-negative direction — a PR declaring card 186 with head claude/issue-18611-x warns nothing. The seat re-probed the predicate in node: warns=false for that pair, warns=false for the control claude/issue-186-real, warns=true for feat/x. The comment at :81 restates the pre-check in the old spelling. Filed by the seat as its own finding card (number in the ACCEPT on [finding] the documented claim pre-check git ls-remote --heads origin | grep issue-<n> has no right delimiter, so the card number is a PREFIX match — grep issue-186 answers five heads for cards 18611 / 18643 / 18651 / 18652 / 18662 and none for card 186, with exit 0 #18830). references/platform-readings.md :379 names the pre-check without prescribing a spelling — checked, not a finding.

② Semver level

  • skip-changeset is correct: AGENTS.md ships in no published package's files[] (the dev's scan carried a 70-package positive control). Clause-②: no on the claim and in the body; PM_SWEEP_REPO=objectstack-ai/objectstack node scripts/pm/check-clause2-carriers.mjs --pair 18918 at 2026-09-18T06:00Z: exit 0, one live claim (5725683819), pr-body.clause2-line DECLARED no, no widening tell.

③ Boundary flags

  • Dev flags: no open questions; one out-of-scope class-(a) finding (above); premise_still_valid: true, re-verified at a base newer than the dispatch's read (0b31d90625db0e85: the head roster changed, the shape held). Gates: 14 derived / 14 run / 0 NOT-MEASURED / 0 UNRUN, plus check:published-list-mirrors beyond the union (1 mirror matches). 0 MCP calls; 3 REST writes, budget held.
  • CI on this head at 2026-09-18T06:10Z: 17 success · 12 skipped · 1 in_progress (Lint & Repo Gates, at step 158 of 360 when read; it measures the ratchet and id-lint on this head) — nothing red. The seat's own ratchet reading on the head blob: 1099 lines; every line over 120 bytes is a pre-existing pinned table row.

Implemented-by: claude/issue-18830-precheck-delimiter
Reviewed-by: session_01BTeBejoPUvRHN8WdAJC6oF

VERDICT: PASS


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

维护者速读(终稿)— PR #18918 · 席位定稿 2026-09-18T06:12Z(草稿在正文,以本评论为准)

改了什么:AGENTS.md 多代理纪律规则 2 里那条「一条命令的认领前置检查」补上右侧分隔符:grep issue-<n> 改成 grep -E 'issue-<n>(-|$)'。一行改动,1099 / 1099,仍是一条命令、一次读;同一条目里今天早些落地的「一次命中只是线索」那句一个字节没动。

为什么改:原写法是前缀匹配——查卡 186 会命中 18612 / 18652 / 18699 三张别的卡的分支,且退出码 0,读起来像「这卡有人在做」;板面到 18,9xx 后,凡号码是更新卡号前缀的卡都在暴露面里。危害方向是静默:读者拿到一个关于自己没问的卡的自信答案,活卡被跳过。

风险与代价(含回滚):只改人读的指令文本,不进构建与发布物(skip-changeset,实测非推断)。新写法严格更窄:老写法能命中的真实在途分支它都能命中,只去掉错卡那部分;另一个候选(锚定 refspec)反而会漏掉两条不守 claude/issue- 命名的真实在途分支,故未采用。派发词里「循环脚本用 refspec 形」的假设经 dev 实测不成立(两处命中是解析器夹具),席位在复核记录里撤回,不影响取舍。回滚 = 还原一行。

席位意见:建议批准。(-|$) 这个交替是关键,裸尾杠会漏掉无 slug 的拼写(实测卡 1172 读 0)。同一缺陷类还活在 duplicate-fix-guard workflow 的可执行匹配里(branch.includes('issue-' + n),方向是漏报),不在本 PR,席位已另立 #18922 交分诊。

你要做的:确认这一行如实补上了分隔符,是则 APPROVE(GOVERNED_APPROVERS 账户);之后由本席按裁决 C 落地。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 18, 2026 11:22
@os-zhuang
os-zhuang enabled auto-merge September 18, 2026 11:23
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Landing record — ruling C, on an authorized APPROVED (skills seat, session_01BTeBejoPUvRHN8WdAJC6oF) · 2026-09-18T11:25Z

os-zhuang (GOVERNED_APPROVERS) approved this PR (review 5247213134 at 2026-09-18T11:22Z), marked it ready at 2026-09-18T11:22Z and added it to the merge queue at 2026-09-18T11:24Z — the two CCR calls this seat's channel could not make, made by the approver's own hand. The seat's pre-landing reads on head e252d0d41a: the review of record 5725952138 names this head; PM_SWEEP_REPO=objectstack-ai/objectstack node scripts/pm/check-clause2-carriers.mjs --pair 18918 exit 0 (card #18830); checks at 2026-09-18T11:25Z: 19 success · 16 skipped, none red. This PR is one line of AGENTS.md (1099 / 1099): the rule-2 pre-check gains its right delimiter; PR #18999 (#18922) carries the same delimiter into the workflow comment and awaits a human merge. needs-user-decision cleared by the seat now (the decision it marked has been made). The merge is the queue's; the card closes on it, and the seat clears its pm:dispatched / assignee residue after the merge lands.


Generated by Claude Code

Merged via the queue into main with commit b84a847 Sep 18, 2026
39 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-18830-precheck-delimiter branch September 18, 2026 11:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants