acdream/docs/plans/2026-07-22-gamewindow-slice-8-checkpoint-i7-session-player.md
Erik 7771c07fb6 refactor(app): compose session and player startup
Move streaming, live-session, hydration, local-player, combat, and teleport construction behind the typed Phase-7 boundary. Add exact-owner runtime bindings and focused spawn-claim classification so partial startup rolls back without retaining old session targets while preserving the accepted construction and frame dependencies.

Co-authored-by: Codex <codex@openai.com>
2026-07-22 18:28:32 +02:00

8.9 KiB

GameWindow Slice 8 — Checkpoint I.7 Session and Player Composition

Status: Complete 2026-07-22

Parent: 2026-07-22-gamewindow-slice-8-checkpoint-i-ordered-composition.md

Scope: Ordered-composition Phase 7 only

1. Outcome

Move the complete streaming, session, hydration, local-player, and teleport construction body out of GameWindow.OnLoad without changing accepted movement, network, world-reveal, combat, portal, or render-frame behavior. GameWindow remains a write-only publication surface and shutdown shell.

This is a structural ownership move. It does not alter retail algorithms or add a divergence-register row.

2. Exact production order

SessionPlayerCompositionPhase preserves the current order:

  1. resolve near/far streaming radii from the immutable quality snapshot and legacy override;
  2. construct and start LandblockStreamer under immediate rollback ownership;
  3. construct StreamingController, origin recentering, runtime settings targets, and WorldRevealCoordinator;
  4. construct the network-update bridge, sealed-dungeon classifier, projection materializer, and world-origin coordinator;
  5. construct and bind LiveSessionController plus local physics timestamps;
  6. construct teardown, deletion, hydration, network-update, liveness, and inbound-session owners;
  7. bind component teardown, landblock hydration, parent acceptance, same-generation network updates, entity-ready, and appearance-applied;
  8. bind live combat operations;
  9. construct mouse-look/gameplay input, streaming-frame, effect-frame, spatial reconciliation, local animation/shadow/projection/frame, and live-object frame owners;
  10. construct player-mode and auto-entry owners and bind developer commands;
  11. transfer the prepared portal tunnel into the sole local-teleport owner;
  12. bind the teleport network sink and retained selection view plane;
  13. publish one complete SessionPlayerResult and transfer rollback ownership.

No live connection starts in this phase. Terminal session start remains Phase 9 so a server cannot publish into a partial frame graph.

3. Typed inputs and outputs

SessionPlayerDependencies contains only stable App owners and state sources. It never stores GameWindow or accepts a callback to a substantial window method. Phase results supply content, render, interaction, and live-presentation owners directly.

SessionPlayerResult carries the exact owners required by Phase 8 and shutdown:

  • streamer, streaming controller, origin recenter, and world reveal;
  • live-session, hydration, network-update, liveness, and inbound-session controllers;
  • gameplay input, streaming-frame, local animation/shadow, live-object frame, player-mode, and auto-entry owners;
  • local teleport owner;
  • one named runtime-binding aggregate.

IGameWindowSessionPlayerPublication publishes those exact identities only after all mandatory resources and binds succeed. Replacement is rejected before any field changes.

4. Focused owners and seams

4.1 Spawn-claim classifier

Move the memoized indoor spawn-claim range check from GameWindow into DatSpawnClaimHydrationClassifier. It retains the exact cell-number boundary, DAT lock, and one-claim memoization. The world-reveal coordinator receives its typed IsUnhydratable method rather than a window callback.

4.2 Runtime bindings

SessionPlayerRuntimeBindings owns named exact-owner leases and releases them in reverse order. Successful releases are removed immediately; failed releases remain retryable without replaying completed work.

The aggregate owns:

  • retained-UI live-session authority;
  • runtime settings targets;
  • live parent acceptance;
  • hydration network bridge;
  • exact EquippedChildRenderController.EntityReady delegate;
  • exact LiveEntityHydrationController.AppearanceApplied delegate;
  • combat attack operations;
  • camera-pointer gameplay frame;
  • developer player-mode and command-bus targets;
  • local teleport network sink;
  • retained selection view-plane authority.

The live-runtime component lifecycle remains attached through the Phase-6 binding owner because it must outlive session teardown and stay callable until LiveEntityRuntime.Clear completes. Landblock-loaded hydration may use that same late lifetime when its publisher outlives the session result.

