Reconcile the architecture, roadmap, milestones, issue ledger, session instructions, and durable memory with the 1,622-line native shell, canonical soak evidence, connected framebuffer comparison, and sole remaining user visual gate. Co-authored-by: Codex <codex@openai.com>
225 lines
11 KiB
Markdown
225 lines
11 KiB
Markdown
# GameWindow Slice 8 Checkpoint K — canonical soak snapshots
|
||
|
||
**Status:** Complete 2026-07-22 (`bca41487`, corrected gate semantics
|
||
`6c5e0604`).
|
||
**Parent:**
|
||
[`2026-07-22-gamewindow-slice-8-composition-lifecycle.md`](2026-07-22-gamewindow-slice-8-composition-lifecycle.md),
|
||
Checkpoint K.
|
||
**Integrated result:** `GameWindow.cs` is 1,622 raw lines, App Release passes
|
||
3,451 tests / 3 skips, and the complete Release suite passes 7,823 tests / 5
|
||
skips.
|
||
**Issue:** [`#232`](../ISSUES.md#232--nine-stop-soak-process-memory-gate-lacks-canonical-owner-snapshots).
|
||
**Behavior rule:** this checkpoint changes diagnostic capture and connected-gate
|
||
evidence only. It does not change rendering, streaming, gameplay, resource
|
||
budgets, or the existing process working/private-memory thresholds.
|
||
|
||
## 1. Outcome
|
||
|
||
Make every scripted `checkpoint <name>` a deferred, acknowledged render-frame
|
||
barrier. A checkpoint is written only after private presentation and the normal
|
||
render diagnostics phase have both observed the same immutable
|
||
`RenderFrameOutcome`. Its JSON contains the canonical world/reveal/resource
|
||
owner snapshot and that exact frame outcome. The script cannot execute the next
|
||
command until serialization and both writes succeed, fail, or are explicitly
|
||
cancelled during shutdown.
|
||
|
||
The nine-stop soak then consumes exactly nine ordered checkpoints, gates
|
||
canonical owner stability at the Caul return → Caul plateau same-location pair,
|
||
labels server-controlled entity/animation population changes as workload
|
||
warnings, and retains process residency as an unchanged secondary guard.
|
||
|
||
## 2. Runtime contract
|
||
|
||
### 2.1 Acknowledgement token
|
||
|
||
Replace the synchronous automation method with a request contract equivalent
|
||
to:
|
||
|
||
```csharp
|
||
enum RetailUiAutomationCheckpointStatus
|
||
{
|
||
Pending,
|
||
Succeeded,
|
||
Failed,
|
||
Cancelled,
|
||
}
|
||
|
||
interface IRetailUiAutomationCheckpoint
|
||
{
|
||
RetailUiAutomationCheckpointStatus Status { get; }
|
||
string? Error { get; }
|
||
}
|
||
|
||
bool TryRequestCheckpoint(
|
||
string name,
|
||
out IRetailUiAutomationCheckpoint? checkpoint,
|
||
out string error);
|
||
```
|
||
|
||
The production token also retains the assigned request sequence and validated
|
||
name across the update → render edge. Only the controller can transition it,
|
||
exactly once, from Pending to a terminal state.
|
||
|
||
`RetailUiAutomationScriptRunner` stores one token together with the active
|
||
command index. While Pending, repeated ticks return without enqueueing again or
|
||
advancing the command. Success clears the token and advances once. Failure or
|
||
cancellation clears it and stops on the token's exact error. Disposal still
|
||
releases held input; runtime shutdown is responsible for cancelling queued
|
||
tokens.
|
||
|
||
### 2.2 FIFO request owner
|
||
|
||
`WorldLifecycleAutomationController` becomes the sole FIFO owner and an
|
||
`IDisposable` frame-phase participant:
|
||
|
||
- validation failure creates no request and consumes no sequence;
|
||
- accepted requests receive one monotonic sequence and enter one FIFO;
|
||
- a successful render drains accepted requests in order;
|
||
- each request serializes one `WorldLifecycleCheckpoint` containing its
|
||
sequence/name, current reveal state, the exact current `RenderFrameOutcome`,
|
||
and one canonical resource snapshot;
|
||
- Succeeded is published only after the JSONL append and named JSON write both
|
||
complete;
|
||
- capture/serialization/I/O failure marks only that request Failed with
|
||
contextual sequence/name error and does not throw out of rendering;
|
||
- shutdown marks every still-pending request Cancelled with an explicit error;
|
||
- enqueue after shutdown fails synchronously and cannot create an orphan token.
|
||
|
||
The controller is adopted by `FrameRootRuntimeBindings` separately from its
|
||
retained-UI late binding, so the binding detaches and pending requests cancel
|
||
under the existing retryable frame-root lifetime.
|
||
|
||
### 2.3 Post-diagnostics render phase
|
||
|
||
Add a narrow `IRenderFramePostDiagnosticsPhase` with a no-op implementation.
|
||
`RenderFrameOrchestrator` calls it exactly once after:
|
||
|
||
1. resource preparation;
|
||
2. world rendering;
|
||
3. private presentation and screenshots;
|
||
4. `IRenderFrameDiagnosticsPhase.Publish`;
|
||
5. then checkpoint drain;
|
||
6. finally the existing GPU-flight close.
|
||
|
||
If an earlier render phase fails, post-diagnostics is not called and the FIFO
|
||
remains pending for the next successful frame. An unexpected post-phase throw
|
||
uses the existing render failure/recovery path, although production capture and
|
||
I/O failures are represented on tokens rather than thrown. No previous-frame
|
||
diagnostic value is paired with a current-frame owner snapshot:
|
||
`WorldLifecycleResourceSnapshotSource.Capture(RenderFrameOutcome)` takes
|
||
visible/total landblocks from the supplied outcome and reads the already-
|
||
published aggregate FPS/frame-time snapshot only after diagnostics runs.
|
||
|
||
## 3. Artifact and soak schema
|
||
|
||
`WorldLifecycleCheckpoint` adds the exact frame outcome. Existing reveal and
|
||
resource fields retain their names. The route adds these nine commands in this
|
||
order at the end of each settled destination block:
|
||
|
||
1. `caul-baseline`
|
||
2. `sawato-baseline`
|
||
3. `rynthid`
|
||
4. `aerlinthe`
|
||
5. `sawato-return`
|
||
6. `holtburg`
|
||
7. `caul-return`
|
||
8. `sawato-plateau`
|
||
9. `caul-plateau`
|
||
|
||
`run-connected-r6-soak.ps1` reads the JSONL only after the route completes and
|
||
requires one row for every expected name, exact sequence 1–9, exact order, and
|
||
the current process id. It embeds those records in the report.
|
||
|
||
Every checkpoint hard-gates zero:
|
||
|
||
- pending live teardowns;
|
||
- pending landblock retirements;
|
||
- staged mesh uploads and bytes;
|
||
- composite warmup work.
|
||
|
||
Every route teleport supplies an explicit identity quaternion so the timed turn
|
||
begins from a reproducible heading. The same-location Caul return → Caul
|
||
plateau comparison requires exact equality for the deterministic loaded/total
|
||
world domain, while visible-landblock and authoritative entity/animation/live-
|
||
entity changes are named workload warnings. Teardown/retirement queues, staged
|
||
work, and composite warmup remain hard zero at every checkpoint. Mesh, atlas,
|
||
tracked-GPU, composite/particle-texture, and VFX owner counts may retire and
|
||
shrink normally; any growth is a hard leak failure when the visible and
|
||
authoritative workload is stable, and a named owner-growth warning when that
|
||
workload changed. Particles, emitters, and active scripts are always transient
|
||
workload warnings rather than silent exclusions. The report therefore says
|
||
which canonical owner grew without mistaking legitimate retirement for a leak.
|
||
Managed used/committed deltas are reported diagnostically. Existing
|
||
working/private-memory, update-p95, and allocation-p50 thresholds remain byte-
|
||
for-byte unchanged as the secondary residency/performance guard.
|
||
|
||
## 4. Implementation sequence
|
||
|
||
1. Add token states and change the automation runtime/script runner to the
|
||
one-token-per-command polling contract. Cover delayed success, repeated
|
||
pending ticks, failure, cancellation, invalid request, and disposal while
|
||
pending.
|
||
2. Refactor `WorldLifecycleAutomationController` into the FIFO request owner;
|
||
pass the frame outcome into snapshot capture and write it into artifacts.
|
||
Cover FIFO order, sequence stability, write failure, no duplicate drain,
|
||
shutdown cancellation, and enqueue-after-dispose.
|
||
3. Add the post-diagnostics phase to `RenderFrameOrchestrator`, wire the
|
||
controller through `FrameRootCompositionPhase`, and adopt its lifetime
|
||
separately from the late UI binding. Pin exact phase order, skipped drain on
|
||
prior failure, post-phase failure recovery, and partial-composition cleanup.
|
||
4. Add the nine route commands. Parse/validate JSONL in the soak, attach the
|
||
canonical checkpoints to the report, add zero-work and same-location owner
|
||
gates, and preserve the old process/performance formulas verbatim.
|
||
5. Run behavior/order, architecture/ownership, and adversarial failure review
|
||
passes. Correct findings and re-run focused App tests, App Release, Release
|
||
build, and the complete Release suite.
|
||
6. Run two fresh-process connected nine-stop routes before closing #232. Both
|
||
must exit gracefully, produce exact ordered checkpoints, pass canonical
|
||
owner/cache gates, and pass the unchanged process residency guard.
|
||
7. Reconcile architecture, roadmap, milestones, issues, AGENTS/CLAUDE, and
|
||
durable memory; commit Checkpoint K as its own bisectable diagnostic unit.
|
||
|
||
## 5. Automated acceptance
|
||
|
||
- one checkpoint command creates one request, one sequence, and one artifact;
|
||
- a pending token blocks all later script commands without duplicate enqueue;
|
||
- render failure delays rather than loses or duplicates the request;
|
||
- diagnostics publication precedes same-frame capture;
|
||
- independent accepted requests drain FIFO and retain name/sequence identity;
|
||
- capture/write failure reaches the script as the exact failed-token error;
|
||
- shutdown reaches pending scripts as explicit cancellation;
|
||
- no controller/runtime reference points back to `GameWindow`;
|
||
- all nine route names and sequences are exact and appear in the soak report;
|
||
- canonical pending/staging/warmup work is zero at every checkpoint;
|
||
- Caul return → plateau deterministic owners/caches are unchanged, while
|
||
authoritative workload deltas are explicitly warned;
|
||
- working/private-memory thresholds and update/allocation formulas are
|
||
unchanged;
|
||
- focused, App, and complete Release suites pass with no new warnings.
|
||
|
||
No visual gate is required for K because it changes diagnostic observation
|
||
only. Checkpoint L owns the final connected framebuffer and user visual gate.
|
||
|
||
## 6. Completion evidence
|
||
|
||
The focused checkpoint suite passes 74 tests. The Release build succeeds with
|
||
only the 17 pre-existing test-project warnings tracked by #228. Two independent
|
||
fresh-process routes produced all nine ordered render-frame checkpoints and
|
||
closed gracefully:
|
||
|
||
- `connected-r6-soak-20260722-201335.report.json`: 403.139 seconds; Caul
|
||
return-to-plateau working/private deltas +20.2/+10.3 MiB; update p95 1.5 ms.
|
||
- `connected-r6-soak-20260722-202025.report.json`: 403.021 seconds; Caul
|
||
return-to-plateau working/private deltas +165.0/+157.2 MiB; update p95 1.3 ms.
|
||
|
||
Every checkpoint had zero pending teardown/retirement, staged upload work, and
|
||
composite warmup work. Neither run found unconfounded canonical owner growth,
|
||
and both passed the unchanged process-residency and performance limits.
|
||
|
||
The first connected implementation run also proved that exact cache equality
|
||
was the wrong leak predicate: visible landblocks and authoritative entities
|
||
changed while mesh/GPU/cache owner counts decreased through legitimate
|
||
retirement. The corrected contract therefore hard-fails owner *growth* when
|
||
the workload is stable, reports named growth warnings when the authoritative
|
||
or visible workload changed, and permits shrinking. It does not weaken the
|
||
process limits or hide an identified owner leak.
|