Skip to content

Commit adf2ca7

Browse files
hotlongclaude
andcommitted
wip: declare the gate's population in the dispatch-derivation spellings
Claude-Session: https://claude.ai/code/session_local_1904ee85-9672-427b-bc91-7e31318013c7 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 49cc761 commit adf2ca7

1 file changed

Lines changed: 68 additions & 1 deletion

File tree

‎scripts/check-pnpm-flag-spellings.mjs‎

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,48 @@ export const ROOTS = Object.freeze([
149149
/** Every tracked `package.json`, the repo root's included. */
150150
export const MANIFEST_PATHSPEC = ':(glob)**/package.json';
151151

152+
/**
153+
* The population above, in the spellings `scripts/pm/dispatch-gates.mjs` can
154+
* match, so a card that adds a script under one of these roots is routed to
155+
* this gate -- a new script is the input this gate is most likely to fail on.
156+
* Without them the derivation reads the `'scripts/'` label above as a bare
157+
* root no dispatch can name, and only `.githooks` reaches the gate.
158+
*
159+
* Honest at the precision the instrument allows, measured on this tree with
160+
* this file's own `kindOf`: the walk descends the whole of each root, and
161+
*
162+
* scripts/** 326 of 434 75.1% the rest: 102 .json, 3 .md, 3 .txt
163+
* packages/**\/scripts/** 171 of 174 98.3% the rest: 2 .json, 1 data file
164+
* .githooks/** 2 of 2 100.0%
165+
*
166+
* The files it skips are baselines and prose a card can touch without this
167+
* gate having anything to say -- a lead the dispatch prints and the gate then
168+
* passes, which is the cheap direction. `packages/**\/scripts/**` carries its
169+
* glob in a non-final segment, so the derivation matches it as a PATTERN: it
170+
* reaches `scripts/` directories under `packages/` and nothing else there.
171+
*
172+
* ⛔ Provenance, never a lookup key: nothing reads these arrays but the
173+
* self-test, which pins them against ROOTS and against the live manifest
174+
* population in both directions. They are literals because the extractor reads
175+
* literals; assembling them at runtime would hide them from the very derivation
176+
* they exist for.
177+
*/
178+
const ROOT_DIR_WATCH_HINTS = ['scripts/**', 'packages/**/scripts/**', '.githooks/**'];
179+
180+
/**
181+
* The manifest half: the root `package.json` (a bare filename is refused as too
182+
* generic; `/**` collapses back to it exactly), and the member manifests,
183+
* enumerated per root that holds one -- `**\/package.json` is dropped by the
184+
* extractor's admission, so the population is spelled the way
185+
* `scripts/git-merge-regen.mjs` spells the same one.
186+
*/
187+
const ROOT_FILE_WATCH_HINTS = ['package.json/**'];
188+
const DECLARED_WATCH_HINTS = [
189+
'packages/**/package.json',
190+
'apps/**/package.json',
191+
'examples/**/package.json',
192+
];
193+
152194
/** The file that owns this rule, and so is not judged by it (see the header). */
153195
export const RULE_OWNING_FILES = Object.freeze([SELF]);
154196

@@ -767,7 +809,7 @@ const SELF_TEST_BATTERIES = Object.freeze({
767809
[NOT_PNPM]: 6,
768810
[PROSE]: 6,
769811
[TREE]: 13,
770-
[PIN]: 3,
812+
[PIN]: 5,
771813
});
772814

773815
// Deleting a battery from the roster silences its floor as surely as zeroing
@@ -930,6 +972,31 @@ const PIN_CASES = [
930972
return labels === 'scripts/ packages/**/scripts/ .githooks/' ? null : labels;
931973
},
932974
},
975+
{
976+
label: 'ROOT_DIR_WATCH_HINTS declares exactly the walked roots',
977+
check: () => {
978+
const walked = ROOTS.map((r) => r.pathspec.replace(/^:\(glob\)/, ''));
979+
return JSON.stringify(walked) === JSON.stringify([...ROOT_DIR_WATCH_HINTS])
980+
? null
981+
: `walked ${JSON.stringify(walked)} but declared ${JSON.stringify(ROOT_DIR_WATCH_HINTS)}`;
982+
},
983+
},
984+
{
985+
label: 'the manifest hints reach every tracked package.json, and each hint reaches one',
986+
check: () => {
987+
const manifests = gitLsFiles(REPO_ROOT, [MANIFEST_PATHSPEC]);
988+
const roots = DECLARED_WATCH_HINTS.map((h) => h.slice(0, h.indexOf('/**/package.json')));
989+
const reached = (path) =>
990+
(path === 'package.json' && ROOT_FILE_WATCH_HINTS.includes('package.json/**')) ||
991+
roots.some((root) => path.startsWith(`${root}/`));
992+
const unreached = manifests.filter((path) => !reached(path));
993+
const dead = roots.filter((root) => !manifests.some((path) => path.startsWith(`${root}/`)));
994+
if (manifests.length === 0) return 'git ls-files listed no package.json';
995+
if (unreached.length > 0) return `undeclared manifest root(s): ${unreached.join(', ')}`;
996+
if (dead.length > 0) return `declared root(s) holding no tracked package.json: ${dead.join(', ')}`;
997+
return null;
998+
},
999+
},
9331000
{
9341001
label: 'no fix line names a spelling this gate rejects',
9351002
check: () => {

0 commit comments

Comments
 (0)