Skip to content

[finding] The regex-literal recogniser now exists twice — js-comment-mask.mjs and check-dispatcher-error-vocabulary.mjs each carry the keyword set and a position rule that deliberately differ #15487

Description

@claude

Found while closing #14742 (PR #15486), which added a regex-literal recogniser to scripts/check-dispatcher-error-vocabulary.mjs. Out of scope there: that card's scope is the scanner's blind spot and its ledgers, and consolidating two modules is a separate change with its own risk.

What is duplicated

Two modules now answer "does a / here open a RegularExpressionLiteral?", each with its own copy:

The 14-word keyword set is byte-identical in both. That set is not decorative: js-comment-mask.mjs's own header records that dropping return from it passes all 23 of its self-test cases and is caught only by the corpus sweep, on scripts/check-test-source-alias.mjs. So the copy that drifts drifts silently in exactly the direction the header warns about.

What is deliberately NOT duplicated, and why a naive extraction is wrong

The two position rules differ on purpose, and the difference is a failure-direction argument rather than an oversight:

preceding token js-comment-mask.mjs check-dispatcher-error-vocabulary.mjs
) , ] division division
} regex division
bare < / > regex division
++ / -- regex division

A masker fails safe by over-masking (it under-reports loudly). A scanner that skips a span it invented desynchronises silently — which is the defect #14742 closed. ⇒ any extraction has to keep the position rule parameterised, not pick one of the two.

Mitigation already in place

#14742 added a --self-test case that runs both recognisers over the same fixtures and asserts they agree everywhere except that documented divergence, and a second case that asserts the divergence itself still exists. So a silent drift is caught today; what is left is the duplication, not an unguarded one.

What a fix would look like

Export the keyword set and a position-rule-parameterised recogniser from one place (most likely js-comment-mask.mjs, which already owns "which bytes are literal"), and have the gate consume it with its conservative rule passed in. ⚠️ js-comment-mask.mjs has a hand-written .d.mts (see #15398) and a corpus sweep in CI — both are part of the cost.

Unassigned and unlabeled, for triage.


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions