Parent: #10631. Split out from PR #10665, which landed the rule and left this half deliberately undone.
PR #10665 taught check:entry-guard a second rule — a scripts/** file that exports a binding
must have every top-level statement that runs something behind the guard — and recorded the files
that already violate it in a ⛔ SHRINK-ONLYKNOWN_IMPORT_UNSAFE list so the gate is green on
the tree as it stands. Nothing new can join the list; these 35 are the standing debt.
The burn-down was kept out of that PR because its claim declared scripts/check-entry-guard.mjs,
and 35 gate scripts is the file surface other seats work in. It is safe to do in any number of
sittings: each file is independent, and the gate itself tells you when a line is ready to go.
Why each one matters
Measured by importing every exporting scripts/ file in a child process for its exports alone:
of the 39 unguarded exporters, 8 ended the importer mid-import and five of those exit 0, and 14
more ran the whole tool loudly. Three further leaks live in files that do carry a guard and leak
conditionally on the importer's argv (qa/qa-rollup.mjs, objectui-range.mjs) or on an env var
(ts-parse.mjs) — invisible to any clean-argv probe. Full table in PR #10665.
The remedy is mechanical, and needs no re-indentation
Five files here already use the inverted idiom, which wraps a trailing dispatch chain with a 4-line
insert and zero re-indentation of the existing branches:
import{isEntrypoint}from'./invoked-as.mjs';// '../invoked-as.mjs' from a subdirconstinvokedDirectly=isEntrypoint(import.meta.url);if(!invokedDirectly){// imported as a module — expose the exports and do nothing else}elseif(process.argv.includes('--self-test')){
...The plain form if (isEntrypoint(import.meta.url)) { ... } is equally accepted, as is storing the
predicate in a const under any name.
Roughly five of the 35 have their whole gate body at top level rather than a trailing dispatch
chain (check-error-status-conformance.mjs, checklist-select.mjs,
check-query-options-erasure-ratchet.mjs, check-release-page-status.mjs,
pm/check-governed-prose.mjs) and need a real main() extraction rather than a wrap. Those are
worth their own sitting.
⚠️pm/check-governed-prose.mjs additionally mutates process.argv at module scope to filter
--self-test out before importing a sibling. That workaround is a scar from exactly this class and
looks stale now that pm/check-governed-merges.mjs carries the guard — worth checking rather than
preserving.
Per file: verify, then delete its line
For each one: add the guard, then node scripts/check-entry-guard.mjs — it fails with the file
named as a STALEKNOWN_IMPORT_UNSAFE entry, which is the signal to delete that line. Confirm
with an import probe (the importer must survive silently) and by running the file as a CLI
unchanged. Demonstrated end to end on check-nul-bytes.mjs in PR #10665.
The 35
node scripts/check-entry-guard.mjs --list prints this live, with the offending line in each file.
Generated by Claude Code
Parent: #10631. Split out from PR #10665, which landed the rule and left this half deliberately undone.
PR #10665 taught
check:entry-guarda second rule — ascripts/**file that exports a bindingmust have every top-level statement that runs something behind the guard — and recorded the files
that already violate it in a ⛔ SHRINK-ONLY
KNOWN_IMPORT_UNSAFElist so the gate is green onthe tree as it stands. Nothing new can join the list; these 35 are the standing debt.
The burn-down was kept out of that PR because its claim declared
scripts/check-entry-guard.mjs,and 35 gate scripts is the file surface other seats work in. It is safe to do in any number of
sittings: each file is independent, and the gate itself tells you when a line is ready to go.
Why each one matters
Measured by importing every exporting
scripts/file in a child process for its exports alone:of the 39 unguarded exporters, 8 ended the importer mid-import and five of those exit 0, and 14
more ran the whole tool loudly. Three further leaks live in files that do carry a guard and leak
conditionally on the importer's argv (
qa/qa-rollup.mjs,objectui-range.mjs) or on an env var(
ts-parse.mjs) — invisible to any clean-argv probe. Full table in PR #10665.The remedy is mechanical, and needs no re-indentation
Five files here already use the inverted idiom, which wraps a trailing dispatch chain with a 4-line
insert and zero re-indentation of the existing branches:
The plain form
if (isEntrypoint(import.meta.url)) { ... }is equally accepted, as is storing thepredicate in a
constunder any name.Roughly five of the 35 have their whole gate body at top level rather than a trailing dispatch
chain (
check-error-status-conformance.mjs,checklist-select.mjs,check-query-options-erasure-ratchet.mjs,check-release-page-status.mjs,pm/check-governed-prose.mjs) and need a realmain()extraction rather than a wrap. Those areworth their own sitting.
pm/check-governed-prose.mjsadditionally mutatesprocess.argvat module scope to filter--self-testout before importing a sibling. That workaround is a scar from exactly this class andlooks stale now that
pm/check-governed-merges.mjscarries the guard — worth checking rather thanpreserving.
Per file: verify, then delete its line
For each one: add the guard, then
node scripts/check-entry-guard.mjs— it fails with the filenamed as a STALE
KNOWN_IMPORT_UNSAFEentry, which is the signal to delete that line. Confirmwith an import probe (the importer must survive silently) and by running the file as a CLI
unchanged. Demonstrated end to end on
check-nul-bytes.mjsin PR #10665.The 35
scripts/ablation-dist-preflight.mjsscripts/check-changeset-no-major.mjsscripts/check-dispatcher-error-vocabulary.mjsscripts/check-driver-memory-census.mjsscripts/check-empty-changeset.mjsscripts/check-engine-split-ratio.mjsscripts/check-error-code-casing.mjsscripts/check-error-status-conformance.mjsscripts/check-examples-live-imports.mjsscripts/check-filter-alias-parity.mjsscripts/check-nul-bytes.mjsscripts/check-org-identifier.mjsscripts/check-query-options-erasure-ratchet.mjsscripts/check-quick-reference-counts.mjsscripts/check-ratchet-remedy-authority.mjsscripts/check-release-page-status.mjsscripts/check-required-contexts.mjsscripts/check-route-envelope.mjsscripts/check-runtime-services-index.mjsscripts/check-shard-attestation.mjsscripts/check-spec-parsed-alias.mjsscripts/check-startup-registry-verdict.mjsscripts/check-tenant-chokepoint.mjsscripts/check-test-completeness.mjsscripts/check-workflow-status-functions.mjsscripts/checklist-select.mjsscripts/docs-audit/check-audit-scope.mjsscripts/measure-test-shard-timings.mjsscripts/objectui-range.mjsscripts/pm/check-governed-prose.mjsscripts/pm/check-label-desc-cap.mjsscripts/pm/check-skill-id-lint.mjsscripts/pm/check-skill-line-ratchet.mjsscripts/qa/qa-rollup.mjsscripts/ts-parse.mjsnode scripts/check-entry-guard.mjs --listprints this live, with the offending line in each file.Generated by Claude Code