Repository navigation
Commit a422f04
fix(scripts): dispatch-gates derives the name-fold loader gate for every file under the roots it walks (#24263)
Fixes #24037
Clause-②: no
The dispatch derivation now names `node
scripts/check-position-name-fold-loaders.mjs` (and its `--self-test`)
for a change to any file under the roots that gate walks. The fix is in
the gate's own source: its roots become the `ROOT_DIR_WATCH_HINTS`
literal the derivation already reads, and the walk is derived from that
literal. `scripts/pm/dispatch-gates.mjs` and
`scripts/pm/dispatch-gates.data.mjs` are **unchanged**: no new gate,
row, ratchet, `--tier` mandate or constant (ruling 6243472660, term 3).
## What changed
- **`scripts/check-position-name-fold-loaders.mjs`.** The walked roots
are now one exported literal, `ROOT_DIR_WATCH_HINTS = ['packages/**',
'examples/**', 'apps/**', 'scripts/**', '.github/**']`. `SCAN_ROOTS` is
derived from it, so the walk and the declaration are one list and cannot
drift. The one root not carried over is `tools`: the tree has no
`tools/` directory (0 tracked files). The scan count is unchanged at
10263 files before and after. A declared root the tree does not have
would print as a dead lead on every card the gate matches.
- **`scripts/pm/bare-root-worklist.mjs`.** The four `REFUSE-WIDE`
verdicts on this gate's `SCAN_ROOTS` rows (packages, examples, apps,
scripts; measured 2026-08-31) are withdrawn. Once `SCAN_ROOTS` is
derived, the bare-word literals they judged no longer exist, so the
self-test's STALE remedy applies: "Delete the entry; do not re-point it
at another row". A comment in their place names the ruling and the
measured consumer. The declaration battery registers two cases per
recorded row, so its floor follows the row count: 128 to 126 (134 to 126
on a run). One docblock sentence that cited the withdrawn 99% row is
annotated. **This file is outside the claim's declared file surface.**
The edit is forced: with the gate change alone, this self-test exits 1
with 5 failures (the STALE case plus four attribution cases).
- **`scripts/pm/dispatch-gates.self-test.mjs`.** One fast-tier block,
against the live tree, for both invocations of the gate. It reads one
probe per declared subtree root off the family's own extracted hints,
plus the exact path PR #24028 edited
(`scripts/cross-package-test-inputs.mjs`), and each must be MATCHED.
In-place ablation: with the subtree hints stripped, the PR #24028 path
and a brand-new package file both read `silent`. A floor case requires
at least five subtree roots, so the loop cannot run zero times.
## The mechanism, measured (the card marked it "likely, not confirmed")
- **Half right.** The extractor (`extractWatchHints`) keys on **no**
constant name and **no** `export`. It reads every quoted, path-shaped
literal in the module body. The gate's roots were invisible because they
were **bare single-segment words**, which `looksPathy` refuses:
`extractWatchHints("const X = 'packages';")` yields `[]`. `'.github'` is
dotted and was already read. So `SCAN_ROOTS` being private was not the
cause; the spelling was. `check:watch-hint-literal` constrains the
declaration to a literal array of admissible literals, and the new one
passes (`--list` shows it).
- **The miss was recorded, not accidental.** `bare-root-worklist.mjs`
held four `REFUSE-WIDE` verdicts on exactly these rows: the declaration
would be true, and was refused for the precision of the matched column.
Three things decide it here:
- Ruling 6243472660 term 3 names this conversion for this gate.
- The worklist's own CONTRADICTED and STALE remedy text allows
withdrawing the verdict when the declaration is deliberate and overrides
the refusal.
- This row has the measured consumer that the worklist's 2026-08-26
re-adjudication used as its criterion: PR #24028, a local union of 98/98
that went red in CI.
- **Precision cost.** The gate is now MATCHED for every tracked file
under the five roots: 10343 of 12129 tracked files (85%; packages 9545,
examples 265, apps 51, scripts 437, .github 45), in both invocations.
One run takes 2.4 s wall.
## Derivation, before and after
| probe | `f5ef054a` | this branch |
|:--|:--|:--|
| `--commands scripts/cross-package-test-inputs.mjs` (the PR #24028
miss) | 28 commands, no name-fold gate | 30 commands; the diff is
exactly the two name-fold commands |
| `--commands` on the four card paths (`dispatch-gates.mjs`,
`.data.mjs`, `.self-test.mjs`, the gate) | 33 commands | n/a (the
derivation files are not in this diff) |
| `--commands` with no paths (this diff, 3 files) | — | 32 commands,
listed under Verification |
## Census (acceptance 2)
**Population, by reading.** Every gate's population constant, read by
`node scripts/pm/bare-root-worklist.mjs`, the derivation-coupled
instrument for this exact species (a population constant holding a bare
top-level word the extractor reads nothing for). Its `--wide` sweep is
the unrestricted contrast, and its CENSUS map holds the fs-trace census
of computed roots. Each root's placement below is the derivation's own
`placeFamily` verdict for a brand-new file under that root, read on this
branch.
Queries over `scripts/*.mjs` and `scripts/pm/*.mjs` on this branch
(files hit; controls first):
- control `isEntrypoint`: 213 · control `readFileSync`: 255
- `readdirSync|readdir\(`: 146 · `\bwalk[A-Za-z]*\(`: 99 · `'ls-files'`:
32 · `SCAN_ROOTS?\b`: 25 · `\bROOTS\b`: 22
- `^(export )?const [A-Z_]*_WATCH_HINTS =` (existing declarations under
`scripts/`): 60 at `f5ef054a`, 61 here. `check:watch-hint-literal
--list` prints 75 declarations repo-wide.
- Bare-root worklist (restricted): 82 rows, 47 gate source files at
`f5ef054a`; 78 rows, 46 files here. Wide contrast sweep: 140 pairs, 84
files at `f5ef054a`; 136 pairs, 83 files here. The diff in both sweeps
is exactly the four name-fold rows.
**Answer: yes, other gates keep roots the same undeclared way. One is
converted in this PR; every other is already read or is listed below
with its reason. No row was added to `dispatch-gates.data.mjs`.**
| how the roots are held today | gates (source file · root) | action |
|:--|:--|:--|
| bare words, private; now the declared literal |
`check-position-name-fold-loaders` · packages, examples, apps, scripts
(plus `.github`, already read) | **converted in this PR** |
| bare word beside a declared literal at the same root (REACHABLE: a
brand-new file under the root derives the gate) |
`check-doc-formula-expressions` (packages/lint) · content, docs, skills;
`check-agent-test-spelling` · scripts, skills; `check-cli-command-ids` ·
scripts; `check-corpus-claim-drift` · skills; `check-doc-authoring` ·
packages, content, docs, skills; `check-doc-route-spelling` · skills;
`check-examples-live-imports` · examples; `check-org-identifier` · apps,
examples, packages; `check-role-word` · skills;
`check-scripts-symbol-anchors` · scripts;
`check-skill-compatibility-version` · skills; `check-skill-frame-sync` ·
skills; `check-skill-identifier-liveness` · skills | already read |
| declared literal, narrower than the root (DECLARED-NARROWER; the gate
reads only that subtree) | `build-skill-docs`, `build-skill-references`
(packages/spec) · skills; `check-declaration-mirrors` · scripts;
`check-driver-conformance` DRIVERS_DIR · packages;
`check-dual-build-cjs-loads` · packages; `check-i18n-coverage` ·
examples; `check-logger-receiver-detach` · apps, examples, packages;
`check-objectql-double-limit` · packages;
`check-ratchet-remedy-authority` · scripts;
`check-where-matcher-conformance` · packages; `pm/check-skill-id-lint` ·
skills | already read |
| bare word; a precise spelling exists and is deferred by a recorded
verdict for want of a consumer (SPELLABLE-UNDECLARED) |
`check-adr-0087-registration` · apps, examples, packages;
`check-skill-compatibility-version` PACKAGE_ROOTS · apps, examples,
packages; `check-i18n-bundles`, `check-i18n-coverage`,
`check-i18n-stale-fill` · packages; `check-skills-token-ratchet` ·
skills | **listed.** The verdict is recorded; declaring re-decides it
and needs its own measured consumer |
| bare word; the root IS the population and the declaration is refused
for precision (REFUSE-WIDE) | `check-dispatcher-error-vocabulary`,
`check-error-code-casing`, `check-error-status-conformance`,
`check-runtime-services-index`, `check-single-authz-resolver`,
`check-skill-identifier-liveness` IMPL_ROOTS,
`measure-durability-swallow-family` · packages;
`check-engine-double-contract` · examples, packages | **listed.**
Recorded verdict, no measured consumer on any of these rows (see open
question). `check-error-status-conformance` is derived by its content
kind instead |
| bare word, REFUSE-WIDE, and the gate is on the `wide-population`
channel (maintainer ruling 2026-09-05) |
`check-optional-error-sink-contract` · packages;
`check-resume-authority-declared` · examples, packages;
`check-verify-stand-in-erasure` · examples, packages | **listed.**
Declared wide by ruling; a subtree hint would contradict the marker |
| bare word; the population is a file-kind filter no glob spells
(REFUSE-UNSPELLABLE) | `check-driver-conformance` CASE_SETS_DIR,
`check-examples-live-imports` PACKAGES_ROOT · packages;
`check-meta-type-normalized` · packages (wide channel);
`check-runner-env-posture` · apps, examples, packages (wide channel) |
**listed.** Its roots cannot be read that way |
| bare word, judged by nobody (UNJUDGED; the map's owner judges these) |
`check-doc-security-posture` (packages/lint) · skills;
`check-live-db-isolation` · apps, examples, packages (wide channel);
`check-vendor-version-stamps` · apps, examples, packages, scripts;
`check-whole-set-label-write` · scripts (MATCHED through other hints).
Measured "not a population": `check-console-injection` ×2,
`check-doc-frontmatter` · docs, `check-doc-security-posture` · docs |
**listed.** The worklist forbids the pass that sees a row from judging
it |
| computed root, no constant (fs-trace CENSUS, 13 families) | wide
channel: `check:route-envelope`, `check:live-db-isolation`,
`check:startup-registry-verdict`, `check:wildcard-fallthrough`,
`check:init-service-contract`, `check:settings-bind-window`;
always-runs: `check:driver-memory-census`; brand-new package file
`silent`: `check:parse-guard`, `check:cli-command-ids`,
`check:type-check-coverage`, `check:type-check-debt`,
`check:error-code-provenance`; MATCHED: `check:org-identifier` |
**listed.** A `join(ROOT, 'packages')` or loop literal is not a literal
the extractor can read, so these cannot be read that way |
| computed root outside both recognisers (the `--wide` sweep's 34 extra
files, each read) | `check-cross-package-test-inputs` (a loop over
packages/apps/examples; its population is test files, and a new test
file under any of the three derives it through the test-file convention
trigger, probed with `examples/app-crm/src/zz-probe.test.ts`);
`check:skill-examples`, `check:yaml-examples` (a `dir:` property,
`path.resolve(REPO_ROOT, 'skills')`); `check:empty-state` (a resolved
packages root; undetermined); `check:object-def-param-keys` (`git
ls-files packages`); `check:service-providers` (`MANIFEST_PARENTS`);
`check:docs-audit-scope` (`walkSrc(join(root, 'packages'))`);
`check:console-sha` (a dist path); `check:tenant-chokepoint` (join-built
file paths); `measure-test-shard-timings --self-test` (a loop literal);
`check:durability-log-level` (derived by its content kind and its
declared scan surface) | **listed.** Computed spellings the extractor
cannot read. Of the 34 extra files: 8 are the CENSUS families in the row
above; `check-self-test-wired` walks `scripts` and declares
`scripts/**/*.mjs`, `.mts` and `.sh` (already read); these 11 are
listed; the other 14 hold the word as a data key, a baseline path built
by `join`, a self-test fixture or path parsing, not a walked root |
**The three earlier instances the card names, read today** (`--commands`
on real files):
- `check:error-status-conformance`: derived for
`packages/metadata/src/loaders/ambiguous-metadata-stem.ts` through its
HTTP-status content kind. Its `SCAN_ROOT packages` row stays
REFUSE-WIDE.
- `check:durability-log-level`: derived for
`packages/metadata/src/loaders/database-loader.ts` through its
durability content kind and its declared scan surface.
- `check:i18n-coverage`: derived for
`examples/app-showcase/src/data/analytics/showcase.cube.ts` through its
declared examples hints. Its packages half stays SPELLABLE-UNDECLARED
and is reached through the extract-config convention trigger.
## Verification
All readings below are on this branch's final head, **`cf4e110f`** (`git
rev-parse --short HEAD`), with no commit after them.
- **Derived local subset.** `node scripts/pm/dispatch-gates.mjs
--commands --repo objectstack-ai/objectstack` with no paths (the change
set came from git: 3 files vs merge base `f5ef054a7`) derived 32
commands. Each was run with its exit code captured before any pipe, and
all 32 exited **0**. `pnpm check:declared-population-live` was also run
beyond the union, because this diff adds a declaration; it exited 0 (268
of 330 families declare a population, all live).
- **Reconciliation.** `--ran` printed `✓ dispatch-gates --ran: 32
derived famil(ies) accounted for — 32 run, 0 NOT-MEASURED (a DERIVED
zero — all 32 recorded an exit code and none of them is 3)`, with exit
0.
- **Verdict lines for the families this diff moves:**
- `node scripts/check-position-name-fold-loaders.mjs` → `10263 file(s)
scanned under packages, examples, apps, scripts, .github; 8
reference(s): 6 test, 2 declared instrument, 0 loader` (exit 0). The
same 10263 at `f5ef054a` with `tools` still in the list.
- `… --self-test` → `39 cases pass` (exit 0).
- `node scripts/pm/bare-root-worklist.mjs --self-test` → `OK self-test:
78 live row(s), 56 unreachable as spelled, 43 recorded verdict(s) — none
stale, none missing, none contradicted` (exit 0). With the gate change
alone it exits 1 with 5 failures.
- `pnpm check:watch-hint-literal` → `75 declaration(s) across 4 rostered
name(s) -- ROOT_DIR_WATCH_HINTS 50 …` (exit 0).
- `pnpm check:pm-dispatch-gates` (the fast tier, as CI runs it on a PR)
→ `✓ dispatch-gates self-test (fast tier): 1902 cases pass` (exit 0, 384
s).
- **Full battery, both tiers** (beyond what a PR runs; it is what
`main`'s push and hourly runs execute): `node
scripts/pm/dispatch-gates.mjs --self-test` run detached → `fast 1902
case(s) in 394.0s · slow 260 case(s) in 1170.8s`, `✓ dispatch-gates
self-test: 2162 cases pass.`, exit 0, 1566 s wall.
- **Other local gates, all exit 0:** `check-ci-filter-parity`,
`check-closing-keyword-parity` (both), `check-comment-mask-corpus`,
`check-declaration-mirrors` (both), `check-scripts-symbol-anchors`
(both), `check-self-test-wired` (both),
`check-self-test-workflow-commands` (both),
`check-whole-set-label-write` (both), `check:agent-test-spelling`,
`check:bash32-floor`, `check:cli-command-ids`,
`check:cross-package-test-inputs`, `check:driver-memory-census`,
`check:entry-guard`, `check:gitlink-declared`, `check:nul-bytes` (12120
text files, no control bytes), `check:parse-guard`,
`check:pnpm-filter-targets`, `check:pnpm-flag-spellings`,
`check:ratchet-remedy-authority`, `check:refd-timer-probe`.
- **Not run locally, CI's to report:** the full `check:*` farm in `Lint
& Repo Gates` and the other required contexts. No package is touched, so
there is no build closure, package `test` or `typecheck` to owe.
## Acceptance notes
- The `tools` root dropped from the walk is a behaviour delta only for a
tree that grows a top-level `tools/`. Today it is a no-op: 10263 files
are scanned before and after. A future `tools/` would need a declared
root, as any other new root would.
- The derivation files need no change: the extractor reads the new
literal as it stands. The self-test block is the only `dispatch-gates*`
edit, and #24073's job-condition rendering is untouched.
- Test files `git grep` finds naming an edited script: none read one.
`packages/spec/src/system/compliance-families-retirement.test.ts` and
`packages/types/src/driver-error-classification.callers.test.ts` mention
the dispatch-gates self-test in prose only, so they are not owed a run.
- Not published: `scripts/**` is in no package's `files[]`, so
`skip-changeset`.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QBcLjVCmcWbZEk6qhYMib2)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 77e9f79 commit a422f04
3 files changed
Lines changed: 83 additions & 28 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
111 | 111 | | |
112 | 112 | | |
113 | 113 | | |
114 | | - | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
115 | 135 | | |
116 | 136 | | |
117 | 137 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
942 | 942 | | |
943 | 943 | | |
944 | 944 | | |
945 | | - | |
946 | | - | |
947 | | - | |
948 | | - | |
949 | | - | |
950 | | - | |
951 | | - | |
952 | | - | |
953 | | - | |
954 | | - | |
955 | | - | |
956 | | - | |
957 | | - | |
958 | | - | |
959 | | - | |
960 | | - | |
961 | | - | |
962 | | - | |
963 | | - | |
964 | | - | |
965 | | - | |
966 | | - | |
967 | | - | |
968 | | - | |
969 | | - | |
| 945 | + | |
| 946 | + | |
| 947 | + | |
| 948 | + | |
| 949 | + | |
| 950 | + | |
| 951 | + | |
| 952 | + | |
| 953 | + | |
| 954 | + | |
970 | 955 | | |
971 | 956 | | |
972 | 957 | | |
| |||
1349 | 1334 | | |
1350 | 1335 | | |
1351 | 1336 | | |
1352 | | - | |
| 1337 | + | |
| 1338 | + | |
1353 | 1339 | | |
1354 | 1340 | | |
1355 | 1341 | | |
| |||
2113 | 2099 | | |
2114 | 2100 | | |
2115 | 2101 | | |
2116 | | - | |
| 2102 | + | |
| 2103 | + | |
| 2104 | + | |
| 2105 | + | |
2117 | 2106 | | |
2118 | 2107 | | |
2119 | 2108 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3851 | 3851 | | |
3852 | 3852 | | |
3853 | 3853 | | |
| 3854 | + | |
| 3855 | + | |
| 3856 | + | |
| 3857 | + | |
| 3858 | + | |
| 3859 | + | |
| 3860 | + | |
| 3861 | + | |
| 3862 | + | |
| 3863 | + | |
| 3864 | + | |
| 3865 | + | |
| 3866 | + | |
| 3867 | + | |
| 3868 | + | |
| 3869 | + | |
| 3870 | + | |
| 3871 | + | |
| 3872 | + | |
| 3873 | + | |
| 3874 | + | |
| 3875 | + | |
| 3876 | + | |
| 3877 | + | |
| 3878 | + | |
| 3879 | + | |
| 3880 | + | |
| 3881 | + | |
| 3882 | + | |
| 3883 | + | |
| 3884 | + | |
| 3885 | + | |
| 3886 | + | |
| 3887 | + | |
| 3888 | + | |
| 3889 | + | |
| 3890 | + | |
| 3891 | + | |
| 3892 | + | |
| 3893 | + | |
| 3894 | + | |
| 3895 | + | |
| 3896 | + | |
| 3897 | + | |
| 3898 | + | |
| 3899 | + | |
3854 | 3900 | | |
3855 | 3901 | | |
3856 | 3902 | | |
| |||
0 commit comments