v0.3.2 — quiescent cache TTL jitter
Viewer: quiescent cache TTL jitter — no more 30-second expiry herd
The run-list cache classifies quiescent runs (stale/unknown/corrupt-result) once and re-derives them on a ~30 s TTL. But a viewer opened on a home full of stale runs classifies all of them in the same cold request — and a single fixed TTL made the whole population expire together, dumping every re-derive on one later poll. At 5,000 runs with 500 stale, that one request spiked to 143.8 ms against the 120 ms P2 budget while its neighbours ran ~65–115 ms. Operators with many stale runs felt the same periodic stutter every 30 seconds; under concurrent load it surfaced as a flaky P2 perf gate.
Each run's quiescent TTL is now deterministically jittered ±25% around 30 s (FNV-1a over the run directory — not Math.random(), so a run keeps the same deadline across requests and restarts, and tests can compute it exactly):
- Any 5 s poll window now inherits roughly a third of the herd at most, instead of all of it.
- The population's amortized ~1/30 s probe rate — the documented contract — is unchanged.
- Resume signals (
.resumingmarker,run.lock) still re-derive immediately, TTL notwithstanding; nothing about resume detection is delayed. - Server-only change:
viewer/distis byte-identical.
Post-fix P2 under the full concurrent root suite: 67.6/87.1/67.4/79.5/91.6 ms — worst sample 91.6 ms, down from the 143.8 ms herd spike.
Pinned by new unit coverage: a cold-classified 500-run herd re-derives as a strict subset per poll and exactly once each; per-entry deadlines hold until their own expiry; jitter is bounded, deterministic, and leaves no dominant 5 s poll window. DESIGN.md §5.4.2/§10 updated from the fixed-30 s contract; MEASUREMENTS.md rebound with the new P2 row. Root suite 485 tests green.