Skip to content

Typecheck: own tsbuildinfo per combined project and cache incremental state in CI (CL-7415) - #629

Merged
TheGreatAxios merged 6 commits into
mainfrom
cl-7415-typecheck-buildinfo-cache
Sep 4, 2026
Merged

TheGreatAxios merged 6 commits into
mainfrom
cl-7415-typecheck-buildinfo-cache

Conversation

@TheGreatAxios

@TheGreatAxios TheGreatAxios commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Two defects

  1. Shared tsbuildinfo clobbers itself. The combined tsconfig.json (the file bare tsc, ESLint's projectService, and editors discover by convention) extends tsconfig.src.json, inheriting tsBuildInfoFile: "dist/tsconfig.tsbuildinfo". The composite tsc --build and the combined --noEmit check both write that same file, so each invalidates the other's incremental state on every run. Fix: COMBINED_COMPILER_OPTIONS in scripts/generate-tsconfig-references.ts now sets tsBuildInfoFile: "tsconfig.tsbuildinfo", landing next to the package's tsconfig.json (already gitignored via *.tsbuildinfo). combinedFieldsMatch already iterates Object.keys(COMBINED_COMPILER_OPTIONS), so drift detection picks the new key up for free. Regenerated every tsconfig.json with bun run scripts/generate-tsconfig-references.ts. The vendored vendor/intx/*/tsconfig.json files are generator output too, so their content hashes in scripts/checks/kill-dates.txt are updated in the same change.

  2. CI caches nothing for typecheck. The typecheck job in .github/workflows/ci.yml only restores node_modules via setup-workbench, so every PR pays the full cost from a cold cache. Added an actions/cache@v4 step keyed on bun.lock, .bun-version, tsconfig.base.json, scripts/generate-tsconfig-references.ts, and github.sha, with a restore-keys prefix so a PR falls back to the newest matching cache (typically main's). Paths are listed per workspace root (apps/*/dist, packages/*/dist, ...) rather than **/dist/**: the recursive glob walks node_modules and follows every workspace symlink in it, and the save step ran for over 40 minutes before it was cancelled. With explicit roots the ~200 MB cache saves in 2s.

CI timings, bun run typecheck step on this branch

run cache step job total
33877407144 not found (seeds it) 457s 8m03s
33878262756 restored 174s ~3m20s

Baseline on main before this change: 416s to 446s step, 7m14s to 7m50s job.

What remains in the warm 174s is the 113 per-project tsc -p --noEmit invocations each re-reading their program on a 4-core runner even when buildinfo says nothing changed. Further cuts mean fewer projects (CL-7249) or a larger runner.

Local timings (this worktree)

  • bun run typecheck run 1 (tsconfigs just regenerated, effectively cold): 45.1s wall
  • bun run typecheck run 2 (warm): 11.4s wall
  • bunx tsc --build tsconfig.build.json immediately after: 0.33s (previously 13.5s, confirming defect 1 is fixed)

Touch-test (does tsc --build skip on fresh mtimes?)

TypeScript 6.0.3. After a warm build, touched every .ts file under packages/ and apps/ (mtime only), then ran tsc --build tsconfig.build.json: 2.5s wall on the first run (partial recompute, not the ~15s cold build; the content-hash check short-circuits most files even though --build's up-to-date check uses mtimes), 0.94s on the second. The per-project --noEmit checks use --incremental content hashes and do not care about mtimes at all.

@linear-code

linear-code Bot commented Sep 4, 2026

Copy link
Copy Markdown

CL-7415

@TheGreatAxios
TheGreatAxios force-pushed the cl-7415-typecheck-buildinfo-cache branch 2 times, most recently from ad65969 to 683bb1e Compare September 4, 2026 13:56
@TheGreatAxios

Copy link
Copy Markdown
Contributor Author

Self-review

Rebased onto main (conflicts were only in scripts/checks/kill-dates.txt), regenerated tsconfigs and recomputed vendor hashes, fixed one confirmed cache-coverage gap, and verified the fix's own claims (near-instant repeat tsc --build).

  • CONFIRMED-FIXED: test/isolation/tsconfig.json is a real incremental project (scripts/typecheck.ts runs tsc -p test/isolation/tsconfig.json --noEmit, base config has incremental: true) that writes a 483 KB test/isolation/tsconfig.tsbuildinfo, but the cache path: list only had test/tsconfig.tsbuildinfo, not test/isolation/tsconfig.tsbuildinfo. That project always recompiled cold on every CI run regardless of cache hits. Added the missing path.
  • CONFIRMED-FIXED: branch was CONFLICTING against main — rebased, resolved the kill-dates.txt hash conflict by recomputing every vendor/intx/* hash with hashDirectory directly (.tsbuildinfo files are already excluded from the hash by scripts/checks/lib/tree-hash.ts, so the tsBuildInfoFile rename doesn't itself change any hash — the diff is just this branch's own tsconfig.json regeneration for vendor/intx/db plus main's independent hash updates for the rest).
  • DISMISSED: cache path list vs package.json workspaces globs — templates is a workspace but is intentionally excluded from scripts/typecheck.ts's PROJECT_GLOBS (never globbed, no dist/tsbuildinfo produced), so its absence from the cache path list is correct, not a gap. The listed roots (apps/*, packages/*, tools/*, workflows/*, vendor/intx/*) match PROJECT_GLOBS exactly.
  • DISMISSED: .gitignore already covers the new tsconfig.tsbuildinfo location via the existing *.tsbuildinfo glob — no change needed.
  • DISMISSED: cache key/restore-keys — key includes github.sha for exact-commit caching, restore-keys drops the sha for prefix fallback to the newest matching cache (main's, typically) as the PR body's timing table confirms. Correct.
  • DISMISSED: generator drift check — combinedFieldsMatch iterates Object.keys(COMBINED_COMPILER_OPTIONS), which now includes tsBuildInfoFile, so drift is caught for free as claimed. Verified by reading scripts/generate-tsconfig-references.ts.

Targeted tests: bun run scripts/checks/killdates.ts (pass), bun run typecheck (pass, ~10-16s locally after regeneration — a local node_modules install anomaly for cronstrue unrelated to this diff needed a manual workaround to verify, not part of the PR), bunx tsc --build tsconfig.build.json twice (0.33s / 0.32s, confirms defect 1 stays fixed after rebase).

Conflict risk: PR #632 ("re-pin Interchange vendor + sidecar modules") also touches scripts/checks/kill-dates.txt — expect another rebase/hash-recompute pass on whichever of these two merges second.

@TheGreatAxios
TheGreatAxios force-pushed the cl-7415-typecheck-buildinfo-cache branch from 683bb1e to 8e49b78 Compare September 4, 2026 14:03
@TheGreatAxios
TheGreatAxios merged commit 4b7a1cf into main Sep 4, 2026
7 checks passed
TheGreatAxios added a commit that referenced this pull request Sep 4, 2026
Main's tsBuildInfoFile change (#629) touched every vendored
tsconfig.json, so the sha256 tree hashes recorded for the 5bc9b5ee pin
drifted. Recompute them via hashDirectory() so check:killdates passes.
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.

1 participant