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

forked from trevato/cs

A test file that only passes if it is loaded second: break the packed → observe → world → bots → packed cycle #406

Merged opened this

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

Merged

Breaks the load-time cycle `packed.ts` → `observe.ts` → `world.ts` → `bots.ts` → `packed.ts`, so the suite's result no longer depends on which file bun loads first. `bun test scripts/train.test.ts` now passes on its own, and so does every other test file (140 of 140).

shipped production is serving it deploy ae07c2d

opened this

Breaks the load-time cycle packed.ts → observe.ts → world.ts → bots.ts → packed.ts, so the suite's result no longer depends on which file bun loads first. bun test scripts/train.test.ts now passes on its own, and so does every other test file (140 of 140).

The cut. OBS_SIZE now lives in src/client/obs-size.ts, which imports nothing. packed.ts reads it from there, and observe.ts re-exports it, so no caller changes. I cut this edge because it is the only thing any module in the ring reads at load time: packed.ts builds SHAPE from it, while bots.ts only uses what it imports from packed.ts inside functions. The workaround from #161 in scripts/train.test.ts is gone: the imports are in their normal order and the comment explaining the old order is deleted.

Test that fails without the fix. scripts/alone.test.ts loads every module under src/ and scripts/ as the first thing a fresh process imports, which enters every import cycle from every end. With packed.ts pointed back at observe.ts it fails, because observe.ts and scripts/train.ts both throw the OBS_SIZE error. It takes about 3 s.

  • Four files are skipped on purpose, listed in ENTRIES in scripts/alone.ts with a reason each: src/server.ts, the two browser main.ts files it lists, and scripts/mutate-result.ts. They do their work when loaded, so loading one alone would start it rather than check it.
  • The test also fails if one of those listed files no longer exists, so the list can't go stale.

Full per-file loop. bun run scripts/alone.ts runs every test file in a process of its own. It runs the whole suite a second time (about 25 s at 8 at a time), so it is a command rather than part of bun test. It gives each test a minute instead of bun's 5 s, because under 8-way load scene.test.ts went past 5 s.

Two more test files that failed alone. The loop found that src/client/grenade.test.ts and src/client/world.test.ts played rounds with bots whose policy another test file had set up. Both now call useShipped() at the top, like cover.test.ts and predict.test.ts already do. The tests were wrong here, not the code. The policy they now load themselves is the same shipped one they had been borrowing.

Bundles. As @atlas noted, nothing is committed for them since #247. A fresh build moves only app: 137,564 → 137,568 raw and 53,443 → 53,440 gzipped. range and example are unchanged, no ceiling moves, and the note under app in src/games.ts records the numbers.

Tests. bun run test passes: the typecheck and 1,678 tests. The golden digests in src/client/replay.test.ts and the pins in src/range/pin.test.ts didn't move. The README lists the new command and says how load order is checked.

To try it: bun test scripts/train.test.ts and bun run scripts/alone.ts.

🤖 Generated with Claude Code

Closes #248

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs