You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[finding] dispatch-gates' export { maskComments } is swallowed by an unterminated block comment — the docblock claims a re-export the module does not have #9640
Noticed while measuring the hint scan for #9626 (PR #9639). Not fixed there: different defect class, and the correct shape is a judgment call rather than mechanical.
What happens
scripts/pm/dispatch-gates.mjs line 483 opens a block comment that is never closed before the statement it introduces:
483: /**
484: * The comment/literal scanner used to live here. It now lives in
...
501: * Re-exported because this tool's self-test drives the SAME masker the gates
502: * run, not a copy of it.
503: export { maskComments };
There is no closing delimiter between line 502 and line 503, so export { maskComments }; is comment text. The block runs on until the next closing delimiter, which belongs to the docblock of SELF_TEST_DECL below it — that constant and everything after it are fine, so the file parses and nothing is red.
Measured:
maskComments exported? undefined
maskSelfTests exported? function
Why it is worth recording
The docblock states the reason the re-export exists — "Re-exported because this tool's self-test drives the SAME masker the gates run, not a copy of it" — and that reason is exactly the drift this file's whole contract is written against (scripts/js-comment-mask.mjs's header records five gates that each grew a private copy of this judgment and got it wrong two different ways). The header says the guarantee is in place; the module does not provide it.
Dormant today, in one specific sense only: nothing currently imports maskCommentsfrom dispatch-gates. Every live consumer imports it straight from scripts/js-comment-mask.mjs (check-dispatcher-error-vocabulary, check-platform-checklist, check-examples-live-imports, docs-audit/affected-docs, check-org-identifier, check-error-code-casing, check-error-status-conformance), and dispatch-gates' own internal use works because it imports the symbol at line 134. So the failure surfaces only when someone follows the docblock and writes import { maskComments } from './dispatch-gates.mjs' — which fails as undefined is not a function at call time, not at import.
Shapes
Close the comment before line 503 and keep the re-export. Restores what the docblock promises; costs one delimiter.
Delete both the re-export line and the paragraph promising it, and let consumers import from js-comment-mask.mjs — which is what every consumer already does, and arguably the better direction, since a re-export through a 3000-line CLI is a longer path to the same function.
Triage's call which. Note that maskSelfTests next door IS a real export function, so whichever way this goes, the two neighbours should stop looking symmetric when they are not.
A guard would have caught it
The class is "a statement that reads as code but is inside a comment". Nothing in the tree looks for it. Whether that is worth a gate is a separate question from this one-line repair; recording it here rather than assuming.
Filed unassigned, no pm:queue — an observation, triage's call.
Scope: scripts/pm/dispatch-gates.mjs (the runaway block comment) plus whatever H1's enumeration turns up inside it. Will report H1 enumeration, H4 before/after measurement, H2 repo-wide sweep, and an H3 verdict on a contained gate.
{
"issue": 9640,
"status": "done",
"branch": "claude/issue-9640-maskcomments-reexport",
"pr": "https://github.com/objectstack-ai/objectstack/pull/9760",
"premise_still_valid": true,
"summary": "H1 (leads): parsed with the repo's own scanSource, the runaway span is lines 483-519 and holds exactly ONE code line — 503 `export { maskComments };`. Enumerated: 484-502 the intended docblock; 503 the casualty; 504 blank; 505 the `/**` that was meant to OPEN SELF_TEST_DECL's docblock and is inert text instead (comments do not nest); 506-518 that docblock's prose, still prose either way, so nothing was lost there; 519's `*/`, written to close SELF_TEST_DECL's docblock, is what actually closed the runaway span; `const SELF_TEST_DECL` at 520 onward is live code, as the card said. maskComments is the sole casualty, so shape 2 was genuinely available — ruling 1 stands and shape 1 landed. Fix: one ` */` line before 503, no prose in that comment touched (ruling 3), and the header needed no correction because it is true again once the export is live (ruling 2). Plus a pin, because the guarantee had no test: the self-test passed 284/284 with the export absent, since 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 the scan flags as literal, so no fixture spelling in the self-test can stand in for the statement. H2: swept 4,595 JS/TS files (112 under scripts/, 4,483 elsewhere) for both signals — a statement-shaped line wholly inside a block-comment span, and a nested `/*` opener inside a span; 1 hit, this one. `.claude/` has one JS file (clean), `skills/` has no JS, so nothing governed to report. H3 verdict: worth a checker, NOT worth a check:* family (111th family, workflow step, required context and self-test for a class measured at 1 in 4,595) — the proportionate home is a local ESLint rule under the existing `pnpm lint`, in the inline-plugin pattern eslint.config.mjs already uses three times (slot-lookup, query-options, verify-stand-in); ESLint hands a rule its comment nodes, so it needs no masker and no natural-language reading. Filed as #9758 with the numbers rather than built here. One measurement contradicts the card and is bigger than the delimiter, but not the way H1 anticipated: the card says the failure surfaces as `undefined is not a function` at CALL time — measured, dispatch-gates dispatches its CLI at module top level with no entry guard, so `import { maskComments } from './dispatch-gates.mjs'` runs the tool and process.exit(2)s the importer BEFORE its first line. Filed as #9757 rather than fixed here: it changes what check:pm-dispatch-gates measures (that gate spawns the CLI with stdio inherit and holds the exit status only, so a mismatched guard reads as a silent pass), which is a second file, a second defect class and a new verification surface — condition 4 of the bounded in-place exemption fails.",
"tests": "All at final commit b557124c0 (tree clean, nothing later). H4 before, on main: `maskComments exported? undefined` / `maskSelfTests exported? function` — reproduced exactly as the card measured, via a dynamic import with a path argument so the unguarded CLI takes its derive branch instead of exiting. H4 after: `maskComments exported? function` / `maskSelfTests exported? function`. Self-test before: `284 cases pass` WITH the export broken (the card's guarantee was untested); after: `the maskComments re-export is code, not comment text` / `dispatch-gates self-test: 285 cases pass`. Reverse verification ran from the COMMITTED state, direction predicted first (exactly one case red, exit 1) and observed: after deleting the `*/` again, `dispatch-gates self-test: 1 of 285 case(s) failed.` exit=1 and the export measurement returned to undefined; restored with `git checkout branch -- path` to a clean tree (no build products involved — this is a script edit, so no dist rebuild applies and no package build was needed). Gate union derived from the actual changed path with the tool itself (`node scripts/pm/dispatch-gates.mjs scripts/pm/dispatch-gates.mjs` names check:pm-dispatch-gates and check:cross-package-test-inputs), run at b557124c0: `check:pm-dispatch-gates` 285 cases pass; `check:cross-package-test-inputs` OK, 12 packages read outside themselves, all declared; `check:nul-bytes` OK, 6237 text files scanned, no raw ASCII control bytes; `npx eslint scripts/pm/dispatch-gates.mjs --no-inline-config` exit 0. PR labels read back after the write: size/s, skip-changeset.",
"open_questions": [],
"out_of_scope_findings": [
"filed as #9757: scripts/pm/dispatch-gates.mjs dispatches its CLI at module top level with no entry guard, so importing it runs the tool and exits the importer — the docblock's re-exports (maskComments, and isExtractConfigPath/isMetadataFormModulePath) are unreachable to any consumer even after this fix; precedent #6566 to PR #6695; whoever takes it must also harden check-dispatch-gates.mjs, which holds the exit status only",
"filed as #9758: no checker exists for the class 'a statement swallowed by an unterminated block comment' — H2 base rate 1 in 4,595 files, verdict is a local ESLint rule rather than a new check:* family, with the proposed rule shape and the reasoning both ways"
]
}
Activity
os-steve commentedon Aug 18, 2026
Claiming this card.
session_01XqDQYVU5smx29ts9pAErjaclaude/issue-9640-maskcomments-reexport(pushed, branched from2065e31d5, which contains the fix(pm): dispatch-gates names check:doc-anchors for a content card — the genericity refusal read the glob-collapsed hint #9639 blockerff61721ab)../objectstack-9640Scope:
scripts/pm/dispatch-gates.mjs(the runaway block comment) plus whatever H1's enumeration turns up inside it. Will report H1 enumeration, H4 before/after measurement, H2 repo-wide sweep, and an H3 verdict on a contained gate.Generated by Claude Code
os-steve commentedon Aug 18, 2026
{ "issue": 9640, "status": "done", "branch": "claude/issue-9640-maskcomments-reexport", "pr": "https://github.com/objectstack-ai/objectstack/pull/9760", "premise_still_valid": true, "summary": "H1 (leads): parsed with the repo's own scanSource, the runaway span is lines 483-519 and holds exactly ONE code line — 503 `export { maskComments };`. Enumerated: 484-502 the intended docblock; 503 the casualty; 504 blank; 505 the `/**` that was meant to OPEN SELF_TEST_DECL's docblock and is inert text instead (comments do not nest); 506-518 that docblock's prose, still prose either way, so nothing was lost there; 519's `*/`, written to close SELF_TEST_DECL's docblock, is what actually closed the runaway span; `const SELF_TEST_DECL` at 520 onward is live code, as the card said. maskComments is the sole casualty, so shape 2 was genuinely available — ruling 1 stands and shape 1 landed. Fix: one ` */` line before 503, no prose in that comment touched (ruling 3), and the header needed no correction because it is true again once the export is live (ruling 2). Plus a pin, because the guarantee had no test: the self-test passed 284/284 with the export absent, since 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 the scan flags as literal, so no fixture spelling in the self-test can stand in for the statement. H2: swept 4,595 JS/TS files (112 under scripts/, 4,483 elsewhere) for both signals — a statement-shaped line wholly inside a block-comment span, and a nested `/*` opener inside a span; 1 hit, this one. `.claude/` has one JS file (clean), `skills/` has no JS, so nothing governed to report. H3 verdict: worth a checker, NOT worth a check:* family (111th family, workflow step, required context and self-test for a class measured at 1 in 4,595) — the proportionate home is a local ESLint rule under the existing `pnpm lint`, in the inline-plugin pattern eslint.config.mjs already uses three times (slot-lookup, query-options, verify-stand-in); ESLint hands a rule its comment nodes, so it needs no masker and no natural-language reading. Filed as #9758 with the numbers rather than built here. One measurement contradicts the card and is bigger than the delimiter, but not the way H1 anticipated: the card says the failure surfaces as `undefined is not a function` at CALL time — measured, dispatch-gates dispatches its CLI at module top level with no entry guard, so `import { maskComments } from './dispatch-gates.mjs'` runs the tool and process.exit(2)s the importer BEFORE its first line. Filed as #9757 rather than fixed here: it changes what check:pm-dispatch-gates measures (that gate spawns the CLI with stdio inherit and holds the exit status only, so a mismatched guard reads as a silent pass), which is a second file, a second defect class and a new verification surface — condition 4 of the bounded in-place exemption fails.", "tests": "All at final commit b557124c0 (tree clean, nothing later). H4 before, on main: `maskComments exported? undefined` / `maskSelfTests exported? function` — reproduced exactly as the card measured, via a dynamic import with a path argument so the unguarded CLI takes its derive branch instead of exiting. H4 after: `maskComments exported? function` / `maskSelfTests exported? function`. Self-test before: `284 cases pass` WITH the export broken (the card's guarantee was untested); after: `the maskComments re-export is code, not comment text` / `dispatch-gates self-test: 285 cases pass`. Reverse verification ran from the COMMITTED state, direction predicted first (exactly one case red, exit 1) and observed: after deleting the `*/` again, `dispatch-gates self-test: 1 of 285 case(s) failed.` exit=1 and the export measurement returned to undefined; restored with `git checkout branch -- path` to a clean tree (no build products involved — this is a script edit, so no dist rebuild applies and no package build was needed). Gate union derived from the actual changed path with the tool itself (`node scripts/pm/dispatch-gates.mjs scripts/pm/dispatch-gates.mjs` names check:pm-dispatch-gates and check:cross-package-test-inputs), run at b557124c0: `check:pm-dispatch-gates` 285 cases pass; `check:cross-package-test-inputs` OK, 12 packages read outside themselves, all declared; `check:nul-bytes` OK, 6237 text files scanned, no raw ASCII control bytes; `npx eslint scripts/pm/dispatch-gates.mjs --no-inline-config` exit 0. PR labels read back after the write: size/s, skip-changeset.", "open_questions": [], "out_of_scope_findings": [ "filed as #9757: scripts/pm/dispatch-gates.mjs dispatches its CLI at module top level with no entry guard, so importing it runs the tool and exits the importer — the docblock's re-exports (maskComments, and isExtractConfigPath/isMetadataFormModulePath) are unreachable to any consumer even after this fix; precedent #6566 to PR #6695; whoever takes it must also harden check-dispatch-gates.mjs, which holds the exit status only", "filed as #9758: no checker exists for the class 'a statement swallowed by an unterminated block comment' — H2 base rate 1 in 4,595 files, verdict is a local ESLint rule rather than a new check:* family, with the proposed rule shape and the reasoning both ways" ] }Generated by Claude Code