Making the Gates Tell the Truth
A QA programme in thirteen items: exit codes that exit, a timing contract, discriminated unions, dependency injection, and five dangerous silent catches de-silenced.
The Programme
Thirteen numbered items, QA-WO1 through WO13, plus CI. The theme is not features. The theme is that a passing test was not evidence.
WO11 — the gates tell the truth. runCli now exits non-zero on a top-level throw, with explicit CommandFailure/executeChecked, and an assets preflight gate for headless runs.
WO1 / WO2 — a protocol smoke suite against a real GameServer on an ephemeral port driven by a socket client, including a chat→echo regression guard. Lobby lifecycle tests: create, join, full-reject, empty-destroy versus keep-alive grace, server-exit reset, match start and revert.
WO12 — one clock. A single ServerTiming contract, with 7 subsystems moved off hardcoded tickRate: 125, and demos recording the effective snapshot cadence rather than the requested one.
WO3 — handleReliable collapsed into handleDatagram, which kills the silent chat-drop class. A dead KillFeed widget was removed.
WO4 / WO5 — wire-type de-duplication. MatchStateManager imports shared match types instead of a drifted hand-copy. ClientEntityKey owns the player_<id> format across ~20 sites. SnapshotEvent becomes a discriminated union with exhaustive switch dispatch at the client boundary — which is what kills "the silent-unrouted-event class".
WO6 / WO8 — CI with a pre-commit hook and a biome count-ratchet gate. shared/ becomes downward-only: the net cluster and collision contract moved into it, the engine keeps re-export shims, and SharedCollisionWorld is pure structural math behind a SweepBackendAdapter. Determinism bit-identical.
WO9 / WO10 / WO13 — a live/demo split in WeaponViewManager so demoplay stop cannot destroy the live viewmodel; ServiceLocator.dispose() now clears 9 stateful singletons; a GameFrameHook DI seam with SpectatorController fully game-free; a leveled log façade with rate-limited warnings and 5 dangerous silent catches de-silenced; hidden source maps and production console.log/debug stripping.
The Numbers
122 files / 1415 tests, three consecutive clean runs
determinism checksum 2768943778 (unchanged)
biome baseline 932 errors / 586 warningsThat biome number is wrong, and finding out why is the next release's story.
Two pre-existing playtest bugs fixed: the lobby bounced back to gametype cards after a match, and the post-game winner model was a black silhouette until made self-lit.
Also: a flaky test where GamePaths.test.ts leaked a browser-shaped global.window, and 34 hidden source maps relocated out of dist/ with 0 dangling `sourceMappingURL`.
Known Unverified Items
Browser and visual passes owed for WO9 in-game viewmodel after demoplay stop, demo POV weapon persistence when switching followed players mid-demo, WO13 scene reloads building fresh services, WO7 spectator and freefly through the GameFrameHook seam, the showcase fullbright intensity of 0.6, and the lobby rematch flow.