perf(streaming): quiesce retired generations and budget teardown

Publish the retail blocking-for-cells edge before deferred recenter work, freeze old-world presentation/simulation/audio, and advance full-window retirement from exact metered entity and owner cursors. This removes synchronous portal teardown without allowing retained owners to remain observable.
This commit is contained in:
Erik 2026-07-24 18:29:52 +02:00
parent b8f6317fe1
commit bb16f74fd4
38 changed files with 1691 additions and 170 deletions

View file

@ -44,9 +44,11 @@ What does NOT go here:
smooth and physics, collision, and wire state remain correct.
- **Build hygiene:** `#228` records 17 clean-Release test-project warnings;
production compilation and all tests pass.
- **Performance side track:** prepared-content Slices AC and unified-residency
Slice D are complete. Slice E cost-budgeted streaming/retirement is next.
Evidence:
- **Performance side track:** Slices AD and Slice E0E3 are complete. Typed
completion admission, immediate generation-scoped old-world quiescence, and
budgeted full-window/recenter retirement are live; E4 cursor-budgeted
publication is next. Physical performance/visual evidence is paused while
the desktop is RDP. Evidence:
[`research/2026-07-24-slice-d-unified-residency-report.md`](research/2026-07-24-slice-d-unified-residency-report.md).
The [documentation map](README.md) defines how this tactical ledger relates to

View file

@ -8,16 +8,20 @@ banner cannot silently override the current program state.
- **Milestone state:** M3, “Cast a spell,” landed 2026-07-21. M4, “Live in the
world,” is active.
- **Active gameplay program:** the pre-M4 world-interaction completion program
- **M4 gameplay program (paused while the authorized performance program
executes):** the pre-M4 world-interaction completion program
in
[`plans/2026-07-23-world-interaction-completion.md`](plans/2026-07-23-world-interaction-completion.md).
The eight-slice `GameWindow` decomposition and its connected visual matrix
are complete.
- **Active performance side track:** Slices AC of
- **Current active engineering program:** Slices AD and Slice E0E3 of
[`plans/2026-07-24-modern-runtime-architecture.md`](plans/2026-07-24-modern-runtime-architecture.md)
are complete. Production world-mesh streaming consumes the validated
prepared package; Slice D unified residency/accounting is next. See the
[Slice C physical cutover report](research/2026-07-24-slice-c-prepared-asset-cutover-report.md).
prepared package, typed residency is bounded/accounted, and streaming now
has typed admission plus immediate old-generation quiescence and metered
retirement cursors. E4 cursor-budgeted publication is next. Physical
GPU/FPS gates wait for the physical console because the desktop is RDP. See
the [Slice D residency report](research/2026-07-24-slice-d-unified-residency-report.md).
- **Completed gates:** R6 locomotion/collision/projectile/teleport/radar and
the final two-client portal-out/materialization observer comparison (`#218`).
- **Separate visual verification:** the shared-alpha lifestone/particle result
@ -28,7 +32,7 @@ banner cannot silently override the current program state.
user decision gate; Linux/headless automation (Track LH) remains future work.
- **Divergence audit:** 178 active rows — IA 17, AD 37, AP 85, TS 34,
and UN 5 — plus the retained retired TS-37 history note.
- **Latest automated baseline:** Release build succeeds; 8,076 tests pass and
- **Latest automated baseline:** Release build succeeds; 8,148 tests pass and
five are intentionally skipped. The capped, uncapped, and dense-Arwic
physical prepared-asset routes all completed their portal/input/lifetime
assertions and disconnected gracefully.

View file

@ -720,8 +720,19 @@ exact reference identity and retry position, rejects stale generations, and
executes every class through the same meter. Priority changes order, never the
budget. Lifecycle artifacts publish worker and per-class backlog, retained
bytes/age, yields, oversizes, overruns, and pending publication/retirement
facts. Publication remains transaction-atomic until Slice E4; retirement
quiesce/cursors belong to E3.
facts.
At a hard login/portal reveal edge, `WorldGenerationQuiescence` makes the old
generation unavailable through the same `WorldRevealCoordinator` lifetime.
World rendering and spatial queries return no old content; object/effect clocks,
liveness, and spatial reconciliation stop; world-space audio is silenced; UI,
network/event/command delivery, portal presentation, destination streaming, and
readiness continue. Canonical live records remain retained until physical
teardown converges, so quiescence neither reconstructs server identity nor
invents Hidden/UnHide transitions. Full-window and shared-origin retirement
advance only from `StreamingController.Tick` through stable resident and
per-owner entity/stage cursors on the frame's one meter. Publication remains
transaction-atomic until Slice E4.
### World-reveal readiness ownership

View file

