On this page

v0.8.0-ps1 was the post-validation performance baseline. All 63 scenes signed off; +0.9% over target / 99.5% target speed across the 120 timing-bearing rows; the retrospective walks through how the matrix moved there. That looked like the end of the speed arc.

It wasn’t. Within hours of the v0.8.0 disc going up, a randomized long-run soak froze. v0.8.1-ps1 is the fix. The story is short.

The shape of the bug

The screensaver picks scenes at random. The soak ran for an extended stretch, the picker eventually selected MARY 4, and the boot proceeded only as far as:

JCPICK ... mary4
JCRECT 2-rect lower=(0,190,608,166) upper=(0,92,361,98)

The runtime then stopped. No crash, no panic. Stuck on the clean-rect save before scene playback could start. Heap fragmented, allocation refused, the runtime had nowhere to go — but the matrix had nothing flagged on MARY 4. The perf rows for that scene came in green.

Why the matrix missed it

The matrix runs each (scene, tide) variant from a deterministic boot, scene by scene, with the same routing every time. That is what makes its numbers comparable — every row is the same kind of run. It is also what makes it a poor fit for finding a bug that needs prior heap state plus a particular random scene pick. The matrix never enters the random-position playback path with another scene’s residual pressure on the heap.

The soak does, by definition. That is the entire point of running one.

The actual fix

v0.8.0’s clean-rect pressure estimator used fgBoundsW * fgBoundsH * 2. Cheap, wrong: it ignored the ocean wave band expansion and the upper/lower split rect that wide-action scenes emit. On MARY 4’s random-load path the real clean save was over 256 KiB; the estimator under-counted and didn’t release optional prefetch/walk memory in time.

v0.8.1’s foreground_pilot.c now computes pressure through one helper that mirrors the clean-save path — pack bounds, ocean wave band, clamping, low-tide split. fgPlayOceanRuntimeScene() calls that estimate before allocating, so wide scenes drop optional pressure before the heap fragments. The fix covers fourteen non-exempt random-position scenes (activity1, activity5, fishing1, fishing2, fishing3, fishing7, fishing8, johnny2, johnny4, johnny5, mary4, mary5, visitor4, walkstuf3) — not a MARY 4-specific bandage.

The VISITOR 3 high/low refresh on the same commit stayed exact to the v0.8.0 matrix baseline. The performance line did not move.

What the discipline says

The project keeps two acceptance bars on purpose: visual signoff and headless perf timing. The two-ledger framing on /about/ is the public version of that. v0.8.1 adds a third loop that keeps both honest:

  • Visual signoff runs to the FISHING 1 bar. Per-scene human review. Catches pixel and SFX wrong.
  • Headless matrix runs every (scene, tide) variant deterministically. Catches timing wrong.
  • Soak runs the actual screensaver loop randomized for hours. Catches state-coupling wrong — bugs that need a particular history to appear.

The matrix and the soak are not redundant. They are tuned for different bugs. The matrix proves that no scene is slow on its own; the soak proves that no scene is broken by its neighbors. A release that promotes performance without exercising the soak is a release that ships the next MARY 4 freeze, signed off and timed.

The receipts