Extract reset, selection, entered-world, and route construction behind LiveSessionHost while preserving the sole LiveSessionController authority. Retain partial route and subscription cleanup for retry, and replace the embedded ACE-only shortcut with the exact named-retail unsigned skill formula. Co-authored-by: Codex <codex@openai.com>
651 lines
34 KiB
Markdown
651 lines
34 KiB
Markdown
# GameWindow Slice 8 — composition and lifecycle shell
|
|
|
|
**Status:** Active 2026-07-22.
|
|
**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.
|
|
- [ ] D — extract retail world-environment/day/weather behavior.
|
|
- [ ] E — extract two-phase raw pointer/camera input, focus, and framebuffer
|
|
resize behind symmetric named subscriptions.
|
|
- [ ] F — extract the sole gameplay input-action router plus focused combat and
|
|
diagnostic command owners.
|
|
- [ ] G — extract two-phase persisted settings/display/quality ownership.
|
|
- [ ] H — give terrain atlas, sky shader, retained `UiHost`, and both frame roots
|
|
explicit single ownership and transfer seams.
|
|
- [ ] I — group `OnLoad` into small ordered, fakeable composition phases with
|
|
transactional partial-acquisition rollback.
|
|
- [ ] J — move the exact retryable shutdown manifest to a focused lifetime
|
|
owner and prove all partial-load/reentrant/retry paths.
|
|
- [ ] K — in a separate #232 commit, add canonical owner snapshots to every soak
|
|
checkpoint without weakening the process-memory guard.
|
|
- [ ] L — corrected-diff reviews, focused and full Release gates, connected
|
|
lifecycle/soak, framebuffer comparison, documentation, memory, and final
|
|
visual handoff.
|
|
|
|
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.
|
|
|
|
### 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.
|
|
|
|
### 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.
|
|
|
|
### 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.
|
|
|
|
### 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.
|
|
|
|
### 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.
|
|
|
|
### 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.
|
|
|
|
### K — canonical soak checkpoints (#232, separate commit)
|
|
|
|
- Extract `WorldLifecycleResourceSnapshotSource` from the window and reuse the
|
|
existing render diagnostics source where fields overlap.
|
|
- Change `checkpoint <name>` 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.
|
|
|
|
### 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.
|
|
|
|
## 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.
|