# GameWindow Slice 8 — composition and lifecycle shell **Status:** Automated implementation and closeout complete 2026-07-22; final user visual matrix pending. **Parent program:** [`docs/architecture/code-structure.md`](../architecture/code-structure.md), Slice 8. **Baseline:** `96f8bfcf`; `GameWindow.cs` is 4,666 raw lines, 196 fields, and 70 methods. The Release suite passes 7,341 tests / 5 fixture or environment skips. The connected lifecycle/reconnect and synchronized nine-stop soak gates pass. **Behavior rule:** This is the final behavior-preserving ownership slice. It must not change accepted input priority, session/reset behavior, update/render order, world presentation, quality settings, or retail gameplay behavior. It may fix resource and callback lifetime defects proven by this slice's ownership audit. ## Progress ledger - [x] A — freeze construction/callback/shutdown order and delete proven dead or test-facade residue. - [x] B — make native-window callback intake an explicit reversible owner and define host-quiescence failure semantics. - [x] C — extract live-session host/reset/binding callbacks and verify the embedded skill formula against named retail. - [x] D — extract retail world-environment/day/weather behavior. - [x] E — extract two-phase raw pointer/camera input, focus, and framebuffer resize behind symmetric named subscriptions. - [x] F — extract the sole gameplay input-action router plus focused combat and diagnostic command owners. - [x] G — extract two-phase persisted settings/display/quality ownership. - [x] H — give terrain atlas, sky shader, retained `UiHost`, and both frame roots explicit single ownership and transfer seams. - [x] I — group `OnLoad` into small ordered, fakeable composition phases with transactional partial-acquisition rollback. Production and failure tests now invoke the same pipeline and carry exact typed prior results. Detailed plan: [`2026-07-22-gamewindow-slice-8-checkpoint-i-ordered-composition.md`](2026-07-22-gamewindow-slice-8-checkpoint-i-ordered-composition.md). - [x] J — move the exact retryable shutdown manifest to a focused lifetime owner and prove all partial-load/reentrant/retry paths. Detailed plan: [`2026-07-22-gamewindow-slice-8-checkpoint-j-lifetime-shutdown.md`](2026-07-22-gamewindow-slice-8-checkpoint-j-lifetime-shutdown.md). - [x] K — in separate #232 commits, add canonical owner snapshots to every soak checkpoint without weakening the process-memory guard. Detailed plan: [`2026-07-22-gamewindow-slice-8-checkpoint-k-canonical-soak.md`](2026-07-22-gamewindow-slice-8-checkpoint-k-canonical-soak.md). - [ ] L — corrected-diff reviews, focused and full Release gates, connected lifecycle/soak, framebuffer comparison, documentation, and memory are complete; only the final user visual handoff remains. Detailed plan: [`2026-07-22-gamewindow-slice-8-checkpoint-l-closeout.md`](2026-07-22-gamewindow-slice-8-checkpoint-l-closeout.md). Checkpoint K leaves `GameWindow.cs` at 1,622 raw lines. The focused lifetime owner holds the typed shutdown roots, exact 18-stage dependency manifest, retry/no-replay state, structured soft-cleanup failures, hard-barrier fallback, and native-window-last release. Deferred same-frame checkpoint capture and two fresh-process nine-stop routes close #232 without weakening the residency guard. App Release passes 3,451 tests / 3 skips and the complete Release suite passes 7,823 / 5 skips. All automated Checkpoint-L gates are complete. Each checked checkpoint lands as a bisectable commit. A checkpoint is not done while a new class delegates a substantial body back into `GameWindow`, stores `GameWindow`, or replaces 196 fields with one runtime/service-locator bag. ## 1. Outcome and non-goals At slice exit `GameWindow` is the native construction shell: ```text GameWindow ├── creates Window + GL + input context ├── invokes ordered composition functions ├── forwards tiny Silk callbacks to typed owners ├── starts LiveSessionController last └── asks GameWindowLifetime to close synchronously ``` The shell may retain injected Core/UI game-state roots whose replacement would be the separately deferred `GameEntity`/client-state aggregation migration. It must not retain AC algorithms, entity scans, session binding/reset bodies, settings algorithms, the input switch, anonymous device subscriptions, or the shutdown operation manifest. This slice does **not**: - alter the frozen twelve-phase update graph or ten-phase render graph; - port a new retail host loop or retire TS-53; - change input bindings, mouse feel, focus/reset semantics, camera formulas, resize/DPI behavior, frame pacing, VSync, MSAA, quality, draw distance, or resource budgets; - change live-session authority, packet parsing, reset order, the 35-second graceful F653 confirmation, reconnect, or transport teardown; - change UI layout, magic, portal presentation, selection, world rendering, or gameplay behavior; - fold full `GameEntity` aggregation, headless mode, Linux support, or GPU particle work into this campaign; - loosen the soak's working/private-memory threshold. ## 2. Frozen host behavior No fresh retail research is required for the host boundaries. One audited exception exists: the embedded skill-formula helper currently cites ACE only, so Checkpoint C must complete the named-retail pseudocode/cross-reference/test workflow before moving or claiming that formula. ### 2.1 Startup and callbacks Preserve this exact order: 1. before `Window.Create`, load persisted Display and resolve VSync/MSAA because these are native-context attributes; 2. create the window and bind `DisplayFramePacingController` immediately; 3. register Load, Update, main Render, pacing Render, Closing, FocusChanged, Move pacing, StateChanged pacing, and FramebufferResize in that order; 4. in `OnLoad`, acquire GL and input from the native window; 5. compose camera/DAT/effects/audio, persisted settings, optional devtools, world/render resources, retained UI, live presentation, streaming, session, teleport, then update/render roots; 6. call `LiveSessionController.Start` last, including when live mode or credentials are absent, because its disabled path still performs the canonical reset. Main Render remains registered before pacing so the wait occurs after all frame work and before Silk's swap. Direct raw MouseMove remains ordered after SilkKeyboard/MouseSource + InputDispatcher subscriptions and before retained `UiHost` device wiring. ### 2.2 Input, focus, and resize Preserve the exact input-action priority: 1. pointer press/release transitions; 2. scroll; 3. combat press/release transitions; 4. Press/DoubleClick gate; 5. retained UI semantic actions; 6. selection interactions; 7. pressed movement/autorun; 8. the remaining UI/debug/player/combat/escape commands. Mouse capture remains three distinct operations: - focus loss and camera-mode exit use lifecycle end and may publish a final movement update; - session reset uses reset semantics and cannot send into the ending session; - process close retires the session first, then releases presentation without an active session. FramebufferResize continues to ignore non-positive sizes, then updates GL viewport, `ViewportAspectState`, camera aspect, and the forced devtools layout reset. It must not mutate retained `UiRoot` size; the next UI draw does that. ### 2.3 Session and reset `LiveSessionController` remains the only session lifecycle owner. The extracted host adapter may hold typed binding/reset collaborators but no second session, generation, identity, GUID, routing, or command map. Preserve `LiveSessionResetManifest` exactly: projection/capture/UI first; equipped projection before the canonical live runtime; live-runtime convergence before identity reset; pending effects/hooks/presentation last. The AC skill formula currently embedded in the window moves only after Checkpoint C adds its missing named-retail citation and conformance tests (or records the proven remaining adaptation). ### 2.4 Update and render `OnUpdate` remains profiler scope plus one immutable `UpdateFrameOrchestrator.Tick`. `OnRender` takes the existing one window-size snapshot and calls one `RenderFrameOrchestrator.Render`. PView's `FramebufferSize` source remains distinct from the logical Window.Size used by the frame/UI/portal/screenshot path. TS-33 and TS-53 remain registered. ### 2.5 Shutdown Closing synchronously completes the retryable transaction while the GL context is current. Direct `Dispose` is the constructed-never-run, Run-failure, and retry fallback. The native window is disposed only after successful completion or the explicitly reported last-resort incomplete fallback described below. The frozen dependency order is: 1. set a no-throw host-quiescence gate and converge live-session shutdown as independent all-attempted **hard** operations; this guarantees F653 and transport teardown before dependents; 2. attempt physical detachment of all window/Silk/UI ingress as explicitly reportable **soft** operations: retry them, record any persistent failure, but do not block now-safe owner/GPU teardown after quiescence; 3. withdraw **both** update and render frame graphs through their shared slot; 4. retire session/UI dependents; 5. clear the live runtime while teardown callbacks remain alive; 6. retire live dependents; 7. wait for submitted GPU work; 8. retire private/render frontends; 9. retire shared textures; 10. retire the mesh adapter; 11. retire remaining render borrowers, including terrain renderer; 12. retire separately owned borrowed assets, including terrain atlas and sky shader, only after their respective renderer stage converges; 13. retire remaining render owners and frame-flight ownership; 14. close DAT mappings; 15. dispose the already-detached input context; 16. dispose GL last; 17. return to `GameWindow.Dispose`, which disposes the native window. The logical quiescence gate makes callbacks inert even when a physical event unsubscribe reports failure. `ResourceShutdownTransaction` therefore gains an explicit non-blocking/reportable operation policy for physical detach only. Those failures remain in the final result and are never swallowed, but they do not strand unrelated resources. Session convergence and GPU drain remain hard barriers. Operations within a stage remain independent and all-attempted. Later stages remain protected until the current stage converges. Successful operations are never replayed on retry or reentrant completion. Silk's `Closing` event is not cancellable. `OnClosing` therefore performs the first synchronous completion attempt and reports an incomplete transaction without pretending success. The outer `Dispose` retries the same retained transaction. If a persistent native/driver failure still prevents convergence, the native window/context is disposed as the explicit last-resort safety net and the incomplete result is logged with the blocked stage; it is never reported as a clean shutdown. Tests pin this fallback instead of assuming a close-cancellation mechanism Silk does not provide. The lifetime state is explicit: `Active`, `RetryableIncomplete`, clean `Complete`, `CompleteWithCleanupFailures`, or terminal `AbandonedIncomplete`. Persistent soft-detach failure followed by otherwise complete teardown produces `CompleteWithCleanupFailures`; repeated Dispose is inert and returns the same immutable non-clean report. Hard-barrier retry is allowed only while the native context is retained. Last-resort native disposal moves to `AbandonedIncomplete`; every later Dispose is inert and reports the retained blocked-stage result without touching GL, callbacks, or the already-destroyed window. ## 3. Architecture and interfaces ### 3.1 Native window intake Add a focused reversible binding equivalent to: ```csharp internal sealed class SilkWindowCallbackBinding : IDisposable { public static SilkWindowCallbackBinding Create( IWindow window, WindowCallbackTargets targets, DisplayFramePacingController pacing); public void Attach(); } ``` `WindowCallbackTargets` is a fixed typed set for Load, Update, Render, Closing, FocusChanged, and FramebufferResize. It is not a general callback list. The binding is published into its lifetime slot after `Create` and before `Attach` begins, so even an attach failure plus rollback failure retains a cleanup owner. Attach treats the current edge as possibly acquired before calling a custom event add accessor and rolls back in reverse order if registration fails. The explicit lifecycle state monitor is released around every external event accessor; external cleanup waits for Attaching/Detaching to converge, while a gate-owned reentrant cleanup reports typed deferred completion instead of deadlocking or falsely succeeding. Dispose detaches in reverse registration order, joins concurrent callers, is idempotent/reentrant-safe, and makes later window events inert. `GameWindow` clears the retained slot only after terminal disposal. The separate pacing Render callback remains ordered after main Render. Every callback enters the shared no-throw host-quiescence monitor, so external shutdown drains an admitted callback, Closing can stop reentrantly, and a failed physical unsubscribe cannot re-enter a retired owner. ### 3.2 Input owners Use two focused owners: - `CameraPointerInputController` owns named raw MouseMove subscriptions, pointer position, camera-mode cursor transitions, focus loss, typed scroll operations, and the existing mode-specific sensitivities. Construction is deliberately two-phase: `AttachRaw` runs after dispatcher/source wiring and before retained `UiHost` wiring; `BindGameplayFrame` fills a focused deferred slot after `GameplayInputFrameController` exists. It consumes canonical `LocalPlayerModeState`, `ChaseCameraInputState`, input capture, and camera owners. - `GameplayInputActionRouter` is the **only** gameplay subscriber to `InputDispatcher.Fired` and owns the frozen priority graph above. Its pointer and scroll edges call typed operations on `CameraPointerInputController`; the pointer owner does not independently subscribe to `Fired`. The router calls existing typed retained-UI, selection, movement, player-mode, interaction, combat-command, and diagnostic-command owners. The window binding, router Fired subscription, pointer raw MouseMove, Combat/Camera events, dispatcher-to-source links, source-to-Silk links, and retained-UI-to-Silk links must all be named and reversible. Shutdown's first stage deactivates them without disposing the input context or the UI owners needed by session reset. `UiHost` therefore exposes a separate idempotent input deactivation seam; its later full Dispose owns windows and rendering. Do not replace these edges with anonymous lambdas retained by a generic subscription bag. Every wrapper on those edges—including Silk sources, dispatcher, raw pointer, retained UiHost, and optional devtools input—checks the same quiescence gate (or performs its no-throw logical deactivate in stage 1). No device callback can re-enter during the potentially 35-second live-session close while physical event removal waits for the following soft-detach stage. Every multi-event Attach is transactional: if the Nth subscription fails, the already-attached prefix is removed in reverse order before the exception escapes. This applies to native window, dispatcher/source/Silk, raw pointer, Combat/Camera, retained `UiHost`, and optional devtools input bindings. ### 3.3 Session and world environment - A focused App session host owns the current selection/entered/reset/binding factories around `LiveSessionLifecycleHost`, `LiveSessionEventRouter`, and `LiveSessionResetManifest`. It resolves the current session through `LiveSessionController`; it does not mirror it. - `WorldEnvironmentController` owns current loaded sky/day state, `AdminEnvirons`, provider refresh, WorldTime synchronization, and Weather changes. The existing retail day-group/weather algorithm moves verbatim. - A named skill-credit resolver owns the formula formerly nested in the session binding only after Checkpoint C verifies it against named retail; until then the current ACE-only interpretation is not overclaimed as retail-faithful. ### 3.4 Settings and diagnostics `RuntimeSettingsController` owns SettingsStore, active toon key, persisted display/audio/gameplay/chat/character values, quality reapply, and UI lock/FPS/combat preferences. It is constructed before `Window.Create` and is the single source for one immutable startup snapshot and Display/VSync/MSAA. After GL/input sources/input dispatcher/camera/audio exist—but still before devtools, the world render dispatcher, terrain, retained UI, or streaming—it applies window/pacing/audio values and resolves the final quality snapshot. Later factories consume that resolved snapshot. A fixed typed `RuntimeSettingsTargets` implementation is late-bound only to support future runtime changes; binding it does not replay startup display or quality transitions. The controller exposes typed state/commands to existing consumers; it does not own those renderers, UI trees, or session state. `RuntimeDiagnosticCommandController` owns command routing for collision wires, time/weather, sensitivity, and nearby-world dumps. State remains solely in its canonical owner: time/weather operations call `WorldEnvironmentController`, sensitivity calls `CameraPointerInputController.AdjustSensitivity`, and world queries use canonical runtime views. It creates no duplicate state or entity cache. Diagnostic algorithms do not remain in the window merely because their input actions originate there. `FramebufferResizeController` is a separate GL-aware typed target. It owns the frozen viewport → `ViewportAspectState` → camera aspect → devtools layout-reset sequence and is not folded into the pointer owner. ### 3.5 Frame-root slots A focused `GameFrameGraphSlot` is the sole publication point for the current `UpdateFrameOrchestrator` and `RenderFrameOrchestrator`. The two Silk stubs resolve through this slot; `GameWindowLifetime` withdraws it after session convergence and before borrowed owners retire. Clearing a lifetime snapshot is not withdrawal while a direct window field can still invoke the graph. ### 3.6 Ordered composition `OnLoad` invokes the narrow production platform phase that owns `GL.GetApi(_window)` and `_window.CreateInput()`, then invokes small composition functions at these existing boundaries: 1. host input/camera; 2. content/effects/audio; 3. persisted settings/devtools; 4. world/render resources; 5. interactions/retained UI; 6. live presentation/landblock publishers; 7. streaming/session/local player/teleport; 8. update/render roots; 9. session start. Each function receives only typed dependencies and may return a small immutable result needed by the next function. There is no stored mega-context. Stable owners are copied to locals before retained delegates are constructed so those delegates cannot capture `GameWindow` accidentally. Construction cycles use the existing focused deferred slots; they do not use callbacks into the window. The production ordering lives in a fixed `GameWindowCompositionPipeline` with typed phase interfaces/factories. Tests invoke that same pipeline with fake platform/acquisition phases; no test-only clone or source-text assertion stands in for partial-load execution. A narrow production `GameWindowPlatformAcquisition` phase is invoked by `OnLoad` and alone calls `GL.GetApi(window)` and `window.CreateInput()` through injectable factories. It publishes GL to the lifetime before attempting input, then publishes input before later phases. Tests execute this exact method with fake factories, including GL success followed by input failure. Each concrete phase uses a transactional acquisition scope so failure after any internal acquisition unwinds the exact prefix. Every acquired disposable is published to the lifetime owner immediately. A composer that cannot publish incrementally must unwind its own partial prefix before throwing. The portal-tunnel transfer remains explicit: publish fallback, prepare GL resources, transfer to `LocalPlayerTeleportController`, then clear the fallback before frame graphs are published. Retained UI uses one `RetailUiRuntimeLease` retained by `GameWindowLifetime` from Host construction through final teardown. The lease initially owns `UiHost`, retains a partially constructed `RetailUiRuntime` before Initialize, and exposes the runtime as a borrower only after Mount succeeds. Constructor failure leaves Host in the lease; Initialize/cleanup failure leaves the exact partial runtime in the lease for later retry; success makes lease disposal call runtime disposal. There is no fallback-to-runtime ownership gap and never two independent host disposers. ### 3.7 Lifetime owner `GameWindowLifetime` owns the one `ResourceShutdownTransaction` and typed teardown-only roots. It does not expose runtime service lookup or gameplay operations. It exists before `Window.Create`, so window/bootstrap acquisitions can publish their ownership immediately. Its transaction preserves §2.5 and fixes these audited gaps: - update and render orchestrators are both withdrawn; - `TerrainAtlas` residency/textures are explicitly released after submitted work and before GL; - the dedicated sky `Shader` is explicitly disposed; - a published `UiHost` is disposed even if `RetailUiRuntime.Mount` fails; - window, dispatcher, pointer, combat, camera, and UI-root callbacks detach before the owners they target. ## 4. Detailed checkpoint execution ### A — freeze and prune - Add structural freeze tests for the current startup/session-start, input, resize, update/render, and shutdown boundaries; later checkpoints replace these with functional owner tests rather than treating source checks as final acceptance. - Extend `ResourceShutdownTransactionTests` for multiple same-stage failures, failure then explicit retry, empty stages, and reentrant completion. - Delete only proven dead/test-facade residue: `_capturedMouse`, obsolete `_streamingRadius`, unused snap constants, `IsPlayerGuid`, `IsDoorName`, and test-only forwarding helpers. Tests call canonical owners directly. Result: the exact native attributes/callbacks, input subscription priority, frame-root/session-start boundary, framebuffer behavior, shutdown stages, and native-window-last edge are frozen. Dead duplicate state and two test-only window facades are removed. Three corrected-diff reviews are clean; 56 focused tests and the complete App suite (2,991 pass / 3 intentional skips) pass. ### B — native window binding and host quiescence - Implement exact attach/reverse-detach/rollback and the no-throw quiescence gate. - Replace direct `Run` event wiring with one owned binding while preserving the two Render handlers and their order. - Add post-detach silence, failure-after-Nth-attach, repeated/reentrant Dispose, callback-during-detach, and persistent physical-detach tests. Result: one fixed typed binding now owns the exact nine Silk edges, including the two ordered Render callbacks. Create/publish/Attach and the explicit lifecycle state preserve cleanup ownership across partial event-accessor failure, rollback failure, concurrent or reentrant shutdown, and condition wakeups. The shared host gate drains admitted callbacks and makes failed physical detach logically inert. Three corrected-diff review loops are clean; 54 focused tests, the App suite (3,027 pass / 3 intentional skips), and the full Release suite (7,386 pass / 5 intentional skips) pass. No connected gate was required because this checkpoint changes ownership only and preserves the frozen callback behavior. ### C — live-session host and skill formula - Extract selection/entry/reset/binding factories around the existing canonical session, router, command, and reset owners. - Before moving the formula, write pseudocode for `SkillFormula::Calculate @ 0x00591960`, cross-check the DAT field semantics against ACE plus a second reference, then add conformance tests. If current behavior differs, register it rather than silently calling the ACE-only formula retail-faithful inside a structural commit. - Keep `LiveSessionController.Start` last; both disabled-live and missing-credential starts must execute the reset path. Result: `LiveSessionHost` now owns reset-plan construction, exact selection and entered-world ordering, and create→attach route factories while resolving all session/command/in-world state through the sole `LiveSessionController`. Partially attached routes and every individual subscription edge retain failed cleanup work; successful edges are never replayed, and reset/new generations remain blocked until teardown converges. Named-retail research corrected the former ACE-only skill shortcut to exact unsigned `SkillFormula::Calculate @ 0x00591960` semantics. Three corrected-diff review loops are clean; focused session/formula/ledger tests, the App suite (3,048 pass / 3 intentional skips), Core.Net (548 pass), the Release build, and the full suite (7,408 pass / 5 intentional skips) pass. No connected gate was required for this ownership checkpoint; the final connected lifecycle gate remains Checkpoint L. ### D — world environment - Move loaded sky/day state, `RefreshSkyForCurrentDay`, `AdminEnvirons`, WorldTime synchronization, provider swaps, and Weather changes verbatim into `WorldEnvironmentController`. - Preserve existing named-retail citations and registered sound adaptation; diagnostics call typed commands rather than owning time/weather state. Result: `WorldEnvironmentController` is now the sole owner of the clock, loaded sky descriptor, selected day group, Weather state, server time sync, AdminEnvirons bridge, and time/weather debug cycles. `GameWindow` preserves its public readonly clock/weather aliases but only composes the owner into render and session seams. Initialization is explicitly one-shot, and missing GameTime restores the documented fallback origin instead of inheriting process-global state. Named-oracle review corrected the day picker to `SkyDesc::CalcPresentDayGroup @ 0x00500E10` and AdminEnvirons to `CPlayerSystem::Handle_Admin__Environs @ 0x0055DE20`; TS-54/TS-55 now register the carried centered-audio and complete fog/ambient/radar gaps. Three corrected-diff reviews are clean; 17 focused tests, the App suite (3,059 pass / 3 intentional skips), the warning-free Release build, and the full suite (7,419 pass / 5 intentional skips) pass. No connected gate was required for this behavior-preserving ownership checkpoint. ### E — pointer, focus, and framebuffer resize - Make SilkKeyboard/Mouse sources and dispatcher links reversible, then attach the raw pointer owner in the existing pre-UiHost order. - Late-bind the gameplay-frame slot without resubscribing or reordering input. - Extract camera mode, lifecycle focus loss, scroll, and sensitivity state. - Extract the independent framebuffer resize target and pin logical Window.Size versus FramebufferSize behavior. - Require rollback after every Nth event add and silence between every shutdown stage for raw/retained/devtools device events. Result: `CameraPointerInputController` now owns raw move, camera-mode cursor, focus-loss, scroll, and per-mode sensitivity policy; its gameplay-frame edge is late-bound without resubscription. Silk keyboard/mouse sources, `InputDispatcher`, retained UI bindings, and the devtools `QuiescentInputContext` are publish-before-attach, terminal after disposal, transactional on every side-effecting event add, and retry only the physical edges that remain pending. Mouse-only hosts retain camera/cursor behavior. `FramebufferResizeController` is the sole physical framebuffer publisher and seeds viewport/aspect/camera state from `FramebufferSize`, while logical UI and frame dimensions remain `Window.Size`. Shutdown now performs no-throw logical input cutoff, retires the live session, then removes physical callbacks; the post-session mouse-look release therefore cannot send a final movement packet, and a bad Silk remove accessor cannot block F653/transport teardown. TS-56 records the carried non-retail camera input scalars. Three corrected-diff review loops are clean; 66 focused App tests, 9 dispatcher-lifetime tests, 5 Core input integration tests, the warning-free production Release build, and the complete Release suite (7,477 pass / 5 intentional skips) pass. `GameWindow` is 4,266 raw lines / 194 fields / 65 methods. No connected gate was required for this behavior-preserving ownership checkpoint; Checkpoint L retains the final connected lifecycle and visual gates. ### F — gameplay action and command routing - Move the frozen action-priority graph into the sole Fired subscriber. - Extract combat mode command behavior and diagnostic command routing to typed owners; retained UI, selection, movement, player mode, and item interaction remain canonical. - Make Combat, Camera, dispatcher, and retained-root subscriptions named, transactional, and symmetrically detached. Result: `GameplayInputActionRouter` is the sole gameplay subscriber to `InputDispatcher.Fired` and preserves the frozen pointer → scroll → combat → Press/DoubleClick gate → retained UI → selection → movement → command priority. Focused command owners now route combat, diagnostics, window/player mode, item-target mode, and Escape without calling feature bodies on `GameWindow`. `RetainedUiGameplayBinding` owns the outside-UI item-drop edge; the combat/diagnostic deferred slots release their targets before session retirement, and the retained binding detaches transactionally afterward. Named-retail review also corrected `ToggleCombatMode @ 0x0056C8C0`: active combat short-circuits to peace without an equipment lookup, while an incompatible Held object prints the exact retail notice and sends no mode request. Three corrected-diff review loops are clean; 54 focused App tests, 20 Core combat tests, the App suite (3,155 pass / 3 intentional skips), the Release build, and the complete suite (7,524 pass / 5 intentional skips) pass. `GameWindow` is 4,057 raw lines / 198 fields / 54 methods. ### G — two-phase runtime settings - Construct `RuntimeSettingsController` before Window.Create and source startup Display/VSync/MSAA from it. - After GL/camera/audio and before devtools/world, apply startup display/pacing/audio and resolve the immutable quality snapshot consumed by downstream factories. - Late-bind typed runtime targets without replaying startup transitions, then move runtime display/quality changes, frame-rate/UI-lock/combat preferences, and toon-scoped state. - Preserve restart-required quality behavior and test transitions/previews without requiring GL. **Implementation result:** one pre-window `RuntimeSettingsController` now owns the concrete settings store, the immutable startup snapshot, current Display / Audio / Gameplay / Chat / Character values, the active toon, resolved quality, and the optional Settings draft. Startup applies pacing, window state, saved FOV, and audio in order exactly once; a failed later substep retries without replaying a successful earlier substep. Complete runtime targets bind only after their borrowers exist and binding performs no replay. Display saves keep the persistence → live window → snapshot → quality order; quality applies alpha-to-coverage → anisotropy → render range → streaming → completion budget. Combat preference changes merge only their three fields into a live draft, so unrelated unsaved Gameplay edits survive. Saved FOV now applies without devtools, correcting the old accidental SettingsVM gate. `/framerate` retains the named-retail live toggle/notice and keeps acdream's shipped cross-launch persistence as documented AP-121. UI-lock convergence requires target, persistence, and Settings baseline publication; a failed substep keeps the same-value command retryable. `GameWindow` is 3,663 raw lines / 162 fields / 37 methods. Thirty-five focused App settings/boundary tests, all 43 `SettingsVMTests`, the UI Abstractions Release suite (534 pass), and the App Release suite (3,183 pass / 3 intentional skips) pass. All three independent corrected-diff reviews are clean; the production App Release build has zero warnings/errors, and the complete Release suite passes 7,553 tests / 5 intentional skips (17 existing test-project warnings remain tracked by #228). ### H — explicit single resource ownership and frame slots - Publish TerrainAtlas and the dedicated sky Shader as separate lifetime roots; renderers remain borrowers and retire before the sole atlas/shader disposal. - Publish `RetailUiRuntimeLease` before Host/Mount acquisition; add separate idempotent input deactivation and test constructor failure, Initialize failure with successful cleanup, transient cleanup followed by lifetime retry, persistent cleanup followed by terminal abandonment, and exactly one Host disposal/no unowned Host on every path. - Publish update/render roots only through `GameFrameGraphSlot` and withdraw the slot after session convergence. - Pin portal fallback/transfer unchanged and test every normal/partial prefix for no leak or double delete. - Make `Shader` construction and `TerrainAtlas.Build` internally exception-safe; phase scopes cannot recover GL names created inside a factory that throws. Inject GL compile/link/texture-allocation failure after every internal name and prove exact rollback/residency release. Checkpoint H is complete. `GameRenderResourceLifetime` is the sole terrain- atlas and dedicated-sky-shader owner; renderers borrow and retire before those roots. `RetailUiRuntimeLease` retains the Host/runtime chain through partial construction, input cutoff, retryable disposal, and explicit terminal abandonment. `GameFrameGraphSlot` publishes update/render roots atomically, and the portal tunnel now uses one prepare-aware fallback/transfer transaction. Shader, terrain, text-renderer, buffer/VAO, bindless, and texture-binding construction/mutation paths use always-on checked GL commit boundaries. A failed cleanup retains the exact name/handle/binding obligation for retry, and successful substeps never replay. `GameWindow` is 3,689 raw lines / 162 fields / 37 methods. The focused ownership gate passes 61 tests, the App Release suite passes 3,236 tests / 3 intentional skips, and all three independent final corrected-diff reviews are clean. The complete Release suite passes 7,606 tests / 5 intentional skips; the 17 existing test-project warnings remain tracked by #228. ### I — ordered production composition - Split the 2,289-line `OnLoad` body at §3.6 boundaries using the fixed typed production pipeline, small immutable phase results, and no stored mega-context. - Remove retained GameWindow captures via stable locals, typed adapters, and existing deferred slots. - Run the same pipeline with fake acquisition phases and inject failure after platform, GL, input, DAT/effects, render resources, retained UI, live/session, teleport transfer, and frame-root publication. Each concrete phase also proves transactional rollback of its internal acquisition prefix. Result: all nine production phases now run through the same executable pipeline as the prefix/failure oracle. Platform and settings results are explicit typed inputs wherever consumed; phases reject mismatched instances, all long-lived owners publish to focused lifetime slots, the frame pair publishes atomically, and session start is terminal. `GameWindow.cs` is 1,945 raw lines. Three corrected-diff passes are clean; App Release passes 3,431 tests / 3 skips and the complete Release suite passes 7,803 tests / 5 skips with the existing 17 #228 warnings. No connected gate was required for the final structural correction; Checkpoint L retains the connected lifecycle and soak gates. ### J — lifetime cutover and shutdown failure policy - Move the teardown-only stage records and shutdown manifest out of GameWindow. - Co-stage no-throw quiescence and live-session convergence as hard operations; retry/report physical detach as non-blocking operations, withdraw both frame graphs next, then preserve the remaining frozen order. - Cover constructed-never-run, Load-never-fired, normal WM_CLOSE, WM_CLOSE then Dispose, direct/repeated/reentrant Dispose, transient/persistent failures, session deferred disposal, optional-devtools absence, GPU-drain failure, and every partial-load prefix. - Verify acquired owners dispose exactly once, unacquired owners never dispose, completed operations never replay, and native-window fallback is last and explicitly reported incomplete when a non-cancellable close cannot converge. - Verify persistent physical-detach failure still retires downstream owners and is reported, while persistent session/GPU barriers still protect dependents; after native fallback the terminal abandoned state makes repeated Dispose inert. Result: `GameWindowLifetime` owns the typed root snapshot, 18-stage manifest, transaction progress, terminal report, and native window. Clean, soft-failure, hard-failure, native-failure, retry, reentrant, and never-run paths are pinned. The UI host remains explicitly rooted through failed physical detach until the native edge is gone; successful finalization releases the completed lifetime graph, while abandonment retains it. No shutdown stage remains in `GameWindow`, which is now 1,625 raw lines. App Release passes 3,441 tests / 3 skips and the complete Release suite passes 7,813 / 5 skips. ### K — canonical soak checkpoints (#232, separate commit) - Extract `WorldLifecycleResourceSnapshotSource` from the window and reuse the existing render diagnostics source where fields overlap. - Change `checkpoint ` from an immediate retained-UI-time capture to a FIFO request with an acknowledgement token. The script runner treats that token as a command barrier: it executes no later command until the token is resolved. After private presentation returns and `RenderFrameDiagnosticsController.Publish` has published the current frame, a post-diagnostics checkpoint phase drains requests using that same immutable `RenderFrameOutcome` plus one sample from every canonical source. This avoids previous-frame diagnostics mixed with current-frame owner counts. - Mark the token Succeeded only after serialization/write completes. Deferred capture/write failure marks it Failed, and the runner stops with that exact error on its next tick. Preserve request sequence/name across the deferred edge, drain independent producers in FIFO order, and cancel pending tokens with an explicit shutdown result. - Store one token against the active script-command index. Repeated pending ticks poll that token and never enqueue again—even when a render failed before the post-diagnostics drain. Clear it only after Success, Failure, or Cancellation is consumed; one command therefore produces one request, write, and sequence increment. - Add exactly nine ordered named `checkpoint` commands, parse the JSONL into the soak report, and assert checkpoint identity/order. - Gate pending teardown, retirement, staging, and warmup at zero; compare exact canonical owner/cache counts and bytes at Caul return → Caul plateau; label authoritative entity/animation population changes as workload warnings. - Preserve process working/private memory as a separately labelled secondary residency guard with unchanged thresholds. Require two fresh-process clean route runs before closing #232. Result: deferred acknowledged checkpoints now drain after current-frame render diagnostics, persist the exact frame outcome plus canonical resource owners, and block the script until both artifacts commit. Seventy-four focused tests, App Release, the full Release suite, and two 403-second fresh-process routes pass. Every route produced the exact nine checkpoints, zero pending/staged/ warmup work, no unconfounded canonical owner growth, graceful exit, and the unchanged process/performance limits. Commits: `bca41487`, `6c5e0604`. ### L — final closeout - Run three independent corrected-diff reviews: retail conformance, architecture/integration, and adversarial lifecycle/failure analysis. - Resolve every confirmed finding and re-review until clean. - Run focused App/Core/UI tests, Release build, and the complete Release suite. - Run connected lifecycle/reconnect and two fresh-process synchronized nine-stop soaks; compare stable framebuffer checkpoints with Slice 7. - Audit every active divergence row that still points at `GameWindow`; retarget ownership paths only. Keep TS-53 and other unresolved mechanisms open. - Update architecture, milestones, roadmap, issues, AGENTS/CLAUDE, and durable memory with final metrics and exact gates. Automated result: 293 focused tests and the 7,823/5 complete Release suite pass. The 314.4-second capped/reconnect lifecycle route passes with six valid PNGs and graceful exits. Its current deterministic frames preserve Slice 7 commit `9d7df1bf` geometry, UI/paperdoll layering, private viewports, depth/alpha, and reveal; live entity/particle/vitals/camera timing account for the accepted differences. All three final corrected-diff reviews are clean. The user's connected visual matrix is the sole remaining acceptance item. ## 5. Automated acceptance - exact window callback attach order, reverse detach, rollback, reentrancy, and post-detach silence; - transactional rollback after every Nth add for all multi-event bindings, plus retained/devtools/raw device silence between every shutdown stage; - exact input subscription/priority order and focus/reset/close semantics; - exact resize order and non-positive-size rejection; - disabled-live and missing-credentials startup still perform reset; live startup remains last; - PView still reads FramebufferSize while RenderFrameInput, retained UI, portal/private presentation, and screenshots share one Window.Size snapshot; - exact session reset trace and current-session borrowing; - partial-load rollback at every composition checkpoint; - TerrainAtlas, sky Shader, UiHost, frame graphs, GPU-flight, DAT, input, GL, and native window have explicit tested lifetimes; terrain/sky renderers remain borrowers and cannot also dispose the separately owned atlas/shader; - throwing Shader/TerrainAtlas leaf factories release every internal GL name and bindless-residency prefix; - shutdown retry/all-attempted/no-replay semantics remain intact; - persistent non-cancellable close fallback names the blocked stage and never reports a clean shutdown; - completed teardown with soft-detach failures reports immutable `CompleteWithCleanupFailures`, and repeated Dispose is inert; - no anonymous MouseMove subscription and no substantial Silk callback body; - no stored `GameWindow`, broad service locator, or feature-owner callback facade into the window; the fixed native `WindowCallbackTargets` binding is the intentional host-boundary exception; - `OnLoad` is ordered composition, `OnUpdate`/`OnRender` remain one handoff, and `OnClosing`/`Dispose` delegate to one lifetime owner; - all canonical soak snapshots are post-diagnostics same-frame atomic, round-trip, preserve request/name order across the deferred edge and nine-name order across two fresh processes, and name the exact owner/property on growth; - checkpoint acknowledgement blocks following script commands, propagates deferred write failure, and reports shutdown cancellation; - repeated pending ticks enqueue exactly once and cannot duplicate a checkpoint after a failed/delayed render; - complete Release suite, lifecycle gate, soak gate, and framebuffer comparison pass. ## 6. Final visual handoff The only user pause is one connected visual smoke gate after all automation is green: - first login world bootstrap and radar; - movement, mouse look/orbit, resize, focus loss/return, combat toggle; - inventory/skills/spellbook shared panel and retained UI input; - outdoor, building, dungeon, portal/recall, paperdoll, particles, alpha; - graceful close and fresh-process reconnect. After that pass the GameWindow structural campaign is complete. The roadmap returns to the carried M3 magic/spell-bar/spellbook/component-book and final two-client portal-out/materialization visual gates before new M4 feature work.