fix(ci): regenerate workspace codegen even when the node_modules cache hits - #9976
Conversation
…e hits main has been red for four consecutive runs with nothing wrong in the tree, and every PR fails validate-code regardless of what it changes -- including a test-only PR touching no UI file. setup-workspace restores a node_modules cache and, on a hit, skips `npm ci` entirely. Skipping `npm ci` skips every workspace lifecycle script, and apps/loopover-ui's `postinstall: fumadocs-mdx` is what generates `.source/` -- the directory tsconfig maps `collections/*` onto. `.source/` is gitignored and is not among the cached paths, so on a cache hit the UI typechecks against modules that do not exist: src/lib/docs-client-loader.tsx(1,32): error TS2307: Cannot find module 'collections/browser' src/lib/docs-source.server.ts(1,22): error TS2307: Cannot find module 'collections/server' The cache key includes the lockfile, which is why it started when it did: a lockfile change mints a fresh key, the first run misses and installs and passes and saves, and every run after it hits and fails. Green through 5079601, red from 40133d7 on, with no relevant change between them. Same shape as the @eslint/js hoist bug the cache step already documents -- it reproduces on no developer machine, because a real `npm ci` always runs postinstall. Reproduced by simulating the cache-hit state: removing apps/loopover-ui/.source with node_modules intact gives exactly those errors, and running the codegen clears them. REGENERATED, NOT CACHED. Adding `.source` to the cache paths is the smaller fix and the wrong one: the key derives from the manifests and lockfile, while `.source` derives from source.config.ts and content/docs/**. A cached copy would serve a docs collection generated from different MDX than the commit under test -- a stale pass, which is worse than an honest failure. Closes #9975
|
Warning ⏸️ LoopOver review result - manual review recommendedReview updated: 2026-07-31 01:05:06 UTC
Review summary Nits — 6 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. Decision record
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9976 +/- ##
==========================================
- Coverage 91.88% 91.00% -0.88%
==========================================
Files 928 928
Lines 113722 113722
Branches 27436 27436
==========================================
- Hits 104489 103495 -994
- Misses 7936 9125 +1189
+ Partials 1297 1102 -195
Flags with carried forward coverage won't be shown. Click here to find out more. |
Unblocks
mainand every open PRmainhas been red for four consecutive runs with nothing wrong in the tree, and every PR failsvalidate-coderegardless of what it changes — including a test-only PR (#9972) that touches no UI file at all.Root cause
setup-workspacerestores anode_modulescache and, on a hit, skipsnpm cientirely. Skippingnpm ciskips every workspace lifecycle script — andapps/loopover-uihas one that matters:That generates
.source/, which is the directorytsconfig.jsonmapscollections/*onto:.source/is gitignored and is not among the cached paths (node_modules,apps/*/node_modules,packages/*/node_modules). So on a cache hit the UI typechecks against modules that do not exist:Why it started when it did
The cache key includes the lockfile. A lockfile change mints a fresh key: the first run misses, installs, generates
.source, passes, and saves the cache. Every run afterwards hits and fails. That is exactly the observed pattern — green through507960134, red from40133d789onward, with no relevant change in between.This is the same shape as the
@eslint/jshoist bug the cache step's own comment already documents:Reproduced, then confirmed fixed
Simulating the cache-hit state locally —
node_modulesintact,.sourceremoved:Regenerated, not cached
Adding
.sourceto the cache paths looks like the smaller fix and is the wrong one. The cache key derives from manifests + lockfile, while.sourcederives fromsource.config.tsandcontent/docs/**. A cached copy would serve a docs collection generated from different MDX than the commit under test — a stale pass, which is worse than an honest failure. It is cheap to regenerate, so it is regenerated every run.The step is deliberately unconditional, with a comment saying so, because the obvious "optimisation" of gating it on the cache miss reintroduces the exact bug.
Verification
actionlintandlint:composite-actionsgreenapps/loopover-uideclares a lifecycle script (postinstall/prepare) across all workspaces and the root — checked, so this one step covers the whole tree todayCloses #9975