docs(architecture): close GameWindow slice 6

This commit is contained in:
Erik 2026-07-22 03:54:11 +02:00
parent e91f310279
commit 9512404e25
9 changed files with 182 additions and 46 deletions

View file

@ -115,7 +115,7 @@ and the final two-client portal-out/materialization observer flow are
user-gated. Deterministic world-lifecycle automation protects fresh login,
outdoor/world-edge/dungeon travel, same-location revisit, exact graceful
disconnect, and uncapped fresh-process reconnect with JSON/PNG artifacts.
Release builds; 7,054 tests pass / 5 skip.
Release builds; 7,182 tests pass / 5 skip.
**Active prerequisite before new M4 subsystem work:** continue the
behavior-preserving `GameWindow` decomposition reconciled on 2026-07-21.
@ -123,18 +123,21 @@ Selection/interaction Slice 1, live-animation-presentation Slice 2, complete
live-session ownership Slice 3, and live-entity App integration Slice 4 are
landed. Focused hydration, teardown, inbound-authority, network-update, and
motion-runtime owners now sit over canonical `LiveEntityRuntime` without a
second GUID dictionary. Slice 5 is complete: the complete DAT
build, render/physics/static publication, retryable retirement, and shared-
origin lifetime barrier are out of `GameWindow`; it is now 8,811 raw lines /
247 fields / 153 methods, down 44% from the 15,723-line campaign baseline.
The lifecycle/reconnect and synchronized nine-stop soak gates pass. Slice 6
update-frame orchestration is active; later slices finish render orchestration
and composition cleanup.
second GUID dictionary. Slice 5 landblock presentation and Slice 6 update-frame
orchestration are complete. Streaming, input, the object/network barrier,
liveness, teleport, player mode, and camera presentation have typed phase
owners; `GameWindow.OnUpdate` is one orchestrator handoff with no substantial
transitive callback facade. `GameWindow` is 7,026 raw lines / 241 fields / 108
methods, down 8,697 lines (55.3%) from the 15,723-line campaign baseline. The
7,182-test Release suite, 314-second lifecycle/reconnect gate, and 394-second
synchronized nine-stop soak pass. Slice 7 draw-frame orchestration is active;
Slice 8 finishes composition and Silk callback cleanup.
See `docs/architecture/code-structure.md`. **Carried:** #153, #116, remaining
R6 ownership cleanup, TS-50/TS-51, Modern Pipeline MP1b+, and #225's
R6 ownership cleanup, TS-50/TS-51/TS-53, Modern Pipeline MP1b+, and #225's
lifestone/particle alpha visual gate.
Start structural work at `docs/architecture/code-structure.md`; start
Start structural work at `memory/project_gamewindow_decomposition.md` and
`docs/architecture/code-structure.md`; start
magic follow-up at `claude-memory/project_magic_ui_and_casting.md`; start
render/streaming work at `claude-memory/project_render_pipeline_digest.md`.

View file

@ -113,7 +113,7 @@ and the final two-client portal-out/materialization observer flow are
user-gated. Deterministic world-lifecycle automation protects fresh login,
outdoor/world-edge/dungeon travel, same-location revisit, exact graceful
disconnect, and uncapped fresh-process reconnect with JSON/PNG artifacts.
Release builds; 7,054 tests pass / 5 skip.
Release builds; 7,182 tests pass / 5 skip.
**Active prerequisite before new M4 subsystem work:** continue the
behavior-preserving `GameWindow` decomposition reconciled on 2026-07-21.
@ -121,18 +121,21 @@ Selection/interaction Slice 1, live-animation-presentation Slice 2, complete
live-session ownership Slice 3, and live-entity App integration Slice 4 are
landed. Focused hydration, teardown, inbound-authority, network-update, and
motion-runtime owners now sit over canonical `LiveEntityRuntime` without a
second GUID dictionary. Slice 5 is complete: the complete DAT
build, render/physics/static publication, retryable retirement, and shared-
origin lifetime barrier are out of `GameWindow`; it is now 8,811 raw lines /
247 fields / 153 methods, down 44% from the 15,723-line campaign baseline.
The lifecycle/reconnect and synchronized nine-stop soak gates pass. Slice 6
update-frame orchestration is active; later slices finish render orchestration
and composition cleanup.
second GUID dictionary. Slice 5 landblock presentation and Slice 6 update-frame
orchestration are complete. Streaming, input, the object/network barrier,
liveness, teleport, player mode, and camera presentation have typed phase
owners; `GameWindow.OnUpdate` is one orchestrator handoff with no substantial
transitive callback facade. `GameWindow` is 7,026 raw lines / 241 fields / 108
methods, down 8,697 lines (55.3%) from the 15,723-line campaign baseline. The
7,182-test Release suite, 314-second lifecycle/reconnect gate, and 394-second
synchronized nine-stop soak pass. Slice 7 draw-frame orchestration is active;
Slice 8 finishes composition and Silk callback cleanup.
See `docs/architecture/code-structure.md`. **Carried:** #153, #116, remaining
R6 ownership cleanup, TS-50/TS-51, Modern Pipeline MP1b+, and #225's
R6 ownership cleanup, TS-50/TS-51/TS-53, Modern Pipeline MP1b+, and #225's
lifestone/particle alpha visual gate.
Start structural work at `docs/architecture/code-structure.md`; start
Start structural work at `memory/project_gamewindow_decomposition.md` and
`docs/architecture/code-structure.md`; start
magic follow-up at `claude-memory/project_magic_ui_and_casting.md`; start
render/streaming work at `claude-memory/project_render_pipeline_digest.md`.

