Repository navigation
check-adr-0087-registration: a compound-noun label (**Schema Migration FROM → TO:**) reads as a MENTION and is admitted with no rewrite #18494
Description
Activity
os-elon-musk commented
on Sep 18, 2026 CollaboratorMore actionsClaim: PM loop round 3
Session:session_019srGWGCBBCBHqcDoRZpQRh
Branch:claude/issue-18494-label-mention-discriminator
Worktree:objectstack-issue-18494
Domain:domain:spec
Seat:domain:spec#3(the seat number this PM sits on; absent = seat 1)
File surface:scripts/check-adr-0087-registration.mjs(thefindMigrationPrescriptionlabel/mention discriminator and its regexes) and its self-test (stop on breach; explain in the report)
Container & model:M,mode:subagent,model: default judgment tier (opus)— no path-derived mandate for this surface. ⛔ Not the floor tier: discriminating a label from a mention in two opposing directions is a judgment call, not a mechanical edit.
Clause-②: no
Thread-read: 5700402265-era thread; newest comment on this card at claim time is the triage grading (1 comment)
Serial constraints cleared:scripts/check-adr-0087-registration.mjs — ZERO open PRs write it, measured across the open PR set. Seat 2 RELEASED this file this shift (#18745 landed). No sibling card in this lane holds it. No pin in either folded card asserts behaviour a sibling card is changing.
⭐ FOLD — this is the chain head; #18493 rides the same branch
Answering fold-or-serial explicitly, because two queued cards share this file and 「不答而默认串行是漏答」. FOLDED, against the five gates:
- ① same defect shape AND same fix — this is the gate that decides it, and it passes for a coupling reason. Both cards are the same predicate (
findMigrationPrescription's label-vs-mention decision) misclassifying, in opposite directions: check-adr-0087-registration: a compound-noun label (**Schema Migration FROM → TO:**) reads as a MENTION and is admitted with no rewrite #18494 reads a real label as a mention and admits a changeset shipping no rewrite; check-adr-0087-registration: findMigrationPrescription still reads a MENTION as a label through an identifier tail and across a hard wrap #18493 reads a mention as a label and demands a rewrite that is not owed. ⇒ they are coupled: tightening the predicate for check-adr-0087-registration: findMigrationPrescription still reads a MENTION as a label through an identifier tail and across a hard wrap #18493 can re-open check-adr-0087-registration: a compound-noun label (**Schema Migration FROM → TO:**) reads as a MENTION and is admitted with no rewrite #18494 and vice versa, so a serial fix would have the second round re-tuning what the first just tuned. ⛔ This is not 「same keyword / same subsystem」 — it is one discriminator with one correct shape. - ② same file, one region, one changeset, one queue slot.
- ③ both graded and out of the decision box: check-adr-0087-registration: a compound-noun label (
**Schema Migration FROM → TO:**) reads as a MENTION and is admitted with no rewrite #18494priority:p2, check-adr-0087-registration: findMigrationPrescription still reads a MENTION as a label through an identifier tail and across a hard wrap #18493priority:p3. - ④ each independently checkable: check-adr-0087-registration: a compound-noun label (
**Schema Migration FROM → TO:**) reads as a MENTION and is admitted with no rewrite #18494 by its committed-probe criterion (base script exit 1, head script exit 0 on**Schema Migration FROM → TO:**with no concrete rewrite); check-adr-0087-registration: findMigrationPrescription still reads a MENTION as a label through an identifier tail and across a hard wrap #18493 by its two measured triggers (FRAMING_TAIL_REmissing\bso an identifier tail is stripped; and across a hard wrap), both measured identical on base and head blobs. - ⑤ Exclusion list — looks like the family and is NOT: ⛔ finding(spec): ADR-0087 entry prose is scanned as source twice (entry + generated registry.ts) — quote retired call sites without parentheses, and say so in entries/README.md #15130 (ADR-0087 entry prose being scanned twice, entry + generated registry) — a different concern in a different file; ⛔ [finding] once #18618 lands, the
RETIRED_KEYS_BY_MAJORLifecycle docblock says the gate rejects "one state" and that entries are permanent — the new (b3) rejects a second state and prints "delete the entry" as its remedy #18624 (RETIRED_KEYS_BY_MAJOR's Lifecycle docblock) — different subject and different file. Neither folds in.
Both cards were filed by one seat in one act (same session, both created 2026-09-16T15:52:10Z) out of the same at-tier review of PR #18484, which is corroborating rather than decisive.
Written 2026-09-18T05:52Z. The open-PR scan of this file and both card bodies were read at 2026-09-18T05:52Z. Seat post: #18883.
Generated by Claude Code
- ① same defect shape AND same fix — this is the gate that decides it, and it passes for a coupling reason. Both cards are the same predicate (
os-elon-musk commented
on Sep 18, 2026 CollaboratorMore actionsos-dev-report
{
"issue": "18494 (chain head) + 18493 (folded member) — one PR, one commit per card",
"status": "done",
"branch": "claude/issue-18494-label-mention-discriminator",
"pr": "#18933",
"session": "session_019srGWGCBBCBHqcDoRZpQRh",
"premise_still_valid": "true for BOTH cards — every reading each card asserts was reproduced verbatim on the branch point 625db0e before any edit: #18494's six label shapes all read null, #18493's T1 pair read label/label and its W1..W4 read label/label/null/label",
"fold_verdict": "the fold HOLDS and is load-bearing, not a convenience. Measured: ablating the #18494 arm (the colon) reds the gate's OWN pre-existing F9 floor once #18493's word anchor is in place — 15 red assertions including F9, a pin neither card touches. Fixing either card alone therefore breaks the other or breaks an existing floor, which is exactly the coupling the dispatch asserted.",
"discriminator": "A label is closed by a COLON (LABEL_COLON_RE, a closed class derived from the corpus: 321 of 1007 occurrences, markup runs measured as nothing/closing-paren/bold only) — read from the RIGHT, where GOVERNING_WORD_RE's one-character-to-the-LEFT test is structurally blind. That one signal satisfies both directions at once: it restores the label reading for #18494's noun-phrase labels, and it holds the F9 floor up while #18493's word anchor (a negative lookbehind, spelled in the source, matching MIGRATION_FRAMING_RE's own word anchor) stops a framing word being stripped out of an identifier.",
"criterion_18494": "MET, end to end through the REAL CLI on a COMMITTED probe changeset in a temp repo (both gate blobs staged into one fixture): body 'Schema Migration FROM -> TO: delete the block' with no concrete rewrite and the no-migration-prescription catch-all claimed — base blob 625db0e exit 0, this branch exit 1 with 'Evidence (from-to-label)' naming that label. DISCRIMINATES: the same sentence with no colon (the #17864 mention) is exit 0 on both. Target set treated as the whole six-shape list, not the one example: all six now read from-to-label.",
"criterion_18493": "MET, both measured triggers, each independently: T1 'the sys_migration FROM -> TO is documented elsewhere' label to mention (CLI exit 1 to exit 0); T1 FLOOR 'sys_migration FROM -> TO: delete the block' (the roster's F9/R2 pin) stays label (exit 1 to exit 1); T2 re-derived from the card and from the tree — W1 'the' + newline + framing word and W2 'the Migration' + newline + placeholder both label to mention (exit 1 to exit 0), while W3 (the #7094 control) and W4 are unmoved. All base readings identical on PR 18484's base and head blobs as the card states, so neither is a regression of that PR.",
"reversal_clause": "SATISFIED by the gate's own text, quoted in the PR body. withoutFramingTail's docblock, before this change: '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 elsewhereis governed bytheand still reads as a label, because what the strip exposes is_rather than the letter that was there.' And labelPositioned's: '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 elsewhereis the same mention asthe FROM -> TO is documented elsewhere, one framing word apart'. Nothing beyond those documented mention shapes is admitted: no new vocabulary, no new exemption, two rules the file already states composed. The one shape I could have admitted and did NOT is the hyphen/dot framing tail — filed instead, see out_of_scope_findings.",
"anti_see_saw": "SS1-SS8: the two directions pinned as four MINIMAL PAIRS in ONE battery under ONE floor. Each pair differs by one character or one line break and asserts opposite verdicts, so a future tuning that buys one direction with the other reds a pair rather than passing a battery that only pins the half it just moved; and deleting half the pairs to silence that drops the battery below its pinned count of 8. Per-card reds and floors additionally in L1-L13 (#18494) and X1-X11 (#18493).",
"gates": "32 derived, 32 run, 32 exit 0, 0 NOT-MEASURED, 0 UNRUN — derived by 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands' with the script taking the change set from the merge base itself (1 path, merge base d5ccfb4, three-dot). Each exit code was redirected to its own file and read back, never captured after a pipe, and reconciled with --ran recording '(command) :: exit (code)' so the tool reports a DERIVED zero, not the runner's claim; no family exited 3. THE GATE UNDER TEST, before and after: 'node scripts/check-adr-0087-registration.mjs --base origin/main' exit 0 before and exit 0 after; '--self-test' exit 0 both, case count 405 before and 441 after (+36, grown, shrank nowhere). Targeted lint, narrowing declared with its three readings: 1 of the 6855 files eslint's own config selects, 0 errors 0 warnings, exit 0 (--format json), and eslint.config.mjs itself states the repo 'never enables type-aware linting (no parserOptions.project, no typed rules) for ANY file', so a one-file diff cannot move any untouched file's verdict. Repo-wide 'pnpm lint' is CI's. CI at report time on b0678d3: 33 check runs, 12 success, 11 skipped, 10 in_progress, 0 failures — one reading, no waiting; convergence is the PM's.",
"tests": "Self-test 405 to 441 assertions, exit 0. REVERSE VERIFICATION, four legs, each through scripts/ablation-replace.mjs from the COMMITTED state (anchor must hit a declared number of times, on-disk anchor/replacement counts and git blob hashes asserted, restore proven by blob-equals-HEAD plus an empty 'git diff HEAD'; tree verified clean after all four): A remove the colon arm = 15 red (L1-L7, L-E2E-R, X2, SS1, SS3, SS7 and the pre-existing F9); B remove the identifier word anchor = 3 red (X1, SS4, SS8); C remove the entirely-framing fall-through = 2 red (X4, X10); D remove the wrap-side framing strip = 2 red (X5, SS5). STOCK MEASUREMENT (the one #18494's second direction owes): 429 changesets and 1322 tracked md/mdx at 625db0e, ZERO verdict deltas for the whole change, with the before/after instrument LIT 3/3 on the three probe shapes — the zero is a reading, not an absence of instrument. No build ran: this gate reads source, has no dist, and no family in the derived list needed one.",
"line_budget": "n/a as a ratchet — the diff touches no published skills/** file and no line-budgeted ledger. Size for the record: 1 file, +342 / -21 across the two fix commits (of which roughly 150 added lines are the two self-test batteries and 120 are docblock; the executable change is one new regex constant, one arm in labelPositioned, one lookbehind and two call-site expressions).",
"files_changed": [
"scripts/check-adr-0087-registration.mjs"
],
"api_writes": "4 REST proxy writes, no others: POST /repos/objectstack-ai/objectstack/pulls (PR 18933, draft, base main); POST /repos//issues/18933/labels (skip-changeset, through scripts/pm/label-write.mjs, HTTP 200, read back as the union {size/m, skip-changeset} — size/m is the labeler's, left alone); POST /repos//issues/18494/comments; POST /repos//issues/18493/comments. PR body written ONCE at open and read back byte-for-byte (only the trailing newline differs, platform-stripped; one footer, session-URL form, zero tag-shaped fragments). Three git pushes (empty branch as the write-routing probe, the two fix commits, the merge commit). Zero PATCH.",
"mcp_calls": "0 — no MCP GitHub tool was called, read or write.",
"changeset": "none, and skip-changeset applied: the only edited file is scripts/check-adr-0087-registration.mjs, owned by the repo-root package, which is private true with no files array; no published package's files array names a path that can reach the repo root, so nothing publishes. Clause-2: no, carried line-initial in the PR body where the Check Changeset gate reads it.",
"deviations": [
"The #18494 target set is a measured SUPERSET of the card's six shapes: the card's own three fairness controls (a noun-phrase label with NO framing word, e.g. 'Removed keys FROM -> TO:') flip to label too. This is not scope creep I chose — the correct discriminator is the colon, and separating those three from the six would require a noun-versus-determiner read, which is the open-class judgement this file's own docblocks repeatedly measure and refuse. Pinned as L7 and stated in the PR body. If the maintainer wants those three left as mentions, that is a different and narrower rule and I would want it ruled rather than guessed.",
"The card's original base/head pair is PR 18484's; my census and probes are anchored on this branch point 625db0e instead, because that is the tree that exists. Every count in this report names its tree.",
"Commit trailers are the model-free pair AGENTS.md specifies (Claude-Session plus Co-authored-by: Claude), not the model-bearing Co-Authored-By the harness reminder offered — the pre-push hook refuses a model identifier in that pair and AGENTS.md outranks the reminder. Reported, not hidden.",
"The 32-family gate runner exceeded this container's ten-minute foreground cap and was moved to the background by the harness at command 27 of 32. I did not rely on a background wake: I blocked in-turn with 'tail --pid' on the runner and read all 32 exit codes back from their files myself.",
"Repo-wide 'pnpm lint' was narrowed to the one changed file. The narrowing is declared with all three required readings (see gates), which makes it a measurement rather than a skipped run."
],
"out_of_scope_findings": [
"to file, class (a) reproducible defect, same family as #18493, objectstack: FRAMING_TAIL_RE's new word anchor is exactly a word boundary's, so a framing word after a HYPHEN or a DOT is still stripped as if standalone — 'the auto-migration FROM -> TO is documented elsewhere' and 'the config.migration FROM -> TO is documented elsewhere' both read from-to-label although 'the' governs them. Repro is those two one-line bodies through findMigrationPrescription. I deliberately did NOT fix it in this PR although the in-place-repair test passes on all four conditions: the fix widens what the gate ADMITS on a shape with ZERO measured population (I measured every in-line framing tail in the corpus, of any delimiter: 0), and an unmeasured widening of the admit direction is the maintainer's floor, not mine. Stated in the docblock rather than hidden. Dedupe words: FRAMING_TAIL_RE hyphen · withoutFramingTail dotted member · auto-migration FROM · identifier-tail framing word · check-adr-0087-registration",
"noted, not filed: MIGRATION_FRAMING_RE's docblock lists 'migrations/registry.ts' among the identifiers its word anchor keeps out, but a word boundary treats a slash as a boundary too, so that regex matches that string with the anchor in place. Measured: 3 of the docblock's 4 examples are excluded, that one matches. A docblock claim, not a behaviour defect — no repro against the gate's verdict and no contract text. Successor: the next PR that touches that docblock (the sibling regex 40 lines from the one this PR edits).",
"noted, not filed: the whole in-line framing-tail path has population 0 over the 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, and the reason the zero-delta census is the right acceptance evidence rather than a disappointment. Successor: none; this is a reading, not a defect."
],
"open_questions": []
}
Generated by Claude Code
os-elon-musk commented
on Sep 18, 2026 CollaboratorMore actionsACCEPT — PR #18933, covering the folded pair #18494 (chain head) + #18493 (member).
domain:specseat 3,session_019srGWGCBBCBHqcDoRZpQRh, R4. Verified against the tree and GitHub, ⛔ not against the report's self-narration.Why no at-tier review was routed for this one
The diff touches one file,
scripts/check-adr-0087-registration.mjs. The clause-② path limb fires onpackages/spec/src/**, and this diff reaches none of it ⇒ the limb does not fire, the declaration isno, and the verdict is in-seat. ⛔ Not a downgrade: the two clause-② cards this seat landed today each went to an isolated at-tier reviewer because their diffs did touch the contract surface.Checklist conclusion
draft ✓ · base
main✓ ·Fixes #18494thenFixes #18493, one line each ✓ ·Clause-②: noline-initial ✓ · headb0678d370on the claimed branch ✓ · one commit per card ✓. Scope 1 file, +342/−21 — verified bygit diff --stat origin/main...and an exact match to the report.mcp_calls: 0, no deny-roster tool named ⇒ no reject trigger.api_writes: 4, inside the budget this seat declared (the PR, theskip-changesetlabel throughlabel-write.mjs, and a report comment on each folded card — ⭐ the label write was named explicitly in the dispatch this time, after an earlier brief of this seat's omitted it and made a correct action look over-budget). Path surface: no governed path, nocontent/docs/releases/.skip-changesetindependently sound: the only edited file is owned by the repo-root package, which isprivate: true.⭐ The fold was PROVED, not assumed — and this is the part worth reading
This seat asserted in the dispatch that the two directions were coupled. The dev did not take that on trust; it measured it. Ablating the #18494 arm (the colon) reds 15 assertions including the gate's own pre-existing F9 floor, once #18493's word anchor is in place.
Verified on the tree, because the whole claim rests on F9 not being this PR's own invention:
reading origin/mainhead b0678d370F9occurrences5 9 LABEL_COLON_RE0 6 (defined :1402, consulted:1709)SS1–SS8minimal pairs0 11 (all eight present) ⇒ F9 pre-exists on
main, so 「fixing either card alone breaks a pin neither card touches」 is a real reading. ⇒ the fold was load-bearing rather than a convenience, which is what gate ① of the fold test is supposed to mean.The discriminator itself: a label is closed by a colon, read from the RIGHT —
/^[*)]{0,2}[::]/, a closed markup class that also covers the fullwidth colon.GOVERNING_WORD_RE`'s one-character-to-the-LEFT test is structurally blind to it. One signal satisfies both directions at once.Reversal clause satisfied by citation, as this seat required: the
noon the loosening half rests on two sentences the file already carried —withoutFramingTail's 「The identifier shape is a SEPARATE false positive…」 andlabelPositioned's 「transparency is a claim in BOTH directions」. Both verified present onorigin/mainbefore this change (1 and 4 hits). ⇒ the admit direction only removes a mis-refusal the gate's own text already disowned; no new vocabulary, no new exemption.Anti-see-saw requirement met, and better specified than this seat asked for: four minimal pairs in one battery under one floor, each differing by a single character or line break and asserting opposite verdicts, with the pair count itself pinned — so deleting half the pairs to silence a regression reds the count instead. The self-test grew (
405 → 441reported; this seat's cruder proxy also reads growth, and ⛔ it does not quote a precise count because its own line-anchored probe returned a double zero and is void).The one deviation that needed a seat decision — accepted, with a veto window
The #18494 target set came out a measured SUPERSET of the card's six shapes. The card's own three fairness controls — a noun-phrase label with no framing word, e.g.
**Removed keys FROM → TO:**— now also read as labels, so the gate will demand a concrete rewrite for them. The dev flagged it rather than burying it, pinned it as L7, and said it would want it ruled rather than guessed.This seat accepts it, on three grounds:
- Direction is stricter, not looser. A gate demanding more is not 门禁削弱, so no maintainer floor is crossed on that axis.
- It is what the discriminator means. A colon-closed migration heading is a label; separating those three would need a noun-versus-determiner read, which this file's own docblocks repeatedly measure and refuse as open-class.
- ⭐ It moves nothing on today's stock. The stock census over 429 changesets and 1322 tracked md/mdx found ZERO verdict deltas for the entire change, with the before/after instrument LIT 3/3 on probe shapes ⇒ the zero is a reading, ⛔ not a missing instrument. The superset is a pin against a future author, not a re-verdict of anything written.
⇒ Handled as a veto window: declared and executed, rolled back on objection.
⚠️ Maintainer: if you want those three noun-phrase-without-framing-word shapes left as mentions, say so and this is reverted to a narrower rule — the dev explicitly asked for that to be ruled rather than guessed, and it is a one-line revert plus L7.Findings carried out
#18937 filed by this seat (class (a)):
FRAMING_TAIL_RE's new word anchor does not cover hyphen or dot delimiters, sothe auto-migration FROM → TO …still reads as a label. ⭐ The dev could have fixed it — the in-place repair passes all four conditions — and declined because the fix moves the admit direction on a shape whose measured population is zero, which is the maintainer's floor. This seat agrees and filed it as a decision-shaped card rather than a patch. The two 「noted, not filed」 items (aMIGRATION_FRAMING_REdocblock claim aboutmigrations/registry.ts, and the zero corpus population of the whole in-line framing-tail path) reach no filing class; ⛔ no cards.Seat process note
⚠️ This seat's first verification pass was void and nearly produced a false negative: it fetched two refs in sequence, soFETCH_HEADhad moved tomainand everygit show FETCH_HEAD:readmaintwice — makingLABEL_COLON_REandSS1–SS8look absent from the head. Re-run against an explicitorigin/<branch>ref, all of it verifies. ⇒ recorded because a reviewer's broken instrument is the most dangerous kind: it fails toward rejecting correct work.CI at this writing on
b0678d370: 0 failures, judged per check by its latest run.Written 2026-09-18T06:44Z. The tree comparisons, the diff stat, the docblock citations on
main, the CI reading and the label state were taken at 2026-09-18T06:40Z.
Generated by Claude Code
- added 2 commits that reference this issue
on Sep 28, 2026
Filed by the
domain:specexecution seat, sessionsession_01KB5PFtxuy1x3dcR5gxudx6, 2026-09-16T15:5xZ, out of the at-tier contract review of PR #18484 (card #17864) — record5700402265, VERDICT PASS. ⛔ Unlabelled beyondfindingand unassigned; grading and routing are triage's.⭐ This one goes the opposite direction from the gate's other known gap: here the gate reads a real label as a mention and admits a changeset that ships no rewrite.
What was measured
scripts/check-adr-0087-registration.mjs's in-line arm now asksGOVERNING_WORD_REof the prefix with one framing word stripped (#17864, PR #18484). A compound-noun label — a noun immediately before the framing word — therefore reads as a mention. All of these arefrom-to-labelon the PR's base andnullon its head:End to end on a committed probe changeset in a private clone: body
**Schema Migration FROM → TO:** delete the block…with no concrete rewrite → base script exit 1, head script exit 0.⛔ Why this did not block PR #18484, stated so it is not re-litigated
The fairness control settles it. With the framing word removed, base already reads the same shapes as mentions:
⇒ head is the consistent application of the gate's pre-existing letter-adjacency rule through a framing word now made transparent, ⛔ not a rule PR #18484 introduced. And the stock writes such labels with a paren, a dash or a bare framing word — all unchanged.
In-tree population of the reached shape: 0 over 1233 tracked
md/mdxat39b7dd7e71and 0 over.changesetatorigin/main9c1897e52c, with 12 seeded scanner controls lit, a 1000-line lit control (the round's own 892 reproduced exactly by an independent per-line grep), and 159 non-null verdicts identical base vs head.The correction this card also carries
PR #18484's body says the dangerous direction is "Structurally, no". That is true only in the gate's operational sense of governs. The compound-noun label is an exposed false-negative shape, and the head docblock names the identifier blind spot but ⛔ not this one. ⇒ whatever is decided below, the docblock owes a sentence.
Two directions — ⛔ no ruling implied
Schema Migrationframing-strips to nothing, so the label reading returns..changesetare the population it would have to be run against.Dedupe words
GOVERNING_WORD_RE·withoutFramingTail·Schema Migration FROM·compound-noun label·check-adr-0087-registrationRefs
PR #18484 · card #17864 · the sibling false-positive card filed in the same stroke
Generated by Claude Code