fix(playwright): isolate the generated child tsconfig's include/exclude - #1953
Conversation
scripts/run-playwright.mjs writes an isolated tsconfig.json (extends: "../../tsconfig.json") for each Playwright run root, but left include/ exclude unset. TypeScript resolves an extended config's *inherited* relative include/exclude entries against the base config's own directory (the repo root), so the isolated config still resolved ".next/dev/types/**/*.ts" (and the broad "**/*.ts") against the shared top-level .next/ directory rather than this run's own NEXT_DIST_DIR output under its dist/ folder. Empirically confirmed with a stale .next/dev/types/*.ts fixture file: before this change, `tsc --showConfig` on the generated child config resolved that repo-root file into the isolated run's file list; after this change it does not. The child config now declares its own include (repo source globs plus this run's own dist/types and dist/dev/types) and exclude (mirrors the root tsconfig's exclude list plus the repo-root .next/**). Verified this is not clobbered by Next's own tsconfig auto-config: writeConfigurationDefaults() returns immediately when the parsed config has "extends" (confirmed by reading node_modules/next/dist/lib/typescript/writeConfigurationDefaults.js). Hashed the generated child tsconfig.json immediately after write and again after a full `next build --webpack` + server start + Playwright test run (npm run test:e2e:pr equivalent, single focused spec) — both hashes match byte-for-byte (sha256 1c744da9634c2d712b1fd9ae428a5808fadf82b9d623d0ce30ca923b56a3ce4a). Ledger #210 (re-scoped 2026-08-13): items 1-2 already closed/refuted; this closes item 3. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLbw9qpfjv5CeNz6XpmteN
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 2 minutes Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
Comment |
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLbw9qpfjv5CeNz6XpmteN
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a5af47d083
ℹ️ 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".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…merged #215, #210, and #293 were queued as `done` in this same PR, each citing a PR (#1949, #1953, #1962) that turned out still to be open, not merged — verified by checking whether each PR's actual file change is present on origin/main (none are). Reconciling the original `done` requests would have closed these rows while their fixes exist only on unmerged branches, one of which (#1949) currently has failing required CI. Converts all three to `update` requests documenting the correction and the real current state, so reconciling this PR now cannot close a row before its fix has actually landed. Leaves #98, #189, and #194 as `done` unchanged — those cite PR #1950 and PR #1947, both confirmed merged into main.
CI triageCI failed on this PR. Automated classification of the 2 failed job(s):
Compared with main CI run #10891 (cancelled). Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger. |
|
Final review summary
The PR was not merged by Codex. Final merge is left to the user. |
Summary
#210:scripts/run-playwright.mjswrites an isolatedtsconfig.json(extends: "../../tsconfig.json") for each Playwright run root under.next-playwright/<runId>/, but leftinclude/excludeunset. TypeScript resolves an extended config's inherited relativeinclude/excludeentries against the base config's own directory (the repo root), so the isolated config actually resolved.next/dev/types/**/*.ts(and the broad**/*.ts) against the shared top-level.next/directory — not this run's ownNEXT_DIST_DIRoutput under its owndist/— pulling stale/foreign route types from whatever the top-level.nexthappened to contain (a priornpm run devornpm run build) into the isolated build's typecheck.include(repo source globs, plus this run's owndist/types/**/*.tsanddist/dev/types/**/*.ts) andexclude(mirrors the root tsconfig's exclude list, plus the repo-root.next/**).#210were already closed/refuted before this PR (roottsconfig.typecheck.jsonalready excludes.next/**, and dropping.next/dev/types/**/*.tsfrom the roottsconfig.json's own include was refuted — Next 16 regenerates that glob itself). This PR only touches item 3, the isolated Playwright tsconfig.What I found empirically
The bug was previously "a real but unconfirmed hypothesis, not a proven bug." I reproduced it directly:
run-playwright.mjsgenerates (pre-fix, noinclude/exclude) into a scratch.next-playwright/<id>/directory and rantsc -p <that config> --showConfig..next/dev/types/stale-route.ts(simulating leftover output from a priornpm run dev/npm run build).tsc --showConfig's resolved file list included"../../.next/dev/types/stale-route.ts"— i.e. the repo-root.nextdirectory, not the isolated run's own dist. Confirmed reproduction.include/excludeper this PR): the same probe no longer resolves that file at all —grep -c stale-routeon the resolved config →0.RAG impact
Not applicable — this PR touches only
scripts/run-playwright.mjs(Playwright test-runner tooling), nosrc/lib/rag/**, retrieval, ranking, or clinical-answer surface.Solo-PR note (operationalRisk)
This change trips
operationalRiskunderscripts/pr-policy.mjs'sclassifyPullRequestFiles(test-runner config:scripts/run-playwright.mjs). Per this repo's PR-bundling rules, anoperationalRisk: truefile is explicitly excluded from bundling regardless of how small the diff is, so this correctly stands as its own solo PR rather than riding with any sibling ledger-sweep PR.Verification
npm run typecheck— green, no output beyond the command echo (tsc viatsconfig.typecheck.json, which already excludes.next/**— unrelated to this change, confirmed still passing):verify:uireproduction — this session's container hit the documented Playwright/Chromium version drift (#255: preinstalled container Chromium waschromium-1194, lock/playwright-coreexpectschromium-1234) when using the container browser path; downloading the matching browser (npx playwright install chromium) succeeded (network access tocdn.playwright.devwas available in this environment), after which the preflight passed (ok: true) and a full isolated production build (next build --webpack) + server start + one focused Playwright spec ran successfully:tsconfig.jsonimmediately after write (reconstructed independently from the exact object literal now inscripts/run-playwright.mjs) and again after the full build+server+test run above completed. Both are byte-identical:writeConfigurationDefaults()innode_modules/next/dist/lib/typescript/writeConfigurationDefaults.jsreally does return immediately when the parsed config has"extends"(if ('extends' in userTsConfig || 'references' in userTsConfig) { return; }) — Next's ownnext builddoes not silently rewrite this isolated child config.npm run verify:pr-local/npm run verify:cheapas a whole gate — the change is a single, narrowly-scoped tsconfig-generation edit inside one script;typecheckplus the direct build/test reproduction above are the smallest checks that actually exercise the changed code path (the isolated tsconfig is only read duringnext build --webpackinsiderun-playwright.mjs, which the reproduction above ran directly).Risk and rollout
tsconfig.jsongenerated per Playwright run root (.next-playwright/<runId>/tsconfig.json); does not touch the roottsconfig.json,tsconfig.typecheck.json, or any non-Playwright build/typecheck path.run-playwright.mjsreturns to its previous (inherited include/exclude) behavior.Notes
.next/dev/types/**/*.tsfrom the roottsconfig.jsoninclude" approach.Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01QLbw9qpfjv5CeNz6XpmteN
Generated by Claude Code