fix(devx): seven gates that import typescript refuse an uninstalled tree with a named prerequisite, not a raw stack (#15783) - #15862
Merged
Conversation
… tree with a named prerequisite, not a raw stack
`check:system-context-census` and six sibling sites still carried the bare
top-level `import ts from 'typescript'` (and, at one site, a bare dynamic
`import('@typescript-eslint/parser')`) that PR #11824 converted everywhere else.
node resolves those before any module body runs, so the gate cannot preflight
its own missing dependency: on a fresh worktree — the checkout shape CLAUDE.md
mandates — it died with a node-internals `ERR_MODULE_NOT_FOUND` stack and exit
**1**, the same code a real finding uses.
Each site now loads the dependency through `scripts/import-prerequisite.mjs`,
in the shape the 27 already-converted sites use, so the answer is
`PREREQUISITE NOT MET`, exit 3, and an explicit "nothing was measured".
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
…an import them without TS7016 `check-exported-any-returns.mts` is inside the ROOT tsc program, where an untyped `.mjs` import is TS7016 — measured, not assumed: converting it added exactly one error (169 vs the 168 the same tree reports with the unconverted file), and `@objectstack/spec-monorepo` is a shrink-only ratchet. The sidecar is the shape three root scripts already use for the same reason, and `check:declaration-mirrors` covers it by discovery. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
…pescript-import-thunks
This was referenced Sep 5, 2026
Open
baozhoutao
marked this pull request as ready for review
September 5, 2026 11:52
baozhoutao
enabled auto-merge
September 5, 2026 11:52
Contributor
Author
|
Flipped ready + auto-merge enabled (11:52Z, Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #15783
Seven gate/census scripts still carried the bare dependency import that PR #11824 converted everywhere else, so on a fresh per-task worktree — the checkout shape
CLAUDE.mdmandates, withpnpm installnever run — they died with a node-internalsERR_MODULE_NOT_FOUNDstack and exit 1, the code a real finding uses. Each now loads its dependency throughscripts/import-prerequisite.mjsand answersPREREQUISITE NOT MET, exit 3, naming the missing package and saying nothing was measured.Population, derived on this base (not recalled)
The card's own re-check, with its control, at merge base
9e9f03abe:Plus the seventh site recorded in this card's 09:33Z comment, which that grep cannot see because it is a dynamic import of a different package —
scripts/check-comment-mask-corpus.mjs:306,@typescript-eslint/parser. Deferring resolution past linking changes when the failure happens, not what it looks like: the rejection reaches the top level unhandled and node prints the same stack with the same exit 1. It is a CI gate (lint.yml) and adispatch-gates --changed --commandsmember, so a dev harvesting the derived family got exit 3 with a named prerequisite from two commands and a raw stack from a third, for one missing install.Deviation from the Claim ruling, with the evidence for it
The ruling excluded
scripts/measure-durability-swallow-family.mjs:259as #15766's live hot file and asked for it as a follow-up. The re-dispatch records that #15808 landed and the file is free; measured rather than assumed — no open PR touches any file in this diff:So it is converted here rather than re-pointed.
scripts/check-system-context-census.mjsis deliberately left alone.The eighth file: why a
.d.mtssidecarcheck-exported-any-returns.mtsruns through the same loader (node 22 type-stripping;tsxvia@objectstack/client's script), so the ruling's conditional is satisfied and it is converted. Two things it needs that the six.mjssites do not:ts.Program/ts.Type/ts.Signaturein annotations move toimport type TS from 'typescript', erased before the graph is linked. Everyts.left in the file is a value use and reads the thunked binding.scripts/import-prerequisite.d.mts. That file is inside the ROOT tsc program, where an untyped.mjsimport is TS7016. Measured, not assumed: with the conversion and no sidecar the root program reported 169 errors against 168 for the identical tree carryingmain's copy of the file — and@objectstack/spec-monorepois a shrink-only ratchet. The sidecar is the shapecheck-regen-pending.d.mts,invoked-as.d.mtsandjs-comment-mask.d.mtsalready use for exactly this reason, andcheck:declaration-mirrorscovers it by discovery (name / kind / required arity —Function.lengthis 3 on both loaders, matching the declared 3).Measurements
BEFORE, dep-less worktree (
mkdir node_modules, no install), exit captured before any pipe — all seven sites:identically for
check-sdui-lockstep.mjs,tenant-audit-census.mjs,audits/14744-…census.mjs,measure-durability-swallow-family.mjs,check-exported-any-returns.mts, and — for@typescript-eslint/parser—check-comment-mask-corpus.mjs(its--self-testleg too, measured againstorigin/main's copy of the file in the same tree).AFTER, dep-less, at this PR's head
ddcf7c133(a second--detachworktree withmkdir node_modulesand no install), ten invocations, all exit 3:plus
check-sdui-lockstep(both legs),tenant-audit-census,measure-durability-swallow-family --self-test=gated, the 14744 audit, andcheck-comment-mask-corpus --self-test.Which module names itself is worth reading rather than assuming: the five sites that also
import { parseSourceFile } from './ts-parse.mjs'refuse asts-parse, because a static import is evaluated before the importing module's body — the same shape the card's positive control shows. That is why nomeasuresstring is passed at those five: it would be text that can never print. The two sites whose own thunk fires first (check-exported-any-returns.mts,check-comment-mask-corpus.mjs) do pass one, and it appears in the output above.Installed tree, each site still runs its real check:
check:system-context-census(self-test + gate)check:sdui-lockstep(self-test + gate)check:swallow-census-controlscheck-comment-mask-corpus.mjs5998 files, 0 disagree, 0 unparseable, 55.1scheck-comment-mask-corpus.mjs --self-testAll 17 self-test cases passed.node scripts/tenant-audit-census.mjscheck-tenant-audit-census.mjsis 0audits/14744-…census.mjs@objectstack/client check:exported-any-returns(viatsx, closure + package built)317 callables reached … 36 ledgered site(s) still openAblation (
scripts/isystem-census.mjs, trap-guarded, on the committed implementation): thunk reverted to the bare import — proven on disk,thunk=0 bare=1— the rawERR_MODULE_NOT_FOUNDstack and exit 1 come back; restored withgit checkout HEAD -- PATH,git hash-objectequal to the HEAD blob69cb3d34c2c0744f00791ec13e26088cf0a42f7e,git diff HEADempty, and the gate answers exit 3 again.Gate family,
node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack, re-derived on this head (no staleness warning): 35 commands, all run, reconciliation35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. 34 exit 0. Alsopnpm check:nul-bytes0, a manualgrep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'over the eight files with no match,check-governed-merges --test FINAL-FILE-LIST→0 of 8 path(s) hit the register, andgit merge-tree --write-tree origin/main HEADafter a fresh fetch → exit 0, no conflict (no path in this diff carries a merge driver).NOT MEASURED, by name:
pnpm check:type-check-debt— exit 3,--re-measure cannot run: 1 workspace dependenc(ies) … have no built type entry point on disk. Its coverage half ran and printed OK; the ratchet entry this diff could move is the root program, and that was measured directly instead: identical tree,npx tsc -p tsconfig.json --noEmitreports 31 errors with this PR's.mts+ sidecar and 31 withmain's copy of the file and no sidecar, 0 of them in the converted file. CI runs the full-closure re-measure.Follow-ups (not in this PR)
prerequisiteNotMetTextstrips only.mjswhen it derives the gate's name, so the first.mtsconsumer labels itselfcheck-exported-any-returns.mts. Cosmetic, and only observable from this PR onward.@objectstack/spec-monorepo's ledger note is declared stale by its owncompositionAt(tallied at 80, recorded 26). Pre-existing, surfaced by the gate itself.🤖 Generated with Claude Code
https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Generated by Claude Code