What
scripts/check-type-check-coverage.mjs holds three invariants — COVERED, REAL, TESTS_COVERED. REAL is the closest one to this gap, and its own words are:
a declared typecheck script actually invokes tsc. A script that echoes, lints, or runs tests is not type coverage.
There is no invariant one notch further along: the script invokes tsc, but over a program whose completeness depends on generated files nothing in the script produces.
The measured instance
apps/docs/tsconfig.json includes .next/types/**/*.ts and .next/dev/types/**/*.ts. Those directories are produced by next typegen, which the wired typecheck script did not run. Measured on origin/main @ 7d483e1e5f, .next deleted:
pnpm --filter @objectstack/docs typecheck -> exit 0
Green, having compiled none of the generated route types. Running typegen first put 6 more files in the program (tsc --listFiles: 1225 -> 1231), including a 160-line validator.ts that checks 13 route entry points. An ablation confirmed the difference is load-bearing: a layout given a params shape its route cannot supply left the bare script at exit 0 / 0 errors and made the typegen'd one fail with TS2344.
That specific instance is repaired in #10879 — the script now generates what it reads. Nothing mechanical stops it, or a future Next/app package, from regressing.
Why it may be worth a card
The gate already parses every tsconfig in every package and already reads each typecheck script (readTsconfig, configsNamedByTypecheck). The missing question is cheap to ask with what it has:
- for each
include entry rooted in a generated / gitignored directory, does the package's typecheck script contain the command that produces it? - and the stricter half: an
include entry naming a generated root that no declared generator covers is a config promising coverage nothing produces — which is what .next/dev/types/**/*.ts is for a plain tsc run.
A small declared table (generated root -> the command that must appear in the script) keeps the Next-specific knowledge out of the logic. Today it would hold one row.
Note the second bullet cannot be answered by deleting the offending glob: Next owns that array. writeConfigurationDefaults re-adds .next/dev/types/**/*.ts on the next next dev / next build, measured directly by running that routine against a narrowed copy. So a guard here has to be able to say "declared, and deliberately not generated" as well as "generated by the script".
Coordination
This would edit scripts/check-type-check-coverage.mjs, the same file #10756 is dispatched against. Different invariant and different failure direction — #10756 is a source directory falling outside tsc, this is a generated directory whose absence makes a check read green — but whichever lands second has to rebase onto the first. Worth sequencing rather than running in parallel.
Found while implementing #10871; deliberately kept out of that PR's diff, which is two files in apps/docs. Unassigned.
What
scripts/check-type-check-coverage.mjsholds three invariants —COVERED,REAL,TESTS_COVERED.REALis the closest one to this gap, and its own words are:There is no invariant one notch further along: the script invokes tsc, but over a program whose completeness depends on generated files nothing in the script produces.
The measured instance
apps/docs/tsconfig.jsonincludes.next/types/**/*.tsand.next/dev/types/**/*.ts. Those directories are produced bynext typegen, which the wiredtypecheckscript did not run. Measured onorigin/main@7d483e1e5f,.nextdeleted:Green, having compiled none of the generated route types. Running typegen first put 6 more files in the program (
tsc --listFiles: 1225 -> 1231), including a 160-linevalidator.tsthat checks 13 route entry points. An ablation confirmed the difference is load-bearing: a layout given aparamsshape its route cannot supply left the bare script at exit 0 / 0 errors and made the typegen'd one fail with TS2344.That specific instance is repaired in #10879 — the script now generates what it reads. Nothing mechanical stops it, or a future Next/app package, from regressing.
Why it may be worth a card
The gate already parses every tsconfig in every package and already reads each
typecheckscript (readTsconfig,configsNamedByTypecheck). The missing question is cheap to ask with what it has:includeentry rooted in a generated / gitignored directory, does the package'stypecheckscript contain the command that produces it?includeentry naming a generated root that no declared generator covers is a config promising coverage nothing produces — which is what.next/dev/types/**/*.tsis for a plaintscrun.A small declared table (generated root -> the command that must appear in the script) keeps the Next-specific knowledge out of the logic. Today it would hold one row.
Note the second bullet cannot be answered by deleting the offending glob: Next owns that array.
writeConfigurationDefaultsre-adds.next/dev/types/**/*.tson the nextnext dev/next build, measured directly by running that routine against a narrowed copy. So a guard here has to be able to say "declared, and deliberately not generated" as well as "generated by the script".Coordination
This would edit
scripts/check-type-check-coverage.mjs, the same file #10756 is dispatched against. Different invariant and different failure direction — #10756 is a source directory falling outside tsc, this is a generated directory whose absence makes a check read green — but whichever lands second has to rebase onto the first. Worth sequencing rather than running in parallel.Found while implementing #10871; deliberately kept out of that PR's diff, which is two files in
apps/docs. Unassigned.