Repository navigation
fix(gate): one discriminator for the ADR-0087 label-vs-mention decision, both directions pinned - #18933
Merged
os-elon-musk merged 3 commits intoSep 18, 2026
Conversation
…colon that closes it `findMigrationPrescription`'s in-line arm reads the ONE character left of the `FROM -> TO` placeholder (`GOVERNING_WORD_RE`). That is sound for the shapes it was measured on and structurally blind to one family: a label whose own words are a noun phrase. `**Schema Migration FROM -> TO:** delete the block` has an ordinary letter immediately before the framed placeholder, so the occurrence read as a MENTION, the body evidenced no prescription, and a changeset claiming `not-required (no-migration-prescription)` while shipping no rewrite at all was admitted -- a published break reaching consumers with neither a prescription nor a ledger entry. The signal the left side cannot supply is on the right: `FROM -> TO:` is the convention's own punctuation for "what follows is the mapping", and a running sentence does not put a colon on its object. `LABEL_COLON_RE` is a closed class derived from the corpus (1322 tracked md/mdx at 625db0e, 1007 occurrences): 321 are closed by a colon, and the markup that may stand between the placeholder and that colon is exactly three runs -- nothing (295), `)` (25) and `**` (1). The full-width colon rides along as this file's ordinary Chinese parity at a measured population of zero, so the disposition does not turn on the author's keyboard. Direction: a colon can only ever make an occurrence a LABEL, which is what the gate REFUSES the catch-all on, so nothing admitted today is refused because of `carriesConcreteRewrite` and nothing refused today is admitted. It is asked AFTER the heading arm so punctuation cannot overturn a denial (#17357). Measured over the whole stock at that tree: 429 changesets and 1322 md/mdx files, ZERO verdict deltas, instrument lit by the probe shape. Clause-②: no Claude-Session: https://claude.ai/code/session_019srGWGCBBCBHqcDoRZpQRh Co-authored-by: Claude <noreply@anthropic.com>
…ose wraps `findMigrationPrescription` reads a MENTION as a LABEL through two failures of the #17864 transparency rule to compose -- the false-positive direction, where the gate hard-blocks a PR by demanding a concrete rewrite the author does not owe, with an evidence line naming the author's own sentence. 1. `FRAMING_TAIL_RE` carried no word anchor while its sibling `MIGRATION_FRAMING_RE` anchors its English alternatives, so a framing word that is merely the tail of an IDENTIFIER was stripped as a word of its own: `the sys_migration FROM -> TO is documented elsewhere` stripped to `the sys_`, exposed `_` instead of the `n` that was really there, and answered "nothing governs this". The anchor is a lookbehind rather than a consuming boundary, because the match is fed to `String.replace`. 2. The in-line arm is computed within ONE line, so a markdown hard wrap put the governor out of its reach in both directions. A prefix that is ENTIRELY a framing word now falls through to the cross-line arm -- transparency means the word is not there, so the placeholder opens its line -- and the cross-line arm strips a framing tail off the line above before asking the closed class. The two cards are coupled rather than adjacent: the anchor takes the F9 floor (`sys_migration FROM -> TO:`) with it unless the colon that actually closes that label is holding it up, which is the first commit on this branch. Pinned as minimal pairs in one battery (SS1-SS8) so neither direction can be traded for the other, plus X1-X11 for both triggers and their floors. The residue `\b` leaves -- a framing word after a hyphen or a dot -- is stated in the docblock rather than reached for: measured over 429 changesets and 1322 tracked md/mdx at 625db0e, the population of every in-line framing tail is 0, so nothing separates those classes, and widening what the gate ADMITS on an unmeasured shape is not this predicate's call. Stock: zero verdict deltas over that corpus, instrument lit 3/3. Self-test 405 -> 441 assertions. Clause-②: no Claude-Session: https://claude.ai/code/session_019srGWGCBBCBHqcDoRZpQRh Co-authored-by: Claude <noreply@anthropic.com>
…bel-mention-discriminator
This was referenced Sep 18, 2026
os-elon-musk
marked this pull request as ready for review
September 18, 2026 06:44
os-elon-musk
deleted the
claude/issue-18494-label-mention-discriminator
branch
September 18, 2026 07:14
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #18494
Fixes #18493
Clause-②: no
Two cards, one predicate:
findMigrationPrescription's label-vs-mention decision inscripts/check-adr-0087-registration.mjs, misclassifying in opposite directions. They arefolded because the repairs are coupled, not because they are adjacent — see "The coupling,
measured" below, which is the reason this is one PR and one battery.
**Schema Migration FROM → TO:**) reads as a MENTION and is admitted with no rewrite #18494 — a real label read as a mention, so a changeset shipping no rewrite wasadmitted under
not-required (no-migration-prescription). Too permissive; the cost is apublished break reaching consumers with neither a prescription nor a ledger entry.
owed. Too strict; the cost is a hard-blocked PR whose evidence line names the author's own
sentence.
What changed
Commit 1 (#18494) —
LABEL_COLON_RE, and one arm inlabelPositioned. The in-line arm reads theONE character LEFT of the placeholder (
GOVERNING_WORD_RE), which is structurally blind to a labelwhose own words are a noun phrase:
**Schema Migration FROM → TO:** delete the blockhas anordinary letter there and is a label all the same. The signal the left side cannot supply is on the
right — the convention's own colon, which a running sentence never puts on its object. The class is
derived from the corpus, not invented: over 1322 tracked
md/mdxat625db0e85(1007occurrences), 321 are closed by a colon and the markup that may stand between the placeholder and
that colon is exactly three runs — nothing (295), a closing paren (25) and a bold marker (1). The
full-width colon rides along as this file's ordinary Chinese parity at a measured population of
zero, on the precedent
REMOVAL_INSTRUCTIONstates for its own Chinese arm. Asked AFTER theheading arm, so punctuation cannot overturn a denial (#17357).
Commit 2 (#18493) — two failures of the #17864 transparency rule to compose:
FRAMING_TAIL_REcarried no word anchor while its siblingMIGRATION_FRAMING_REanchorsits English alternatives, so a framing word that is merely the tail of an identifier was
stripped as a word of its own:
the sys_migration FROM → TO is documented elsewherestripped tothe sys_, exposed an underscore instead of the letter that was really there, and answered"nothing governs this". The anchor is a negative lookbehind rather than a consuming
boundary, because the match is fed to
String.replaceand a consumed delimiter would be deletedwith the word.
both directions. A prefix that is entirely a framing word now falls through to the
cross-line arm — transparency means the word is not there, so the placeholder opens its line —
and the cross-line arm strips a framing tail off the line above before asking
WRAPPED_GOVERNOR_RE.The reversal clause — #18493's half admits inputs the gate refuses today
That is legitimate only as the removal of a mis-refusal, and the gate's own docblock on
withoutFramingTailsaid so before the anchor existed, in these words:and, on the wrap,
labelPositioned's own statement of the rule:Nothing beyond those documented mention shapes is admitted: the change adds no vocabulary and no
new exemption, it composes two rules the file already states. Counter-evidence for that claim is
the residue, stated in the docblock rather than reached for — a framing word after a hyphen or a
dot is still stripped, exactly as a word boundary reads it. Measured over the same tree, the
population of EVERY in-line framing tail, of any delimiter, is 0, so no reading here separates
those classes, and widening what the gate ADMITS on an unmeasured shape is the maintainer's floor.
Filed as a finding instead.
Per-card criteria, each demonstrated independently
Through the real CLI on a committed probe changeset in a temp repo, with the gate's
pre-change blob and its post-change blob staged into the same fixture, reading the process exit
code (
base=625db0e85,head= this branch):**Schema Migration FROM → TO:** delete the block, no concrete rewriteEvidence (from-to-label)naming that labelthe sys_migration FROM → TO is documented elsewheresys_migration FROM → TO: delete the block(F9/R2)#18494's card lists six label shapes, all reading
nullon current main; the whole list wastreated as the target set and all six now read
from-to-label, as do the card's own three fairnesscontrols (a noun-phrase label with no framing word in it at all — the same defect one word
shorter, which this discriminator cannot and should not separate).
The coupling, measured
Word-anchoring
FRAMING_TAIL_REtakes the gate's own F9 floor with it —sys_migration FROM → TO:stopped being a label by an accident of the strip — unless the colonthat actually closes that label is holding it up. That is not an argument; it is ablation A below,
where removing the #18494 arm reds F9, a pin neither card touches.
Reverse verification, each leg through
scripts/ablation-replace.mjs(anchor must hit, on-diskcounts and blob hashes asserted, restore proven by blob-equals-HEAD and an empty
git diff HEAD):Anti-see-saw:
SS1-SS8pins the two directions as minimal pairs in ONE battery under onefloor — each pair differs by one character or one line break and asserts opposite verdicts, so a
tuning that buys one direction with the other reds a pair, and deleting half the pairs to silence
that drops the battery below its pinned count.
L1-L13andX1-X11carry each card's own reds andfloors.
The gate I am editing judges this PR
Before:
exit 0, self-test405assertions. After:exit 0, self-test441assertions — thebattery grew by 36 and shrank nowhere.
Gates
Derived from the change set by
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(1 path, three-dot semantics, merge base
d5ccfb4e3), each run with its exit code redirected to afile and read back, then reconciled with
--ran: 32 derived, 32 run, 0 NOT-MEASURED, 0 UNRUN,all exit 0 — a derived zero, not a claimed one, and no family exited 3.
Stock measurement, the one #18494's second direction owes: over 429 changesets and 1322
tracked
md/mdxat625db0e85, zero verdict deltas for the whole change, with thebefore/after instrument lit 3/3 by the three probe shapes.
pnpm lintnarrowed and thenarrowing declared: 1 of the 6855 files eslint's own config selects, 0 errors 0 warnings, exit 0
(
--format json); the config states that this repo "never enables type-aware linting(no
parserOptions.project, no typed rules) for ANY file", so a one-file diff cannot move theverdict on a file it did not touch. Readings taken at
b0678d370.origin/mainmerged once beforethis PR opened.
Acceptance notes
Noted, not filed — observations, no repro, no contract text:
MIGRATION_FRAMING_RE's docblock namesmigrations/registry.tsamong the identifiers its wordanchor keeps out, but a word boundary treats a slash as a boundary too, so that one alternative
of the claim does not hold as written. Successor: the next PR that touches that docblock.
so both arms repaired here are pins against a future author rather than against today's stock —
exactly as both cards state.
维护者速读(草稿)
改了什么 —— 一个门禁的判别器:changeset 正文里的
FROM → TO到底是「这里就是改写清单」(标签)还是「改写清单在别处」(提及)。两张卡是同一个判断的两个反方向,合成一个 PR 修:一边放过了不带改写
的破坏性变更,一边拦住了本不该拦的作者。
为什么改 —— 放过的那一边是真成本:破坏性改动进了消费者手里,既没有改写说明,也没有登记入账,而
门禁报的是一次干净的运行。拦错的那一边是摩擦成本:作者被要求补一份他不欠的改写,而门禁给出的「证据」
就是他自己那句话。两边不能分开修——收紧一边会把另一边推得更远,这份 PR 的实测把这条耦合摆出来了。
风险与代价(含回滚) —— 全量实测:429 份 changeset、1322 个 md/mdx 文件,判定零变化,仪器三/三
⚠️ 只回退第一个而留下第二个会红掉门禁已有的 F9 底线——这正是两张卡耦合的机械证据,不是本 PR 的缺陷。
点亮;门禁自身 32 族全绿。回滚按倒序:先回退第二个 commit(#18493)、再回退第一个(#18494)。
未做的事:词边界在连字符/点号后留下的残余没有跟着修,已作为 finding 上报,因为那会在零实测的形状上
放宽门禁的接纳面,那是维护者的底线。
席位意见 ——
你要做的 —— 判两件事:① #18494 那一半是 widening(门禁更严),它落在六种拼法之外还带上了卡面
自己的三个 fairness control——这个判别器分不开、也不该分开它们,请确认这个更大的目标集可以接受;
② #18493 那一半让门禁接纳了它今天拒收的输入,上面引了门禁自己的原话证明那是误拒,请确认这条引用
成立。若两条都成立,这个 PR 只欠合并。
Generated by Claude Code