@ -68,7 +68,7 @@ accepted-divergence entries (#96, #49, #50).
|---|---|---|---|---|---|
| AD-38 | Outgoing teleport viewports retire when retail's quantized animation level exceeds the last captured visible level 1022 (index 96), suppressing levels 1023/1024 up to 20.2 ms before retail's literal `elapsed >= 1.0` state edge. Incoming fades retain the exact timer. | `src/AcDream.Core/World/TeleportAnimSequencer.cs` (`OutgoingViewportReachedTerminalProjection`) | An uncapped 2000 FPS pass can publish the finite tunnel at levels 1023/1024 even though the paired 2013 retail capture switches viewports after 1022. The table-level cutover preserves the captured visible viewport ordering without throttling the application. | Exit sound, viewport replacement, and logout tunnel entry can occur at most two easing-table quanta (about 20.2 ms) earlier than retail's logical timer. | `UIGlobals::GetAnimLevel @ 0x004EE540`; `gmSmartBoxUI::UseTime @ 0x004D6E30`; paired retail/acdream captures documented in `docs/research/2026-07-15-retail-portal-space-pseudocode.md` |
| AD-1 | Lost-cell machinery replaced by recoverable outdoor demote (**#107** safety net) + outdoor-restore `max(terrainZ, z)` under-terrain lift; retail goes `GotoLostCell` | `src/AcDream.Core/Physics/PhysicsEngine.cs:553` (+ :808) | acdream has no lost-cell state machine; outdoor landcell is the recoverable equivalent; the #107 auto-entry hold should make the demote branch unreachable | Gap in the hold → player committed to outdoor terrain inside/under a building (fake-grounded spawn, fall-through); a legit below-heightmap server restore is silently lifted — upward warp vs server | `GotoLostCell` pc:283418; `SetPositionInternal` 0x00515bd0, pc:283892-283945 |
| AD-2 | Async readiness gates replace retail's synchronous destination cell load. **#229 refinement (2026-07-20):** login and F751 portal-space exit now share `WorldRevealReadinessBarrier`, so neither path can expose the normal viewport until the same render-publication, composite-texture, and collision domains converge. A hydratable indoor claim requires its owning Near-tier static/EnvCell mesh set, destination composites, and exact EnvCell physics (`IsSpawnCellReady`); an outdoor claim requires those render domains plus terrain/collision residency for the priority near ring. Hard-recenter generations and tier-aware completion application prevent stale overlapping loads/unloads or Far/Near jobs from opening or erasing the gate; mesh upload remains separate from balanced landblock ownership. Claims beyond NumCells still take the loud forced-placement path. `WorldRevealCoordinator` owns this shared lifetime; diagnostic telemetry observes its generation without defining another readiness path. The portal hold→materialize→regain-control lifecycle remains owned by `TeleportAnimSequencer`. | `src/AcDream.App/Streaming/WorldRevealCoordinator.cs`; `src/AcDream.App/Streaming/WorldRevealReadinessBarrier.cs`; `src/AcDream.App/Streaming/StreamingOriginRecenterCoordinator.cs`; `src/AcDream.App/Streaming/LandblockPresentationPipeline.cs`; `src/AcDream.App/Rendering/GameWindow.cs` (owner wiring + draw eligibility); `src/AcDream.App/Streaming/StreamingController.cs` (`IsRenderNeighborhoodResident`); `src/AcDream.App/Streaming/GpuWorldState.cs` (`IsRenderReady`); `src/AcDream.App/Rendering/Wb/LandblockSpawnAdapter.cs`; `src/AcDream.Core/Physics/PhysicsEngine.cs` (`IsSpawnCellReady`, `IsNeighborhoodTerrainResident`) | This is the asynchronous equivalent of retail leaving `SmartBox::position_update_complete` false while `CellManager::blocking_for_cells` is set: neither initial login nor portal arrival may reveal an empty collision world, a terrain-only Far shell, or a published-but-not-drawable GPU landblock. Indoor does not require a terrain heightmap, only the owning render landblock and exact EnvCell. | Gate opens early → grey/untextured first login or portal reveal, free-fall, wrong-cell rooting, or missing scenery; predicate never satisfies (streamer/DAT/upload failure) → login remains behind the world render gate, while portal transit reaches its existing loud timeout/forced-placement diagnostic. | `SmartBox::UseTime` 0x00455410; `gmSmartBoxUI::EndTeleportAnimation` 0x004D65A0 |
| AD-2 | Async readiness gates replace retail's synchronous destination cell load. **#229 refinement (2026-07-20):** login and F751 portal-space exit now share `WorldRevealReadinessBarrier`, so neither path can expose the normal viewport until the same render-publication, composite-texture, and collision domains converge. A hydratable indoor claim requires its owning Near-tier static/EnvCell mesh set, destination composites, and exact EnvCell physics (`IsSpawnCellReady`); an outdoor claim requires those render domains plus terrain/collision residency for the priority near ring. Hard-recenter generations and tier-aware completion application prevent stale overlapping loads/unloads or Far/Near jobs from opening or erasing the gate; mesh upload remains separate from balanced landblock ownership. Claims beyond NumCells still take the loud forced-placement path. `WorldRevealCoordinator` owns this shared lifetime; diagnostic telemetry observes its generation without defining another readiness path. **Slice E3 refinement (2026-07-24):** the same generation now publishes an immediate `WorldGenerationQuiescence` edge: old-world drawing/spatial queries, simulation/effect clocks, reconciliation, targeting, and 3-D audio stop while retained physical teardown advances through metered cursors and destination network/UI/streaming/readiness remain live. The portal hold→materialize→regain-control lifecycle remains owned by `TeleportAnimSequencer`. | `src/AcDream.App/Streaming/WorldRevealCoordinator.cs`; `src/AcDream.App/Streaming/WorldGenerationQuiescence.cs`; `src/AcDream.App/Streaming/WorldRevealReadinessBarrier.cs`; `src/AcDream.App/Streaming/StreamingOriginRecenterCoordinator.cs`; `src/AcDream.App/Streaming/LandblockPresentationPipeline.cs`; `src/AcDream.App/Rendering/GameWindow.cs` (owner wiring + draw eligibility); `src/AcDream.App/Streaming/StreamingController.cs` (`IsRenderNeighborhoodResident`); `src/AcDream.App/Streaming/GpuWorldState.cs` (`IsRenderReady`); `src/AcDream.App/Rendering/Wb/LandblockSpawnAdapter.cs`; `src/AcDream.Core/Physics/PhysicsEngine.cs` (`IsSpawnCellReady`, `IsNeighborhoodTerrainResident`) | This is the asynchronous equivalent of retail leaving `SmartBox::position_update_complete` false while `CellManager::blocking_for_cells` is set: neither initial login nor portal arrival may reveal or continue simulating an old/partial collision world, a terrain-only Far shell, or a published-but-not-drawable GPU landblock. Indoor does not require a terrain heightmap, only the owning render landblock and exact EnvCell. | Gate opens early → grey/untextured first login or portal reveal, free-fall, wrong-cell rooting, missing scenery, or a still-active old generation; predicate never satisfies (streamer/DAT/upload failure) → login remains behind the world render gate, while portal transit reaches its existing loud timeout/forced-placement diagnostic. | `SmartBox::UseTime` 0x00455410; `gmSmartBoxUI::EndTeleportAnimation` 0x004D65A0 |
| AD-3 | Outdoor seeds always walk the transit array (retail skips the walk when the seed CLandCell is null/unloaded); per-cell lookups no-op on unhydrated data | `src/AcDream.Core/Physics/CellTransit.cs:503` | Equivalence argument: with nothing hydrated every lookup inside the walk no-ops, so the result matches retail's skipped walk | Near partially-streamed landblocks, building-transit promotion silently can't fire until structs hydrate — membership stays outdoor while the player is inside a building | `CObjCell::find_cell_list` 0052b535-0052b56c (null-CLandCell case) |
| AD-4 | `point_in_cell` against an unhydrated CellBSP returns false (skip) rather than the null-node "inside" default; retail never queries unloaded cells | `src/AcDream.Core/Physics/CellTransit.cs:588` | The null-node default would make an unhydrated cell spuriously claim every point; skipping is the conservative streaming-safe choice | During hydration, a point genuinely inside a not-yet-loaded cell resolves outdoor/stale — transient membership misclassification driving wrong collision set and render root | `CEnvCell::find_visible_child_cell` :311397; cell-BSP vtable[0x84] |
| AD-5 | Outdoor `point_in_cell` is an identity compare against the global XY-column cell from `LandDefs.AdjustToOutside` (no per-cell containment test) | `src/AcDream.Core/Physics/CellTransit.cs:865` | Landcells are disjoint 24 m columns — identity-compare against the column under the sphere centre is exactly equivalent to retail's per-candidate test | If block-origin/lcoord math is wrong at a landblock seam, the compare silently never matches — outdoor membership freezes at boundaries (the pre-#106 symptom) | `find_cell_list` pick pc:308788-308825; `CLandCell::point_in_cell` (get_block_offset pc:308804) |

View file

@ -1605,13 +1605,16 @@ port in any phase — no separate listing here.
> and dense-Arwic physical routes passed; third-visit cache residence was
> non-growing and no checkpoint retained staged or retiring bytes. [Residency
> report](../research/2026-07-24-slice-d-unified-residency-report.md). Slice E
> cost-budgeted streaming/retirement is active. E2 has replaced the flat
> cost-budgeted streaming/retirement is active. E2 replaced the flat
> deferred list, count-only throttle, priority hunt, and unload bypass with one
> typed-meter scheduler over explicit stable destination/control/unload/Near/
> Far queues; production prices worker results before adoption and lifecycle
> artifacts expose exact backlog/retained-byte facts. E3 next adds immediate
> old-generation quiesce and cursored retirement. F/G and J retain their
> explicit approval gates.
> artifacts expose exact backlog/retained-byte facts. E3 now makes the old
> generation unavailable at the hard reveal edge and freezes its world
> simulation/audio while full-window and shared-origin teardown advance through
> metered resident, entity, and owner-stage cursors with exact retry receipts.
> E4 cursor-budgets publication next. F/G and J retain their explicit approval
> gates.
**Spec:** `docs/superpowers/specs/2026-07-05-modern-pipeline-design.md` (the
umbrella design — read it first). **Goal:** smoothness first (no frame over

View file

@ -93,10 +93,12 @@ The separately authorized modern-runtime performance program has completed
Slices AD: corrected measurement, prepared-package bake/dedup, package-only
production streaming, and typed unified residency. Its physical capped,
uncapped, and dense connected gates pass without a visual-quality change.
Slice E0E2 now define and enforce typed completion admission through explicit
stable priority queues; E3 adds immediate old-generation quiesce and cursored
retirement next. Slices F/G remain behind their explicit ECS approval gate,
and Slice J remains behind its gameplay-owner approval gate.
Slice E0E3 now define and enforce typed completion admission through explicit
stable priority queues, publish an immediate generation-scoped old-world
quiesce at login/portal boundaries, and advance full-window/recenter teardown
through exact metered retirement cursors. E4 next makes publication itself
cursor-budgeted. Slices F/G remain behind their explicit ECS approval gate, and
Slice J remains behind its gameplay-owner approval gate.
Slice 1's 18-cell favorite-spell overflow bar is user-accepted. Slice 2's
status hand selected-object availability and existing

View file

@ -2,7 +2,7 @@
**Date:** 2026-07-24
**Status:** Slices AD complete. Slice E is active (E0/E1 complete).
**Status:** Slices AD complete. Slice E is active (E0E3 complete).
**Scope:** Reconcile and sequence the existing Modern Pipeline (`MP`) and
Linux/headless (`LH`) tracks using the 2026-07-24 connected performance audit.

View file

@ -1,6 +1,6 @@
# Modern Runtime Slice E — Cost-budgeted streaming and retirement
**Status:** active — E0/E1/E2 complete; E3 quiesce and budgeted retirement next
**Status:** active — E0/E1/E2/E3 complete; E4 cursor-budgeted publication next
**Program:** `docs/plans/2026-07-24-modern-runtime-architecture.md`
**Baseline:** Slice D closeout commit `66690805`
**Behavior contract:** no visual-quality or retail-behavior reduction
@ -288,6 +288,35 @@ E6; the active desktop was RDP and is not valid performance evidence.
- Prove no old generation ticks, emits, collides, targets, or renders while its
retained memory converges.
**Complete 2026-07-24.** `WorldGenerationQuiescence` now publishes the hard
login/portal edge through one generation-scoped availability state owned by
`WorldRevealCoordinator`. The edge withdraws world drawing, picking/radar
spatial queries, target selection, object/static animation, PhysicsScript time,
particle/effect progression, liveness, spatial reconciliation, and owner-tagged
3-D audio while network/event/command, portal presentation, UI, streaming, and
destination readiness continue. A superseding reveal remains continuously
quiescent and only its exact generation can reopen the world; canonical live
records and readiness state remain retained, so the mechanism does not
synthesize Hidden/UnHide or rebuild server identity.
Full-window and shared-origin retirement are now retained frame transactions.
Generation invalidation, worker-inbox clearing, accepted-payload release,
region clearing, stable resident capture, and landblock detachment all resume
from exact cursors through the frame's single `StreamingWorkMeter`.
`LandblockRetirementCoordinator` preserves stable FIFO order and advances one
entity or one owner stage per reservation across scripts, classifications,
lighting, translucency, plugin projection, terrain, physics, cell visibility,
building registries, and environment cells. Failures retry the exact unfinished
entity/stage without replaying committed work. A landblock detach remains one
named indivisible spatial boundary; its complete entity count is charged before
the operation.
Validation: 51 focused reveal/quiescence/retirement tests passed; the complete
App suite passed 3,666 / 3 skipped; the complete solution passed 8,148 / 5
skipped; Release solution build green. The physical connected performance and
visual gate remains deferred to E6 because the active desktop is RDP and is not
valid GPU/FPS evidence.
### E4 — Cursor-budgeted publication
- Move stable ordered arrays/cost facts into retained receipts.