From 4efb218b9c4a1585004d620ca340b29757179eb0 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 00:32:45 +0000 Subject: [PATCH 1/2] test(scripts): read the vi.mock anti-exemption pin over the comment-blanked gate, and name the offending line The pin in `scripts/__tests__/check-vi-mock-inherit.test.ts` matched `/\.test\.tsx?['"`]\s*[,\]]/` against the RAW text of `scripts/check-vi-mock-inherit.mjs`. That gate's leading docblock is the per-slice logbook objectui#6892 writes every sweep record into, and a record names test files: a backticked filename followed by a comma is byte-identical to one entry of the exemption array the pin exists to catch. It went red on running prose twice (objectui#8116 at 69 of 69, objectui#8207 at `e104c509d`), and both times the repair was to reword the sentence. Apply the gate's own rule -- only text the language would EXECUTE is judged -- to the gate's own source: run the ENTRY pattern over `maskComments(src)`. A real exemption array is a string literal, which the shared masker leaves intact, so the pin keeps every tooth; the header docblock becomes unreachable. The DECLARATION pattern still reads the raw source: `^\s*` stops at a docblock's ` * ` prefix, so it has no false red to narrow away. Report the offending LINES instead of `not.toMatch`, which printed the whole ~1850-line source as "received" and never said where the match was. A sibling case drives both directions with the raw match as its control: the array fixture must match before masking and still be reported after it, the header-record fixture must match before masking and be gone after it, and an array written below that prose is still reported. Census unmoved: `node scripts/check-vi-mock-inherit.mjs` exits 0 at 663 judged / 663 inherit / 0 auto-mocked / 0 other workspace before and after. Part of objectui#8117 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr --- .../__tests__/check-vi-mock-inherit.test.ts | 85 ++++++++++++++++++- 1 file changed, 82 insertions(+), 3 deletions(-) diff --git a/scripts/__tests__/check-vi-mock-inherit.test.ts b/scripts/__tests__/check-vi-mock-inherit.test.ts index 650fd8eba6..3bd7dd19b0 100644 --- a/scripts/__tests__/check-vi-mock-inherit.test.ts +++ b/scripts/__tests__/check-vi-mock-inherit.test.ts @@ -15,7 +15,7 @@ import { scan, summarise, } from '../check-vi-mock-inherit.mjs'; -import { scanSource } from '../js-comment-mask.mjs'; +import { maskComments, scanSource } from '../js-comment-mask.mjs'; /** * objectui#6849 — the test for `scripts/check-vi-mock-inherit.mjs`. @@ -55,6 +55,9 @@ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../ /** A quote, from its code point — see "Fixture discipline" above. */ const Q = String.fromCharCode(39); +/** A backtick, from its code point — same discipline as `Q`. */ +const BT = String.fromCharCode(96); + const COVERED = '@object-ui/react'; /** Escape a specifier list for embedding in a `RegExp` source. */ @@ -339,6 +342,41 @@ describe('the failing shape — a factory that hand-lists the export surface', ( // Scope — the narrow gate triage ruled for, and what it must NOT touch // --------------------------------------------------------------------------- +/** + * The shape a hand-written array of exempt file paths declares itself with. + * + * Named rather than inlined so a failure can point at THE pattern instead of + * asking the reader to copy one out of an expectation by hand (objectui#8117). + */ +const EXEMPTION_DECLARATION_RE = /^\s*(export )?const (ALLOW|EXEMPT|IGNORE|SKIP|KNOWN)[A-Z_]*\s*=/m; + +/** The shape one ENTRY of such an array has: a quoted test file, then `,` or `]`. */ +const EXEMPTION_ENTRY_RE = /\.test\.tsx?['"`]\s*[,\]]/; + +/** + * Every line of `code` that matches `re`, as `: `. + * + * ## Why not `expect(src).not.toMatch(re)` (objectui#8117) + * + * `not.toMatch` over this gate prints its ~1850-line source as the "received" + * value and never says WHERE the match was; locating it needed a separate + * `grep -nP` with the pattern copied out of this file by hand. The assertion + * below is the same assertion — zero matches — reported so its failure names + * the offending line. `line` is looked up in `original`, which is the raw + * source: `maskComments` preserves byte offsets, so the numbering is shared. + */ +function offendingLines(code: string, re: RegExp, original: string = code) { + const lines = original.split('\n'); + const all = new RegExp(re.source, re.flags.includes('g') ? re.flags : `${re.flags}g`); + const out: string[] = []; + for (let m = all.exec(code); m; m = all.exec(code)) { + const n = code.slice(0, m.index).split('\n').length; + out.push(`${n}: ${lines[n - 1].trim()}`); + if (all.lastIndex === m.index) all.lastIndex += 1; + } + return [...new Set(out)]; +} + describe('scope — narrow, and out of scope by construction rather than by exemption', () => { it('a RELATIVE specifier is never judged — whole-module replacement is legitimate', () => { // `plugin-calendar/src/registration.test.tsx` replaces `./ObjectCalendar` @@ -365,8 +403,49 @@ describe('scope — narrow, and out of scope by construction rather than by exem // Triage: ⛔ 不要顺手加例外白名单. An exemption means the recogniser called // correct code broken — the repair is the recogniser, not a carve-out. const src = fs.readFileSync(path.join(repoRoot, 'scripts/check-vi-mock-inherit.mjs'), 'utf8'); - expect(src).not.toMatch(/^\s*(export )?const (ALLOW|EXEMPT|IGNORE|SKIP|KNOWN)[A-Z_]*\s*=/m); - expect(src).not.toMatch(/\.test\.tsx?['"`]\s*[,\]]/); + // objectui#8117: the ENTRY pattern is read over the COMMENT-BLANKED source, + // the gate's own "only text the language would EXECUTE is judged" rule + // turned on the gate's own file. The header docblock is this sweep's + // per-slice logbook by construction, so recording a sweep means naming test + // files — and a backticked filename followed by a comma is byte-identical + // to one entry of the array this pin exists to catch. It reddened twice on + // running prose (#8116, #8207 at `e104c509d`), and both times the repair + // was to reword the sentence: a tax on every future slice author, paid to a + // pin whose failure text points at a regex while the only "fix" it suggests + // is the carve-out the comment above forbids. Blanking costs the pin + // nothing — a real exemption array is a string LITERAL, which the shared + // masker leaves intact; the sibling case below drives both directions. + // + // The DECLARATION pattern still reads the raw source: it cannot match a + // docblock line (`^\s*` reaches the ` * ` prefix and stops), so it has no + // false red to fix and narrowing it would buy nothing. + expect(offendingLines(src, EXEMPTION_DECLARATION_RE)).toEqual([]); + expect(offendingLines(maskComments(src), EXEMPTION_ENTRY_RE, src)).toEqual([]); + }); + + it('that pin reads CODE, and the header prose it used to redden on is intact', () => { + // Both legs are needed: on a tree whose header already avoids the comma, + // an empty reading proves only that today's prose dodges the pattern, not + // that the pin stopped judging prose. The RAW assertions are the control — + // each fixture MUST match before masking, or the leg below measures nothing. + const entry = (file: string) => `${Q}packages/x/src/${file}${Q},`; + const array = `const ALLOWLIST = [${entry('A.test.tsx')} ${entry('B.test.ts')}];`; + // The exact shape #8116 measured: one sweep record naming a swept file. + const prose = `/**\n * ${BT}ObjectView.expandFls-7429.test.tsx${BT}, landed by objectui#7429\n */`; + + expect(EXEMPTION_ENTRY_RE.test(array), 'the positive fixture is matchable at all').toBe(true); + expect(EXEMPTION_ENTRY_RE.test(prose), 'the prose fixture is matchable BEFORE masking').toBe(true); + + // A real exemption array survives the mask — the pin keeps every tooth. + expect(offendingLines(maskComments(array), EXEMPTION_ENTRY_RE, array)).toEqual([ + `1: ${array}`, + ]); + // The header record does not — that is the false red, and it is gone. + expect(offendingLines(maskComments(prose), EXEMPTION_ENTRY_RE, prose)).toEqual([]); + // And the same masking must not blind the pin to an array written INSIDE + // the docblock's file: prose above it does not shelter the code below it. + const both = `${prose}\n${array}`; + expect(offendingLines(maskComments(both), EXEMPTION_ENTRY_RE, both)).toEqual([`4: ${array}`]); }); it('the covered set is non-empty and names only real workspace packages', () => { From 2a10ce4e12d841084e253db14da1c0560cd936e8 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 00:43:15 +0000 Subject: [PATCH 2/2] test(scripts): count to the first non-whitespace byte of the match, not to its start Caught by the dispatch note's second positive control, which asked for the ANCHORED carve-out shape (`const KNOWN_BAD = [...]`) alongside the unanchored inline list. The pin went red as it must, but the line it named was [ "1853: " ] an EMPTY line, one above the declaration. `EXEMPTION_DECLARATION_RE` opens with `^\s*` and `\s` matches a newline, so against a declaration with a blank line above it the match STARTS on that blank line. Counting to `m.index` therefore reported the blank line. A failure message that names the wrong line is the defect this branch is about, one level down, so the repair gets its own case rather than a comment. Part of objectui#8117 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr --- .../__tests__/check-vi-mock-inherit.test.ts | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/scripts/__tests__/check-vi-mock-inherit.test.ts b/scripts/__tests__/check-vi-mock-inherit.test.ts index 3bd7dd19b0..0a10eea781 100644 --- a/scripts/__tests__/check-vi-mock-inherit.test.ts +++ b/scripts/__tests__/check-vi-mock-inherit.test.ts @@ -370,7 +370,13 @@ function offendingLines(code: string, re: RegExp, original: string = code) { const all = new RegExp(re.source, re.flags.includes('g') ? re.flags : `${re.flags}g`); const out: string[] = []; for (let m = all.exec(code); m; m = all.exec(code)) { - const n = code.slice(0, m.index).split('\n').length; + // Count to the first NON-WHITESPACE byte of the match, not to `m.index`. + // `EXEMPTION_DECLARATION_RE` opens with `^\s*`, and `\s` matches a newline: + // against a declaration with a blank line above it the match STARTS on that + // blank line, so the naive offset reported `1853: ` — an empty line, one + // above the carve-out, which is worse than useless in a failure message. + const at = m.index + /^\s*/.exec(m[0])![0].length; + const n = code.slice(0, at).split('\n').length; out.push(`${n}: ${lines[n - 1].trim()}`); if (all.lastIndex === m.index) all.lastIndex += 1; } @@ -448,6 +454,18 @@ describe('scope — narrow, and out of scope by construction rather than by exem expect(offendingLines(maskComments(both), EXEMPTION_ENTRY_RE, both)).toEqual([`4: ${array}`]); }); + it('a reported line is the DECLARATION, never the blank line above it', () => { + // Measured, not hypothetical: the first draft of `offendingLines` counted to + // `m.index`, and `EXEMPTION_DECLARATION_RE` opens with `^\s*` where `\s` + // matches a newline. Appending a carve-out to the gate with a blank line + // before it therefore reported `1853: ` — an empty line, one above the + // declaration. A failure message that names the wrong line is the defect + // objectui#8117 is about, one level down, so it gets its own case. + const decl = "const KNOWN_BAD = ['packages/x/src/A.test.tsx'];"; + const withBlankLineAbove = `const ok = 1;\n\n${decl}\n`; + expect(offendingLines(withBlankLineAbove, EXEMPTION_DECLARATION_RE)).toEqual([`3: ${decl}`]); + }); + it('the covered set is non-empty and names only real workspace packages', () => { // A typo here empties the population silently, and the gate then reports OK // over nothing. The `covered` floor below is the other half of that guard.