From 5ecaa5612d8b2d35543e1590cbddcf76c4daec78 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 24 Jul 2026 21:01:40 +0200 Subject: [PATCH] docs(runtime): approve render scene program --- AGENTS.md | 8 +- CLAUDE.md | 8 +- docs/ISSUES.md | 7 +- docs/README.md | 13 +- docs/plans/2026-04-11-roadmap.md | 9 +- docs/plans/2026-05-12-milestones.md | 8 +- .../2026-07-24-modern-runtime-architecture.md | 44 +- ...-modern-runtime-slices-f-g-render-scene.md | 596 ++++++++++++++++++ 8 files changed, 662 insertions(+), 31 deletions(-) create mode 100644 docs/plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md diff --git a/AGENTS.md b/AGENTS.md index 209aea75..2150d6f2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -150,9 +150,11 @@ and receive retail's centered wait cue instead of forced early reveal. E6 deterministic/resource suites, Release build, complete tests, capped/uncapped nine-stop routes, and pinned dense Arwic pass on exact binary `91e82c3c`. Every checkpoint converged without pending publication, retirement, upload, -warmup, or class backlog. Slices F/G -remain behind the explicit ECS decision gate and Slice J behind its separate -gameplay-owner gate. Evidence: +warmup, or class backlog. The user explicitly approved Slices F–L, including +the F/G ECS and Slice J gameplay-owner gates, on 2026-07-24. Slice F is active +from pre-runtime rollback anchor `e7d9d6fa`. The implementation-ready F/G +ownership, shadow-scene, cutover, and acceptance contract is +`docs/plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md`. Evidence: `docs/research/2026-07-24-slice-c-prepared-asset-cutover-report.md` and `docs/research/2026-07-24-slice-e-cost-budgeted-streaming-report.md`. diff --git a/CLAUDE.md b/CLAUDE.md index df3cc98e..ce3264de 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -148,9 +148,11 @@ and receive retail's centered wait cue instead of forced early reveal. E6 deterministic/resource suites, Release build, complete tests, capped/uncapped nine-stop routes, and pinned dense Arwic pass on exact binary `91e82c3c`. Every checkpoint converged without pending publication, retirement, upload, -warmup, or class backlog. Slices F/G -remain behind the explicit ECS decision gate and Slice J behind its separate -gameplay-owner gate. Evidence: +warmup, or class backlog. The user explicitly approved Slices F–L, including +the F/G ECS and Slice J gameplay-owner gates, on 2026-07-24. Slice F is active +from pre-runtime rollback anchor `e7d9d6fa`. The implementation-ready F/G +ownership, shadow-scene, cutover, and acceptance contract is +`docs/plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md`. Evidence: `docs/research/2026-07-24-slice-c-prepared-asset-cutover-report.md` and `docs/research/2026-07-24-slice-e-cost-budgeted-streaming-report.md`. diff --git a/docs/ISSUES.md b/docs/ISSUES.md index 76cb0d57..be8739fc 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -52,7 +52,12 @@ What does NOT go here: every typed budget dimension; incomplete worlds remain in portal space with retail's centered wait cue. E6 deterministic/resource suites and all three physical-local connected routes pass with zero stranded work/resource - backlog. Slices F/G retain their explicit approval gate. Evidence: + backlog. Slices F–L, including the former F/G and J gates, were explicitly + approved 2026-07-24. Slice F now executes from the pre-runtime rollback + anchor `e7d9d6fa`; its ownership, shadow-scene, cutover, and acceptance + contract is + [`plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md`](plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md). + Evidence: [`research/2026-07-24-slice-e-cost-budgeted-streaming-report.md`](research/2026-07-24-slice-e-cost-budgeted-streaming-report.md). The [documentation map](README.md) defines how this tactical ledger relates to diff --git a/docs/README.md b/docs/README.md index 9b7c90cd..28fe4dfb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -25,16 +25,21 @@ banner cannot silently override the current program state. typed budget dimension; incomplete destinations remain in portal space and receive retail's centered wait cue instead of forced early reveal. E6's deterministic/resource gates and capped, uncapped, and dense-Arwic - physical-local routes pass. Slices F/G await their explicit approval gate. - See the [Slice E streaming report](research/2026-07-24-slice-e-cost-budgeted-streaming-report.md). + physical-local routes pass. Slices F–L, including the F/G and J approval + gates, were explicitly authorized 2026-07-24; Slice F is active. + Their post-E evidence, ownership map, shadow-comparison design, cutover + sequence, and acceptance matrix are implementation-ready in the + [F/G render-scene plan](plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md). + See also the [Slice E streaming report](research/2026-07-24-slice-e-cost-budgeted-streaming-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 in `#225`; its connected resource-lifetime and performance routes pass. - **Carried behavior debt:** `#153` (far teleport onto an unstreamed edge), `#116` (two narrowed slide-response cases), and divergence rows TS-50/TS-51. -- **Deferred engineering tracks:** render ECS/MP3 remains behind its explicit - user decision gate; Linux/headless automation (Track LH) remains future work. +- **Active engineering track:** render ECS/MP3 is executing from the + implementation-ready F/G plan, followed by the approved Linux/headless + automation slices. The pre-F/G runtime rollback anchor is `e7d9d6fa`. - **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,164 tests pass and diff --git a/docs/plans/2026-04-11-roadmap.md b/docs/plans/2026-04-11-roadmap.md index 9983d9fb..5bba8945 100644 --- a/docs/plans/2026-04-11-roadmap.md +++ b/docs/plans/2026-04-11-roadmap.md @@ -1625,8 +1625,13 @@ port in any phase — no separate listing here. > retirement, upload, warmup, or class backlog. Capped/uncapped CPU p99 improved > 34.7%/30.4% from Slice A and maximum frame allocation fell 84.7%/82.2%. > [Streaming report](../research/2026-07-24-slice-e-cost-budgeted-streaming-report.md). -> F/G and J -> retain their explicit approval gates. +> Dense Arwic already meets the provisional 3.33 ms median target; CPU tail +> cost remains above GPU cost. The implementation-ready +> [F/G render-scene plan](2026-07-24-modern-runtime-slices-f-g-render-scene.md) +> records the post-E decision evidence, exact owner boundary, non-drawing +> shadow referee, production cutover, and acceptance matrix. The user +> explicitly approved Slices F–L, including the F/G and J gates, on +> 2026-07-24. Slice F is active from pre-runtime rollback anchor `e7d9d6fa`. **Spec:** `docs/superpowers/specs/2026-07-05-modern-pipeline-design.md` (the umbrella design — read it first). **Goal:** smoothness first (no frame over diff --git a/docs/plans/2026-05-12-milestones.md b/docs/plans/2026-05-12-milestones.md index 15813ffd..aa340680 100644 --- a/docs/plans/2026-05-12-milestones.md +++ b/docs/plans/2026-05-12-milestones.md @@ -106,9 +106,11 @@ complete tests, capped/uncapped nine-stop routes, and pinned dense Arwic pass on exact binary `91e82c3c`; all checkpoints converge with no stranded publication, retirement, upload, warmup, or resource backlog. Capped/uncapped CPU p99 is 34.7%/30.4% below Slice A and maximum frame allocation is -84.7%/82.2% lower. Slices F/G remain behind their explicit ECS approval gate, -and Slice J -remains behind its gameplay-owner approval gate. +84.7%/82.2% lower. The user explicitly approved Slices F–L, including both +the F/G ECS and Slice J gameplay-owner gates, on 2026-07-24. Slice F is active +from rollback anchor `e7d9d6fa`, using the implementation-ready post-E +ownership, shadow-comparison, cutover, and acceptance contract in +[`2026-07-24-modern-runtime-slices-f-g-render-scene.md`](2026-07-24-modern-runtime-slices-f-g-render-scene.md). Slice 1's 18-cell favorite-spell overflow bar is user-accepted. Slice 2's status hand selected-object availability and existing diff --git a/docs/plans/2026-07-24-modern-runtime-architecture.md b/docs/plans/2026-07-24-modern-runtime-architecture.md index fe1ac56e..45a5d6cc 100644 --- a/docs/plans/2026-07-24-modern-runtime-architecture.md +++ b/docs/plans/2026-07-24-modern-runtime-architecture.md @@ -2,7 +2,8 @@ **Date:** 2026-07-24 -**Status:** Slices A–E complete. Slices F/G await their explicit approval gate. +**Status:** Slices A–E complete. Slices F–L explicitly approved 2026-07-24; +Slice F is active. **Scope:** Reconcile and sequence the existing Modern Pipeline (`MP`) and Linux/headless (`LH`) tracks using the 2026-07-24 connected performance audit. @@ -34,7 +35,10 @@ section 13. do not touch that deferral. **Slices F and G resume the deferred MP3 work and MUST NOT start without explicit user approval recorded against this section**, taken on the post-Slice-E corrected uncapped-local - profile (does partition/submission cost still dominate?). Note the prior + profile (does partition/submission cost still dominate?). + **Approval recorded 2026-07-24:** after reviewing the post-E result and + rewrite risk, the user authorized "all slices." F/G may proceed from the + pre-runtime rollback anchor `e7d9d6fa`. Note the prior "GPU-bound at ~200 FPS" Sawato reading is itself invalidated by the `GpuFrameTimer` boundary artifact this plan's Slice A corrects — the question is genuinely open until re-measured. @@ -45,9 +49,10 @@ section 13. covers streaming and WB rendering only. Slice H's network-I/O item and Slice J's gameplay-owner moves touch otherwise-frozen subsystems (network, chat, input) and each requires its own recorded user - authorization before starting. (The 2026-07-24 receive-thread robustness - fix was separately reviewed and user-approved as a bug fix, not a - rework.) + authorization before starting. **Approval recorded 2026-07-24:** the + user's authorization for "all slices" lifts the Slice J gate as well. + (The 2026-07-24 receive-thread robustness fix was separately reviewed and + user-approved as a bug fix, not a rework.) 4. **Evidence-base corrections.** The §1 exception-traffic row previously cited "4,520 + 1,168" — figures with no derivation in the audit or its committed artifacts; the verifiable figures are the focused-trace 1,587 @@ -799,6 +804,8 @@ Slices G and H. ### Slice F — Incremental render scene foundation +**Prepared plan:** [`2026-07-24-modern-runtime-slices-f-g-render-scene.md`](2026-07-24-modern-runtime-slices-f-g-render-scene.md). + **Purpose:** Stop rebuilding/partitioning the world each frame. - Add acdream-owned `IRenderScene`, identifiers, components, and delta journal. @@ -1170,14 +1177,21 @@ an improvement" carries the same evidence burden as a regression claim. ## 14. Current execution point -Slices A–C are complete. Slice C replaced production live-DAT world-mesh -extraction with the validated prepared source and passed all connected, -performance, lifetime, automated, and user-visual gates. Its physical -uncapped result is CPU p50/p95/p99 1.409/4.909/6.496 ms, GPU -0.832/2.510/2.706 ms, a 39.9 MiB largest frame allocation, zero invalid Setup -probe exceptions, and a passing warm repeated-Caul memory assertion. Slice D -is the next execution point; it unifies accounting and policy around the -specialized caches that remain, rather than replacing their working storage. +Slices A–E are complete. Slice E's exact physical-local Release binary +produced uncapped CPU p50/p95/p99 1.216/4.216/5.450 ms and GPU +0.725/2.486/2.666 ms across the nine-stop route. Dense Arwic, with 15,530 +entities and 111 animated entities, produced CPU 2.652/4.153/5.736 ms and GPU +1.576/2.504/2.662 ms. Every stable checkpoint converged without pending +publication, retirement, upload, warmup, or resource backlog. + +The dense median already satisfies the provisional 3.33 ms / 300 FPS target. +CPU tail cost remains above GPU cost and the normal draw path still scans and +partitions resident entities, so F/G can improve CPU utilization, scaling, and +tail behavior, but a dramatic average-FPS gain is not promised. The +implementation-ready F/G contract and ownership map are +[`2026-07-24-modern-runtime-slices-f-g-render-scene.md`](2026-07-24-modern-runtime-slices-f-g-render-scene.md). +The §0.1 and §0.3 gates were explicitly lifted 2026-07-24. Slice F is the +current execution point; `e7d9d6fa` is the pre-runtime rollback anchor. The intended order is therefore: @@ -1186,8 +1200,8 @@ honest metrics + committed baselines (A — exit criteria block C) -> prepared content (B, C) -> typed residence (D — unify/retune, not rebuild) -> cost-budgeted streaming (E) - -> [user decision gate: lift the ECS deferral? §0.1] - -> incremental render scene (F — referee sub-slice first) + -> [APPROVED 2026-07-24: ECS deferral lifted under §0.1] + -> incremental render scene (F — CURRENT; referee first) -> delta GPU submission (G) -> residual frame cleanup (H-a, H-b, H-c) -> flat collision assets (I — floats; depends only on B) diff --git a/docs/plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md b/docs/plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md new file mode 100644 index 00000000..179199b6 --- /dev/null +++ b/docs/plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md @@ -0,0 +1,596 @@ +# Modern Runtime Slices F/G — Incremental Render Scene and Delta Submission + +**Date:** 2026-07-24 + +**Status:** approved 2026-07-24; Slice F active + +**Program:** `docs/plans/2026-07-24-modern-runtime-architecture.md` + +**Baseline:** Slice E closeout commits `91e82c3c` and `e7d9d6fa` + +**Behavior contract:** no change to pixels, view distance, particles, PView +visibility, clipping, draw order, selection, lighting, animation, or +retail-faithful gameplay + +## 1. Decision record + +### 1.1 Why this work has a separate approval gate + +Slices A–E optimized measurement, prepared content, residency, streaming, and +retirement without replacing the renderer's scene model. Slices F/G resume the +MP3 work that the user explicitly deferred on 2026-07-05: + +- Slice F introduces a second, render-only projection in non-drawing shadow + mode. +- Slice G makes that projection the renderer's production input and removes the + old whole-world enumeration/partition path. + +This is a materially larger regression surface than changing an isolated +scheduler or cache. A wrong cell bucket, incarnation, transform, material +variant, or draw-order classification can produce the historical +stairs/doorway/player-vanish bug classes while still compiling and appearing +faster. The approval gate therefore remains binding. + +Approval had to be explicit and recorded as: + +> Approved — continue with all slices. + +The user supplied that approval on 2026-07-24 after reviewing the post-E +evidence and rewrite risk. Runtime work therefore proceeds from the exact +pre-F/G anchor `e7d9d6fa`. + +### 1.2 Post-Slice-E evidence + +Physical-local Release captures on exact binary +`91e82c3c6850fcedbf20322b2ecf4fdcd11a2b2a` produced: + +| Capture | CPU p50 / p95 / p99 | GPU p50 / p95 / p99 | +|---|---:|---:| +| Uncapped nine-stop | 1.216 / 4.216 / 5.450 ms | 0.725 / 2.486 / 2.666 ms | +| Dense Arwic uncapped | 2.652 / 4.153 / 5.736 ms | 1.576 / 2.504 / 2.662 ms | + +Dense Arwic exercised 15,530 entities and 111 animated entities. Its CPU +median is already below the provisional 3.33 ms / 300 FPS target. Therefore: + +- F/G is not needed to claim that one provisional median target. +- CPU p95/p99 still exceed GPU p95/p99, leaving measurable CPU headroom. +- The current path still scales with the resident entity population rather + than only with scene changes and visible buckets. +- The expected win is lower CPU utilization, better dense-scene scaling, + lower tail cost, and a clean future snapshot/headless seam. +- A dramatic average-FPS increase is possible but is not promised. + +The go/no-go decision is consequently about accepting architectural rewrite +risk for throughput headroom and a cleaner long-term runtime boundary, not +about repairing an existing visual or stability failure. + +## 2. Current owner map + +| Concern | Current owner | Current cost/contract | F/G treatment | +|---|---|---|---| +| Logical live identity and accepted state | `LiveEntityRuntime` | sole GUID/incarnation authority | unchanged; emits exact projection facts only | +| Spatial landblock membership | `GpuWorldState` | sole loaded/pending bucket authority | unchanged; journals committed render projection deltas | +| Static publication/retirement | `LandblockPresentationPipeline` and retirement coordinator | retained exact Slice-E receipts | append render deltas at existing committed receipt boundaries | +| Live presentation resources | `EntitySpawnAdapter` | exact per-incarnation mesh/composite ownership | unchanged; appearance facts copied into render projection | +| Equipped-child presentation | `EquippedChildRenderController` | final current transform and visibility | copied into equipped projection archetype | +| Static animation | `RetailStaticAnimatingObjectScheduler` | final root transform for active animated statics | active-only synchronization into dynamic transform components | +| Frame camera/root/building facts | `WorldRenderFrameBuilder` | borrowed one-frame facts | retained | +| Retail cell visibility | `PortalVisibilityBuilder` / `RetailPViewRenderer` | retail PView and viewcone oracle | retained without algorithm changes | +| Per-frame entity split | `InteriorEntityPartition` | scans every resident `WorldEntity` | replaced by incremental scene indices in G | +| Visibility walk/classification | `WbDrawDispatcher` | walks entity/mesh pairs and rebuilds instance groups | consumes packed frame candidates and dirty instance ranges in G | +| Alpha order | `RetailAlphaQueue` | shared stable far-to-near ordering | retained | +| Selection | retail selection scene/sink | visible part publication and lighting | same accepted parts and transforms from frame view | +| Lighting | `LightManager` plus dispatcher selection | per-object retail light set | same algorithm over packed bounds | +| GL ownership | `WbMeshAdapter`, texture/residency owners, dispatcher buffers | render-thread only | unchanged | + +`GpuWorldState` remains the canonical spatial projection. The new render scene +is a derived, disposable presentation index. It cannot answer gameplay, +network, collision, inventory, interaction, radar, target, or persistence +questions. + +## 3. Target boundary + +### 3.1 Acdream-owned API + +Arch is an implementation detail in `AcDream.App`. No Arch type crosses an +acdream interface, enters Core, or appears in a test fixture outside App. + +The boundary is equivalent to: + +```csharp +internal interface IRenderScene +{ + RenderSceneGeneration Generation { get; } + RenderProjectionCounts Counts { get; } + + RenderDeltaApplyResult Apply(ReadOnlySpan deltas); + void SynchronizeDynamicSources(in DynamicProjectionSyncInput input); + RenderSceneDigest BuildDigest(RenderSceneDigestBuffer reuse); + RenderSceneQuery OpenQuery(); + void Clear(RenderSceneGeneration replacementGeneration); +} +``` + +The exact API may split mutation, query, and diagnostics into narrower +interfaces, but these rules are fixed: + +- mutation is update-thread only; +- draw receives only a borrowed read/query surface; +- draw cannot call `LiveEntityRuntime`, `GpuWorldState`, or `WorldEntity` + dictionaries; +- Arch entities and `.Value` primitives stay inside the scene implementation; +- all external identities are acdream-owned wrapper types; +- session/world generations are explicit; +- stale incarnation deltas are rejected rather than applied to a reused slot. + +### 3.2 Identity + +Use distinct wrapper identities: + +```text +RenderProjectionId +RenderOwnerIncarnation +RenderSceneGeneration +RenderSpatialBucket +RenderAssetHandle +``` + +Projection keys are derived presentation identities, not a second gameplay +GUID map: + +- static: world generation + canonical landblock + current static entity id; +- live root: current local `WorldEntity.Id` + accepted instance sequence; +- equipped child: parent local id + attachment slot/child local id + + incarnation; +- EnvCell: world generation + cell id. + +The scene may keep a source-key-to-projection lookup solely to apply deltas. It +may not expose that lookup as object identity to gameplay consumers. + +### 3.3 Component set + +Initial packed components: + +```text +RenderTransform +PreviousRenderTransform +RenderMeshSet +RenderMaterialVariant +RenderSpatialResidency +RenderWorldBounds +RenderFlags +RenderDegradeState +RenderSortKey +RenderOwnerIncarnation +RenderDirtyMask +``` + +Archetypes remain narrow: + +- outdoor static; +- indoor-cell static; +- live/dynamic root; +- active animated static; +- equipped child; +- translucent/light-bearing variants only where query density justifies them. + +Do not attach every component to every projection. Effects, particles, and +lights remain in their existing owners during F/G unless a measured query +benefit and an exact parity fixture justify a packed reference. + +### 3.4 Delta journal + +One update-thread-owned `RenderProjectionJournal` receives: + +```text +Register +UpdateTransform +UpdateAppearance +UpdateFlags +Rebucket +Unregister +ClearGeneration +``` + +Each delta carries: + +- scene generation; +- projection source key; +- exact owner incarnation; +- monotonically increasing journal sequence; +- complete payload for the changed channel. + +Rules: + +- structural order is exact; +- updates may coalesce only within one host tick, after the most recent + structural edge for the same projection/incarnation; +- register/unregister and generation boundaries never coalesce away; +- unregister of an old incarnation cannot remove its replacement; +- a journal drains fully at the update-to-render boundary; +- any carry-over at frame publication is an invariant failure; +- callback reentrancy appends after the current sequence and cannot invalidate + active iteration; +- no bounded queue or worker thread is introduced in F/G—the accepted host + thread remains the only writer. + +### 3.5 Static versus dynamic synchronization + +Static projections are change-driven: + +- landblock spatial publication registers them once; +- appearance or static-animation membership changes issue explicit deltas; +- rebucket/retirement removes them once. + +Dynamic root and equipped-child transforms are synchronized after animation, +physics, remote motion, local-player projection, and attachment transforms +have reached their existing final frame state. The synchronizer walks only +the scene's dynamic/active-animated source registry, compares packed final +facts, and emits updates for changed records. It never scans all resident +statics. + +This active-only synchronization is deliberate. Retrofitting presentation +version counters into every simulation setter during F would broaden the +change into gameplay/physics ownership. A later measured slice may replace +the comparison with versioned producers without changing `IRenderScene`. + +## 4. Referee before the match + +The comparison oracle lands before Arch or shadow storage. + +`CurrentRenderSceneOracle` captures the current accepted render input after +PView construction and before dispatcher classification. Its deterministic +digest contains, in stable sort order: + +- source/projection identity and incarnation; +- spatial class: outdoor static, cell static, dynamic, equipped; +- canonical landblock and full cell; +- root transform and world bounds; +- mesh ids and part transforms in order; +- material/palette/texture replacement identity; +- draw/ancestor/hidden/translucency/degrade flags; +- active-animation classification; +- PView survivor class and clip-route identity; +- expected selection part ids; +- opaque/alpha classification identity. + +The oracle is validated on the current production path first. It must be: + +- deterministic across repeated unchanged frames; +- allocation-free when disabled; +- bounded and reusable when enabled; +- independent of dictionary enumeration order; +- continuously sampled during login, portal transit, reveal, movement, + animation, appearance change, and teardown—not only at stable checkpoints. + +The oracle does not decide what retail should draw. It records what the +already accepted current path supplies, so F/G cannot silently redefine +parity in favor of the new implementation. + +## 5. Slice F — Non-drawing shadow render scene + +### F0 — Current-path oracle + +1. Add acdream-owned digest/value types and reusable buffers. +2. Capture the current partition and dispatcher candidate identity without + changing draw behavior. +3. Add deterministic unit fixtures for static, dynamic, animated, equipped, + translucent, hidden, duplicate ids across landblocks, and GUID reuse. +4. Extend canonical lifecycle artifacts with digest generation, counts, + mismatch count, journal depth, and scene bytes. +5. Run the current pipeline alone through the canonical route and establish + the referee's own stability. + +**Commit gate:** no Arch dependency; identical screenshots; no material +performance regression with comparison disabled. + +### F1 — Scene types and contained Arch adapter + +1. Verify Arch's current license and selected package API; pin one exact + version in `AcDream.App` only. +2. Add `IRenderScene`, wrapper ids, component structs, query contracts, and + `ArchRenderScene`. +3. Add an architecture test preventing Arch namespaces outside the allowed App + folder and preventing primitive id extraction outside the owner assembly. +4. Add memory accounting for chunks, lookup/index storage, journal buffers, + and retained synchronization sources. +5. Prove create/update/remove/clear and stale-incarnation rejection in pure App + tests. + +**Commit gate:** the scene is unbound and non-drawing; full suite green. + +### F2 — Static projection journal + +1. Append Register deltas from the existing final landblock spatial publication + receipt. +2. Append Unregister deltas from the exact retirement/demotion receipt. +3. Preserve owner landblock identity independently of the caller's current + draw landblock—the #119 cache lesson. +4. Mirror indoor cell statics, outdoor statics, scenery, building shells, and + EnvCell projection identity without changing their resource ownership. +5. Make same-landblock rehydrate a reconcile operation: retained identities + update, omitted identities unregister, and new identities register. +6. Clear by exact world generation on login, portal supersession, session + reset, and graceful shutdown. + +**Commit gate:** shadow static digest equals the referee over deterministic +publication/retirement permutations. + +### F3 — Live and equipped projection journal + +1. Register only after the current live record, materialized projection, and + presentation resources have committed. +2. Use exact local id + instance sequence; never server GUID alone. +3. Journal loaded/pending visibility edges without treating rebucket as + logical recreate. +4. Mirror appearance, mesh refs, palette/material variants, draw flags, + ancestor visibility, full cell, and bounds. +5. Mirror equipped children after their current attachment transform update. +6. Unregister exactly once on pickup/parenting/withdraw/delete/session reset, + rejecting callbacks from displaced generations. + +**Commit gate:** duplicate CreateObject, reentrant callback, pending-to-loaded, +loaded-to-loaded, hidden, parent/child, delete/recreate, and GUID-reuse tests +have zero leaked or stale projections. + +### F4 — Dynamic synchronization and incremental indices + +1. Synchronize final current-frame transforms for live roots, active animated + statics, and equipped children. +2. Maintain outdoor-static, per-cell-static, dynamic, translucent, selectable, + light-candidate, and dirty-record indices incrementally. +3. Preserve `InteriorEntityPartition.IsIndoorCellId` semantics. +4. Preserve retail's special dynamic routing: + - outdoor dynamics under an interior root enter the outside stage; + - exit-portal-straddling dynamics may enter both stages; + - out-of-flood indoor dynamics remain members but fail the per-dynamic + viewcone cull. +5. Assert index counts and membership against the current partition every + sampled frame. + +**Commit gate:** no whole-static-world synchronization in a steady frame; +unchanged dynamic records emit no update. + +### F5 — Continuous shadow comparison + +1. Apply the journal and build the shadow digest at the update/render boundary. +2. Compare continuously at a fixed diagnostic cadence and at every canonical + checkpoint. +3. Record the first exact mismatch with both projections and source channel; + never log an unbounded mismatch storm. +4. Run deterministic portal, churn, animation, appearance, hidden, selection, + and teardown tests. +5. Run capped and uncapped nine-stop routes plus dense Arwic on the physical + display. +6. Prove: + - zero mismatches; + - zero stale delta applications; + - zero journal carry-over; + - zero retained old-generation scene state; + - bounded shadow memory; + - no pixel changes because the shadow does not draw. + +**Slice F gate:** all evidence above passes before any production consumer is +switched. F may temporarily cost memory and a small amount of CPU in diagnostic +mode; those costs are reported separately and shadow comparison is disabled by +default after its gate. + +## 6. Slice G — Frame product and production cutover + +### G0 — Borrowed double-buffered frame product + +Add two reusable `RenderFrameArena` instances. Building frame N writes the +arena not borrowed by draw N-1 and publishes a generation-stamped +`RenderFrameView`. + +The view contains spans/ranges for: + +- visible outdoor static candidates; +- visible per-cell static candidates keyed by PView order; +- dynamic candidates; +- final root/part transforms; +- opaque and alpha classification records; +- per-object light sets; +- selection parts and lighting; +- existing PView/clip products by borrowed reference; +- diagnostic counts and source digest. + +Rules: + +- no extra frame of latency; +- no render thread is introduced; +- a view is invalid after its arena is reused; +- no consumer retains spans across frame completion; +- abort recycles the incomplete arena without publishing it; +- world generation and frame sequence must match at draw. + +### G1 — Replace whole-world partition with scene queries + +1. Query outdoor statics directly. +2. Query each PView-visible cell bucket in the exact existing far-to-near order. +3. Query the dynamic set once, then apply the existing per-dynamic viewcone and + outside-stage/straddle rules. +4. Preserve look-in cells as a distinct landscape-stage source. +5. Preserve particle-owner filtering against the exact mesh survivor set. +6. Compare the new candidate digest with the old partition without drawing + twice. + +**Commit gate:** exact candidate parity through indoor/outdoor transitions, +door apertures, look-ins, non-flooded rooms, and portal straddles. + +### G2 — Packed dispatcher input + +1. Introduce an acdream-owned `RenderInstanceCandidate` consumed by + `WbDrawDispatcher`. +2. Copy every current `WorldEntity` fact the dispatcher actually uses: + - mesh refs and ordered part transforms; + - root transform; + - owner landblock/cell; + - palette and texture replacement identity; + - hidden/draw/ancestor flags; + - scale, bounds, source setup/gfx id; + - selection owner identity; + - translucency/degrade state. +3. Preserve cache key and invalidation semantics, especially owner landblock + identity and incomplete-mesh retry. +4. Keep Wb/texture/selection/light/alpha owners unchanged. +5. Add old-input/new-input instance-set comparison at the dispatcher boundary. + +**Commit gate:** identical instance keys, model matrices, material identities, +clip slots, light sets, selection parts, alpha records, and draw counts. + +### G3 — Dirty instance ranges and reusable command storage + +1. Retain persistent instance records keyed by projection + mesh part + batch. +2. Rebuild classification only for Register, Appearance, Material, Mesh, + Degrade, or relevant Flags dirtiness. +3. Update transform/light/selection fields through dirty ranges. +4. Reuse MDI command, batch, sort, and alpha scratch storage. +5. Cache static command templates by scene generation and visible-cell set only + after parity proves the simpler indexed path. +6. Keep resource upload and GL retirement on the accepted render thread. +7. Do not add GPU culling, GPU particles, or render-worker jobs in G. + +**Commit gate:** warm unchanged frames rebuild no static classification and +allocate no core scene/dispatcher memory. + +### G4 — Cutover + +1. Run old and new input construction in compare-only mode; draw only the old + path. +2. Fix every mismatch at its source. +3. Switch the single production draw input to `RenderFrameView`. +4. Run instance-set and fixed-camera image comparisons. +5. Obtain the user's connected visual confirmation. +6. Delete: + - production `InteriorEntityPartition` use; + - full `LandblockEntries` walk from normal world draw; + - transition flags and dual-input compare code; + - obsolete static classification rebuild paths. +7. Keep only reusable oracle tooling behind diagnostics/tests. + +There is no permanent runtime fallback. A failed gate reverts the cutover +commit; it does not ship a hidden old/new switch. + +### G5 — Physical performance and lifecycle gate + +Run the exact Slice-E reference matrix: + +- capped physical-local nine-stop; +- uncapped physical-local nine-stop; +- pinned dense-Arwic uncapped with stationary turn; +- fresh login, portal/dungeon, same-location revisit, world edge; +- appearance, hidden/unhide, equipped-child changes; +- graceful logout/reconnect; +- rapid generation replacement and GUID reuse. + +Report, without changing thresholds: + +- CPU/GPU p50/p95/p99/p99.9 and maximum; +- update, PView, scene query, frame build, dispatcher, alpha, and GL stages; +- frame-thread and process allocation; +- scene/chunk/index/journal bytes; +- managed heap, LOH/POH fragmentation, GC pauses; +- tracked CPU/GPU/staging/retiring bytes; +- instance/draw/triangle counts; +- screenshot and instance-set comparison. + +## 7. Acceptance matrix + +### 7.1 Correctness + +- Exact static/live/equipped projection count and digest. +- Exact PView cell order and viewcone behavior. +- Exact outside-stage and portal-straddling dynamic behavior. +- Exact opaque/clip-map/alpha classification and stable alpha order. +- Exact root and part transforms with no one-frame lag. +- Exact hidden, NoDraw, ancestor visibility, and translucency behavior. +- Exact material/palette/texture replacement identity. +- Exact light sets and selection-part placement. +- Exact incarnation behavior across stale updates and GUID reuse. +- Zero replay of logical create/default script/effect work on rebucket. +- Zero draw calls into gameplay/spatial dictionaries. + +### 7.2 Resource and lifecycle + +- Journal empty at every frame publication. +- No old world generation in scene after replacement converges. +- Scene memory plateaus on third location visit. +- No stale Arch entity handle after removal/reuse. +- No extra mesh/texture/composite owner. +- No unbalanced reference, staged upload, dynamic light, effect, or alpha + record. +- Graceful shutdown drains scene and GL retirement exactly once. + +### 7.3 Performance + +The program goals remain: + +- dense uncapped p50 at or below 3.33 ms, or a newly attributed blocker; +- traversal p99 at or below 16.67 ms; +- no post-warm frame above 33.3 ms without an attributed indivisible/OS event; +- steady update p95 at or below 2 ms; +- core render-scene/dispatcher allocation p50 of zero; +- whole-client steady allocation initially at or below 4 KiB/frame; +- no known exception-as-control-flow site. + +Because Slice E already satisfies the dense median target, G must additionally +show one of: + +- a statistically meaningful CPU p95/p99 reduction; +- lower CPU utilization at equal uncapped throughput; +- materially improved resident-entity scaling; +- or a documented result that the removed scan was no longer dominant and the + next measured bottleneck belongs to Slice H. + +No visual-quality reduction is an acceptable way to pass. + +## 8. Commit and review sequence + +Each sub-slice is one or more bisectable commits, but a commit may not mix +shadow storage, production cutover, and old-path deletion. + +For every commit: + +1. inspect the complete diff for authority leakage, stale identity, lifecycle + asymmetry, and allocations; +2. run focused App tests; +3. run `dotnet build AcDream.slnx -c Release`; +4. run the complete Release solution tests before a sub-slice gate; +5. update architecture, roadmap, issues, divergence register, and memory in the + same commit when their truth changes; +6. introduce no retail-divergence row—F/G is performance-only and any visible + difference is a bug. + +No substantial feature body enters `GameWindow`. Composition changes live in +`FrameRootComposition`; scene, journal, oracle, synchronization, and frame +product owners live under focused `AcDream.App/Rendering` namespaces. + +## 9. Stop/rollback conditions + +Stop the current sub-slice and fix the root cause when: + +- the shadow digest differs; +- source identity requires a second authoritative GUID map; +- a draw consumer must call back into `LiveEntityRuntime` or `GpuWorldState`; +- delta order cannot represent a reentrant lifecycle edge; +- the new path needs a timer, suppression flag, or retry workaround; +- a screenshot/instance difference cannot be explained; +- the frame product adds a frame of latency; +- memory fails to plateau; +- F/G performance is worse outside explicitly enabled shadow comparison. + +The rollback unit is the failing sub-slice commit. Do not retain a permanent +legacy fallback, dual draw, or user-facing renderer switch. + +## 10. Approval and rollback state + +This plan is approved and active. + +- Pre-F/G runtime rollback anchor: `e7d9d6fa`. +- Every production cutover commit is added here and to + `claude-memory/project_render_pipeline_digest.md`. +- Shadow/referee commits precede the production switch and need not be reverted + for a visual mismatch unless they independently change runtime behavior. +- A failed visual gate reverts the exact cutover commit(s); it does not use + `git reset`, discard later evidence, or enable a permanent fallback.