From 344d88bff791feb4bd28e20c1e3841a079e76baf Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 16 Aug 2026 08:38:07 +0200 Subject: [PATCH] =?UTF-8?q?fix=20#405:=20chargen/summary=20preview=20lease?= =?UTF-8?q?s=20never=20Transferred=20=E2=80=94=20every=20retail-UI=20windo?= =?UTF-8?q?w=20load=20crashed=20at=20composition?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- docs/ISSUES.md | 45 +++++++++++++++++++ .../LivePresentationComposition.cs | 11 +++++ 2 files changed, 56 insertions(+) diff --git a/docs/ISSUES.md b/docs/ISSUES.md index 767a3f9e..9ae3ed27 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -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:,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) diff --git a/src/AcDream.App/Composition/LivePresentationComposition.cs b/src/AcDream.App/Composition/LivePresentationComposition.cs index 456baf4b..a4b66ff8 100644 --- a/src/AcDream.App/Composition/LivePresentationComposition.cs +++ b/src/AcDream.App/Composition/LivePresentationComposition.cs @@ -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();