Skip to content

[finding] 21 private comment-strippers live outside scripts/, and no gate watches the family — check:parse-guard is the wrong instrument #12307

Description

@yinlianghui

Filed unassigned by the os-dev seat implementing #12267. Observation-class; recording the census, not claiming it.

Why this is filed separately from #12267

#12267 offered closure B: "widen check:parse-guard's population beyond scripts/ so the next copy is caught mechanically." That card's premise for B is that scripts/check-parse-guard.mjs "exists because two private stripComments families drifted apart". It does not.

check-parse-guard governs the three TypeScript parser entry pointsts.createSourceFile, ts.createProgram, ts.transpileModule — and bans them outside scripts/ts-parse.mjs. The stripComments sentence appears in its header only as a cited precedent for why a one-time sweep does not hold:

That is not a theory about the tree, it is the tree's own measured result twice over: check-entry-guard.mjs exists because a one-time sweep of 33 files did not stop a twelfth spelling of "was I run?", and js-comment-mask.mjs exists because two private stripComments families drifted apart in two different directions.

Widening that gate's population would extend a ban on raw parser entry points to package sources. It would not catch a single private comment-stripper. Its own header also argues against the widening on two independent grounds: parses outside scripts/** are deliberately not banned (a published package must not depend on repo tooling to answer "did this parse?"), and declaring a broader root is refused because it would name the gate for every card in the tree.

So B was closed as moot in #12267 rather than implemented, and the class it was aiming at is filed here instead.

The census — the measurement #12267 asked for

Counted on 0acadda3dd, over git ls-files for *.{ts,tsx,mts,cts,js,mjs,cjs}, excluding scripts/:

21 files carry a private comment-stripping implementation. Two populations, found by two different probes:

  • 14 files carry a regex-based stripper (probe: the fixed string [\s\S]*?\*\/, plus the //…$ line-strip forms).
  • 7 files carry a hand-rolled character-scanner named stripComments (probe: the identifier).

The two sets are disjoint. Exactly 2 of the 21 are the byte-identical naive pair #12267 repaired.

The 7 char-scanner copies — the drift is already measurable

These are string-aware, so they do not have the phantom-comment defect. They have the other one the shared module exists to end: they disagree with each other about what to emit.

fileblock-comment newlinesstrings
packages/metadata/src/metadata-route-ledger.conformance.test.tspreservedkept
packages/cloud-connection/src/cloud-connection-route-ledger.conformance.test.tspreserved (with an 80-line rationale)kept
packages/cli/src/utils/console-route-ledger.conformance.test.tspreservedkept
packages/cli/src/commands/serve-cluster-host-resolution.test.tsblanked to spaces, offsets preserveddropped
packages/triggers/trigger-api/src/trigger-api-route-ledger.conformance.test.tsdroppedkept
packages/plugins/plugin-auth/src/rate-limit-storage-isolation.test.tsdroppedkept
packages/plugins/plugin-approvals/src/admin-exemption-retired.test.tsdroppedkept

Three preserve newlines, three drop them, one blanks to spaces. Every one of these feeds a gate that reports a line number to an author. js-comment-mask.mjs already exports both projections (maskComments keeps offsets, stripComments keeps line numbers only) precisely so this choice is made once.

The 14 regex copies

examples/app-showcase/test/inert-wirings.test.ts · packages/cli/src/commands/artifact-child-env.pin.test.ts · packages/cli/src/commands/migrate/multi-value-columns.no-auto-run.test.ts · packages/cli/src/commands/serve-multi-node-cap-advisory.pin.test.ts · packages/cli/src/commands/serve-verify-security-parity.contract.test.ts · packages/cloud-connection/src/canonical-expression-envelopes.test.ts · packages/drivers/driver-sql/src/live-dialect-matrix.isolation.test.ts · packages/lint/src/validate-expressions.test.ts · packages/lint/src/validate-org-axis-red-lines.test.ts · packages/lint/src/validate-rule-compilability.test.ts · packages/lint/src/validate-security-posture.test.ts · packages/metadata-protocol/src/migrations/live-mysql-database.isolation.test.ts · packages/platform-objects/src/pages/canonical-expression-envelopes.test.ts · packages/runtime/src/error-envelope.conformance.test.ts

The two canonical-expression-envelopes.test.ts entries are converted by #12267's PR. Two of the remaining ones are notable because the file already importsmaskComments and keeps a regex beside it: serve-multi-node-cap-advisory.pin.test.ts (documented as deliberate, out of scope for #10514) and serve-verify-security-parity.contract.test.ts.

What is not claimed here

No verdict is claimed to be wrong today. This is a census of an unwatched population, in the same posture #9367, #10453 and #12267 were filed in. Whether each of the 21 should convert is per-row: some feed scanners that report neither an offset nor a line, some are deliberate, and at least one parses a speculative prose snippet where a strict answer would be wrong.

What is claimed is the structural fact #12267 asked for a number on: the population check:parse-guard cannot see is 21, not 2, and no gate in the tree watches it.check-comment-mask-corpus.mjs verifies the shared mask against a real parser, but says nothing about who adopted it. Hand-filing has now produced three cards (#10453, #12267, this one) for one conversion.

Possible closures

  • A. A new adoption gate — the check-entry-guard.mjs shape, applied to comment-stripping rather than to "was I run?": scan for the regex shapes and the private-scanner shape outside scripts/, with a shrink-only ledger for the rows that are deliberate. Population spelled as subtree globs (packages/**, examples/**) so bare-root-worklist's TRIAGE map and check:pm-dispatch-gates' escapable-literal species are both unreachable by construction.
  • B. Convert the rows that are plainly wrong (the char-scanner disagreement table above) and leave the class unwatched.
  • C. Leave it — and accept that the next residue is found by hand, as the last three were.

No recommendation recorded.

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions