refactor(app): make session start terminal

Move live-session startup and its existing diagnostics into the typed Phase-9 owner. GameWindow.OnLoad now ends immediately after that phase, so no callback binding, publication, or allocation can occur after the session becomes active.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-22 19:06:00 +02:00
parent 3628aeb520
commit 54244d31f1
11 changed files with 139 additions and 39 deletions

View file

@ -0,0 +1,38 @@
using AcDream.App.Composition;
using AcDream.App.Net;
namespace AcDream.App.Tests.Composition;
public sealed class SessionStartCompositionTests
{
[Fact]
public void DiagnosticsPreserveMissingCredentialAndFailureMessagesOnly()
{
var messages = new List<string>();
SessionStartCompositionPhase.Report(
new LiveSessionStartResult(
LiveSessionStartStatus.MissingCredentials),
messages.Add);
SessionStartCompositionPhase.Report(
new LiveSessionStartResult(
LiveSessionStartStatus.Failed,
Error: new InvalidOperationException("boom")),
messages.Add);
SessionStartCompositionPhase.Report(
new LiveSessionStartResult(LiveSessionStartStatus.Disabled),
messages.Add);
SessionStartCompositionPhase.Report(
new LiveSessionStartResult(LiveSessionStartStatus.Connected),
messages.Add);
Assert.Equal(2, messages.Count);
Assert.Equal(
"live: ACDREAM_LIVE set but TEST_USER/TEST_PASS missing; skipping",
messages[0]);
Assert.StartsWith(
"live: session failed: System.InvalidOperationException: boom",
messages[1],
StringComparison.Ordinal);
}
}

View file

@ -66,7 +66,8 @@ public sealed class GameWindowSlice8BoundaryTests
"this).Compose(",
"new SessionPlayerCompositionPhase(",
"FrameRootResult frameRoots = new FrameRootCompositionPhase(",
"frameRoots.SessionHost.Start(_options)");
"new SessionStartCompositionPhase(",
".Start(frameRoots);");
string framePhase = File.ReadAllText(Path.Combine(
FindRepoRoot(),
@ -97,7 +98,7 @@ public sealed class GameWindowSlice8BoundaryTests
"_publication.PublishSessionPlayer(result);");
Assert.Equal(1, CountOccurrences(
body,
"frameRoots.SessionHost.Start(_options)"));
".Start(frameRoots);"));
string phaseOne = Slice(
File.ReadAllText(Path.Combine(
FindRepoRoot(),
@ -117,11 +118,22 @@ public sealed class GameWindowSlice8BoundaryTests
"if (firstKeyboard is not null && firstMouse is not null)",
phaseOne,
StringComparison.Ordinal);
string startPhase = File.ReadAllText(Path.Combine(
FindRepoRoot(),
"src",
"AcDream.App",
"Composition",
"SessionStartComposition.cs"));
AssertAppearsInOrder(
startPhase,
"frame.SessionHost.Start(_dependencies.Options)",
"switch (result.Status)",
"case LiveSessionStartStatus.MissingCredentials:",
"case LiveSessionStartStatus.Failed:");
int start = body.IndexOf(
"frameRoots.SessionHost.Start(_options)",
".Start(frameRoots);",
StringComparison.Ordinal);
string postStart = body[start..];
Assert.Contains("switch (liveStart.Status)", postStart, StringComparison.Ordinal);
string postStart = body[(start + ".Start(frameRoots);".Length)..];
Assert.Empty(System.Text.RegularExpressions.Regex.Matches(
postStart,
@"(?m)^\s+_[A-Za-z]\w*\s*(?:\?\?=|=)"));
@ -343,7 +355,8 @@ public sealed class GameWindowSlice8BoundaryTests
"new WorldRenderCompositionPhase(",
"new SessionPlayerCompositionPhase(",
"new FrameRootCompositionPhase(",
"frameRoots.SessionHost.Start(_options)");
"new SessionStartCompositionPhase(",
".Start(frameRoots);");
string sessionPhase = File.ReadAllText(Path.Combine(
FindRepoRoot(),
"src",