fix #405: chargen/summary preview leases never Transferred — every retail-UI window load crashed at composition

Campaign CC gate round 1, first finding. CC6b-MOUNT's chargen preview
lease and CC5's summary preview lease both rode into the published live
presentation beside the paperdoll/appraisal siblings but never got their
Transfer() calls in CompletePresentation's ladder, so the composition
scope's unpublished-resource leak guard threw on every real window load
with retail UI mounted (launcher path and dev path alike) and the client
died before connecting. Two-line fix at the ladder; verified by a live
launch reaching started/connected/characterList with a graceful close.

Also files #406: the launcher recorded this crash as exited{code:0,
reason:graceful} — the session orchestrator's exit observation is wrong
and misled the first diagnosis; the console repro showed the real
0xE0434352.

No automated suite executes the transfer ladder (needs a live GPU
window) — the coverage gap is recorded in #405's closing note.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-16 08:38:07 +02:00
parent 84d0bbd14c
commit 344d88bff7
2 changed files with 56 additions and 0 deletions

View file

@ -24,6 +24,51 @@ What does NOT go here:
- Every session: scan OPEN issues at start; promote/close anything we touched during the session before ending.
- Promoting to a Phase: mark as `DONE (promoted to Phase X)` + commit SHA where the Phase entry landed.
## #406 — Launcher records a crashed client as `exited{code:0,reason:"graceful"}`
**Status:** OPEN (Campaign CC gate round 1, 2026-08-16)
**Severity:** MEDIUM (diagnosis-misleading, not data-loss)
Found while diagnosing #405: the client process died with exit code
`0xE0434352` (.NET unhandled exception, stack on stderr), but the
launcher's session status stream recorded `{"e":"exited","code":0,
"reason":"graceful"}` — the exact opposite of what happened. Running the
identical binary + session config from a console shows the true nonzero
exit code, so the corruption is in the launcher's session-orchestrator
exit observation (wrong process handle/exit-code read, or a default that
masks the real code), not in the client. §LA1 explicitly promises
`exited{code,reason}` carries the real termination; a launcher that
reports "graceful" for a crash sends any future gate/automation
diagnosis in the wrong direction (it did exactly that this round until
the console repro). Investigate the launcher-side session orchestrator's
exit capture; a test should pin a nonzero-exit child producing
`exited{code:<nonzero>,reason:"crashed"|"failed"}` per the LA contract's
vocabulary.
## #405 — CLOSED: chargen/summary preview leases missing Transfer killed every retail-UI window load
**Status:** DONE (`fix #405` commit, 2026-08-16 — Campaign CC gate round 1)
**Severity:** CRITICAL (client unusable via launcher/retail-UI path)
`LivePresentationCompositionPhase.CompletePresentation`'s lease-transfer
ladder never gained `chargenPreviewLease?.Transfer()` (CC6b-MOUNT) nor
`summaryPreviewLease?.Transfer()` (CC5, faithfully duplicating the same
miss). Both resources rode into the published result beside the
paperdoll/appraisal siblings, but `CompositionAcquisitionScope.Complete()`
saw two acquired-unpublished leases and threw
`InvalidOperationException: Composition phase completed with unpublished
resources: chargen preview viewport, summary preview viewport` on EVERY
real window load with retail UI mounted — the client died ~1.7 s after
start, before connecting. Five review rounds read past it because no
automated suite executes the transfer ladder (it needs a live GPU
window; `LivePresentationCompositionTests` covers scope mechanics only)
and no graphical launch happened between CC6b-MOUNT's landing and the
user's gate. Follow-up test-coverage gap: a composition-level fake-GPU
harness that drives `ComposeCore` through `scope.Complete()` would have
caught this and remains unbuilt — weigh it against the E6 deterministic
suite patterns before CC's campaign close. Verified fixed by a live
launch: `started → connected → characterList`, graceful close.
## #404 — ChargenSkillScoreResolver duplicates ChargenTableReader's own SkillTable read
**Status:** OPEN (post-CC cleanup follow-up)

View file

@ -1535,6 +1535,17 @@ internal sealed class LivePresentationCompositionPhase
retainedGameplayLease?.Transfer();
paperdollLease?.Transfer();
creatureAppraisalLease?.Transfer();
// #405: these two Transfer calls were MISSING from CC6b-MOUNT (chargen)
// and CC5 (summary) — both leases rode into the published result at
// the paperdoll siblings' positions above, but without the Transfer
// the scope's unpublished-resource leak guard threw on every real
// window load ("Composition phase completed with unpublished
// resources: chargen preview viewport, summary preview viewport"),
// killing the client at startup whenever retail UI mounted the
// chargen screen. No automated suite executes this ladder (it needs
// a live GPU window), which is how five review rounds read past it.
chargenPreviewLease?.Transfer();
summaryPreviewLease?.Transfer();
envCellLease.Transfer();
clipFrameLease.Transfer();
portalDepthLease.Transfer();