Skip to content

Commit 46559f6

Browse files
os-elon-muskclaude
andauthored
fix(gate): one discriminator for the ADR-0087 label-vs-mention decision, both directions pinned (#18933)
Fixes #18494 Fixes #18493 Clause-②: no Two cards, one predicate: `findMigrationPrescription`'s label-vs-mention decision in `scripts/check-adr-0087-registration.mjs`, misclassifying in **opposite** directions. They are folded 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. - **#18494** — a real **label** read as a **mention**, so a changeset shipping **no rewrite** was admitted under `not-required (no-migration-prescription)`. Too permissive; the cost is a published break reaching consumers with neither a prescription nor a ledger entry. - **#18493** — a **mention** read as a **label**, so a concrete rewrite was demanded that is not 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 in `labelPositioned`. The in-line arm reads the ONE character LEFT of the placeholder (`GOVERNING_WORD_RE`), which is structurally blind to a label whose own words are a noun phrase: `**Schema Migration FROM → TO:** delete the block` has an ordinary 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`/`mdx` at `625db0e85` (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), 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_INSTRUCTION` states for its own Chinese arm. Asked AFTER the heading arm, so punctuation cannot overturn a denial (#17357). Commit 2 (#18493) — two failures of the #17864 transparency rule to compose: 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 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.replace` and a consumed delimiter would be deleted with the word. 2. The in-line arm is computed within ONE line, so a 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 `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 `withoutFramingTail` said so before the anchor existed, in these words: > The identifier shape is a SEPARATE false positive, stated rather than hidden and out of this > repair's reach: `the sys_migration FROM → TO is documented elsewhere` is governed by `the` and > still reads as a label, because what the strip exposes is `_` rather than the letter that was > there. and, on the wrap, `labelPositioned`'s own statement of the rule: > A FRAMING word between the governor and the placeholder is transparent, and transparency is a > claim in BOTH directions (#17864). It does not make an occurrence a label — `the Migration FROM → > TO is documented elsewhere` is the same mention as `the FROM → TO is documented elsewhere`, one > framing word apart 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): | case | base | head | |:---|:---|:---| | **#18494** probe: `**Schema Migration FROM → TO:** delete the block`, no concrete rewrite | exit **0** | exit **1**, `Evidence (from-to-label)` naming that label | | #18494 control: the same sentence with no colon (the #17864 mention) | exit 0 | exit 0 | | **#18493** T1 mention: `the sys_migration FROM → TO is documented elsewhere` | exit **1** | exit **0** | | **#18493** T1 label FLOOR: `sys_migration FROM → TO: delete the block` (F9/R2) | exit 1 | exit **1** | | **#18493** T2 W1: governor ends the line, framing word opens the next | exit **1** | exit **0** | | **#18493** T2 W2: governor and framing word above, placeholder below | exit **1** | exit **0** | #18494's card lists six label shapes, all reading `null` on current main; the whole list was treated as the target set and all six now read `from-to-label`, as do the card's own three fairness controls (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_RE` takes the gate's **own F9 floor** with it — `sys_migration FROM → TO:` stopped being a label by an accident of the strip — unless the colon that 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-disk counts and blob hashes asserted, restore proven by blob-equals-HEAD and an empty `git diff HEAD`): | ablation | what is removed | self-test | |:---|:---|:---| | A | the colon arm | **15 red**: L1-L7, L-E2E-R, X2, SS1, SS3, SS7 — and **F9**, the pre-existing floor | | B | the identifier word anchor | **3 red**: X1, SS4, SS8 | | C | the entirely-framing fall-through | **2 red**: X4, X10 | | D | the wrap-side framing strip | **2 red**: X5, SS5 | Anti-see-saw: `SS1-SS8` pins the two directions as **minimal pairs in ONE battery** under **one** floor — 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-L13` and `X1-X11` carry each card's own reds and floors. ## The gate I am editing judges this PR Before: `exit 0`, self-test `405` assertions. After: `exit 0`, self-test `441` assertions — the battery 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 a file 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`/`mdx` at `625db0e85`, **zero** verdict deltas for the whole change, with the before/after instrument **lit 3/3** by the three probe shapes. `pnpm lint` narrowed and the narrowing 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 the verdict on a file it did not touch. Readings taken at `b0678d370`. `origin/main` merged once before this PR opened. ## Acceptance notes Noted, not filed — observations, no repro, no contract text: - `MIGRATION_FRAMING_RE`'s docblock names `migrations/registry.ts` among the identifiers its word anchor 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. - The in-line framing-tail path has population 0 over the whole corpus, in every delimiter class, 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 文件,判定零变化,仪器三/三 点亮;门禁自身 32 族全绿。回滚按**倒序**:先回退第二个 commit(#18493)、再回退第一个(#18494)。 ⚠️ 只回退第一个而留下第二个会红掉门禁已有的 F9 底线——这正是两张卡耦合的机械证据,不是本 PR 的缺陷。 未做的事:词边界在连字符/点号后留下的残余没有跟着修,已作为 finding 上报,因为那会在零实测的形状上 放宽门禁的接纳面,那是维护者的底线。 **席位意见** —— **你要做的** —— 判两件事:① #18494 那一半是 widening(门禁更严),它落在六种拼法之外还带上了卡面 自己的三个 fairness control——这个判别器分不开、也不该分开它们,请确认这个更大的目标集可以接受; ② #18493 那一半让门禁接纳了它今天拒收的输入,上面引了门禁自己的原话证明那是**误拒**,请确认这条引用 成立。若两条都成立,这个 PR 只欠合并。 --- _Generated by [Claude Code](https://claude.ai/code/session_019srGWGCBBCBHqcDoRZpQRh)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent f112a74 commit 46559f6

1 file changed

Lines changed: 342 additions & 21 deletions

File tree

0 commit comments

Comments
 (0)