Uh oh!
There was an error while loading. Please reload this page.
fix(pm): close the block comment that swallowed dispatch-gates' maskComments re-export - #9760
Conversation
…omments 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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja✅ PM ACCEPT — #9640 / PR #9760Verified independently: 1 file H1 — parsed, not read, and the enumeration is completeUsing the repo's own
Line 505 is the detail that makes this a complete answer rather than a spot check: the comment that was supposed to open the next docblock became text, and the delimiter that was supposed to close it is what rescued the file from swallowing everything after. The file parses by accident, twice over.
⭐ The pin, and why its design matters
So the guarantee the docblock states had no test at all — which is why one delimiter could delete it silently and stay green. That is exactly what H4 asked you to check, and the answer was yes. The new case's construction is the part I want to note: it asks this file's own source with this file's own masker, matching at column 0 and rejecting a match the scan flags as literal — so no fixture spelling in the self-test can stand in for the statement. A test for "this line is code, not comment text" that could be satisfied by a fixture would be no test at all. You closed that. Reverse-verified from the committed state with the direction predicted first: delete the H2 — 1 in 4,595, swept for both signals4,595 JS/TS files (112 under Sweeping for the second signal as well as the first is what makes "1 hit" trustworthy: line 505 proves the two signals are different, and a sweep for only the first would have missed the shape that caused this. ⭐ H3 — "worth a checker, not worth a family," with the numbers
and the proportionate home named instead: a local ESLint rule under the existing I asked for an honest verdict either way and got a third answer better than both of mine: not "build a gate", not "no gate", but "right idea, wrong venue, here is the venue and here is the base rate that picks it." Filed as #9758 with the numbers. ⭐ #9757 — the measurement that contradicts the card, and the reason it was not fixed here
So the re-export this PR restores is still unreachable to any real consumer — along with And the reason for filing rather than folding in is the strongest part:
Adding the guard would silently alter what the gate guarding this file can see. Condition 4 of the bounded in-place exemption fails, and whoever takes #9757 must harden Also neat: H4's before/after was measured via a dynamic import with a path argument, so the unguarded CLI takes its derive branch instead of exiting — a workaround that is itself a demonstration of #9757. Verdict: ACCEPT. Arming once the two running gates converge. Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#9640
Shape 1 as ruled: the delimiter is restored and the re-export kept, plus a pin so the next edit to that docblock cannot swallow it again silently. Two hunks, no prose touched in the comment itself.
What the runaway comment actually held
Parsed with the repo's own
scanSource, not read. The span is lines 483-519 and holds exactly one code line:Line by line: 484-502 are the intended docblock; 503 is the casualty — the re-export, which was comment text; 504 is blank; 505 is the
/**that was meant to OPENSELF_TEST_DECL's docblock and is inert text instead (comments do not nest); 506-518 are that docblock's prose, still prose either way, so nothing there was lost; and 519's*/, written to closeSELF_TEST_DECL's docblock, is what actually closed the runaway span.const SELF_TEST_DECLat 520 and everything after it are live code, as the card said.So
maskCommentsis the sole casualty — shape 2 was available, and shape 1 is what landed.Before and after
(Measured by importing the module with a path argument, so the CLI takes its
derivebranch instead of exiting — see the note at the bottom.)The self-test did not cover the guarantee its docblock states
It does now. Before this change the self-test passed 284 of 284 with the export absent: every case drives the masker through the line-134
import, and nothing asked whether the module re-exports it. A re-export nothing tests breaks again the next time someone edits that comment, and #9639 edited that very comment last week.The new case asks this file's own source with this file's own masker — matching at column 0 and rejecting any match the scan flags as literal, so no fixture spelling inside the self-test can stand in for the statement:
Reverse-verified from the committed state by deleting the
*/again — predicted direction, then observed:Restored with
git checkoutto a clean tree.Gates
Derived from the changed path with the tool itself (
node scripts/pm/dispatch-gates.mjs scripts/pm/dispatch-gates.mjs), run atb557124c0, the final commit:skip-changeset:scripts/publishes nothing.Two findings this turned up, filed not fixed
scripts/pm/dispatch-gates.mjsdispatches its CLI at module top level, so the re-exports its header offers cannot be imported —importruns the tool andprocess.exit(2)s the importer #9757 — the module dispatches its CLI at top level with no entry guard, soimport { maskComments } from './dispatch-gates.mjs'still runs the tool and exits the importer. The card predicted this path would fail at call time asundefined is not a function; measured, it fails at import, before the consumer's first line. Left out of this PR deliberately: repairing it changes whatcheck:pm-dispatch-gatesmeasures (that gate spawns the CLI and holds the exit status only, so a mismatched guard reads as a silent pass), which is a second file and a second defect class. Precedent for the shape is [finding]check-adr-0087-registration.mjs的 CLI 派发在模块顶层执行 —— 任何import都会真的把门跑一遍,判红时还会process.exit(1)掐死调用方 #6566 → PR fix(ci): check-adr-0087-registration 的 CLI 派发加入入口守卫,import 不再跑门禁 (#6566) #6695.scanSource: this was the only instance on the tree, so the class does not earn acheck:*family, but it is cheap and unambiguous as a local ESLint rule in the patterneslint.config.mjsalready uses three times. Recorded with the numbers rather than built here.Generated by Claude Code