From b557124c0d202d118307118244fd66ead229552c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 22:12:01 +0000 Subject: [PATCH] fix(pm): close the block comment that swallowed dispatch-gates' maskComments re-export The docblock above `export { maskComments };` never closed, so the statement was comment text and the module had no `maskComments` export while its header said the re-export was in place. The block ran on to the next `*/`, which belongs to the docblock of `SELF_TEST_DECL` below it, so the file parsed and no gate went red. Measured before: `maskComments exported? undefined` / `maskSelfTests exported? function`. After: both `function`. Pinned in the tool's own self-test, which is where the guarantee was missing: 284 cases passed with the export absent, because every case drives the masker through the line-134 import and nothing asked whether the module re-exports it. The new case asks this file's own source with this file's own masker, matching at column 0 and rejecting a match flagged as literal, so a fixture spelling in the self-test cannot stand in for the statement. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja --- scripts/pm/dispatch-gates.mjs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/scripts/pm/dispatch-gates.mjs b/scripts/pm/dispatch-gates.mjs index 40630d37bd..15a26ed7b4 100644 --- a/scripts/pm/dispatch-gates.mjs +++ b/scripts/pm/dispatch-gates.mjs @@ -500,6 +500,7 @@ export function resolveCheckToFiles(checkName, scriptsMap) { * * Re-exported because this tool's self-test drives the SAME masker the gates * run, not a copy of it. + */ export { maskComments }; /** @@ -2182,6 +2183,24 @@ function selfTest() { t('a quote inside a regex literal does not open a string', commentHints.includes('packages/client/src')); t('masking preserves every offset', maskComments(commented).length === commented.length); + // ...and the re-export of that masker is CODE, not comment text (#9640). The + // statement sits at the end of the longest docblock in this file, and a + // missing `*/` swallows it into prose that still parses: the module then has + // no `maskComments` export while its header says it has one, and nothing goes + // red — every gate stayed green over it until someone parsed for it. Asked of + // this file's own source with this file's own masker, which is what the + // docblock claims. Column 0 only, and a match the scan flags as literal is + // rejected, so no fixture spelling in this self-test can stand in for the + // statement. + const ownSource = readFileSync(new URL(import.meta.url), 'utf8'); + const ownScan = scanSource(ownSource); + t( + 'the maskComments re-export is code, not comment text', + [...ownSource.matchAll(/^export \{ maskComments \};$/gm)].some( + (m) => !ownScan.comment[m.index] && !ownScan.literal[m.index], + ), + ); + // The self-test boundary. The fixture puts a column-0 `}` inside a template // literal on purpose: that is the shape this tree really has (a check script // whose self-test embeds TS sources as fixtures), and a boundary that stopped