4.3 Portal transfer

The prepared tunnel follows the existing single-owner transaction:

Phase 6 fallback slot -> Phase 7 LocalPlayerTeleportController

If the destination factory throws, the fallback retains the tunnel. Once the controller exists, Phase 7 immediately owns it for rollback. A later failure disposes the controller and tunnel exactly once; the fallback is already empty.

4.4 Streamer and session rollback

The streamer is scope-owned before Start. Any later Phase-7 failure disposes it, which joins the worker and releases pending work. The live-session controller is also scope-owned immediately. Rollback order is:

  1. detach external bindings;
  2. dispose local teleport if transfer completed;
  3. dispose live-session ownership;
  4. dispose the streamer;
  5. aggregate and retain any incomplete cleanup for retry.

Normal shutdown remains behaviorally ordered: quiesce input, gracefully retire the live session and reset graph, withdraw frame borrowers, detach Phase-7 bindings, stop the streamer, clear live entities, then release presentation and GL owners.

5. Publication and cutover

  • OnLoad calls one SessionPlayerCompositionPhase.Compose(...) paragraph.
  • The old radius, streamer, session, hydration, player, and teleport construction body is deleted.
  • Phase 8 consumes SessionPlayerResult; it does not rediscover the new owners through nullable window fields.
  • Existing steady-state/reset code may temporarily read published fields until Checkpoint I.8 completes the root cutover.
  • No second GUID map, world state, input subscriber, portal owner, or session authority is introduced.

6. Automated gates

Construction and rollback

  • exact construction trace, including streamer-start and portal-transfer positions;
  • failure before and after streamer start stops the worker exactly once;
  • failure at every bind/publication boundary releases in reverse order;
  • partial cleanup retries only failed edges and never replays completed ones;
  • portal destination-factory failure preserves fallback ownership;
  • later failure disposes the transferred teleport owner exactly once;
  • publication rejects replacement atomically.

Binding and lifetime

  • exact-owner unbind and stale-token rejection for every new deferred seam;
  • EntityReady and AppearanceApplied detach the exact delegates once;
  • callbacks are safe before bind and inert after deactivation where the source contract permits it;
  • live-runtime component teardown stays bound until live records are cleared;
  • session/UI/command targets cannot retain a failed Phase-7 graph;
  • runtime settings targets do not replay startup values when bound;
  • no duplicate input, combat, streamer, hydration, or portal owner.

Behavior and structure

  • live/offline gates and initial placeholder origin remain unchanged;
  • near/far and legacy radius selection are byte-for-byte equivalent;
  • spawn-claim cell boundaries preserve the former memoized behavior;
  • session packet routing, hydration order, combat target selection, player-mode auto-entry, and portal presentation remain unchanged;
  • GameWindow contains no Phase-7 construction body or spawn-claim algorithm;
  • App Release tests, clean solution Release build, and full Release tests pass;
  • source/divergence audit and three self-review passes are clean.

7. Exit evidence

I.7 is complete when Phase 7 is the production path, every Phase-7 external edge has explicit reversible ownership, failure and retry gates pass, the old window body is gone, documentation/memory report the measured class size and test totals, and the commit is independently buildable. I.8 then composes the update/render roots and terminal session start over the typed result graph.

8. Completion evidence

  • SessionPlayerCompositionPhase is the production Phase-7 path. The former 432-line radius/streaming/session/hydration/player/teleport block is absent from GameWindow.
  • SessionPlayerRuntimeBindings plus exact-owner tokens cover every Phase-7 late edge. Focused tests cover reverse retry, rebind, and stale-token safety.
  • DatSpawnClaimHydrationClassifier owns the former window memo and exact indoor-cell boundaries, including missing/empty DAT cases and reset.
  • GameWindow.cs is 2,479 raw lines, down 13,244 lines (84.2%) from the 15,723-line campaign baseline.
  • App Release: 3,420 passed / 3 intentional skips. Complete Release suite: 7,792 passed / 5 intentional skips. Clean solution build: 0 errors and the 17 pre-existing test warnings tracked by #228.
  • Behavior/order, architecture/ownership, and adversarial rollback reviews are clean. No gameplay mechanism changed and no divergence row was introduced.