View file

@ -24,17 +24,19 @@ What does NOT go here:
- Every session: scan OPEN issues at start; promote/close anything we touched during the session before ending.
- Promoting to a Phase: mark as `DONE (promoted to Phase X)` + commit SHA where the Phase entry landed.
## Current queue — 2026-07-21
## Current queue — 2026-07-22
- **Active structural work:** `GameWindow` decomposition. Selection/interaction
ownership, live animation presentation, and complete live-session ownership
are landed; Slice 4 live-entity App integration is next in
- **Active structural work:** `GameWindow` decomposition. Slices 16 are
complete; `GameWindow.OnUpdate` is one typed orchestration handoff and the
class is 7,026 lines / 241 fields / 108 methods. Slice 7 draw-frame
orchestration is active in
[`docs/architecture/code-structure.md`](architecture/code-structure.md).
This is the behavior-preserving prerequisite before new M4 feature bodies.
- **Separate rendering gate:** `#225`, lifestone/particle alpha ordering. Its
connected performance, lifetime, and unattended portal routes pass.
- **Carried behavior debt:** `#153` far-teleport unstreamed-edge arrival and
`#116` slide response. TS-50/TS-51 are tracked in the divergence register.
`#116` slide response. TS-50/TS-51/TS-53 are tracked in the divergence
register.
- **Deferred visual fidelity:** `#226` retail landscape detail overlay.
- **Build hygiene:** `#228` records 17 clean-Release test-project warnings;
production compilation and all tests pass.

View file

@ -1,8 +1,9 @@
# acdream — code structure & extraction sequence
**Status:** Living document. Created 2026-05-16; implementation reconciliation
completed 2026-07-21; Slices 15 landed the same day. This is the active
structural program before new M4 subsystems enter the App layer.
completed 2026-07-21; Slices 16 landed by 2026-07-22. Slice 7 draw-frame
orchestration is the active structural program before new M4 subsystems enter
the App layer.
**Purpose:** Describe the desired structural state of the App layer,
explain the rules we've adopted, and lay out the safe extraction
sequence from today's reality (one 15,723-line `GameWindow.cs` at the
@ -28,6 +29,7 @@ after Slice 2 14,546 lines / 277 fields / 190 method
after Slice 3 14,310 lines / 274 fields / 190 methods
after Slice 4 10,301 lines / 267 fields / 163 methods
after Slice 5 closeout 8,811 lines / 247 fields / 153 methods
after Slice 6 closeout 7,026 lines / 241 fields / 108 methods
```
`GameWindow` is the single object that:
@ -396,7 +398,7 @@ useful ordering seam, but its ownership status is **partial**.
| Startup options | **Complete** | `RuntimeOptions` owns startup configuration (`eda936dc`). Remaining direct environment reads are legacy runtime diagnostics, not startup configuration. |
| Network session | **Complete** | `LiveSessionController` owns resolve/create/bind/Connect/selection/EnterWorld/Tick/stop/reconnect/disposal; `LiveSessionLifecycleHost` is the narrow App composition boundary; `LiveSessionEventRouter` and `LiveSessionCommandRouter` own exact inbound/outbound lifetimes. `GameWindow` retains one controller field and focused domain sink factories only (`d9ccf8a6`, `6a5d9e2e`). |
| Live identity/lifetime | **Complete App integration** | `LiveEntityRuntime` owns incarnation identity, accepted snapshots/timestamps, runtime components, and logical/spatial lifetime. `LiveEntityHydrationController`, `LiveEntityRuntimeTeardownController`, and `LiveEntityNetworkUpdateController` own DAT-backed hydration, retryable cleanup, and accepted Position/Vector/State/Movement presentation without a second GUID owner (`aa90c646`). |
| Inbound/object-frame order | **Partial** | `RetailInboundEventDispatcher`, `RetailLiveFrameCoordinator`, `LiveEntityAnimationScheduler`, `LiveEntityAnimationPresenter`, static scheduler, remote/projectile updaters, and teleport owners are shipped. `AdvanceLiveObjectRuntimeCore` retains the visible cross-owner order until Slice 6. |
| Inbound/object-frame order | **Complete App orchestration** | `UpdateFrameOrchestrator` owns the complete typed host phase graph; `RetailInboundEventDispatcher`, `RetailLiveFrameCoordinator`, `LiveObjectFrameController`, `LiveSpatialPresentationReconciler`, streaming/input/teleport/player-mode/camera owners preserve the accepted order. `GameWindow.OnUpdate` is one profiler-scoped handoff (`e91f3102`). |
| World reveal | **Complete** | `WorldRevealCoordinator` owns login/portal readiness and reveal lifetime (`a4ef5788`). The accepted deterministic lifecycle trace did not change after extraction. |
| Retained gameplay UI | **Mostly complete feature ownership** | `RetailUiRuntime` and focused panel/controllers own layout and behavior. `GameWindow.OnLoad` still performs substantial service composition, which is allowed until the final composition cleanup. |
| Selection/interaction | **Complete** | `WorldSelectionQuery` owns read-only picking/classification/range queries; `SelectionInteractionController` owns selection intent, Use/PickUp transport, exact-incarnation queues, and auto-walk deferral; `ItemInteractionController` owns ItemHolder policy plus the shared retail inventory-request transaction. `GameWindow` retains construction and narrow lifecycle forwarding only. |
@ -572,11 +574,11 @@ resource pin/release balance, collision footprints across landblock seams, and
first-login bootstrap replacement. The deterministic world-lifecycle gate and
nine-destination resource soak pass.
#### Slice 6 — extract update-frame orchestration
#### Slice 6 — extract update-frame orchestration — COMPLETE 2026-07-22
Detailed execution ledger:
[`docs/plans/2026-07-21-gamewindow-slice-6-update-frame-orchestration.md`](../plans/2026-07-21-gamewindow-slice-6-update-frame-orchestration.md)
(active).
(complete).
After the stateful bodies above have owners, make the update path a real
orchestrator instead of delegates back into the window. It preserves the
@ -590,6 +592,18 @@ graph and registered TS-53 host-order adaptation live in the detailed ledger.
Frame-order tests and the existing R6 gate must produce the same lifecycle and
movement traces before and after extraction.
The production cutover is complete in `e91f3102`. `GameWindow.OnUpdate` now
contains the profiler scope and one `UpdateFrameOrchestrator.Tick` handoff;
streaming, input, the object/network barrier, liveness, teleport, player-mode,
and camera phases have typed owners with no substantial callback facade into
the window. The complete Release suite passes 7,182 tests with five intentional
skips. The 314-second lifecycle/reconnect gate and 394-second synchronized
nine-stop resource soak both pass with graceful exits, stable live-owner
counts, and a 0.8 ms update-frame p95 at the final Caul checkpoint.
`GameWindow` is 7,026 raw lines / 241 fields / 108 methods: 8,697 lines (55.3%)
smaller than the campaign baseline. TS-50, TS-51, and TS-53 remain accurately
registered; this behavior-preserving extraction introduced no new divergence.
#### Slice 7 — extract `RenderFrameOrchestrator`
Move the complete draw graph and its reusable frame-local scratch state into a

View file

@ -257,10 +257,10 @@ AP-94..AP-112 for the confirmed retail-UI completion gaps.
| TS-47 | **NARROWED 2026-07-13** — typed routing now ports the named-retail recall/house/PK travel, age/birth, local display/location, UI persistence, AFK/consent, emote, friends, squelch/filter, and fill-components families. Retail-owned verbs outside the researched family set still fall through to ACE until individually verified. | `src/AcDream.UI.Abstractions/Panels/Chat/RetailClientCommandCatalog.cs`; `src/AcDream.App/UI/ClientCommandController.cs`; `src/AcDream.Core.Net/Messages/ClientCommandRequests.cs` | The high-use researched families have decomp pseudocode, typed actions, and conformance tests; unresearched registry entries must follow the same evidence-first path | An unported retail-owned verb can still produce ACE unknown-command output or server-specific behavior instead of its client action | `ClientCommunicationSystem` command-table construction around `0x00581A40..0x005850A0`; `docs/research/2026-07-13-retail-client-command-routing-pseudocode.md`; `docs/research/2026-07-13-retail-client-command-families-pseudocode.md` |
| TS-48 | Dragging an item onto another player honors the authoritative `DragItemOnPlayerOpensSecureTrade` option, but the option's default-true branch stops at the existing unavailable toast because the secure-trade transaction and UI are not ported. Direct player giving through `GiveObjectRequest 0x00CD` works when the option is disabled; NPC giving is complete. | `src/AcDream.App/UI/ItemInteractionController.cs` (`PlaceIn3D`, `PolicyActionMessage`); `src/AcDream.Core/Items/ItemInteractionPolicy.cs` | The player/NPC distinction and character preference are now faithful; inventing a direct gift while the option requests secure trade would be a worse behavioral divergence. Secure trade is a separate multi-party state machine beyond the starter-dungeon NPC-give slice. | With retail's default character options, an item dragged onto another player cannot be exchanged until the secure-trade subsystem lands. | `ItemHolder::AttemptPlaceIn3D @ 0x00588600`; `PlayerModule::DragItemOnPlayerOpensSecureTrade @ 0x005D31B0`; `ClientTradeSystem`; `docs/research/2026-07-13-retail-give-item-pseudocode.md` |
| TS-49 | Hidden-object availability is bridged through `TargetManager.NotifyVoyeurOfEventAndClear(ExitWorld)` because acdream has not ported retail's DetectionManager. Retail `CObjCell::hide_object` sends `LeftDetection` to detection voyeurs; acdream instead withholds Hidden hosts from ordinary `GetObjectA` relationship creation and uses the existing non-Ok target update to tear down MoveTo/Sticky consumers and clear watched-role subscriptions while preserving the hidden object's own watcher role. | `src/AcDream.App/Physics/EntityPhysicsHost.cs` (`NotifyHidden`); `src/AcDream.App/Physics/LiveEntityMotionRuntimeController.cs` (`ResolvePhysicsHost`); `src/AcDream.Core/Physics/Motion/TargetManager.cs` (`NotifyVoyeurOfEventAndClear`) | The current movement consumers already share TargetManager's status fan-out; the bridge prevents pursuit of an unavailable object without inventing a second partial detection database. | Plugins or future systems listening specifically for retail detection enter/leave events receive no `LeftDetection`; only movement/sticky target consumers observe the equivalent availability loss. | `CObjCell::hide_object @ 0x0052BE30`; retire by porting DetectionManager/CObjCell detection-voyeur delivery and routing Hidden through `LeftDetection` |
| TS-50 | `AnimationDone` executes semantically at each owner's retail `CPhysicsObj::process_hooks` boundary, but all other animation hooks are retained in `AnimationHookFrameQueue` until final root/part/equipped-child pose publication. Retail executes the complete hook stream before transition and the Target/Movement/PartArray/Position manager tail because its current CPartArray pose already exists in-place. Static owners correctly reach `process_hooks` only after their root, parts, and children are current. | `src/AcDream.App/Rendering/Vfx/AnimationHookFrameQueue.cs`; `src/AcDream.App/Rendering/RetailStaticAnimatingObjectScheduler.cs`; frame drain in `src/AcDream.App/Rendering/GameWindow.cs` | The modern renderer publishes immutable effect-pose snapshots after all root/child composition; deferred visual sinks avoid attaching particles/lights/audio to the previous pose. Semantic `AnimationDone` is split out and exact, so motion completion and manager behavior are not delayed. Pose-owner lifetime tokens prevent deferred hooks from crossing delete/local-ID reuse. | A non-AnimationDone hook with same-quantum semantic consequences (notably `CallPES`, default-script chaining, audio/particle creation relative to a transition) runs later than retail and can observe post-tail state or start one render frame late. | `CPhysicsObj::process_hooks @ 0x00511550`; `CPhysicsObj::UpdatePositionInternal @ 0x00512C30`; `CPhysicsObj::animate_static_object @ 0x00513DF0`; retire by publishing the current per-object/child pose before hook routing or splitting semantic and presentation sinks without changing authored hook order |
| TS-51 | Particle and PhysicsScript tails advance once per render frame after the complete ordinary/static object worksets. Retail advances each ordinary object's ParticleManager then ScriptManager inside every admitted `UpdateObjectInternal` quantum; `animate_static_object` instead advances that static owner's ScriptManager then ParticleManager and only then `process_hooks`, using its whole admitted elapsed interval. acdream's shared tail is Particle → Script after static hook capture. | `src/AcDream.App/Rendering/GameWindow.cs` (`AdvanceLiveObjectRuntime` final `_particleSystem.Tick(dt)` / `_scriptRunner.Tick(...)`); `src/AcDream.App/Rendering/RetailStaticAnimatingObjectScheduler.cs` | The current managers are shared presentation/runtime owners rather than per-object manager instances. R6 makes root motion, animation, object clocks, workset membership, and ordinary manager order faithful without pretending the shared tails have per-owner timing or static-tail order. Splitting ownership safely requires a later effect-lifetime slice. | A render fragment below retail's minimum object quantum can advance an effect while its owner waits; a catch-up frame advances an owner's root through several quanta but its effect tail only once; static hooks can route before their script/particle managers and static default scripts/particles use render elapsed in Particle → Script order rather than `animate_static_object` elapsed/discard and Script → Particle → hooks timing. | `CPhysicsObj::UpdateObjectInternal @ 0x005156B0`; `CPhysicsObj::animate_static_object @ 0x00513DF0`; retire by giving live/static owners incarnation-bound particle/script managers and ticking each manager in the owning object quantum/order |
| TS-50 | `AnimationDone` executes semantically at each owner's retail `CPhysicsObj::process_hooks` boundary, but all other animation hooks are retained in `AnimationHookFrameQueue` until final root/part/equipped-child pose publication. Retail executes the complete hook stream before transition and the Target/Movement/PartArray/Position manager tail because its current CPartArray pose already exists in-place. Static owners correctly reach `process_hooks` only after their root, parts, and children are current. | `src/AcDream.App/Rendering/Vfx/AnimationHookFrameQueue.cs`; `src/AcDream.App/Rendering/RetailStaticAnimatingObjectScheduler.cs`; shared frame drain in `src/AcDream.App/Update/LiveObjectFrameController.cs` (`LiveEffectFrameController`) | The modern renderer publishes immutable effect-pose snapshots after all root/child composition; deferred visual sinks avoid attaching particles/lights/audio to the previous pose. Semantic `AnimationDone` is split out and exact, so motion completion and manager behavior are not delayed. Pose-owner lifetime tokens prevent deferred hooks from crossing delete/local-ID reuse. | A non-AnimationDone hook with same-quantum semantic consequences (notably `CallPES`, default-script chaining, audio/particle creation relative to a transition) runs later than retail and can observe post-tail state or start one render frame late. | `CPhysicsObj::process_hooks @ 0x00511550`; `CPhysicsObj::UpdatePositionInternal @ 0x00512C30`; `CPhysicsObj::animate_static_object @ 0x00513DF0`; retire by publishing the current per-object/child pose before hook routing or splitting semantic and presentation sinks without changing authored hook order |
| TS-51 | Particle and PhysicsScript tails advance once per render frame after the complete ordinary/static object worksets. Retail advances each ordinary object's ParticleManager then ScriptManager inside every admitted `UpdateObjectInternal` quantum; `animate_static_object` instead advances that static owner's ScriptManager then ParticleManager and only then `process_hooks`, using its whole admitted elapsed interval. acdream's shared tail is Particle → Script after static hook capture. | `src/AcDream.App/Update/LiveObjectFrameController.cs` (`LiveObjectFrameController` + `LiveEffectFrameController` shared `_particles.Tick` / `_scripts.Tick` tail); `src/AcDream.App/Rendering/RetailStaticAnimatingObjectScheduler.cs` | The current managers are shared presentation/runtime owners rather than per-object manager instances. R6 makes root motion, animation, object clocks, workset membership, and ordinary manager order faithful without pretending the shared tails have per-owner timing or static-tail order. Splitting ownership safely requires a later effect-lifetime slice. | A render fragment below retail's minimum object quantum can advance an effect while its owner waits; a catch-up frame advances an owner's root through several quanta but its effect tail only once; static hooks can route before their script/particle managers and static default scripts/particles use render elapsed in Particle → Script order rather than `animate_static_object` elapsed/discard and Script → Particle → hooks timing. | `CPhysicsObj::UpdateObjectInternal @ 0x005156B0`; `CPhysicsObj::animate_static_object @ 0x00513DF0`; retire by giving live/static owners incarnation-bound particle/script managers and ticking each manager in the owning object quantum/order |
| TS-52 | The terrain shader applies retail-authored base/overlay/road `TerrainTex.TexTiling` but omits the separate Environment Detail Textures pass and its viewer-distance fade (**#226**). | `src/AcDream.App/Rendering/TerrainAtlas.cs`; `src/AcDream.App/Rendering/TerrainModernRenderer.cs`; `src/AcDream.App/Rendering/Shaders/terrain_modern.frag` | `bb5acab9` fixed the user-visible stretched/blurry regression by porting the distinct base-tiling contract. An earlier experimental detail array darkened the whole ground because its source/neutral blend contract was wrong, so it was correctly reverted rather than guessed into production. | With retail's Environment Detail Textures preference enabled, close terrain lacks the extra high-frequency modulation/fade even though authored base texture scale is correct. | `LScape::GenerateDetailSurfaces` / `SetDetailTexturing @ 0x00506B40`; `ACRender::landPolyDraw @ 0x006B6450..0x006B6525`; issue #226 |
| TS-53 | acdream advances retained UI time on the draw seam and local teleport/UI-camera presentation after its SmartBox-shaped object → inbound network → CommandInterpreter barrier. Retail `Client::UseTime` calls `UIElementManager::UseTime` first, whose global time message reaches `gmSmartBoxUI::UseTime`, and publishes player-camera work from the physics/player callback rather than one post-network camera tail. Slice 6 preserves the accepted host order as an ownership-only extraction. | `src/AcDream.App/Rendering/GameWindow.cs` (`OnUpdate` teleport/camera tails and `_retailUiRuntime.Tick` in `OnRender`); `docs/plans/2026-07-21-gamewindow-slice-6-update-frame-orchestration.md` | Current retained UI, portal transit, reveal, camera, and connected movement traces are accepted; changing cross-subsystem host order while extracting ownership would combine a behavior change with the structural cutover. | Retained UI, teleport, and camera presentation can observe same-frame object/inbound/player state one host update earlier or later than retail at transition boundaries; a future exact host-order port must prove UI, input, reveal, and camera consequences together. | `Client::UseTime @ 0x00411C40`; `UIElementManager::UseTime`; `gmSmartBoxUI::UseTime @ 0x004D6E30`; `CPhysics::UseTime @ 0x00509950`; retire only with a focused host-order port and connected portal/camera comparison |
| TS-53 | acdream advances retained UI time on the draw seam and local teleport/UI-camera presentation after its SmartBox-shaped object → inbound network → CommandInterpreter barrier. Retail `Client::UseTime` calls `UIElementManager::UseTime` first, whose global time message reaches `gmSmartBoxUI::UseTime`, and publishes player-camera work from the physics/player callback rather than one post-network camera tail. Slice 6 preserves the accepted host order as an ownership-only extraction. | `src/AcDream.App/Update/UpdateFrameOrchestrator.cs` (post-live-frame teleport/camera phases); `src/AcDream.App/Rendering/GameWindow.cs` (`_retailUiRuntime.Tick` in `OnRender`); `docs/plans/2026-07-21-gamewindow-slice-6-update-frame-orchestration.md` | Current retained UI, portal transit, reveal, camera, and connected movement traces are accepted; changing cross-subsystem host order while extracting ownership would combine a behavior change with the structural cutover. | Retained UI, teleport, and camera presentation can observe same-frame object/inbound/player state one host update earlier or later than retail at transition boundaries; a future exact host-order port must prove UI, input, reveal, and camera consequences together. | `Client::UseTime @ 0x00411C40`; `UIElementManager::UseTime`; `gmSmartBoxUI::UseTime @ 0x004D6E30`; `CPhysics::UseTime @ 0x00509950`; retire only with a focused host-order port and connected portal/camera comparison |
---

View file

@ -1,6 +1,6 @@
# acdream — strategic roadmap
**Status:** Living document. Updated 2026-07-21. **M3 landed; M4 is next after the active `GameWindow` structural prerequisite.** M3's retail casting/UI, R6 locomotion/collision/projectile/teleport/radar rebaseline, deterministic fresh-login/portal world lifecycle, and final two-client portal observer flow are user-gated. The current program is the behavior-preserving ownership campaign in [`docs/architecture/code-structure.md`](../architecture/code-structure.md); new M4 quest/emote/character-creation feature bodies wait until that campaign is complete. Issue #225's lifestone/particle alpha comparison remains a separate rendering visual gate.
**Status:** Living document. Updated 2026-07-22. **M3 landed; M4 is next after the active `GameWindow` structural prerequisite.** M3's retail casting/UI, R6 locomotion/collision/projectile/teleport/radar rebaseline, deterministic fresh-login/portal world lifecycle, and final two-client portal observer flow are user-gated. The current program is the behavior-preserving ownership campaign in [`docs/architecture/code-structure.md`](../architecture/code-structure.md); Slices 16 are complete and Slice 7 draw-frame orchestration is active. New M4 quest/emote/character-creation feature bodies wait until that campaign is complete. Issue #225's lifestone/particle alpha comparison remains a separate rendering visual gate.
**Purpose:** One source of truth for where the project is and where it's going. Every observed defect or missing feature has a named phase that owns it; when something looks wrong in-game, look here to find the phase that'll address it. Implementation details live in per-phase specs under `docs/superpowers/specs/`, not in this file.
---
@ -56,9 +56,19 @@ session replacement, including failure/retry and fast relogin. Shutdown keeps
the reset graph alive until disposal converges. `GameWindow` is 8,811 raw
lines / 247 fields / 153 methods (44% below the campaign baseline); 7,054
Release tests, the capped/reconnect lifecycle gate, and the synchronized
nine-stop resource soak pass. Slice 6 update-frame orchestration is active;
its detailed checkpoint ledger is
nine-stop resource soak pass.
Slice 6 update-frame orchestration is complete. Streaming, input, the retail-
shaped object/network barrier, liveness, local teleport, player mode, and
camera presentation now have typed phase owners. `GameWindow.OnUpdate` is one
orchestrator handoff, with no substantial transitive callback facade back into
the window. `GameWindow` is 7,026 raw lines / 241 fields / 108 methods, down
8,697 lines (55.3%) from the campaign baseline. The complete Release suite
passes 7,182 tests / 5 skips; the 314-second lifecycle/reconnect gate and
394-second synchronized nine-stop resource soak pass with graceful exits and
stable owner counts. The completed ledger is
[`2026-07-21-gamewindow-slice-6-update-frame-orchestration.md`](2026-07-21-gamewindow-slice-6-update-frame-orchestration.md).
Slice 7 `RenderFrameOrchestrator` extraction is now active.
This is a behavior-preserving structural program. Severe regressions still get
root-cause fixes in separate commits; ordinary feature work resumes with M4

View file

@ -23,16 +23,20 @@ complete. Slice 5 landblock presentation is also complete:
the worker DAT transaction, render/physics/static publishers, and retryable
Near/full retirement now have focused owners. The direct production cutover
also serializes complete old-window retirement with teleport and session
origin lifetimes. `GameWindow` is 8,811 raw lines / 247 fields / 153 methods,
down 1,490 lines from the Slice-5 baseline and 6,912 (44%) from the campaign
baseline. The full Release suite passes 7,054 tests / 5 skips; the 311-second
capped/reconnect lifecycle gate and synchronized 394-second nine-destination
resource soak both pass. Slice 6 update-frame orchestration is active under
origin lifetimes. Slice 6 update-frame orchestration is complete: streaming,
input, the object/network barrier, liveness, teleport, player mode, and camera
presentation have typed phase owners, and `GameWindow.OnUpdate` is one
orchestrator handoff. `GameWindow` is 7,026 raw lines / 241 fields / 108
methods, down 8,697 lines (55.3%) from the campaign baseline. The full Release
suite passes 7,182 tests / 5 skips; the 314-second capped/reconnect lifecycle
gate and synchronized 394-second nine-destination resource soak both pass with
graceful exits and stable owner counts. The completed Slice 6 ledger is
[`2026-07-21-gamewindow-slice-6-update-frame-orchestration.md`](2026-07-21-gamewindow-slice-6-update-frame-orchestration.md).
Slice 7 draw-frame orchestration is active.
Carried:
#153 far-teleport residual, #116 slide-response, the remaining R6 ownership cleanup plus
registered TS-50/TS-51 timing residuals (the complete-root-Frame/object-workset
registered TS-50/TS-51/TS-53 timing residuals (the complete-root-Frame/object-workset
cutover is automated- and visual-gate complete; Release builds with 17 known
test-project warnings tracked by #228, and 6,575 tests pass / 5 skip), and
the deferred Modern Pipeline track (MP1b+). The separate #225 shared-alpha

View file

@ -1,6 +1,6 @@
# GameWindow Slice 6 — update-frame orchestration
**Status:** Active 2026-07-21.
**Status:** Complete 2026-07-22.
**Parent program:** [`docs/architecture/code-structure.md`](../architecture/code-structure.md), Slice 6.
**Baseline:** `d4ecac1d`; `GameWindow.cs` is 8,811 raw lines, 247 fields, and
153 methods. Release baseline: 7,054 passed / 5 skipped. The connected
@ -29,7 +29,7 @@ never hidden behind a retry, delay, suppression flag, or reordered callback.
`UpdateFrameOrchestrator`.
- [x] G — delete the old `OnUpdate` bodies, callback facades, and obsolete
frame state; run focused corrected-diff reviews after each ownership edge.
- [ ] H — full Release suite, connected lifecycle/reconnect gate, synchronized
- [x] H — full Release suite, connected lifecycle/reconnect gate, synchronized
resource soak, documentation, durable memory, and line/field/method closeout.
Every checked checkpoint is committed as one bisectable architectural unit.
@ -437,7 +437,7 @@ Focused App/Core tests cover destination readiness, forced holds, same-cell
placement, LoginComplete order, reset/disposal, GUID reuse, reentrancy,
host rollback, auto-entry idempotence, and completion-mailbox ordering. The
full App suite is green at 2,814 passed / 3 skipped. `GameWindow.cs` is 7,351
lines at this checkpoint, down from the slice baseline of 15,723.
lines at this checkpoint, down from the 15,723-line campaign baseline.
### F/G — camera, cutover, and deletion
@ -467,7 +467,7 @@ retains no duplicate lifecycle state. Focused Release tests are green at
37/37, the App suite at 2,820 passed / 3 skipped, and the full suite at 7,179
passed / 5 skipped. All three corrected-diff reviews are clean.
`GameWindow.cs` is 7,160 lines, down 8,563 lines (54.5%) from the 15,723-line
slice baseline.
campaign baseline.
**Checkpoint G completed 2026-07-22.** `GameWindow.OnUpdate` now owns only the
update profiler scope and one `UpdateFrameOrchestrator.Tick` call. Teardown,
@ -501,6 +501,22 @@ The slice requires no new visual behavior. If connected screenshots or traces
change, return to the responsible checkpoint; do not defer the difference to
Slice 7.
**Completed 2026-07-22.** The complete Release suite is green at 7,182 passed /
5 fixture or environment skips. The deterministic lifecycle/reconnect gate
passed in 314.195 seconds across capped login/travel checkpoints, graceful close,
and a fresh-process reconnect. Its only warning was the expected set of 25
world-edge empty landblocks. The synchronized nine-stop resource soak passed in
393.581 seconds with movement, turn, jump, combat, teleport waits, fatal-log scan,
and graceful exit. The final Caul plateau held the same 21,025 entity and 13
animation-owner counts as the earlier Caul return, with update-frame p95 at
0.8 ms; working/private memory increased by 112.2/111.0 MiB across that retained
route, inside the existing deterministic gate. The soak's only diagnostics were
35 known DAT-driven missing VFX table/emitter records and the same 25 expected
world-edge misses. The divergence audit keeps TS-50, TS-51, and TS-53 unchanged
and found no new behavior adaptation. Final `GameWindow` size is 7,026 raw
lines / 241 fields / 108 methods, versus 8,811 / 247 / 153 at Slice 6 entry and
15,723 / 278 / 205 at the campaign baseline.
## 6. Review gate for every checkpoint
After each implementation checkpoint:

View file

@ -0,0 +1,84 @@
# GameWindow decomposition — current truth
## Current state
The behavior-preserving App ownership campaign is complete through Slice 6.
`GameWindow.cs` moved from the 2026-07-21 baseline of 15,723 lines / 278 fields /
205 methods to 7,026 lines / 241 fields / 108 methods: 8,697 lines (55.3%) were
removed without changing accepted gameplay or rendering behavior.
| Slice | Ownership moved out | Closeout size |
|---|---|---:|
| 1 | world selection and interaction intent | 14,912 / 278 / 191 |
| 2 | live animation presentation | 14,546 / 277 / 190 |
| 3 | complete live-session lifecycle and routing | 14,310 / 274 / 190 |
| 4 | live-entity hydration, teardown, and network presentation | 10,301 / 267 / 163 |
| 5 | landblock build, publication, retirement, and shared-origin lifetime | 8,811 / 247 / 153 |
| 6 | complete update-frame orchestration | 7,026 / 241 / 108 |
Slice 6 implementation commits are `99a3e819`, `4e4aac2c`, `0bc9fda9`,
`c5570383`, `eeb0f6b4`, `947c61d2`, and production cutover `e91f3102`.
The detailed ledgers and earlier commit sets live under `docs/plans/2026-07-21-
gamewindow-slice-*.md` and `docs/architecture/code-structure.md`.
## Frozen update graph
`GameWindow.OnUpdate` starts the profiler scope and calls one
`UpdateFrameOrchestrator.Tick`. The accepted production graph is:
1. retry retained live-entity teardown;
2. normalize/publish the update and PhysicsScript clocks;
3. converge streaming origin, residence, readiness, and rescued projections;
4. sample semantic input, raw mouse, and combat intent;
5. advance live objects and deferred presentation hooks;
6. drain inbound network traffic inside one world mutation batch;
7. run the local post-network position tail;
8. reconcile root/child/emitter/light presentation without advancing time;
9. expire liveness;
10. advance local teleport/reveal/tunnel presentation;
11. evaluate one-shot player-mode entry;
12. publish fly/chase/player camera presentation.
`LiveEntityRuntime` remains the canonical identity/incarnation owner.
`GpuWorldState` remains the spatial bucket owner. `LiveSessionController` owns
the session generation. Extracted phase owners query these typed runtimes and
must not create replacement dictionaries, service locators, or callback
facades into substantial `GameWindow` methods.
## Accepted verification
- Release suite: 7,182 passed / 5 fixture or environment skips.
- Connected lifecycle/reconnect: 314.195 seconds, graceful close and fresh
process reconnect passed; only 25 expected world-edge empty landblocks.
- Synchronized nine-stop resource soak: 393.581 seconds, graceful exit; stable
21,025 entity and 13 animation-owner counts at the Caul return and Caul
plateau; update p95 0.8 ms. Working/private memory delta was +112.2/+111.0
MiB, inside the gate.
- The 35 missing VFX table/emitter diagnostics are known DAT-driven records,
not a Slice 6 regression.
- TS-50, TS-51, and TS-53 remain registered; Slice 6 introduced no new retail
divergence.
## Next work
Slice 7 extracts `RenderFrameOrchestrator`: the modern draw graph, portal/PView
visibility routing, landscape/opaque/shared-alpha flushes, particles, debug
draw, paperdoll, retained UI, frame fences, and reusable frame-local scratch.
It must keep the exact accepted order and use a small immutable service set plus
explicit per-frame input. It may not become a GL service locator or call
substantial draw bodies back on `GameWindow`.
Slice 8 then groups composition and shutdown wiring and reduces Silk callbacks
to narrow calls into input, update, render, resize, focus, and shutdown owners.
## Do not retry
- Do not reintroduce delegate facades into `GameWindow`; an ordering wrapper is
not an extraction until the state and behavior body move.
- Do not reorder the frozen update graph during structural work. TS-53 records
the known retail host-order difference for a separate evidence-backed port.
- Do not add a second GUID, session, spatial, or resource owner.
- Do not fold full `GameEntity` aggregation into this campaign; evaluate it
after Slice 8.
- Small value/policy callbacks and diagnostics are acceptable only when they do
not call a substantial window body or hide mutable ownership.