docs(architecture): plan focused window lifetime
This commit is contained in:
parent
530b4bd8f5
commit
5a55d08106
2 changed files with 171 additions and 1 deletions
|
|
@ -0,0 +1,169 @@
|
||||||
|
# GameWindow Slice 8 Checkpoint J — lifetime and shutdown
|
||||||
|
|
||||||
|
**Status:** Active 2026-07-22.
|
||||||
|
**Parent:**
|
||||||
|
[`2026-07-22-gamewindow-slice-8-composition-lifecycle.md`](2026-07-22-gamewindow-slice-8-composition-lifecycle.md),
|
||||||
|
Checkpoint J.
|
||||||
|
**Integrated baseline:** `530b4bd8`; Checkpoint I is complete, the production
|
||||||
|
startup path uses the tested nine-phase pipeline, `GameWindow.cs` is 1,945 raw
|
||||||
|
lines, App Release passes 3,431 tests / 3 skips, and the complete Release suite
|
||||||
|
passes 7,803 tests / 5 skips.
|
||||||
|
**Behavior rule:** preserve the accepted disconnect, reset, callback cutoff,
|
||||||
|
frame withdrawal, GL dependency, and native-window-last order. This checkpoint
|
||||||
|
changes lifetime ownership and failure reporting, not gameplay behavior.
|
||||||
|
|
||||||
|
## 1. Outcome
|
||||||
|
|
||||||
|
Replace `GameWindow.CreateShutdownTransaction` and the window-owned transaction
|
||||||
|
field with one pre-window `GameWindowLifetime`. The lifetime owns:
|
||||||
|
|
||||||
|
- the single staged `ResourceShutdownTransaction`;
|
||||||
|
- the first immutable typed shutdown-root snapshot;
|
||||||
|
- the native window root once `Window.Create` succeeds;
|
||||||
|
- explicit `Active`, `RetryableIncomplete`, `Complete`,
|
||||||
|
`CompleteWithCleanupFailures`, and `AbandonedIncomplete` state;
|
||||||
|
- one immutable report returned by every terminal repeated call.
|
||||||
|
|
||||||
|
`GameWindow.OnClosing` performs a synchronous non-terminal attempt while the GL
|
||||||
|
context is current. `GameWindow.Dispose` retries the retained transaction and
|
||||||
|
then releases the native window. A persistent hard barrier forces the named,
|
||||||
|
logged last-resort native fallback and terminal abandonment; it never reports a
|
||||||
|
clean shutdown.
|
||||||
|
|
||||||
|
## 2. Typed ownership boundary
|
||||||
|
|
||||||
|
`GameWindowShutdownRoots` is a teardown-only aggregate of cohesive records, not
|
||||||
|
a runtime service locator. It exposes no gameplay operations and is captured
|
||||||
|
exactly once when shutdown first starts:
|
||||||
|
|
||||||
|
1. `IngressShutdownRoots` — quiescence, command/input logical cutoff, physical
|
||||||
|
callback owners, session controller, and native callback binding.
|
||||||
|
2. `FrameShutdownRoots` — atomic frame publication, frame/session bindings, and
|
||||||
|
UI/session late bindings.
|
||||||
|
3. `LiveShutdownRoots` — retained UI, interaction/streaming owners, canonical
|
||||||
|
live runtime, hook/effect/audio owners, and effect state.
|
||||||
|
4. `RenderShutdownRoots` — GPU-flight barrier, private/render frontends,
|
||||||
|
texture/mesh/render resources, dedicated atlas/sky roots, and construction
|
||||||
|
cleanup.
|
||||||
|
5. `PlatformShutdownRoots` — DAT mapping, input context, and GL.
|
||||||
|
|
||||||
|
The records retain exact object identities. Operations call those identities
|
||||||
|
directly; no stage stores `GameWindow`, a callback facade into it, a dictionary,
|
||||||
|
or an untyped service provider. The window may retain borrowed fields until the
|
||||||
|
host itself dies, but only `GameWindowLifetime` drives release after capture.
|
||||||
|
|
||||||
|
## 3. Transaction policy
|
||||||
|
|
||||||
|
Extend `ResourceShutdownOperation` with a defaulted policy:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
ResourceShutdownOperationPolicy.HardBarrier
|
||||||
|
ResourceShutdownOperationPolicy.ReportAndContinue
|
||||||
|
```
|
||||||
|
|
||||||
|
Existing call sites remain hard by default. All operations in a stage are
|
||||||
|
attempted independently. Successful operations never replay. A hard failure
|
||||||
|
remains pending and protects later stages. A report-and-continue operation is
|
||||||
|
retried once; a second failure becomes a structured cleanup failure, marks that
|
||||||
|
operation settled, and allows the stage to converge. The transaction exposes
|
||||||
|
its current stage and immutable cleanup failures without swallowing exceptions.
|
||||||
|
|
||||||
|
Only physical ingress removal is soft. Logical quiescence, live-session
|
||||||
|
convergence, frame withdrawal, owner disposal, GPU drain, DAT/input/GL release,
|
||||||
|
and all dependency barriers remain hard.
|
||||||
|
|
||||||
|
## 4. Frozen stage order
|
||||||
|
|
||||||
|
The manifest outside `GameWindow` uses this exact order:
|
||||||
|
|
||||||
|
1. `host and session barriers`
|
||||||
|
- stop accepting callbacks;
|
||||||
|
- deactivate combat/diagnostic/retained/gameplay/pointer/dispatcher/device
|
||||||
|
paths;
|
||||||
|
- quiesce retained/devtools input;
|
||||||
|
- dispose the live-session controller and require converged disposal.
|
||||||
|
2. `physical ingress cleanup` — settings VM, retained/gameplay/pointer/
|
||||||
|
dispatcher/device bindings, retained/devtools input, and native window
|
||||||
|
callbacks; every operation is report-and-continue.
|
||||||
|
3. `frame borrowers` — withdraw the exact atomic frame pair, then frame-root and
|
||||||
|
session/player bindings.
|
||||||
|
4. `session dependents` — late bindings, mouse presentation, retained UI,
|
||||||
|
combat/item/container owners, streamer, and equipped children.
|
||||||
|
5. `live entities` — clear canonical runtime while teardown callbacks live.
|
||||||
|
6. `effect dispatch edges` — live bindings, effect advance, hook registrations.
|
||||||
|
7. `live entity dependents` — lights, presentation, remote teleport, effect
|
||||||
|
state, and audio.
|
||||||
|
8. `submitted GPU work` — hard wait barrier.
|
||||||
|
9. `render frontends`.
|
||||||
|
10. `shared texture owners`.
|
||||||
|
11. `mesh adapter`.
|
||||||
|
12. `remaining render owners`.
|
||||||
|
13. `dedicated render resources` — sky shader then terrain atlas.
|
||||||
|
14. `failed render construction cleanup`.
|
||||||
|
15. `frame flight owner`.
|
||||||
|
16. `content mappings`.
|
||||||
|
17. `input context`.
|
||||||
|
18. `OpenGL context`.
|
||||||
|
19. Native window release/fallback outside the transaction and last.
|
||||||
|
|
||||||
|
The former late native-callback operation moves to stage 2. Logical cutoff makes
|
||||||
|
copied callbacks inert before the potentially long session close, so a broken
|
||||||
|
event remove cannot prevent F653/transport teardown or strand unrelated owners.
|
||||||
|
|
||||||
|
## 5. State and reporting
|
||||||
|
|
||||||
|
`GameWindowLifetimeReport` contains status, blocked stage, structured soft
|
||||||
|
cleanup failures, and the retained hard/native error when present.
|
||||||
|
|
||||||
|
- `TryComplete(roots)` captures roots once and never performs native fallback.
|
||||||
|
It is used by `OnClosing`.
|
||||||
|
- `CompleteAndReleaseNativeWindow(roots)` retries hard work, then disposes the
|
||||||
|
native window. If hard convergence still fails, it retains the blocked-stage
|
||||||
|
report, marks eligible partial owners abandoned, releases the native fallback,
|
||||||
|
and becomes `AbandonedIncomplete`.
|
||||||
|
- Clean transaction + no soft failures becomes `Complete`.
|
||||||
|
- Clean transaction + soft failures becomes `CompleteWithCleanupFailures`.
|
||||||
|
- Reentrant completion is inert while the outer call owns progress.
|
||||||
|
- Every terminal repeated call returns the same report and touches no owner.
|
||||||
|
- Native window publication is single-owner, pre-Run-safe, and released once.
|
||||||
|
|
||||||
|
## 6. Implementation sequence
|
||||||
|
|
||||||
|
1. Add operation policy, structured cleanup-failure exposure, and focused
|
||||||
|
transaction tests for transient/persistent soft cleanup, mixed hard/soft
|
||||||
|
stages, retry/no-replay, and reentrancy.
|
||||||
|
2. Add `GameWindowLifetime`, report/state types, typed root records, and the
|
||||||
|
manifest factory. Test every stage trace using fakes, optional-null roots,
|
||||||
|
persistent session/GPU barriers, persistent soft detach, clean/native-failure
|
||||||
|
finalization, terminal abandonment, and repeated/reentrant calls.
|
||||||
|
3. Publish the native window immediately after creation; replace the window
|
||||||
|
transaction/manifest with one typed root capture and the two narrow lifetime
|
||||||
|
calls. Remove all shutdown feature bodies and update source-shape tests to
|
||||||
|
inspect the focused owner.
|
||||||
|
4. Exercise constructed-never-run, Load-never-fired, partial composition
|
||||||
|
prefixes, normal close then Dispose, direct Dispose, transient retry, and
|
||||||
|
optional audio/devtools/retained-UI absence.
|
||||||
|
5. Run behavior-order, architecture/ownership, and adversarial failure review
|
||||||
|
passes; correct every finding. Run focused tests, App Release, solution
|
||||||
|
Release build, and complete Release tests.
|
||||||
|
6. Reconcile architecture, roadmap, milestones, issues, AGENTS/CLAUDE, and
|
||||||
|
durable memory; commit Checkpoint J as one bisectable ownership unit.
|
||||||
|
|
||||||
|
## 7. Acceptance
|
||||||
|
|
||||||
|
- No shutdown stage or substantial release body remains in `GameWindow`.
|
||||||
|
- No lifetime/manifest type stores `GameWindow` or a general callback facade.
|
||||||
|
- Session and GPU hard failures never run protected dependent stages.
|
||||||
|
- Persistent physical-detach failure does not strand frame/live/render/content/
|
||||||
|
input/GL owners and produces `CompleteWithCleanupFailures`.
|
||||||
|
- Both frame roots become unreachable before any borrower retires.
|
||||||
|
- Every acquired owner releases once; absent owners are no-ops; failed owners
|
||||||
|
retry without replaying completed work.
|
||||||
|
- Direct, repeated, concurrent-safe/reentrant, close-then-dispose, and every
|
||||||
|
partial-load path are deterministic.
|
||||||
|
- Native window release is last. Hard non-convergence becomes named terminal
|
||||||
|
abandonment; repeated calls are inert and preserve the same report.
|
||||||
|
- App production builds without warnings; only #228's 17 test warnings remain;
|
||||||
|
focused, App, and complete Release suites pass.
|
||||||
|
- No retail-divergence row is added unless review discovers an actual behavior
|
||||||
|
change; this ownership correction itself is behavior-preserving.
|
||||||
|
|
@ -33,7 +33,8 @@ audit.
|
||||||
invoke the same pipeline and carry exact typed prior results. Detailed plan:
|
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).
|
[`2026-07-22-gamewindow-slice-8-checkpoint-i-ordered-composition.md`](2026-07-22-gamewindow-slice-8-checkpoint-i-ordered-composition.md).
|
||||||
- [ ] J — move the exact retryable shutdown manifest to a focused lifetime
|
- [ ] J — move the exact retryable shutdown manifest to a focused lifetime
|
||||||
owner and prove all partial-load/reentrant/retry paths.
|
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).
|
||||||
- [ ] K — in a separate #232 commit, add canonical owner snapshots to every soak
|
- [ ] K — in a separate #232 commit, add canonical owner snapshots to every soak
|
||||||
checkpoint without weakening the process-memory guard.
|
checkpoint without weakening the process-memory guard.
|
||||||
- [ ] L — corrected-diff reviews, focused and full Release gates, connected
|
- [ ] L — corrected-diff reviews, focused and full Release gates, connected
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue