Give terrain, sky, retained UI, portal preparation, and the update/render frame pair explicit single owners. Make shader, texture, text, bindless, and GL construction prefixes checked and retryable so partial failure cannot lose or replay resource ownership. Co-authored-by: Codex <codex@openai.com>
208 lines
11 KiB
Markdown
208 lines
11 KiB
Markdown
# GameWindow Slice 8 — Checkpoint H Resource Ownership Plan
|
|
|
|
## Objective
|
|
|
|
Replace the remaining implicit, constructor-local, and nullable-field resource
|
|
ownership in `GameWindow` with explicit single-owner transactions. This is a
|
|
behavior-preserving lifetime cutover: draw/update order, portal presentation,
|
|
retained UI behavior, settings behavior, and the frozen shutdown order do not
|
|
change.
|
|
|
|
Checkpoint H does not move the complete shutdown manifest; that is Checkpoint
|
|
J. It supplies the typed roots and retry semantics that J will consume.
|
|
|
|
## Frozen invariants
|
|
|
|
1. Every GL/kernel-owning object is published to exactly one owner immediately
|
|
after successful construction.
|
|
2. Renderers borrow the terrain atlas and dedicated sky shader. They never
|
|
dispose those resources. The renderer borrower retires before the sole
|
|
resource owner releases the borrowed atlas/shader.
|
|
3. A leaf factory that throws before returning must release every GL name it
|
|
created. Outer phase/lifetime rollback cannot recover a name that was never
|
|
published.
|
|
4. Bindless residency is a resource prefix: partial handle acquisition rolls
|
|
back, successful non-residency is not replayed after a later failure, and
|
|
textures are not deleted while a resident handle remains.
|
|
5. Retained UI input is quiesced before the live-session barrier and physically
|
|
detached afterward, independently of runtime/host disposal.
|
|
6. Exactly one retained-UI ownership chain exists. Before runtime construction
|
|
the lease owns the `UiHost`; after a runtime object is published the lease
|
|
retains that exact partial/full runtime and delegates final disposal to it.
|
|
Constructor or initialization failure never leaves a host in a local only.
|
|
7. Update and render roots publish atomically as one frame graph. Silk callbacks
|
|
resolve only through the slot; an empty/withdrawn slot is safely inert.
|
|
8. Portal tunnel ownership starts in one fallback slot. Transfer clears the
|
|
fallback only after the complete local-teleport controller factory returns;
|
|
any earlier failure leaves the same tunnel reachable by shutdown.
|
|
9. Successful disposal is never replayed. Failed disposal remains retryable.
|
|
Terminal abandonment is explicit and retains references for native/process
|
|
fallback rather than silently losing ownership.
|
|
|
|
## Typed owners
|
|
|
|
### `OwnedResourceSlot<T>` and `GameRenderResourceLifetime`
|
|
|
|
- `OwnedResourceSlot<T>` acquires through a factory, rejects duplicate
|
|
publication, exposes a typed borrower, and clears ownership only after
|
|
`Dispose` succeeds.
|
|
- `GameRenderResourceLifetime` contains separate slots for `TerrainAtlas` and
|
|
the dedicated sky `Shader`.
|
|
- `GameWindow` acquires both through this owner. Shutdown releases the sky
|
|
renderer and terrain renderer first, then the two resource slots, then GL.
|
|
|
|
### `RetailUiRuntimeLease`
|
|
|
|
- The lease exists before `OnLoad` and acquires the `UiHost` through a factory.
|
|
- Runtime construction and initialization are separate. The runtime is stored
|
|
in the lease before initialization begins.
|
|
- Initialization failure attempts immediate cleanup. Successful cleanup
|
|
rethrows the original initialization error; cleanup failure reports both and
|
|
leaves the exact runtime in the lease for lifetime retry.
|
|
- The lease exposes idempotent `QuiesceInput` and retryable `DeactivateInput`
|
|
operations against the retained host.
|
|
- If no runtime was constructed, lease disposal directly disposes the host. If
|
|
a runtime exists, runtime disposal remains the one path that disposes the
|
|
host. There are never two host disposers.
|
|
- Explicit terminal abandonment is allowed only after a failed disposal pass;
|
|
it makes later disposal inert while retaining the unresolved references for
|
|
the native/process fallback handled by Checkpoint J.
|
|
|
|
### `GameFrameGraphSlot`
|
|
|
|
- `IGameUpdateFrameRoot` and `IGameRenderFrameRoot` are the narrow frame seams.
|
|
- `UpdateFrameOrchestrator` and `RenderFrameOrchestrator` implement those seams.
|
|
- `Publish(update, render)` is atomic and one-shot until withdrawal.
|
|
- `Tick`/`Render` are inert before publication and after withdrawal.
|
|
- Shutdown withdraws the pair only after live-session convergence and before
|
|
any frame borrower retires.
|
|
|
|
### `TransferableResourceSlot<T>`
|
|
|
|
- `Acquire` owns one fallback resource.
|
|
- `Transfer(factory)` retains fallback ownership while the complete destination
|
|
factory runs and clears it only after that factory returns successfully.
|
|
- Failed acquisition, resource preparation, destination construction, binding,
|
|
and normal shutdown prefixes are covered without double disposal.
|
|
|
|
## Exception-safe GL leaves
|
|
|
|
### Shader program construction
|
|
|
|
`ShaderProgramConstruction` uses a narrow `IShaderProgramBuildApi`. It tracks
|
|
the vertex shader, fragment shader, and linked program as soon as each name is
|
|
returned. Compile, attach, link, detach, or cleanup failure attempts every
|
|
remaining rollback operation. A clean rollback preserves the original failure;
|
|
rollback failures are aggregated with it. `Shader.Dispose` becomes idempotent
|
|
and retryable.
|
|
|
|
### Terrain atlas construction and residency
|
|
|
|
`GlTextureConstructionTransaction` tracks every texture name allocated by
|
|
terrain, alpha, and fallback paths. `TerrainAtlas.Build`, `BuildAlphaAtlas`, and
|
|
`BuildFallback` allocate only through that transaction. The transaction commits
|
|
only after the complete `TerrainAtlas` object exists; failure rolls back all
|
|
names in reverse acquisition order and reports cleanup failures with the
|
|
original error.
|
|
|
|
`BindlessTexturePair` owns the terrain/alpha residency pair. Partial acquisition
|
|
releases the first handle. Release attempts both handles, remembers successful
|
|
substeps, and is retryable. `TerrainAtlas.Dispose` releases residency first,
|
|
then independently deletes both texture names through the existing retryable
|
|
shutdown transaction.
|
|
|
|
## Production integration order
|
|
|
|
1. Construct render-resource lifetime, UI lease, frame slot, and portal
|
|
fallback slot before `Window.Create`/`OnLoad` acquisitions.
|
|
2. Acquire the atlas through `GameRenderResourceLifetime`; construct
|
|
`TerrainModernRenderer` as a borrower.
|
|
3. Acquire `UiHost` through `RetailUiRuntimeLease`, wire input/assets, construct
|
|
and publish `RetailUiRuntime` before initialization, then expose host/runtime
|
|
only as borrower aliases.
|
|
4. Acquire/prepare portal presentation in the fallback slot.
|
|
5. Acquire the dedicated sky shader through the render-resource lifetime, then
|
|
construct `SkyRenderer` as a borrower.
|
|
6. Transfer the portal fallback only through the complete
|
|
`LocalPlayerTeleportController` factory.
|
|
7. Construct update/render roots as locals and publish them atomically through
|
|
`GameFrameGraphSlot`.
|
|
8. Update/render callbacks resolve only through the slot.
|
|
9. Shutdown quiesces/deactivates UI through the lease, withdraws frame roots,
|
|
disposes the UI lease and renderer borrowers, releases atlas/sky roots, then
|
|
reaches GL.
|
|
|
|
## Automated gates
|
|
|
|
- owned-resource acquire/borrow/release, duplicate acquire, transient failure,
|
|
retry, and no replay;
|
|
- UI host acquisition, runtime constructor failure, Initialize failure with
|
|
successful cleanup, transient cleanup then lifetime retry, persistent cleanup
|
|
then explicit abandonment, separate input quiescence/deactivation, and exact
|
|
host disposal count;
|
|
- frame pair atomic publication, duplicate publication, update/render routing,
|
|
withdrawal, pre-publication/post-withdrawal silence, and republish policy;
|
|
- portal fallback acquisition/preparation/transfer failures plus successful
|
|
transfer and every shutdown prefix, with exact one-resource disposal;
|
|
- vertex/fragment compile failure, program creation/link failure, and cleanup
|
|
failure after every created shader/program name;
|
|
- terrain/alpha/fallback texture allocation and upload failure after every
|
|
created name, reverse rollback, cleanup aggregation, and committed-name
|
|
non-deletion;
|
|
- bindless first/second acquisition failure, release partial failure/retry, and
|
|
no deletion before residency release;
|
|
- source boundary proves direct frame-root fields, constructor-local atlas/sky
|
|
ownership, direct UI host/runtime ownership, and nullable portal fallback are
|
|
removed from `GameWindow`;
|
|
- focused App tests, production App Release build, solution Release build, and
|
|
complete Release suite.
|
|
|
|
## Review and commit gate
|
|
|
|
The existing architecture/integration, retail-conformance, and adversarial
|
|
reviewers inspect the complete tracked and untracked diff independently. Every
|
|
confirmed finding is corrected and all three repeat until clean. Architecture,
|
|
roadmap, milestones, issues, memory, `CLAUDE.md`, and `AGENTS.md` are reconciled
|
|
in the same bisectable Checkpoint H commit.
|
|
|
|
## Implementation result — 2026-07-22
|
|
|
|
Checkpoint H landed the planned ownership graph without changing the accepted
|
|
update/render order or gameplay behavior:
|
|
|
|
- `GameRenderResourceLifetime` owns the terrain atlas and dedicated sky shader;
|
|
renderers borrow them and retire first.
|
|
- `RetailUiRuntimeLease` owns Host/runtime construction, initialization, input
|
|
cutoff, retryable disposal, and explicit terminal abandonment as one chain.
|
|
- `GameFrameGraphSlot` publishes update/render roots atomically and makes empty
|
|
or withdrawn callbacks inert.
|
|
- `TransferableResourceSlot.AcquirePrepared` publishes the portal presentation
|
|
before mesh preparation, retries the same partial resource, and refuses
|
|
transfer until preparation has committed.
|
|
- GL name creation records the returned name before post-command validation.
|
|
Shader/program, texture, text-renderer, buffer/VAO, bindless-residency, and
|
|
texture-binding operations advance ownership only after an always-on checked
|
|
GL commit boundary.
|
|
- Failed construction cleanup is retained by `GlConstructionCleanupLedger`;
|
|
exact pending names and binding-restore obligations remain retryable, while
|
|
successful cleanup stages never replay.
|
|
|
|
Four corrected-diff cycles closed issues found by the architecture, retail,
|
|
and adversarial reviewers: partial bindless mutation, lost GL rollback names,
|
|
constructor-local text resources, reentrant UI ownership, portal preparation,
|
|
unchecked production GL calls, leaked texture binding, and the bindless post-
|
|
commit verification gap. All three final reviews are clean.
|
|
|
|
Automated acceptance:
|
|
|
|
- focused Checkpoint H ownership/lifetime gate: 61 passed;
|
|
- App Release suite: 3,236 passed / 3 intentional skips;
|
|
- production App Release build: zero warnings and zero errors;
|
|
- complete solution Release suite: 7,606 passed / 5 intentional skips; solution
|
|
build has zero errors and the 17 existing test-project warnings tracked by
|
|
#228;
|
|
- `GameWindow.cs`: 3,689 raw lines / 162 fields / 37 methods, versus 15,723 /
|
|
278 / 205 at the campaign baseline.
|
|
|
|
No AC-specific algorithm or intended retail behavior changed, so Checkpoint H
|
|
adds no retail-divergence row. Checkpoint I is the next active unit.
|