ci(types): run the root Vitest config's type program directly - #8004
Merged
baozhoutao merged 1 commit intoSep 6, 2026
Conversation
The repo-root `vitest.config.mts` had no runnable gate of its own (objectui#7328). A program did already contain it — `apps/console/tsconfig.node.json` has listed `../../vitest.config.mts` and `vitest.config.ts` since objectui#3476 — but the only invocation of that program was the console's own `type-check` script, reached through the task runner, whose `type-check` task waits on `^build`. So the cheapest compiler in the repo that reads the root Vitest config was reachable only behind a full workspace build, and no local gate union short of that could go red on it. PR #7291 is the measured cost: a conditionally spread `dist` project whose literal `extends: true` widened to `boolean` degraded the whole `projects` array to `never[]`; `type-check:scripts`, `type-check:vitest-setup` and the vitest runs were all green, and CI answered with three errors, two of them reported at `../../vitest.config.mts`. Adding the file to an existing root program was measured and is not available: `tsconfig.scripts.json` includes only `scripts/**/*.ts` and `tsconfig.vitest-setup.json` only `./vitest.setup*.ts(x)`, neither glob admits `.mts`, and the setup program deliberately ships no `@types/node` while the root config imports `path` and `url`. A NEW root program was measured too: its resolved source set is the same nine files as `apps/console/tsconfig.node.json`'s, so it would only add a second option set over seven shared files — the "green in one project, red in the other" hazard `tsconfig.scripts.json`'s header documents. So the program keeps its single home and gains a second, cheap runner: `type-check:vitest-config` invokes it directly, in the cheap half of the `Type Check` job beside `pnpm type-check:scripts`. Nothing in its program imports an `@object-ui/*` package (the 40 `@object-ui/*` occurrences in `vite.config.ts` are alias-map strings), so it needs the install and nothing built: 2.0s on a worktree with no `dist/` anywhere. `scripts/__tests__/vitest-config-type-check.test.ts` pins the behaviour — that every root `vitest.config.*` is in the resolved program, that the merging consumer is too, that `allowJs` stays off so the root config's `@ts-expect-error` remains live, and that CI runs the script before the build. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MM7kaS4dPpYHV5BsMyu4tQ
This was referenced Sep 6, 2026
Contributor
Author
|
Standing down on Generated by Claude Code |
baozhoutao
marked this pull request as ready for review
September 6, 2026 08:41
baozhoutao
deleted the
claude/issue-7328-root-vitest-config-type-program
branch
September 6, 2026 08:57
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.
Fixes #7328
The repo-root
vitest.config.mtshad no runnable gate of its own. This gives it one that costs two seconds, and proves it goes red on the exact defect that cost a CI cycle in PR #7291.What was actually missing — a runner, not a program
The card and the triage both read the gap as "no type program contains this file". Measured on
origin/main15789d5, that is not quite it.apps/console/tsconfig.node.jsonhas listed the file outright since objectui#3476:What was missing was any way to RUN that program short of the console's own
type-checkscript —tsc --noEmit && tsc -b tsconfig.node.json --force— reached through the task runner, whosetype-checktask waits on^build. So the cheapest compiler in the repo that reads the root Vitest config was reachable only behind a full workspace build, and no local gate union short of that could go red on it.Measured cost of the two routes, same box, same worktree:
type-checkthrough the task runner (35 builds + 1 type-check)tsc -b apps/console/tsconfig.node.json --force, on a worktree with nodist/anywhereWhy not a new root program (the two readings the triage asked for)
The
.mtsglob trap — confirmed. Neither existing root program's globs admit the extension:tsconfig.scripts.jsonincludes onlyscripts/**/*.ts,tsconfig.vitest-setup.jsonincludes./vitest.setup*.tsand./vitest.setup*.tsx. Anincludeentry alone was never going to be the fix.@types/node— confirmed, and the setup program is ruled out. One correction to the assumption: the root config importspathandurlas BARE specifiers, notnode:path(grep -n 'node:' vitest.config.mtsfinds nothing). The consequence is the same — the program needs@types/node— andtsconfig.vitest-setup.jsondeliberately ships without it, at a documented cost of 12 errors inside third-party declarations, withvitest.setup.network-escape-guard.tswritten against that constraint. Untouched, per the triage boundary.A NEW root program was measured, and it is strictly worse. A minimal
tsconfig.vitest-config.jsonincluding exactly./vitest.config.mtsand./apps/console/vitest.config.tscompiles green in 1.1s — and--listFilesshows its non-node_modulessource set is these nine files:That is the SAME nine files
apps/console/tsconfig.node.jsonalready resolves. A new program would therefore add nothing but a second option set over seven shared files — the "green in one project, red in the other" hazardtsconfig.scripts.json's own header documents at length, and the reason that file matches the console node project's options deliberately. It would also re-checkscripts/*.tsunder a third option set, which the dispatch ruled out.So: one program, one option set, one new runner.
The change
package.json—"type-check:vitest-config": "tsc -b apps/console/tsconfig.node.json --force".--forceso an up-to-date.tsbuildinfocan never turn the gate into a silent no-op..github/workflows/ci.yml— one step in the existingType Checkjob,Type-check the root Vitest config, placed in the CHEAP half besidepnpm type-check:scripts(after the install, before the Turbo cache restore andpnpm type-check). The dispatch allows a workflow edit when a new script must be wired into an existing job; this is that edit and nothing else. No timeout changed, no job added.content/docs/guide/ci-cd-pipeline.md— forced, not optional:scripts/__tests__/ci-cd-pipeline-doc.test.tsfails when the workflow runs a first-party command the job table does not name. The new command is added to thetype-checkrow in ci.yml order, with the rationale.scripts/__tests__/vitest-config-type-check.test.ts— new pin, the sibling ofscripts-type-check.test.tsandvitest-setup-type-check.test.ts. It asserts behaviour, never spelling: TypeScript's own resolution of the project, not a string search for a filename.⛔
vitest.config.mtsis not edited. The program forced no change to it.Done criterion — red WITHOUT the console's type-check
The planted defect is the #7291 shape itself: drop the
as constfromextends: true as constin the conditionally spreaddistproject. Mutation proven on disk by marker counts and a moved blob hash, never by an editor's exit code; restore bygit checkout HEAD -- vitest.config.mtsunder atrapwith absolute paths.error TSlinespnpm type-check:vitest-configddd41ba)pnpm type-check:vitest-configThe three errors, verbatim from the mutated run:
Three errors, two of them at
vitest.config.mts— the same shape PR #7291's repair round recorded from CI job 100117481182, reproduced here in 2 seconds by a command that runs no task-runner build and notsc --noEmitover the console app.Restore proven by state, not by an exit code:
RESTORED_HASH == HEAD_BLOB == 77a40ce4…, andgit diff HEAD/git status --shortboth empty.Gates — at commit
ddd41ba, exit codes captured by redirect-then-capturepnpm type-check:vitest-config(new)error TSlines, 2.0spnpm type-check:scriptspnpm type-check:vitest-setupturbo run type-check --filter=@object-ui/consoleTasks: 36 successful, 36 totalpnpm exec vitest run scripts/Test Files 108 passed (108)/Tests 3255 passed (3255)node scripts/check-type-check-coverage.mjstype-check… 1 not compiled"pnpm lint:root32 problems (0 errors, 32 warnings), all pre-existing, none in the new filepnpm check:control-bytespnpm check:doc-fencespnpm docs:check-linksnode scripts/check-changeset-presence.mjsnode scripts/check-governed-queue-guard.mjs --test(all 4 changed paths)turbo ls --affectedagainst the branch point reports0 no packages— this diff touches no workspace package, so no packagetestortype-checkis owed beyond the console run above (kept because the console must still compile the merged config).Live E2E (informational)is red on every branch today for an upstream reason (objectui#7990 / objectstack#16186). It is not this diff's.Not in this PR
scripts/check-type-check-coverage.mjsis untouched. Its subject is workspace PACKAGES — it iterates the workspace and asks per package whethertype-checkreaches its sources and its tests — so it models no repo-root file and makes no claim, true or false, aboutvitest.config.mts. The triage's fallback ("if the mechanical route fails, the coverage report must stop calling the root config covered") is conditional on a failure that did not happen.The docs-only answer is not taken either: the lane fact stays true, but it is no longer the only thing standing between this file and a CI-only red.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MM7kaS4dPpYHV5BsMyu4tQ
Generated by Claude Code