Repository navigation
fix(site): fix tsconfig and sync-spec-docs.mts drift breaking verify - #372
Merged
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Two independent bugs, both hidden because neither ran as a required PR gate. apps/site's tsconfig.json maps `@generated-docs/*` to a single hardcoded `./.source/*`. `types:check`/`verify` set `PDPP_SITE_SOURCE_DIR` to `.source-verify` (and `dev` to `.source-dev`), so fumadocs-mdx writes each mode's output to its own directory instead. #340 isolated these directories, and kept matching webpack/turbopack aliases in `next.config.ts` in sync, so dev and verify runs stop clobbering each other's generated files. `tsc` has no way to read that env var, so it always resolved `.source`, which `verify` never populates: `tsc --noEmit` failed with `TS2307: Cannot find module '@generated-docs/dynamic.ts'`. `next build` never hit this, because Next's own bundler uses the parameterized alias, not tsconfig's `paths`, so the bug was invisible to any build/deploy path and to every CI job, none of which invoke `apps/site`'s `verify` or `types:check` at all. List all three mode directories in `paths` as fallbacks; tsc resolves whichever one the run populated. `apps/site/scripts/sync-spec-docs.mjs` is a generated artifact compiled from `sync-spec-docs.mts` (`scripts/check-generated-artifacts.ts` asserts they're byte-identical). #366 added stale-`.md` cleanup logic by editing the compiled `.mjs` directly and never touched the `.mts` source, so the two diverged. Port the same logic into `.mts` and regenerate `.mjs` from it. `generated-artifacts:check` only runs in semantic-release.yml, gated on a version actually publishing, so it's absent from the PR-required checks and this went uncaught since #366 merged. Root/site spec drift (spec-check.yml) stayed green throughout because it only runs `spec:check`, which diffs generated markdown against the root specs and never invokes tsc or generated-artifacts:check. Verified: `pnpm --dir apps/site run verify` now gets past types:check, test (247/247), and build. `pnpm generated-artifacts:check` reports 7 byte-identical artifacts. `ultracite check` still fails on an unrelated, pre-existing `playwright` import in `apps/site/scripts/style-differ.mjs`, present unmodified on main and out of scope here. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
…gate
The previous commit's tsconfig fix listed `.source`, `.source-verify`, and
`.source-dev` as fallback `paths` for `@generated-docs/*`, so `tsc` would
resolve whichever directory exists. That is unsound: `tsc` picks the first
entry that exists, not the one the current run generated, so a `.source`
left behind by an unrelated `next build`/`next dev` run masks a real type
error in `verify`'s own `.source-verify` output. Reproduced: with a valid
`.source` present and a `docs-source.ts` import renamed to break against a
freshly-regenerated `.source-verify` (the same shape a real fumadocs-mdx or
source-config change could produce), `tsc --noEmit` against the fallback
list still exited 0.
Fix: give `verify` a dedicated `tsconfig.verify.json` that resolves
`@generated-docs/*` against `.source-verify` only, selected by a new
`PDPP_SITE_TSCONFIG` env var alongside the existing `PDPP_SITE_SOURCE_DIR`.
`next build` has its own internal type-check pass that reads
`tsconfig.json` directly, separate from the webpack/turbopack aliases its
bundler uses, so it needs the same fix: `next.config.mjs` now sets
`typescript.tsconfigPath` from the same env var. The base `tsconfig.json`
goes back to a single `.source` path, for the editor and a plain
`types:check`. Re-ran the same masking repro against the fix: with the
same stale, valid `.source` present, `tsc -p tsconfig.verify.json --noEmit`
correctly fails on the broken `.source-verify`.
`ultracite check` (the linter step inside `apps/site`'s `check`/`verify`)
failed on `scripts/style-differ.mjs`'s `import { chromium } from
"playwright"`, flagged as an unresolved import. `playwright` is a real
dependency (`apps/site/package.json`); the import resolves under
TypeScript and at runtime. The failure is Biome's documented resolver gap
with re-exports (`export * from 'playwright-core'` in `playwright`'s
`index.d.ts`): `playwright-core` is only an indirect dependency here, so
pnpm's isolated `node_modules` gives Biome's resolver nothing to follow.
`apps/site/biome.jsonc` already carries a scoped waiver for this exact
upstream gap (biomejs/biome#9143, #6464) for `src/**`; `style-differ.mjs`
sits outside `src/`, so it wasn't covered. Added a second, narrowly scoped
override for this one file with its own rationale, rather than widening the
`src/**` waiver's stated scope. `style-differ.mjs` itself is unmodified: it
is a real, actively-referenced visual-regression diagnostic (used to prove
CSS-migration behavior preservation, per its own header comment), not dead
code.
Both original bugs (the tsconfig path drift and the hand-edited
`sync-spec-docs.mjs` generated-artifact drift) reached `main` because no PR
check ran `apps/site`'s `types:check`/`verify` or the root
`generated-artifacts:check`; the latter only runs post-merge in
`semantic-release.yml`, gated on an actual version publish. Added
`.github/workflows/site-generated-docs-check.yml`, path-scoped to
`apps/site/**` the same way `react-doctor.yml` (this repo's existing
apps/site-only PR check, a React-health regression scan) is, running
`types:check` (in verify mode, via the same `PDPP_SITE_SOURCE_DIR`/
`PDPP_SITE_TSCONFIG` pair `verify` sets) and `generated-artifacts:check`.
Deliberately not the full `verify` script: `verify` also runs the test
suite and a production `next build`, real coverage but not what closes this
gap, and roughly doubles wall time for no additional defect coverage here.
Verified: `pnpm --dir apps/site run verify` passes end to end (exit 0):
types:check, 250/250 tests, `ultracite check` (0 errors, 4 pre-existing
unrelated warnings), `generated-artifacts:check` (7 byte-identical
artifacts), and `next build` (log shows `Using tsconfig file:
tsconfig.verify.json`). The new workflow's two steps
(`PDPP_SITE_SOURCE_DIR=.source-verify PDPP_SITE_TSCONFIG=tsconfig.verify.json
pnpm --dir apps/site run types:check` and `pnpm generated-artifacts:check`)
both pass when run standalone from the repo root, matching how the
workflow invokes them.
Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
tnunamak
force-pushed
the
fix/site-generated-docs
branch
from
September 23, 2026 15:29
2741071 to
ab4a2d5
Compare
tsconfig.verify.json still described a fallback list in the base config that the previous commit removed. Assisted-by: AI Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Fixes two failures found while verifying a dependency bump on
origin/main, both reproducible on a fresh checkout:pnpm --dir apps/site run verify(this repo's combined typecheck/test/lint/build command for the public documentation site underapps/site/) failed withTS2307: Cannot find module '@generated-docs/dynamic.ts'.pnpm generated-artifacts:check(a script that recompiles a small set of TypeScript sources and asserts the checked-in compiled.js/.mjsoutput is byte-identical, so no one hand-edits generated files) failed with drift inapps/site/scripts/sync-spec-docs.mjs.Why
Bug 1 is a stale path mapping.
apps/sitegenerates its documentation-page source (via thefumadocs-mdxlibrary) into a directory controlled by thePDPP_SITE_SOURCE_DIRenvironment variable, isolated per run mode (.source-devforpnpm dev,.source-verifyforpnpm verify) so concurrent dev/verify runs cannot clobber each other's output.apps/site/next.config.mjs's webpack and Turbopack (Next.js's alternate, opt-in bundler) aliases both read that variable correctly.apps/site/tsconfig.json'spathsentry for the same@generated-docs/*import alias does not; it was hardcoded to the default./.source/*and never updated when the per-mode isolation was added. TypeScript'stsc, invoked directly intypes:check, has no way to read an environment variable frompaths, so it always looked in.source, which averifyrun never populates. No CI workflow in this repository ranapps/site'sverifyortypes:check, so nothing caught this.The first fix here listed all three mode directories (
.source,.source-verify,.source-dev) inpathsas fallbacks, on the assumption thattscwould resolve whichever one the current run populated. That is unsound:tscresolves the first listed directory that exists, not the one the current run generated, so a.sourceleft behind by an unrelatednext build/next devrun would mask a real type error inverify's own.source-verifyoutput. Reproduced by seeding a valid.source, then breakingdocs-source.ts's import against a freshly regenerated.source-verify:tsc --noEmitagainst the fallback list still exited 0. Fixed by givingverifya dedicatedtsconfig.verify.jsonthat resolves@generated-docs/*against.source-verifyonly, selected by a newPDPP_SITE_TSCONFIGenv var.next build's own internal type-check pass also readstsconfig.jsondirectly, separately from the bundler aliases, sonext.config.mjsnow setstypescript.tsconfigPathfrom the same variable. The basetsconfig.jsonkeeps a single.sourcepath for the editor and a plaintypes:check. Re-ran the repro against the fix: with the same stale.sourcepresent, the per-modetscpass correctly fails on the broken.source-verify.Bug 2 is real generated-artifact drift, not a tooling gap.
apps/site/scripts/sync-spec-docs.mjsis compiled output; its source issync-spec-docs.mts, andscripts/check-generated-artifacts.tsis the check that keeps them in sync. PR #366 added stale-file cleanup logic (removing a leftover.mdpage that an earlier revision of this script used to write, which otherwise collides with the.mdxpage of the same name and fails the site build) by editing the compiled.mjsfile directly, without making the matching change in the.mtssource.generated-artifacts:checkonly runs in.github/workflows/semantic-release.yml, gated on semantic-release deciding a new version will actually publish, so it was not a required PR check and this drift shipped unnoticed. Fixed by porting the same cleanup logic intosync-spec-docs.mtsand regeneratingsync-spec-docs.mjsfrom it; the regenerated file is byte-identical to what was already committed, confirming the port is faithful.Neither bug was caught by the CI check named "root/site spec drift" (
.github/workflows/spec-check.yml, jobspec-check): that job runspnpm spec:check, which only diffs generated markdown against the root specs and never invokestscorgenerated-artifacts:check.Fixed the remaining
verifyfailure.ultracite check(the linter step insideapps/site'scheck/verify; it runs Biome, a Rust-based JS/TS linter, under the hood) failed onscripts/style-differ.mjs'simport { chromium } from "playwright", flagged as an unresolved import.playwrightis a real, declared dependency, and the import resolves cleanly under both TypeScript and Node at runtime. The failure is Biome's own documented resolver gap:playwrightre-exports fromplaywright-core, an indirect (not directly declared) dependency here, which pnpm's isolatednode_moduleslayout hides from Biome's resolver even though Node itself resolves it fine.apps/site/biome.jsoncalready carries a scoped waiver for this exact upstream gap (biomejs/biome#9143,#6464) coveringsrc/**;style-differ.mjssits outsidesrc/, so a second, narrowly scoped override was added for this one file.style-differ.mjsitself is unmodified: it's a real, actively used computed-style diff tool, not dead code.Added a PR-time gate. Added
.github/workflows/site-generated-docs-check.yml, path-scoped toapps/site/**the same wayreact-doctor.yml(this repo's existingapps/site-only PR check, a React-health regression scan) is scoped. It runstypes:checkin verify mode (PDPP_SITE_SOURCE_DIR=.source-verify PDPP_SITE_TSCONFIG=tsconfig.verify.json) andgenerated-artifacts:check, the two commands that would have caught both bugs above. It runs those two commands specifically, not the fullverifyscript:verifyalso runs the test suite and a productionnext build, real coverage but roughly double the wall time for no extra coverage against these two bug classes.Verification
pnpm --dir apps/site run verify: passes end to end (exit 0), coveringtypes:check, 250/250 tests (3 new, covering the per-mode tsconfig selection),ultracite check(0 errors, 4 pre-existing unrelated warnings),generated-artifacts:check(7 byte-identical artifacts), andnext build(log confirmsUsing tsconfig file: tsconfig.verify.json).pnpm generated-artifacts:checkandpnpm spec:check: both pass, unaffected.Not verified: whether the pre-existing scope of the
playwright/ultraciteresolver gap extends to other files beyondstyle-differ.mjs; not audited beyond the one file this PR touches.Assisted-by: AI