Skip to content

Commit 3ad668e

Browse files
committed
feat(scripts): wire the comment-mask corpus sweep and correct the header's instrument ordering (#10640)
1 parent c2362f0 commit 3ad668e

3 files changed

Lines changed: 62 additions & 7 deletions

File tree

‎.github/workflows/lint.yml‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,45 @@ jobs:
198198
- name: scripts/ TypeScript parses go through one module
199199
run: pnpm check:parse-guard
200200

201+
# The comment-mask CORPUS sweep (#10640) — the other instrument for the
202+
# module the two gates above delegate "is this span a comment, or code?"
203+
# to. `js-comment-mask.mjs --self-test` pins the SHAPES someone wrote
204+
# down; this parses every .{ts,tsx,mts,cts,js,mjs,cjs,jsx} file in the
205+
# tree with @typescript-eslint/parser and diffs its comment ranges
206+
# against the mask's, byte for byte. Neither subsumes the other, and that
207+
# is measured in both directions on this tree rather than assumed:
208+
# deleting the `{` counting inside `${...}` fails a pinned case and the
209+
# sweep reads 0 disagreements over 4,741 files (the tree does not write
210+
# that shape), while dropping `return` from REGEX_AFTER_KEYWORD passes all
211+
# 23 pinned cases and the sweep names check-test-source-alias.mjs, where
212+
# `return /(^|[^a-z])dist\//` is written today.
213+
# The defect this would have caught shipped: 16 files disagreeing, 15 of
214+
# them reading commented-out text as live code, 10,252 comment bytes in
215+
# one file — and the instrument that found it lived in an agent's
216+
# scratchpad, which is why re-deriving it was impossible until this file.
217+
# WHY A HARD GATE ON EVERY PR, and not an on-demand flag: the sweep's
218+
# verdict depends on the CORPUS as much as on the masker, so a PR that
219+
# writes a shape the mask reads wrong turns ~20 source-scanning gates
220+
# into liars on that file, on a PR that never touched the masker. That
221+
# arrival is not detectable by any convention a human or an agent has to
222+
# remember at the right moment — the failure mode this repo has already
223+
# paid for at #4690 and again here.
224+
# WHY A STEP AND NOT A JOB: a new job's `name:` is a required-context
225+
# contract (scripts/check-required-contexts.mjs) that only a
226+
# maintainer-present Settings change can enrol, and an unenrolled job is
227+
# an advisory gate — #5617 verbatim. This job is already required.
228+
# Invoked as `node` rather than `pnpm check:*` for the same reason as the
229+
# other `node scripts/…` steps in this lane: that alias is a line in root
230+
# package.json, inside the @changesets/cli v3 fence (#9465).
231+
# Runs its own comparator self-test first — 12 cases proving the
232+
# comparison can still REPORT, because "0 files disagree" and "the
233+
# comparison is broken" otherwise print the same line.
234+
# Cost, measured on a contended 4-vCPU container: 4,741 files, 72 MB of
235+
# source, 45–48 s, of which the parser is 45 s. The step prints CI's own
236+
# number on every run.
237+
- name: Comment mask agrees with a real parser over the whole corpus
238+
run: node scripts/check-comment-mask-corpus.mjs
239+
201240
# Stack-collection enumerations vs the schema (#6242). `stack.zod.ts`
202241
# decides which collections a stack may declare; eight other enumerations
203242
# of that same set are hand-maintained (the map-format list, the

‎scripts/check-comment-mask-corpus.mjs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,8 @@ async function main(argv) {
372372
console.error(` ${row.firstDivergence.excerpt}`);
373373
}
374374
}
375-
const shown = unparseable.length + disagreements.length;
376-
if (shown > ROW_LIMIT * 2) console.error(` ... and ${shown - ROW_LIMIT * 2} more`);
375+
const suppressed = Math.max(0, unparseable.length - ROW_LIMIT) + Math.max(0, disagreements.length - ROW_LIMIT);
376+
if (suppressed) console.error(` ... and ${suppressed} more (the counts below are over ALL files, not just the rows printed)`);
377377

378378
if (disagreements.length || unparseable.length) {
379379
console.error(

‎scripts/js-comment-mask.mjs‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,33 @@
6161
* cause was the template scan above; the same sweep after the fix disagrees on
6262
* 0 files.
6363
*
64+
* That sweep is a SCRIPT now, not a paragraph (#10640):
65+
*
66+
* node scripts/check-comment-mask-corpus.mjs
67+
*
68+
* It runs in CI on every pull request, and it carries the control that makes
69+
* its green mean something -- `--masker <path>` re-derives the 16 files above
70+
* against the pre-fix implementation. When this description and that script
71+
* disagree, the script is the one that ran.
72+
*
6473
* The lesson is about the claim, not the bug. A failure DIRECTION is a
6574
* property of an implementation, not of an intention, and this one cannot be
6675
* read off the code -- it took an independent parser over the whole tree to
6776
* find out which way the module actually failed. So the honest statement is
6877
* the one that can be re-derived: the shapes below are pinned, the sweep just
6978
* described is the way to check the rest, and neither direction is promised by
70-
* construction. Re-run it after touching `scanSource` -- and note that the
71-
* sweep is the STRONGER instrument of the two. A mutation that deleted the
72-
* brace counting inside `${...}` passed every case below AND the whole sweep,
73-
* because the tree did not happen to write the shape; the case that now holds
74-
* it was written from the mutation, not from the corpus.
79+
* construction. Re-run both after touching `scanSource`.
80+
*
81+
* Neither is the stronger instrument -- that ordering was claimed here once
82+
* and both directions of it have since been measured, on the same tree, in one
83+
* sitting (#10640). Deleting the brace counting inside `${...}` fails the case
84+
* below that was written from that mutation, and the sweep reads 0
85+
* disagreements over 4,741 files, because the tree does not write the shape.
86+
* Dropping `return` from `REGEX_AFTER_KEYWORD` passes all 23 cases below, and
87+
* the sweep names `scripts/check-test-source-alias.mjs`, where
88+
* `return /(^|[^a-z])dist\//` is written today. The self-test pins shapes
89+
* someone thought of, the sweep finds shapes the tree actually contains, and
90+
* neither substitutes for the other.
7591
*/
7692

7793
/** A character that can end an identifier -- i.e. a value, so `/` is division. */

0 commit comments

Comments
 (0)