125125
126126// dispatch-gates: whole-tree-population -- `collectSources` walks every authored JS/TS file from the repo root, so the corpus is the whole tree; the one literal below names the masker this gate exercises, not the files it reads.
127127
128- import { readdirSync , readFileSync } from 'node:fs' ;
129- import { dirname , extname , join , relative , resolve } from 'node:path' ;
128+ import { mkdirSync , mkdtempSync , readdirSync , readFileSync , rmSync , writeFileSync } from 'node:fs' ;
129+ import { tmpdir } from 'node:os' ;
130+ import { dirname , extname , join , relative , resolve , sep } from 'node:path' ;
130131import { fileURLToPath , pathToFileURL } from 'node:url' ;
131132import { isEntrypoint } from './invoked-as.mjs' ;
132133
@@ -137,11 +138,24 @@ const REPO_ROOT = resolve(HERE, '..');
137138export const SOURCE_EXTENSIONS = new Set ( [ '.ts' , '.tsx' , '.mts' , '.cts' , '.js' , '.mjs' , '.cjs' , '.jsx' ] ) ;
138139
139140/**
140- * Directories that hold dependencies or build output rather than source. Same
141- * list `js-comment-mask.mjs`'s header states, so the prose and the instrument
142- * cannot drift apart. Every package in this tree builds to `dist`.
141+ * Directories that hold dependencies or build output rather than source -- plus
142+ * one that holds ANOTHER REPOSITORY. Every package in this tree builds to
143+ * `dist`. `js-comment-mask.mjs`'s header quotes the six this walk started from
144+ * as part of the 2026-08-21 measurement it records; the set below is the
145+ * instrument and has grown past that sentence since (`.git`, and now `.cache`),
146+ * so this declaration is the list, and the header is the history.
147+ *
148+ * `.cache` is where `scripts/build-console.sh` materialises objectui at the
149+ * pinned SHA: a whole foreign checkout, gitignored, that every console pin bump
150+ * MUST create because the console cannot be built without it. Walked, it put
151+ * ~4,300 files this repo does not author into the corpus and reported one of
152+ * them as a disagreement -- against a masker objectui's pages have no stake in.
153+ * The failure text below is correct for OUR sources and wrong for those: it
154+ * sends the reader to pin a shape in `js-comment-mask.mjs`, which is the last
155+ * thing a pin bump should be editing. CI never saw it, because the lint job
156+ * does not build the console; every instance landed on a person instead.
143157 */
144- export const SKIPPED_DIRECTORIES = new Set ( [ 'node_modules' , 'dist' , '.next' , 'build' , '.turbo' , 'coverage' , '.git' ] ) ;
158+ export const SKIPPED_DIRECTORIES = new Set ( [ 'node_modules' , 'dist' , '.next' , 'build' , '.turbo' , 'coverage' , '.git' , '.cache' ] ) ;
145159
146160/** Below this, the corpus is not a corpus -- see the header. */
147161export const CORPUS_FLOOR = 1000 ;
@@ -449,7 +463,7 @@ async function main(argv) {
449463// not red. A battery BELOW its floor means cases stopped running; the remedy is
450464// to find what stopped registering.
451465const SELF_TEST_BATTERIES = Object . freeze ( {
452- 'check-comment-mask-corpus self-test' : 12 ,
466+ 'check-comment-mask-corpus self-test' : 17 ,
453467} ) ;
454468
455469// DELETING an entry silences that battery's floor exactly as effectively as
@@ -611,6 +625,47 @@ async function runSelfTestCases(parse) {
611625 ok ( `the corpus walk finds at least ${ CORPUS_FLOOR } files in this tree` , collectSources ( ) . length >= CORPUS_FLOOR ) ;
612626 ok ( '...and every path it returns carries a known source extension' , collectSources ( ) . every ( ( file ) => SOURCE_EXTENSIONS . has ( extname ( file ) ) ) ) ;
613627
628+ // ── The walk's exclusions, on a REAL tree, in both directions ─────────────
629+ //
630+ // `SKIPPED_DIRECTORIES` is the kind of declaration that reads as obviously
631+ // correct and is measured by nothing: for `.cache` it was wrong for as long
632+ // as `scripts/build-console.sh` has existed, and the only reader who ever
633+ // found out was an operator staring at a red gate over someone else's file.
634+ // So the exclusion is proven the way the corpus is judged -- by walking a
635+ // directory on disk. The SAME BYTES are planted twice, inside `.cache` and
636+ // outside it, against a masker that disagrees with the parser on them: the
637+ // copy outside reds, the copy inside never enters the corpus at all, and the
638+ // only variable between the two is location.
639+ //
640+ // ⚠️ These cases run on the production sweep path too (`main()` calls this
641+ // body on every sweep), which is deliberate: what they hold is a property of
642+ // the corpus that sweep is about to report on. The fixture is two files in a
643+ // temp dir, removed in `finally`.
644+ const plantedSource = 'export const Probe = () => null;\n' ;
645+ const fixtureRoot = mkdtempSync ( join ( tmpdir ( ) , 'comment-mask-corpus-' ) ) ;
646+ try {
647+ const outsidePath = join ( 'src' , 'probe.tsx' ) ;
648+ const insidePath = join ( '.cache' , 'objectui-pin' , 'src' , 'probe.tsx' ) ;
649+ for ( const relPath of [ outsidePath , insidePath ] ) {
650+ mkdirSync ( dirname ( join ( fixtureRoot , relPath ) ) , { recursive : true } ) ;
651+ writeFileSync ( join ( fixtureRoot , relPath ) , plantedSource , 'utf8' ) ;
652+ }
653+
654+ const collected = collectSources ( fixtureRoot ) . map ( ( file ) => relative ( fixtureRoot , file ) ) ;
655+ ok ( 'the walk collects a planted source that sits outside .cache' , collected . includes ( outsidePath ) ) ;
656+ ok ( '...and collects NOTHING under .cache' , collected . every ( ( file ) => ! file . split ( sep ) . includes ( '.cache' ) ) ) ;
657+
658+ const swept = sweep ( { root : fixtureRoot , parse, scan : flagEverything } ) ;
659+ ok ( 'the copy outside .cache DISAGREES -- the plant is genuinely red' , swept . disagreements . length === 1 && swept . disagreements [ 0 ] . file === outsidePath ) ;
660+ ok ( '...and the sweep judged exactly the one file it walked' , swept . files . length === 1 ) ;
661+ // Excluded by LOCATION, not because those bytes happen to agree: compared
662+ // directly, the identical copy under `.cache` disagrees just as loudly.
663+ const wouldDisagree = compareFile ( join ( fixtureRoot , insidePath ) , plantedSource , { scan : flagEverything , parse } ) ;
664+ ok ( '...while the identical bytes under .cache would have disagreed if walked' , wouldDisagree . overMasks > 0 ) ;
665+ } finally {
666+ rmSync ( fixtureRoot , { recursive : true , force : true } ) ;
667+ }
668+
614669 SELF_TEST_CASE_COUNT = cases . length ;
615670 for ( const testCase of cases ) if ( ! testCase . condition ) failures . push ( testCase . label ) ;
616671 return { failures, cases } ;
0 commit comments