Keep the source typecheck out of Next's build output again (#210) - #2501
Conversation
`tsconfig.typecheck.json` exists to answer one question — "is the source itself sound?" — without reading gitignored build artifacts, because a stale generated validator reports errors that no longer exist in source and CI, on a fresh checkout, never sees them. A permanently-red local gate is why real type errors reach CI instead of being caught before push (`docs/outstanding-issues.md` #210). Excluding `.next/**` stopped being sufficient. An `exclude` filters what the `include` globs collect; it cannot drop a file that an included file IMPORTS. Next 16 regenerates `next-env.d.ts` with import "./.next/dev/types/routes.d.ts"; import "./.next/dev/types/root-params.d.ts"; so the moment `next dev` or `next build` runs, the source-health typecheck is reading build output again through the back door. Measured on 2026-09-01: `next dev` left `.next/dev/types/routes.d.ts` with a stray fragment (`d": {}`) where a shorter write had not truncated a longer previous file, and `npm run typecheck` reported 106 syntax errors against source that was completely sound. Deleting `.next` made it pass instantly. Reproduced deliberately here — the same corrupt artefact gives 106 errors under the old config and exit 0 under the new one. `next-env.typecheck.d.ts` carries the half of `next-env.d.ts` that is real type information (the two reference directives, which resolve inside `node_modules`) and none of the half that points at build output. `tsconfig.typecheck.json` includes it and excludes `next-env.d.ts` by name — `**/*.ts` matches `.d.ts`, so dropping it from `include` alone would not keep it out. Route-signature validation is not lost: `tsconfig.json` still uses the real `next-env.d.ts`, so `next build` (CI's Build job) keeps typechecking the generated types against the actual routes. `tests/typecheck-config-isolation.test.ts` fails if either the include or the exclude is undone, if the stand-in grows a reference into build output, or if a Next upgrade adds a reference directive to `next-env.d.ts` that the stand-in does not carry.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_32bc55c3-2121-48c6-a70b-9d57de5d1e15) |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Summary
tsconfig.typecheck.jsonexists to answer one narrow question — is the source itself sound? — without reading gitignored build artifacts.docs/outstanding-issues.md#210records why: a stale generated validator reports errors that no longer exist in source, CI never sees them on a fresh checkout, and a permanently-red local gate gets abandoned, which is how real type errors reach CI instead of being caught before push.That protection has quietly stopped working. An
excludefilters what theincludeglobs collect; it cannot drop a file that an included file imports. Next 16 regeneratesnext-env.d.tswithimport "./.next/dev/types/routes.d.ts"andimport "./.next/dev/types/root-params.d.ts"in it, so from the momentnext devornext buildruns, the source-health typecheck reads build output again through the back door — with.next/**still sitting inexclude, doing nothing.Measured, not hypothetical. On 2026-09-01
next devleft.next/dev/types/routes.d.tscarrying a stray fragment (d": {}) where a shorter write had not truncated a longer previous file.npm run typecheckreported 106 syntax errors against source that was completely sound; deleting.nextmade it pass instantly. That cost a working session's confidence in the gate — exactly the failure mode#210describes.The fix.
next-env.typecheck.d.tsis a committed stand-in carrying the half ofnext-env.d.tsthat is real type information — the two/// <reference types="…" />directives, which resolve insidenode_modules— and none of the half that points at build output.tsconfig.typecheck.jsonincludes it and excludesnext-env.d.tsby name, because**/*.tsmatches.d.tsand dropping it fromincludealone would not keep it out.Route-signature validation is not lost.
tsconfig.jsonstill uses the realnext-env.d.ts, sonext build— CI's Build job — keeps typechecking the generated types against the actual routes. This change only narrows the local source-health gate, which is what it was always meant to be.Verification
Reproduced the failure, then proved the fix against it. The corrupt artefact was recreated deliberately (
next-env.d.tswith both build-output imports, plus aroutes.d.tscarrying the same stray-fragment shape). Under the previous config:Under the new config, on the identical artefact:
npx tsc -p tsconfig.typecheck.json --noEmit→ exit 0, no output.tests/typecheck-config-isolation.test.ts—Test Files 1 passed (1)/Tests 4 passed (4). It fails if the include or the exclude is undone, if the stand-in grows a reference into build output, or if a Next upgrade adds a reference directive tonext-env.d.tsthat the stand-in does not carry.npx tsc -p tsconfig.typecheck.json --noEmiton a clean tree — exit 0.npm run format— clean.Verification not run: the broad gates. This diff is one JSONC config, one
.d.tscontaining only reference directives, and one test — no product code, no UI, no routing, no clinical or RAG surface, soverify:ui, the full unit suite and the domain checks have no plausible regression to catch here.check:production-readinessis unrelated and fails on pre-existing privacy debt tracked as#HVTYAT.Risk and rollout
next-env.d.ts, the stand-in must gain it too, which the test enforces whenever a localnext dev/next buildhas produced that file.npm run typecheckreturns to reading.next/dev/typeswhenever the app has been run locally.Notes
Split from the answer-page work in #2500 on purpose: that diff is clinical-risk and carries the governance preflight, and this repository's bundling rules forbid combining such a change with unrelated maintenance.
Generated by Claude Code
Note
Low Risk
Local/developer typecheck config only; no runtime, CI build, or product behavior changes beyond avoiding false typecheck failures from
.nextartifacts.Overview
Restores #210’s guarantee that
npm run typecheck(tsconfig.typecheck.json) only judges source, not gitignored.nextoutput. Next 16’s regeneratednext-env.d.tsimports./.next/dev/types/*.d.ts, so excluding.next/**no longer helped—stale or corrupt route types could flood the gate with false errors.The PR adds
next-env.typecheck.d.ts, a committed stand-in with only thenextandnext/image-types/globalreference directives (no build imports), switches the typecheck config to include that file and explicitly excludenext-env.d.ts, and addstests/typecheck-config-isolation.test.tsto lock include/exclude and reference parity on Next upgrades.tsconfig.jsonstill uses the realnext-env.d.ts, sonext buildroute typing is unchanged.Reviewed by Cursor Bugbot for commit 7a9f713. Configure here.