Skip to content

fix(playwright): isolate the generated child tsconfig's include/exclude - #1953

Merged
BigSimmo merged 8 commits into
mainfrom
claude/playwright-tsconfig-isolation
Aug 14, 2026
Merged

fix(playwright): isolate the generated child tsconfig's include/exclude#1953
BigSimmo merged 8 commits into
mainfrom
claude/playwright-tsconfig-isolation

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Summary

  • Closes the narrowed, still-open part of ledger #210: scripts/run-playwright.mjs writes an isolated tsconfig.json (extends: "../../tsconfig.json") for each Playwright run root under .next-playwright/<runId>/, 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 actually resolved .next/dev/types/**/*.ts (and the broad **/*.ts) against the shared top-level .next/ directory — not this run's own NEXT_DIST_DIR output under its own dist/ — pulling stale/foreign route types from whatever the top-level .next happened to contain (a prior npm run dev or npm run build) into the isolated build's typecheck.
  • The fix gives the generated child tsconfig its own explicit include (repo source globs, plus this run's own dist/types/**/*.ts and dist/dev/types/**/*.ts) and exclude (mirrors the root tsconfig's exclude list, plus the repo-root .next/**).
  • Items 1 and 2 of ledger #210 were already closed/refuted before this PR (root tsconfig.typecheck.json already excludes .next/**, and dropping .next/dev/types/**/*.ts from the root tsconfig.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:

  1. Wrote the exact isolated child tsconfig run-playwright.mjs generates (pre-fix, no include/exclude) into a scratch .next-playwright/<id>/ directory and ran tsc -p <that config> --showConfig.
  2. Planted a fake stale file at repo-root .next/dev/types/stale-route.ts (simulating leftover output from a prior npm run dev/npm run build).
  3. Before the fix: tsc --showConfig's resolved file list included "../../.next/dev/types/stale-route.ts" — i.e. the repo-root .next directory, not the isolated run's own dist. Confirmed reproduction.
  4. After the fix (child config gets its own explicit include/exclude per this PR): the same probe no longer resolves that file at all — grep -c stale-route on the resolved config → 0.

RAG impact

Not applicable — this PR touches only scripts/run-playwright.mjs (Playwright test-runner tooling), no src/lib/rag/**, retrieval, ranking, or clinical-answer surface.

Solo-PR note (operationalRisk)

This change trips operationalRisk under scripts/pr-policy.mjs's classifyPullRequestFiles (test-runner config: scripts/run-playwright.mjs). Per this repo's PR-bundling rules, an operationalRisk: true file 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 via tsconfig.typecheck.json, which already excludes .next/** — unrelated to this change, confirmed still passing):
    > prompt-for-codex-medical-knowledge-base@0.1.0 typecheck
    > node scripts/run-heavy.mjs --npm-script typecheck:internal
    
    > prompt-for-codex-medical-knowledge-base@0.1.0 typecheck:internal
    > node ./node_modules/typescript/bin/tsc -p tsconfig.typecheck.json --noEmit --tsBuildInfoFile /tmp/clinical-kb-tsc-cache/51b73b0319f72aa793c5/tsconfig.tsbuildinfo
    
  • Focused verify:ui reproduction — this session's container hit the documented Playwright/Chromium version drift (#255: preinstalled container Chromium was chromium-1194, lock/playwright-core expects chromium-1234) when using the container browser path; downloading the matching browser (npx playwright install chromium) succeeded (network access to cdn.playwright.dev was 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:
    Starting isolated production Playwright server at http://localhost:3291 (.next-playwright/verify-fix-repro)
    ▲ Next.js 16.3.0
    ✓ Ready in 142ms
    
    Running 1 test using 1 worker
    
      ✓  1 [chromium] › tests/ui-smoke.spec.ts:1108:7 › Clinical KB UI smoke coverage › anonymous user can see enabled live search without a forced sign-in gate @critical (815ms)
    
      1 passed (5.4s)
    Keeping Playwright build root for cache reuse (.next-playwright/verify-fix-repro)
    
  • Hashed the generated child tsconfig.json immediately after write (reconstructed independently from the exact object literal now in scripts/run-playwright.mjs) and again after the full build+server+test run above completed. Both are byte-identical:
    sha256: 1c744da9634c2d712b1fd9ae428a5808fadf82b9d623d0ce30ca923b56a3ce4a  (before, reconstructed at write-time)
    sha256: 1c744da9634c2d712b1fd9ae428a5808fadf82b9d623d0ce30ca923b56a3ce4a  (after, actual file post-build)
    diff <before> <after> → no output ("IDENTICAL")
    
    This empirically confirms writeConfigurationDefaults() in node_modules/next/dist/lib/typescript/writeConfigurationDefaults.js really does return immediately when the parsed config has "extends" (if ('extends' in userTsConfig || 'references' in userTsConfig) { return; }) — Next's own next build does not silently rewrite this isolated child config.
  • Not run: npm run verify:pr-local / npm run verify:cheap as a whole gate — the change is a single, narrowly-scoped tsconfig-generation edit inside one script; typecheck plus the direct build/test reproduction above are the smallest checks that actually exercise the changed code path (the isolated tsconfig is only read during next build --webpack inside run-playwright.mjs, which the reproduction above ran directly).

Risk and rollout

  • Risk: Low. Only affects the isolated tsconfig.json generated per Playwright run root (.next-playwright/<runId>/tsconfig.json); does not touch the root tsconfig.json, tsconfig.typecheck.json, or any non-Playwright build/typecheck path.
  • Rollback: Revert this commit; run-playwright.mjs returns to its previous (inherited include/exclude) behavior.
  • Provider or production effects: None.

Notes

  • Does not remove typecheck from any gate.
  • Did not retry the previously-refuted "drop .next/dev/types/**/*.ts from the root tsconfig.json include" approach.
  • No Clinical Governance Preflight section included — this is build-tooling only (Playwright test-runner config generation), not a clinical/RAG/ingestion/answer-generation/source-governance surface.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01QLbw9qpfjv5CeNz6XpmteN


Generated by Claude Code

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
@supabase

supabase Bot commented Aug 14, 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 ↗︎.

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8b9828cd-b1c5-4b45-b7c7-32d437b0a473

📥 Commits

Reviewing files that changed from the base of the PR and between 5e5938d and e6408cd.

📒 Files selected for processing (4)
  • docs/branch-review-records/39296f14956e2712c76344bea1eb1d312c64370049420fc3dd6939b28780721b.record.md
  • docs/branch-review-records/40b0c05db4e9b44c17bc78bb0246cd15d4f72e244027e5a389bee78924c450cf.record.md
  • docs/branch-review-records/c9661626e5c2a0e5f848b375b83006a00452994ad503349944c2fb345c8b42a1.record.md
  • scripts/run-playwright.mjs

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

@BigSimmo
BigSimmo enabled auto-merge August 14, 2026 14:38

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread scripts/run-playwright.mjs
@BigSimmo
BigSimmo disabled auto-merge August 14, 2026 14:43
@BigSimmo
BigSimmo enabled auto-merge August 14, 2026 14:52
BigSimmo pushed a commit that referenced this pull request Aug 14, 2026
…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.
@github-actions

Copy link
Copy Markdown
Contributor

CI triage

CI failed on this PR. Automated classification of the 2 failed job(s):

  • Production UI (1)needs investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.
  • PR requiredneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.

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.

@BigSimmo
BigSimmo merged commit 18f4f1f into main Aug 14, 2026
26 checks passed
@BigSimmo
BigSimmo deleted the claude/playwright-tsconfig-isolation branch August 14, 2026 17:06

Copy link
Copy Markdown
Owner Author

Final review summary

  • Final reviewed head: e6408cdc8d500c19920771f476e01c992275a975; base at review: 5e5938df5770f345f20e36f80e35278f25494cea.
  • GitHub shows this PR was externally merged into main as 18f4f1f65ff5b1473b5eb093626f998198adf3ff. Its merge tree was clean; no branch update was needed after the final review.
  • No PR-introduced P0–P2 defect remained. The existing inline concern was validated as correct; all review threads are resolved.
  • Independent adversarial pass: manual contract and merge-tree review; no additional actionable finding.
  • Decisive local checks: git diff --check, docs/ledger native guards; focused Playwright/Next build unavailable locally because node_modules was absent.
  • Exact-head CI: required aggregate passed, including Static PR checks, Unit coverage, and Production UI critical. SAST and Secret Scan passed. Build was correctly skipped; no advisory blocker was present.
  • Residual risk: no local dependency-backed replay was possible; exact hosted checks passed.

The PR was not merged by Codex. Final merge is left to the user.

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