Skip to content

Keep the source typecheck out of Next's build output again (#210) - #2501

Merged
BigSimmo merged 4 commits into
mainfrom
claude/typecheck-build-artifact-isolation
Sep 1, 2026
Merged

Keep the source typecheck out of Next's build output again (#210)#2501
BigSimmo merged 4 commits into
mainfrom
claude/typecheck-build-artifact-isolation

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Summary

  • tsconfig.typecheck.json exists to answer one narrow question — is the source itself sound? — without reading gitignored build artifacts. docs/outstanding-issues.md #210 records 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 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" and import "./.next/dev/types/root-params.d.ts" in it, so from the moment next dev or next build runs, the source-health typecheck reads build output again through the back door — with .next/** still sitting in exclude, doing nothing.

  • Measured, not hypothetical. On 2026-09-01 next dev left .next/dev/types/routes.d.ts carrying a stray fragment (d": {}) where a shorter write had not truncated a longer previous file. npm run typecheck reported 106 syntax errors against source that was completely sound; deleting .next made it pass instantly. That cost a working session's confidence in the gate — exactly the failure mode #210 describes.

  • The fix. next-env.typecheck.d.ts is a committed stand-in carrying the half of next-env.d.ts that is real type information — the two /// <reference types="…" /> 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, because **/*.ts matches .d.ts and 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. 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.ts with both build-output imports, plus a routes.d.ts carrying the same stray-fragment shape). Under the previous config:

    .next/dev/types/routes.d.ts(4,1): error TS1434: Unexpected keyword or identifier.
    .next/dev/types/routes.d.ts(4,7): error TS1002: Unterminated string literal.
    .next/dev/types/routes.d.ts(5,12): error TS1005: ';' expected.
    

    Under the new config, on the identical artefact: npx tsc -p tsconfig.typecheck.json --noEmitexit 0, no output.

  • tests/typecheck-config-isolation.test.tsTest 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 to next-env.d.ts that the stand-in does not carry.

  • npx tsc -p tsconfig.typecheck.json --noEmit on a clean tree — exit 0.

  • npm run format — clean.

Verification not run: the broad gates. This diff is one JSONC config, one .d.ts containing only reference directives, and one test — no product code, no UI, no routing, no clinical or RAG surface, so verify:ui, the full unit suite and the domain checks have no plausible regression to catch here. check:production-readiness is unrelated and fails on pre-existing privacy debt tracked as #HVTYAT.

Risk and rollout

  • Risk: Low, and local-only. The change narrows what a local developer gate reads; it cannot affect the build, the app, or CI. The one thing to watch is drift — if a future Next upgrade adds a reference directive to next-env.d.ts, the stand-in must gain it too, which the test enforces whenever a local next dev/next build has produced that file.
  • Rollback: Revert the commit. npm run typecheck returns to reading .next/dev/types whenever the app has been run locally.
  • Provider or production effects: None
  • RAG impact: none

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 .next artifacts.

Overview
Restores #210’s guarantee that npm run typecheck (tsconfig.typecheck.json) only judges source, not gitignored .next output. Next 16’s regenerated next-env.d.ts imports ./.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 the next and next/image-types/global reference directives (no build imports), switches the typecheck config to include that file and explicitly exclude next-env.d.ts, and adds tests/typecheck-config-isolation.test.ts to lock include/exclude and reference parity on Next upgrades. tsconfig.json still uses the real next-env.d.ts, so next build route typing is unchanged.

Reviewed by Cursor Bugbot for commit 7a9f713. Configure here.

`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.
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 6e1b1bb1-3156-4931-8aa7-d7c6b5ab9934


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@supabase

supabase Bot commented Sep 1, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@cursor

cursor Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot 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)

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-01T12:31:34.331419Z 7a9f713 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@BigSimmo
BigSimmo enabled auto-merge September 1, 2026 12:34
@BigSimmo
BigSimmo disabled auto-merge September 1, 2026 13:03
@BigSimmo
BigSimmo enabled auto-merge (squash) September 1, 2026 13:03
@BigSimmo
BigSimmo merged commit 414cad1 into main Sep 1, 2026
27 checks passed
@BigSimmo
BigSimmo deleted the claude/typecheck-build-artifact-isolation branch September 1, 2026 13:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants