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, user-gated. Deterministic world-lifecycle automation protects fresh login,
outdoor/world-edge/dungeon travel, same-location revisit, exact graceful outdoor/world-edge/dungeon travel, same-location revisit, exact graceful
disconnect, and uncapped fresh-process reconnect with JSON/PNG artifacts. 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 **Active prerequisite before new M4 subsystem work:** continue the
behavior-preserving `GameWindow` decomposition reconciled on 2026-07-21. 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 live-session ownership Slice 3, and live-entity App integration Slice 4 are
landed. Focused hydration, teardown, inbound-authority, network-update, and landed. Focused hydration, teardown, inbound-authority, network-update, and
motion-runtime owners now sit over canonical `LiveEntityRuntime` without a motion-runtime owners now sit over canonical `LiveEntityRuntime` without a
second GUID dictionary. Slice 5 is complete: the complete DAT second GUID dictionary. Slice 5 landblock presentation and Slice 6 update-frame
build, render/physics/static publication, retryable retirement, and shared- orchestration are complete. Streaming, input, the object/network barrier,
origin lifetime barrier are out of `GameWindow`; it is now 8,811 raw lines / liveness, teleport, player mode, and camera presentation have typed phase
247 fields / 153 methods, down 44% from the 15,723-line campaign baseline. owners; `GameWindow.OnUpdate` is one orchestrator handoff with no substantial
The lifecycle/reconnect and synchronized nine-stop soak gates pass. Slice 6 transitive callback facade. `GameWindow` is 7,026 raw lines / 241 fields / 108
update-frame orchestration is active; later slices finish render orchestration methods, down 8,697 lines (55.3%) from the 15,723-line campaign baseline. The
and composition cleanup. 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 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. 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 magic follow-up at `claude-memory/project_magic_ui_and_casting.md`; start
render/streaming work at `claude-memory/project_render_pipeline_digest.md`. 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, user-gated. Deterministic world-lifecycle automation protects fresh login,
outdoor/world-edge/dungeon travel, same-location revisit, exact graceful outdoor/world-edge/dungeon travel, same-location revisit, exact graceful
disconnect, and uncapped fresh-process reconnect with JSON/PNG artifacts. 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 **Active prerequisite before new M4 subsystem work:** continue the
behavior-preserving `GameWindow` decomposition reconciled on 2026-07-21. 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 live-session ownership Slice 3, and live-entity App integration Slice 4 are
landed. Focused hydration, teardown, inbound-authority, network-update, and landed. Focused hydration, teardown, inbound-authority, network-update, and
motion-runtime owners now sit over canonical `LiveEntityRuntime` without a motion-runtime owners now sit over canonical `LiveEntityRuntime` without a
second GUID dictionary. Slice 5 is complete: the complete DAT second GUID dictionary. Slice 5 landblock presentation and Slice 6 update-frame
build, render/physics/static publication, retryable retirement, and shared- orchestration are complete. Streaming, input, the object/network barrier,
origin lifetime barrier are out of `GameWindow`; it is now 8,811 raw lines / liveness, teleport, player mode, and camera presentation have typed phase
247 fields / 153 methods, down 44% from the 15,723-line campaign baseline. owners; `GameWindow.OnUpdate` is one orchestrator handoff with no substantial
The lifecycle/reconnect and synchronized nine-stop soak gates pass. Slice 6 transitive callback facade. `GameWindow` is 7,026 raw lines / 241 fields / 108
update-frame orchestration is active; later slices finish render orchestration methods, down 8,697 lines (55.3%) from the 15,723-line campaign baseline. The
and composition cleanup. 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 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. 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 magic follow-up at `claude-memory/project_magic_ui_and_casting.md`; start
render/streaming work at `claude-memory/project_render_pipeline_digest.md`. 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. - 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. - 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 - **Active structural work:** `GameWindow` decomposition. Slices 16 are
ownership, live animation presentation, and complete live-session ownership complete; `GameWindow.OnUpdate` is one typed orchestration handoff and the
are landed; Slice 4 live-entity App integration is next in 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). [`docs/architecture/code-structure.md`](architecture/code-structure.md).
This is the behavior-preserving prerequisite before new M4 feature bodies. This is the behavior-preserving prerequisite before new M4 feature bodies.
- **Separate rendering gate:** `#225`, lifestone/particle alpha ordering. Its - **Separate rendering gate:** `#225`, lifestone/particle alpha ordering. Its
connected performance, lifetime, and unattended portal routes pass. connected performance, lifetime, and unattended portal routes pass.
- **Carried behavior debt:** `#153` far-teleport unstreamed-edge arrival and - **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. - **Deferred visual fidelity:** `#226` retail landscape detail overlay.
- **Build hygiene:** `#228` records 17 clean-Release test-project warnings; - **Build hygiene:** `#228` records 17 clean-Release test-project warnings;
production compilation and all tests pass. production compilation and all tests pass.

View file

@ -1,8 +1,9 @@
# acdream — code structure & extraction sequence # acdream — code structure & extraction sequence
**Status:** Living document. Created 2026-05-16; implementation reconciliation **Status:** Living document. Created 2026-05-16; implementation reconciliation
completed 2026-07-21; Slices 15 landed the same day. This is the active completed 2026-07-21; Slices 16 landed by 2026-07-22. Slice 7 draw-frame
structural program before new M4 subsystems enter the App layer. orchestration is the active structural program before new M4 subsystems enter
the App layer.
**Purpose:** Describe the desired structural state of 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 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 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 3 14,310 lines / 274 fields / 190 methods
after Slice 4 10,301 lines / 267 fields / 163 methods after Slice 4 10,301 lines / 267 fields / 163 methods
after Slice 5 closeout 8,811 lines / 247 fields / 153 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: `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. | | 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`). | | 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`). | | 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. | | 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. | | 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. | | 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 first-login bootstrap replacement. The deterministic world-lifecycle gate and
nine-destination resource soak pass. nine-destination resource soak pass.
#### Slice 6 — extract update-frame orchestration #### Slice 6 — extract update-frame orchestration — COMPLETE 2026-07-22
Detailed execution ledger: 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) [`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 After the stateful bodies above have owners, make the update path a real
orchestrator instead of delegates back into the window. It preserves the 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 Frame-order tests and the existing R6 gate must produce the same lifecycle and
movement traces before and after extraction. 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` #### Slice 7 — extract `RenderFrameOrchestrator`
Move the complete draw graph and its reusable frame-local scratch state into a 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-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-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-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-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/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-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-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 # 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. **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 the reset graph alive until disposal converges. `GameWindow` is 8,811 raw
lines / 247 fields / 153 methods (44% below the campaign baseline); 7,054 lines / 247 fields / 153 methods (44% below the campaign baseline); 7,054
Release tests, the capped/reconnect lifecycle gate, and the synchronized Release tests, the capped/reconnect lifecycle gate, and the synchronized
nine-stop resource soak pass. Slice 6 update-frame orchestration is active; nine-stop resource soak pass.
its detailed checkpoint ledger is
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). [`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 This is a behavior-preserving structural program. Severe regressions still get
root-cause fixes in separate commits; ordinary feature work resumes with M4 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 the worker DAT transaction, render/physics/static publishers, and retryable
Near/full retirement now have focused owners. The direct production cutover Near/full retirement now have focused owners. The direct production cutover
also serializes complete old-window retirement with teleport and session also serializes complete old-window retirement with teleport and session
origin lifetimes. `GameWindow` is 8,811 raw lines / 247 fields / 153 methods, origin lifetimes. Slice 6 update-frame orchestration is complete: streaming,
down 1,490 lines from the Slice-5 baseline and 6,912 (44%) from the campaign input, the object/network barrier, liveness, teleport, player mode, and camera
baseline. The full Release suite passes 7,054 tests / 5 skips; the 311-second presentation have typed phase owners, and `GameWindow.OnUpdate` is one
capped/reconnect lifecycle gate and synchronized 394-second nine-destination orchestrator handoff. `GameWindow` is 7,026 raw lines / 241 fields / 108
resource soak both pass. Slice 6 update-frame orchestration is active under 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). [`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: Carried:
#153 far-teleport residual, #116 slide-response, the remaining R6 ownership cleanup plus #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 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 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 the deferred Modern Pipeline track (MP1b+). The separate #225 shared-alpha

View file

@ -1,6 +1,6 @@
# GameWindow Slice 6 — update-frame orchestration # 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. **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 **Baseline:** `d4ecac1d`; `GameWindow.cs` is 8,811 raw lines, 247 fields, and
153 methods. Release baseline: 7,054 passed / 5 skipped. The connected 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`. `UpdateFrameOrchestrator`.
- [x] G — delete the old `OnUpdate` bodies, callback facades, and obsolete - [x] G — delete the old `OnUpdate` bodies, callback facades, and obsolete
frame state; run focused corrected-diff reviews after each ownership edge. 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. resource soak, documentation, durable memory, and line/field/method closeout.
Every checked checkpoint is committed as one bisectable architectural unit. 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, placement, LoginComplete order, reset/disposal, GUID reuse, reentrancy,
host rollback, auto-entry idempotence, and completion-mailbox ordering. The 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 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 ### 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 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. 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 `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 **Checkpoint G completed 2026-07-22.** `GameWindow.OnUpdate` now owns only the
update profiler scope and one `UpdateFrameOrchestrator.Tick` call. Teardown, 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 change, return to the responsible checkpoint; do not defer the difference to
Slice 7. 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 ## 6. Review gate for every checkpoint
After each implementation 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.