Impact
Workers Builds: loopover-ui has failed on every one of the last 25+ commits on main, and it is the deploy path — no GitHub Actions workflow runs wrangler deploy (ui-deploy.yml is named "Validate UI Worker" and only validates).
Production is therefore serving stale code. Two concrete, verifiable examples, both merged to main on 2026-07-28 and neither live:
#9574 added fleetAccuracy.basis. Live GET https://api.loopover.ai/v1/public/stats has no basis key.
#9594 added the /v1/public/decision-ledger/anchor-payload auth exemption. Live, it still returns 401.
Root cause
The Cloudflare build command is npm run build:cloudflare → npm ci && npm run ui:build.
ui:build runs turbo run build --filter=@loopover/engine, then ui:openapi, whose scripts/write-ui-openapi.ts reaches src/openapi/schemas.ts, which imports @loopover/contract/dist/public-api.js. Nothing in that chain builds @loopover/contract — @loopover/engine does not depend on it — so on a clean checkout the import resolves to a directory that was never emitted:
Error [ERR_MODULE_NOT_FOUND]: Cannot find module
'/opt/buildhome/repo/node_modules/@loopover/contract/dist/public-api.js'
imported from /opt/buildhome/repo/src/openapi/schemas.ts
It passes in test:ci only by accident of ordering: npm run typecheck runs earlier in that chain, and the //#typecheck turbo task already carries an explicit @loopover/contract#build edge — added for exactly this failure mode, and documented in turbo.json as "the root package.json dependency does NOT create a build edge for a root (//#) task". Cloudflare runs ui:build on its own, so the incidental ordering never applies.
Fix
Add the same edge to ui:build's own turbo invocation — the level that actually owns the dependency.
Verified against a genuinely clean tree (package dist/ and .tsbuildinfo files removed, TURBO_FORCE=1 to defeat the shared worktree cache): without the change ui:build exits 1 on the error above; with it, exit 0 and both dist artifacts are emitted.
Related, worth a separate look
Workers Builds: loopover-api fails on the same commits. Whether it shares this root cause is unconfirmed — its build log has not been read.
packages/loopover-engine's build does not clear its own .tsbuildinfo (@loopover/contract's build does). Deleting dist/ without deleting .tsbuildinfo makes tsc a silent no-op, so a local "clean rebuild" can appear to succeed while emitting nothing. This masked the reproduction twice before TURBO_FORCE=1 and an explicit .tsbuildinfo sweep. Harmless on a fresh clone; a real trap locally and for any cached CI runner.
Impact
Workers Builds: loopover-uihas failed on every one of the last 25+ commits onmain, and it is the deploy path — no GitHub Actions workflow runswrangler deploy(ui-deploy.ymlis named "Validate UI Worker" and only validates).Production is therefore serving stale code. Two concrete, verifiable examples, both merged to
mainon 2026-07-28 and neither live:#9574addedfleetAccuracy.basis. LiveGET https://api.loopover.ai/v1/public/statshas nobasiskey.#9594added the/v1/public/decision-ledger/anchor-payloadauth exemption. Live, it still returns401.Root cause
The Cloudflare build command is
npm run build:cloudflare→npm ci && npm run ui:build.ui:buildrunsturbo run build --filter=@loopover/engine, thenui:openapi, whosescripts/write-ui-openapi.tsreachessrc/openapi/schemas.ts, which imports@loopover/contract/dist/public-api.js. Nothing in that chain builds@loopover/contract—@loopover/enginedoes not depend on it — so on a clean checkout the import resolves to a directory that was never emitted:It passes in
test:cionly by accident of ordering:npm run typecheckruns earlier in that chain, and the//#typecheckturbo task already carries an explicit@loopover/contract#buildedge — added for exactly this failure mode, and documented inturbo.jsonas "the root package.json dependency does NOT create a build edge for a root (//#) task". Cloudflare runsui:buildon its own, so the incidental ordering never applies.Fix
Add the same edge to
ui:build's own turbo invocation — the level that actually owns the dependency.Verified against a genuinely clean tree (package
dist/and.tsbuildinfofiles removed,TURBO_FORCE=1to defeat the shared worktree cache): without the changeui:buildexits 1 on the error above; with it, exit 0 and both dist artifacts are emitted.Related, worth a separate look
Workers Builds: loopover-apifails on the same commits. Whether it shares this root cause is unconfirmed — its build log has not been read.packages/loopover-engine's build does not clear its own.tsbuildinfo(@loopover/contract's build does). Deletingdist/without deleting.tsbuildinfomakestsca silent no-op, so a local "clean rebuild" can appear to succeed while emitting nothing. This masked the reproduction twice beforeTURBO_FORCE=1and an explicit.tsbuildinfosweep. Harmless on a fresh clone; a real trap locally and for any cached CI runner.