Found while measuring the build derivation for #4185. Not a live defect today — filed as an observation so the next reader does not have to re-measure it, and so the coincidence keeping it dormant is on the record rather than in one agent's head.
What is dormant
Vite hands CSS to postcss-load-config, which searches upward from the Vite root. So a package whose vite build processes CSS and which has no postcss.config.* of its own would read the repo-root postcss.config.mjs — a file outside its own directory, and therefore invisible to turbo's build cache key exactly as the root tsconfig.json was before #4185.
The guard that ships with #4185 (scripts/__tests__/helpers/build-program.ts) does not model postcss config discovery, and deliberately so: it would mean reproducing a plugin-adjacent resolution whose defaults drift between versions. That decision is sound only while nothing reaches the root config.
Why it is dormant — measured, both halves
Nothing reaches it, because two independent facts happen to hold at once:
- Every
vite build package that actually processes CSS carries its own postcss config, which stops the upward walk before the repo root: apps/console, packages/components, packages/runner, examples/console-starter, examples/byo-backend-console.
packages/fields is the only vite build package with no postcss config of its own, and it does have a CSS file — but packages/fields/src/index.css never enters the Vite graph. Nothing imports it: packages/fields/scripts/build-css.mjs compiles it separately, invoking postcss with an explicit plugin list (postcss([tailwindPostcss()])) that reads no config file at all.
Remove either fact and the root config silently becomes part of a build program.
Why it is worth recording
The trigger is one line. Adding import './index.css' to packages/fields/src/index.tsx — an ordinary-looking change, and the shape every other CSS-carrying package already uses — would pull the repo-root postcss.config.mjs into that package's build program. Turbo would not hash it, build would replay a stale dist/, and #4185's guard would stay green, because the derivation does not follow postcss.
That is the same "looks like enforcement, isn't" shape the class keeps producing, with the twist that the guard's own blind spot is what hides it.
Options, if this is ever picked up
C is what is in place. B looks like the cheapest thing that would actually retire the risk, but it is a judgement call about a file no user hits today, so this is filed unassigned and unqueued for triage rather than fixed inside #4185's scope.
Related
Generated by Claude Code
Found while measuring the
buildderivation for #4185. Not a live defect today — filed as an observation so the next reader does not have to re-measure it, and so the coincidence keeping it dormant is on the record rather than in one agent's head.What is dormant
Vite hands CSS to
postcss-load-config, which searches upward from the Vite root. So a package whosevite buildprocesses CSS and which has nopostcss.config.*of its own would read the repo-rootpostcss.config.mjs— a file outside its own directory, and therefore invisible to turbo'sbuildcache key exactly as the roottsconfig.jsonwas before #4185.The guard that ships with #4185 (
scripts/__tests__/helpers/build-program.ts) does not model postcss config discovery, and deliberately so: it would mean reproducing a plugin-adjacent resolution whose defaults drift between versions. That decision is sound only while nothing reaches the root config.Why it is dormant — measured, both halves
Nothing reaches it, because two independent facts happen to hold at once:
vite buildpackage that actually processes CSS carries its own postcss config, which stops the upward walk before the repo root:apps/console,packages/components,packages/runner,examples/console-starter,examples/byo-backend-console.packages/fieldsis the onlyvite buildpackage with no postcss config of its own, and it does have a CSS file — butpackages/fields/src/index.cssnever enters the Vite graph. Nothing imports it:packages/fields/scripts/build-css.mjscompiles it separately, invoking postcss with an explicit plugin list (postcss([tailwindPostcss()])) that reads no config file at all.Remove either fact and the root config silently becomes part of a build program.
Why it is worth recording
The trigger is one line. Adding
import './index.css'topackages/fields/src/index.tsx— an ordinary-looking change, and the shape every other CSS-carrying package already uses — would pull the repo-rootpostcss.config.mjsinto that package's build program. Turbo would not hash it,buildwould replay a staledist/, and #4185's guard would stay green, because the derivation does not follow postcss.That is the same "looks like enforcement, isn't" shape the class keeps producing, with the twist that the guard's own blind spot is what hides it.
Options, if this is ever picked up
build-program.tspostcss discovery. Modelpostcss-load-config's upward search from eachvite buildroot. Cost: a third config-resolution mirror to keep in step with a dependency, for a file nothing reads today.packages/fieldsits ownpostcss.config.js. Two lines, matches what its five siblings already do, and makes fact 1 hold universally so the upward walk can never reach the root. Does not close the class, but removes the only package that could trigger it.buildinputs have the same out-of-package hole as #3514 / #4178 — roottsconfig.json/tsconfig.base.jsonandscripts/vite-*.tsare not hashed; measured frozen at 3f85d1417964dce6 #4185: the blind spot is stated in the derivation's docblock alongside its other narrowings, with the measurement above.C is what is in place. B looks like the cheapest thing that would actually retire the risk, but it is a judgement call about a file no user hits today, so this is filed unassigned and unqueued for triage rather than fixed inside #4185's scope.
Related
type-check的手维护 inputs 名单已两次因"包程序越出包目录"失真 —— 评估从 tsconfig include 派生或加钉扎测试 #3514 / PR ci(turbo): derive the type-check inputs guard from each package's tsc program (#3514) #4176 —type-check, the class origin and the guard architecture.testinputs have the same out-of-package hole #3514 closed fortype-check— the rootvitest.config.mtsevery package re-exports is not hashed #4178 / PR ci(turbo): derive thetestinputs guard from each package's Vitest config program (#4178) #4188 —test.lintinputs have the same out-of-package hole as #3514 / #4178 — the rooteslint.config.jsthat IS the lint program is not hashed; measured frozen at 79872f192ee4828c #4184 / turbobuildinputs have the same out-of-package hole as #3514 / #4178 — roottsconfig.json/tsconfig.base.jsonandscripts/vite-*.tsare not hashed; measured frozen at 3f85d1417964dce6 #4185 —lintandbuild; this was found by the latter's derivation work.Generated by Claude Code