acdream/memory/project_gamewindow_decomposition.md
Erik f9736ece6c fix(runtime): restore interaction completion ownership
Preserve prepublication local motion completion, require the PartArray enter-world lifecycle port, and balance deferred Use busy ownership across dispatch and cancellation. Reconcile the completed GameWindow connected gates and add regression coverage.

Co-authored-by: Codex <codex@openai.com>
2026-07-23 05:51:51 +02:00

234 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# GameWindow decomposition — current truth
## Current state
All eight behavior-preserving App ownership slices and their automated closeout
are complete. `GameWindow.cs` moved from the 2026-07-21 baseline of 15,723
lines / 278 fields / 205 methods to a 1,622-line native
composition/callback shell: 14,101 lines (89.7%) were removed without changing
accepted gameplay or rendering behavior. The user's final connected visual
matrix passed 2026-07-23; the campaign is complete.
| 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 |
| 7 | complete render-frame orchestration and failure recovery | 4,666 / 196 / 70 |
| 8 AE | shell freeze, native/session/environment composition, reversible pointer/input/framebuffer ownership | 4,266 / 194 / 65 |
| 8 F | sole gameplay action route, typed commands, retained-root callback lifetime | 4,057 / 198 / 54 |
| 8 G | pre-window/runtime settings ownership, one startup snapshot, inert late target binding | 3,663 / 162 / 37 |
| 8 H | render/UI/frame/portal resource roots plus checked retryable GL leaves | 3,689 / 162 / 37 |
| 8 I | executable ordered startup composition and terminal session start | 1,945 / startup shell |
| 8 J | retryable typed lifetime/shutdown owner | 1,625 / lifetime shell |
| 8 KL | acknowledged canonical soak capture and automated closeout | 1,622 / native shell |
Slice 8 is an ordered checkpoint campaign rather than another feature-body
move. A froze/pruned the shell boundary; B gave all nine native window callback
edges one reversible owner plus host quiescence; C added `LiveSessionHost` for
reset/selection/entry/route composition while keeping `LiveSessionController`
the sole session owner. C also replaced the embedded ACE shortcut with the
named-retail `SkillFormula::Calculate @ 0x00591960` port. Partial route
construction and individual detach edges are retained and retried; reset and a
new generation cannot pass an incompletely detached route. D added
`WorldEnvironmentController` as the one-shot owner of WorldTime, loaded sky,
day-group selection, Weather, server synchronization, AdminEnvirons, and debug
cycles. `GameWindow` retains only ABI-compatible readonly aliases and typed
composition edges. The named-oracle correction is
`SkyDesc::CalcPresentDayGroup @ 0x00500E10`; the carried AdminEnvirons audio and
full fog/ambient/radar gaps are TS-54/TS-55.
E adds `CameraPointerInputController`, `FramebufferResizeController`, terminal
publish-before-attach Silk/dispatcher/retained input owners, and a quiescent
non-owning input-context view for optional devtools. Mouse-only hosts still
receive raw camera/cursor behavior. Logical callback deactivation runs before
the graceful session close; physical removal and the local mouse-look release
run only after session retirement. This prevents both copied callback reentry
and a failed event accessor from blocking F653/transport teardown. The carried
non-retail post-filter camera scalars are explicitly registered as TS-56.
F adds `GameplayInputActionRouter` as the sole `InputDispatcher.Fired`
subscriber while preserving the frozen action priority. Typed command owners
replace the remaining combat, diagnostic, window/player mode, item-target,
and Escape bodies. `RetainedUiGameplayBinding` owns the outside-UI item-drop
event. The two deferred command slots release their targets before session
retirement; the retained binding alone detaches its physical edge
transactionally afterward. Retail
review also corrected the carried default-combat mismatch: active combat
short-circuits directly to peace, and an incompatible Held object prints the
exact retail notice without a wire request or local mode mutation.
G adds `RuntimeSettingsController` as the sole concrete settings-store,
current-state, startup-snapshot, resolved-quality, active-toon, and optional
Settings-draft owner. It is constructed before `Window.Create`; startup applies
monitor pacing, window state, saved FOV, and audio in order once, with
substep-granular retry after failure. Complete runtime targets bind only after
UI/terrain/dispatcher/render-range/streaming exist and binding performs no
replay. The Settings save order and five-step quality application order remain
frozen. Combat mutations preserve unrelated unsaved Gameplay draft fields, and
successful external gameplay commands advance only their fields in the
SettingsVM persisted baseline so Cancel cannot resurrect stale command state.
UI-lock target, persistence, and baseline publication share an explicit
convergence flag so target/save failures remain retryable for the same value.
Saved FOV now applies without devtools, fixing the former accidental
SettingsVM gate. AP-121 records the intentional modern persistence added to
the named-retail `/framerate` live toggle/notice.
H adds explicit ownership for the terrain atlas, dedicated sky shader,
retained Host/runtime chain, atomic update/render root pair, and portal tunnel
fallback/preparation/transfer. Every GL construction or mutation prefix added
to the checkpoint advances CPU ownership only after an always-on checked
driver commit. Failed shader/program/texture/buffer/VAO/text construction
retains exact names through the construction ledger; bindless residency and
the prior texture binding retain retry obligations across transient failure.
UI input cutoff and resource slots reject reentrant ownership mutation, and
portal preparation retries the same published fallback instead of replaying
the factory. This is a lifetime-only cutover; no AC algorithm or accepted
presentation order changed.
Slice 6 implementation commits are `99a3e819`, `4e4aac2c`, `0bc9fda9`,
`c5570383`, `eeb0f6b4`, `947c61d2`, and production cutover `e91f3102`.
Slice 7 implementation commits are `7e4cfb37`, `733126a2`, `bc6f09f9`,
`6d6e5b5f`, `85239fb3`, `28e1cf80`, and production cutover `9d7df1bf`.
The detailed ledgers live under `docs/plans/2026-07-2*-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.
## Frozen render graph
`GameWindow.OnRender` creates one value-only `RenderFrameInput` and calls
`RenderFrameOrchestrator.Render`. The accepted healthy order is:
1. begin the GPU-flight transaction;
2. begin/reset frame resources, clear, and publish live resources;
3. begin the optional ImGui frame;
4. advance weather display preparation;
5. draw the complete world/PView/shared-alpha/particle/debug scene;
6. draw the portal/private viewport using the pre-private foundation snapshot;
7. refresh/draw paperdoll, retained gameplay UI, then submit ImGui;
8. capture a requested screenshot;
9. publish title/resource/frame diagnostics;
10. close the GPU-flight transaction.
Recovery is one reverse-lifetime transaction. An active ImGui frame closes
through the owning Silk controller, and text rendering restores exact borrowed
GL state on success or failure. The orchestrator and its immediate phase owners
retain no direct `GameWindow` or anonymous callback bag. Recursive reachability
through canonical UI/input owners is not frame ownership; the known paths and
review rule live in `docs/architecture/code-structure.md`.
## Accepted verification
- Final automated closeout: 293 focused Slice 8 tests pass; App Release passes
3,451 / 3 intentional skips; the complete Release suite passes 7,823 / 5.
The Release build retains only the 17 pre-existing test-project warnings
tracked by #228. Behavior/retail, architecture/ownership, and adversarial
failure reviews are clean.
- Checkpoint K (`bca41487`, `6c5e0604`): two fresh-process 403-second
nine-stop soaks produce the exact ordered same-frame canonical checkpoints,
zero pending teardown/retirement/staging/warmup work, no unconfounded owner
growth, unchanged process/performance gates, and graceful exits. #232 is
closed.
- Checkpoint L connected lifecycle/reconnect passes in 314.4 seconds with six
valid PNGs and graceful capped/uncapped exits. The uncapped final checkpoint
is 174.74 FPS / 5.72 ms. Frames reconstructed from exact Slice 7 commit
`9d7df1bf` preserve deterministic geometry, UI/paperdoll layering, private
viewports, depth/alpha, and world reveal; remaining differences are live
entities, particles, vitals, and sub-frame camera timing.
- Slice 8 Checkpoint H: 61 focused ownership/lifetime tests pass; App Release
passes 3,236 tests / 3 intentional skips. Four corrected-diff cycles closed
every architecture, retail, and adversarial finding; all three final reviews
are clean. The production App build has zero warnings/errors. The complete
Release suite passes 7,606 tests / 5 intentional skips; the 17 existing test-
project warnings remain tracked by #228.
- Slice 8 Checkpoint G Release suite: 7,553 passed / 5 fixture or environment
skips; App 3,183/3 skips, UI Abstractions 534/0, 35 focused App
settings/boundary tests, and all 43 `SettingsVMTests` pass. The production App
build has zero warnings/errors; the complete solution retains the 17 existing
test-project warnings tracked by #228. All three independent corrected-diff
reviews are clean.
- Slice 8 Checkpoint F Release suite: 7,524 passed / 5 fixture or environment
skips; App 3,155/3 skips, 54 focused App ownership tests and 20 Core combat
conformance tests pass, and all three independent corrected-diff reviews are
clean.
- Slice 8 Checkpoint E Release suite: 7,477 passed / 5 fixture or environment
skips; App 3,108/3 skips, UI Abstractions 533/0, and all three independent
corrected-diff reviews are clean.
- Slice 8 Checkpoint D Release suite: 7,419 passed / 5 fixture or environment
skips; App 3,059/3 skips. Focused environment/boundary tests and all three
independent corrected-diff reviews are clean.
- Slice 8 Checkpoint C Release suite: 7,408 passed / 5 fixture or environment
skips; App 3,048/3 skips and Core.Net 548/0. All three independent corrected-
diff reviews are clean.
- Release suite: 7,341 passed / 5 fixture or environment skips.
- Connected lifecycle/reconnect: 315.6 seconds, graceful capped close and fresh
process uncapped reconnect passed; only 25 expected world-edge empty
landblocks.
- The six lifecycle PNGs preserve Slice 6 world geometry, depth, UI/paperdoll,
private viewport, and presentation. Differences are live weather/particles,
authoritative vitals, and small scripted camera settling.
- Synchronized nine-stop resource soak: 395.2 seconds, nine materializations,
all movement/jump/combat exercises, and graceful exit passed; update p95 was
at or below 0.8 ms. Caul return → plateau working/private delta was
+85.7/+59.3 MiB, inside the unchanged gate.
- Two Slice-7 identical-binary runs exceeded the coarse process-residency
threshold while deterministic ownership/lifecycle/timing checks passed.
Checkpoint K closed #232 by adding canonical owner snapshots; it did not
loosen the process threshold or treat residency alone as an identified leak.
- The 1833 missing VFX table/emitter diagnostics are known DAT-driven records,
not a Slice 7 regression.
- TS-50, TS-51, and TS-53 remain registered; Slice 7 introduced no new retail
divergence.
## Next work
Resume M4 feature work through the extracted owners. The connected matrix
passed first login/radar; movement, mouse, resize, focus, and combat; the shared
inventory/skills/spellbook panel; outdoor, building, dungeon, recall/portal,
paperdoll, and particle presentation; then graceful reconnect. Full
`GameEntity` aggregation remains a separate migration and must not be folded
into ordinary M4 work.
## 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 or render graphs 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.
- Do not revert Checkpoint K to exact cache equality: normal retirement may
shrink owners, and visible/server workload changes may change populations.
Hard-fail owner growth only when workload is stable, name workload-confounded
growth explicitly, and preserve the unchanged process-residency limits.
- Small value/policy callbacks and diagnostics are acceptable only when they do
not call a substantial window body or hide mutable ownership.