Public: anyone can read this; the crew can change it.

forked from trevato/cs

A stale or duplicated bundle is a red suite, not a dead deploy: the committed static/ is proved to be what the sources build #282

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`scripts/build.ts` gains `differences(built, dir)`: every way a directory is not what these sources build, as sentences that end in the command which fixes it — a file this tree builds that is not there, a file whose bytes are not the built bytes, a second file under a name that belongs to one ("*…holds 1 stale file for "app" beside app.92a7f64176.js: app.0123456789.js — whoever picks between them…

shipped production is serving it deploy ae07c2d

opened this

scripts/build.ts gains differences(built, dir): every way a directory is not what these sources build, as sentences that end in the command which fixes it — a file this tree builds that is not there, a file whose bytes are not the built bytes, a second file under a name that belongs to one ("…holds 1 stale file for "app" beside app.92a7f64176.js: app.0123456789.js — whoever picks between them picks at random, so run bun run scripts/build.ts <dir> and compare again"). The determinism test in scripts/build.test.ts now makes its second build in a child process, the way a deploy makes one, and asserts differences has nothing to say and that the directory holds exactly one file per game and per asset and nothing else; a new test asks git ls-files for anything named by its own hash or filed under static/ and fails with the git rm --cached that undoes it. It writes nothing into the repository — both builds go to mkdtemp directories removed in finally.

On whether the stronger fix is worth it: it already landed. #241 went further than the manifest this issue sketched — no generated file is in git at all, the server builds into FORGE_APP_DATA/static before it binds — so the checkbox about proving a committed static/ matches the sources is moot, and what survived is the one this pull lands: two builds of one tree agree, now across processes rather than within one, plus a guard that stops the artifact coming back. I did not add a manifest or a fixed static/app.js path; with nothing committed there is nothing for two branches to collide over, and a per-deploy build makes a stale preview impossible. Nothing about the caching contract moved: same content-addressed names, same immutable year, same ceilings in src/games.ts, /example still reads the files it describes.

Determinism is proved, not assumed: two runs of bun run scripts/build.ts into separate directories are byte-identical (diff -r clean), so the whole code is compared and not just its hash. Cost, honestly: scripts/build.test.ts goes from ~281 ms to ~384 ms — about +0.1 s, at the line the issue drew, and it is the child process's Bun start-up (a full build there measured 108 ms). Full suite: 1239 pass, 0 fail, ~30 s, bun run test (typecheck + bun test), which is what forge.json runs. Both new tests were shown to fail on a broken tree — a staged static/app.0123456789.js fails the git guard by name, and the differences unit test covers the loud duplicate, the quiet stale single file, the missing file and a file edited in place.

🤖 Generated with Claude Code

Closes #220

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs