perf #418: publish landblocks under the meter, not one per streaming tick

Phase-1 measurement (new [publish-timing]/[stream-tick] probe surfaces,
ACDREAM_PROBE_REVEAL_TIMING=1) refuted the ~31 ms-per-admission
hypothesis: the hold runs at ~64 fps with the streaming tick at ~32 Hz,
the whole 625-block window costs only ~500 ms of publication CPU (far
blocks ~0.17 ms, near 2-43 ms), and steady state showed ZERO meter
yields with ~0.22 ms of the 2 ms budget used - yet exactly one block
published per tick against a ~400-deep completion queue.

The real limiter: Runtime's collision-generation activation is a
deliberate two-poll transaction (the first
TryAcquireCollisionPrefixMutationPermission poll parks residents and
refuses by design), and LandblockPresentationPipeline.Advance's metered
arm returned Completed=false on ANY nonterminal commit, which
DrainAndApply treats as end-of-frame. One landblock per 32 Hz tick =
the flat 32/s, with the authored budget ~90% idle.

Fix: the metered arm now uses the same Runtime-owned gate the unmetered
arm and the synchronous CompletePublication API always used
(CanContinueMutationSynchronously). The second poll runs in the same
frame under the same meter, so the unchanged 2 ms elapsed-time ceiling
is now genuinely the authoritative per-frame bound; with any real debt
(live residents parked mid-game, pending withdrawals, dispatch backlog)
publication defers to the next frame exactly as before. No budget
values change, no reveal-gate/readiness change, and the streamed result
is byte-identical - only the frame scheduling of identical operations.

Measured A/B (this binary, two runs): totalMs 12689 / 12734 vs baseline
26728/27395/27503; loaded slope 32/s -> bursts of 100-360/s, 625/625 in
~6-7 s vs ~23 s. The remaining ~12.7 s floor is fully attributed in
docs/ISSUES.md: ~8 s of real budgeted readiness work plus retail's
authored tunnel exit (TunnelContinue 2-5 s + two 1 s fades, golden
constants), so the <12 s acceptance needs a lead decision on the
hold-time budget, not another hidden limiter.

New regression pin:
MeteredLoaded_NonterminalCommitWithoutDebt_CompletesInOneMeteredAdvance.
Gates: Release build 0 errors; App tests 5576/3 skips/0 failed;
Runtime tests 1756/0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-17 20:11:35 +02:00
parent 45f379560a
commit 11106c70e7
6 changed files with 408 additions and 5 deletions

View file

@ -72,6 +72,52 @@ off-threading the per-landblock publication cost — NOT raising budgets
line) is a profile SCALE of the same env-tunable options, so it is also
already exonerated. Verify (a) first next session.
**2026-08-17 (later): 31 ms-per-admission hypothesis REFUTED by
measurement; the REAL limiter found and FIXED (this commit).** The probe
extension (`[publish-timing]` per-landblock per-stage attribution +
`[stream-tick]` per-second meter/yield/backlog rollups, same
`ACDREAM_PROBE_REVEAL_TIMING=1` env) measured: hold frame rate ~64 fps
(NOT ~32 — prediction (a) false), streaming tick at ~32 Hz (every other
render frame), per-landblock publication cost TINY (whole 625-block
window ≈ 500 ms CPU total; far blocks ~0.17 ms, near blocks 243 ms),
and steady state showed ZERO meter yields with ~0.22 ms of the 2.0 ms
budget used per tick — yet exactly one block published per tick with
~400 completions queued. **Root cause:** Runtime's collision-generation
activation is a deliberate TWO-POLL transaction
(`TryAcquireCollisionPrefixMutationPermission` parks residents and
refuses its first poll by design), and
`LandblockPresentationPipeline.Advance`'s metered arm returned
`Completed=false` on ANY nonterminal commit (`meter is not null || …`),
which `DrainAndApply` treats as "stop draining this frame" — one
landblock per 32 Hz tick = the flat 32/s, with the budget ~90% idle.
**Fix:** the metered arm now uses the same Runtime-owned gate the
unmetered arm and the synchronous `CompletePublication` API always used
(`CanContinueMutationSynchronously` — no pending prefix projections,
collision reports, or dispatch debt): the second poll runs in the same
frame under the same meter, so the authored 2 ms elapsed-time ceiling
(unchanged) is now genuinely the authoritative bound. With real debt
(live residents parked mid-game, pending withdrawals) Runtime keeps
reporting nonterminal-with-debt and publication defers to the next
frame exactly as before; regression test
`MeteredLoaded_NonterminalCommitWithoutDebt_CompletesInOneMeteredAdvance`
pins the debt-free single-advance completion. **Measured (this
binary):** loaded slope 32/s → bursts of 100360/s (625/625 at ~6.17.1
s vs ~22.9 s); `[stream-tick]` yields are now Time-limit yields at the
2 ms ceiling. A/B totals: **12689 / 12734 ms** (baseline
26728/27395/27503) — a 2.2x cut, but ABOVE the 12000 acceptance, and
the remainder is fully attributed: gate-ready at 8136/7617 ms (≈1 s
session+build start, ≈5 s drip at the authored 2 ms/tick destination
budget over ≈500 ms of real publication CPU at a 32 Hz tick, ≈0.41.2 s
destination-priority mesh uploads, ≈0.6 s composites), then retail's
AUTHORED tunnel exit (TunnelContinue min 2.0 s / max 5.0 s + two 1.0 s
view-plane fades, golden constants @0x007BD268/70/78 in
`TeleportAnimSequencer`) adds a tunnel-phase-dependent 3.16 s
(measured 4523 / 5086 ms) before `WorldViewportObserved`. Reaching
<12 s therefore requires either accepting ~12.7 s, or a LEAD decision
to widen the destination-lane time budget during the hold (a budget
change, out of scope per this round's constraints) — no artifact-shaped
limiter remains.
## #417 — World ambience keeps playing (and re-firing) on the character-select screen after the in-world logoff
**Status:** ✅ FIXED 2026-08-17 (logout-audio round; fix + tests in the same