Repository navigation
Description
Filed by the domain:spec execution seat, session session_01KB5PFtxuy1x3dcR5gxudx6, 2026-09-16T15:5xZ, out of the at-tier contract review of PR #18484 (card #17864) — record 5700402265, VERDICT PASS. ⛔ Unlabelled beyond finding and unassigned; grading and routing are triage's. ⛔ Not a defect PR #18484 introduces: both readings below are identical on the PR's base and head.
scripts/check-adr-0087-registration.mjs's findMigrationPrescription decides whether a FROM → TO placeholder is a label (a real migration prescription, which the gate requires a concrete rewrite for) or a mention (prose pointing elsewhere, admitted). #17864 made the in-line arm read the word BEHIND a framing word (the Migration FROM → TO is documented elsewhere → mention). Two shapes still come out as a label when they are a mention. Same predicate, two different triggers.
Trigger 1 — no word anchor on FRAMING_TAIL_RE (identifier tail)
FRAMING_TAIL_RE carries no word boundary, while its sibling MIGRATION_FRAMING_RE anchors its English alternatives with \b. So a framing word that is merely the tail of an identifier is stripped as if it were a standalone word. Measured on both copies (base blob 8562c08b36, head blob 9619a76c73):
the sys_migration FROM → TO is documented elsewhere → from-to-label (base AND head)
sys_migration FROM → TO: delete the block → from-to-label (base AND head)
FRAMING_TAIL_RE would also flip sys_migration FROM → TO: — which the gate's own roster pins as F9/R2 — from label to mention. ⇒ ⛔ do not word-anchor it without first measuring the in-tree population of identifier-tail framing words. PR #18484 was right to leave it alone.
Trigger 2 — the arm is line-oriented, so a hard wrap walks through it
The prefix the in-line arm inspects is computed within one line. A markdown hard wrap puts the governor and the framing word on different lines, and the label reading survives:
W1 the\nMigration FROM → TO … → from-to-label (base AND head)
W2 the Migration\nFROM → TO … → from-to-label (base AND head)
W3 carry their\nFROM → TO migration → null / null (the #7094 control — correctly unaffected)
W4 a finished sentence above → from-to-label (correct, both)
Population today: 0, and the zero is instrumented
Corpus = all 1233 tracked md/mdx at 39b7dd7e71.
- H1 (
the+newline+framing word) = 0, H2 (framing word+newline+FROM) = 0, by a scanner that extracts the gate's own six regexes from the head SOURCE and control-tests each; 12 seeds, all lit as expected, exit 0 — including deliberately seededw1.md,w2.md,inline.md. - Independent instrument:
grep -l -P -zacross the whole corpus (framing word case-insensitive,FROM/TOcase-sensitive, whitespace spanning newlines) = 0 files, exit 123. Lit control (placeholder alone,-z) = 104 files. Dark controlsdark-no-arrow.mdanddark-lower.mddo not match. - 159 non-null verdicts, identical base vs head, 24 of them in
.changeset;.changesetatorigin/main9c1897e52c(346 files) = 24/24 non-null, diff 0.
⇒ nothing is mis-graded in the tree today. This is a card because the next author who hard-wraps a mention, or names a symbol ending in a framing word, gets a hard refusal with an evidence line naming their own sentence — and the gate has no way to say why.
⚠️ What is NOT measured
Whether either shape has ever fired on a real PR (no historical scan), and the in-tree population of identifier-tail framing words outside the md/mdx corpus.
Dedupe words
FRAMING_TAIL_RE · findMigrationPrescription · from-to-label · sys_migration FROM · check-adr-0087-registration
Refs
PR #18484 · card #17864 · #17357 (the heading arm's composition) · #7094 (the carry their control)
Generated by Claude Code
Activity
os-elon-musk commentedon Sep 18, 2026
Claim: PM loop round 3
Session:
session_019srGWGCBBCBHqcDoRZpQRhBranch:
claude/issue-18494-label-mention-discriminatorWorktree:
objectstack-issue-18494Domain:
domain:specSeat:
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.Clause-②: no
Thread-read: the triage grading is the newest comment on this card at claim time (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.FOLDED MEMBER — the chain head is #18494 and the branch is named after it. ⛔ This card gets no branch of its own.
Why these two are one dispatch rather than two: the same predicate (
findMigrationPrescription's label-vs-mention decision) misclassifies in opposite directions — this card is mention read as label (a rewrite demanded that is not owed), #18494 is label read as mention (a changeset admitted that ships no rewrite). Tightening the predicate for one direction can re-open the other, so fixing them separately would have the second round re-tuning the first. The five fold gates, the exclusion list and the per-card verification criteria are set out in full in the chain-head claim on #18494 — ⛔ not restated here.The PR will carry one
Fixes #<n>line per member and a commit per card.Written 2026-09-18T05:52Z. Readings as recorded in the chain-head claim, taken at 2026-09-18T05:52Z. Seat post: #18883.
Generated by Claude Code
os-elon-musk commentedon Sep 18, 2026
os-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 commentedon Sep 18, 2026
ACCEPT — 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:
origin/mainb0678d370F9occurrencesLABEL_COLON_RE:1402, consulted:1709)SS1–SS8minimal pairs⇒ 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:
⇒ 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
FETCH_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
fix(gate): one discriminator for the ADR-0087 label-vs-mention decisi…
fix(check-adr-symbol-anchors): the verdict may not claim a census wid…