Skip to content

Production is serving stale code: ui:build cannot complete on a clean checkout, so Workers Builds (the deploy path) fails #9731

Description

@JSONbored

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:cloudflarenpm 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.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions