fix(ui): gate — no void frames around the login wormhole; vitals icons centered

The login tunnel now covers from the first world-facing frame (the
sky-void backdrop can never present pre-tunnel) and holds through an
atomic tunnel-to-world swap at reveal completion — the void is
structurally unreachable on both edges, pinned by frame-sequence tests
across WorldSceneRenderer/WorldRevealCoordinator/LocalPlayerTeleport-
Controller/RuntimeWorldTransitState. Vitals detail icons draw at their
authored centered offsets in both stacked and side-by-side layouts.
Implemented and live-probed by the fix agent; finalized by the lead
after the agent parked post-verification (gates re-run green:
App 5512/3, Runtime 1747/0).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-17 12:30:51 +02:00
parent 2f8c046aba
commit fdc4fd496d
17 changed files with 649 additions and 66 deletions

View file

@ -362,11 +362,16 @@ public sealed class WorldRenderFrameBuilderTests
"private AcDream.App.Rendering.SkyPesFrameController?",
gameWindow,
StringComparison.Ordinal);
// Gate-fix round (2026-08-17): the renderer's own IsWaitingForLogin
// short-circuit is deleted — the frame gate
// (LocalPlayerTeleportRenderStateSource) folds the waiting state
// into PortalViewportVisible, so the portal-visible return above
// covers every waiting frame (one gate computes, this phase
// enforces).
AssertAppearsInOrder(
worldScene,
"_alpha.BeginFrame();",
"_frames.Build(",
"if (_login.IsWaitingForLogin)",
"_passes.DrawFlatTerrain(",
"NormalWorldDrawn: true");
AssertAppearsInOrder(

View file

@ -45,29 +45,31 @@ public sealed class WorldSceneRendererTests
}
[Fact]
public void LoginWait_DrawsFlatSkyThenCompletesFrameWithoutWorldGeometry()
public void LoginWait_IsOwnedByTheFrameGate_NotByARendererShortCircuit()
{
// Gate-fix round (2026-08-17): the sky-only waiting skip is DELETED.
// Live pre-world frames present the portal-viewport frame shape —
// LocalPlayerTeleportRenderStateSource folds IsWaitingForLogin into
// PortalViewportVisible (retail's pre-player gameplay screen draws
// NO world: black behind the UI, never a sky-only backdrop), so in
// production this renderer NEVER runs while waiting. One gate
// computes the frame's visibility and this phase only enforces it: a
// waiting flag without the portal cover (unreachable in production)
// draws the ordinary flat world rather than re-implementing a second
// gate here.
var rig = new Rig(portalVisible: false, waitingForLogin: true, clipRoot: null);
WorldRenderFrameOutcome result = rig.Renderer.Render(default);
Assert.False(result.NormalWorldDrawn);
Assert.Equal(0, result.VisibleLandblocks);
Assert.Equal(0, result.TotalLandblocks);
Assert.Equal(
[
"selection:begin",
"alpha:begin",
"frame:build",
"passes:begin",
"flat:clip",
"flat:sky",
"alpha:end",
"visibility:mark",
"visibility:complete",
"selection:complete",
],
rig.Calls);
Assert.True(result.NormalWorldDrawn);
Assert.True(rig.Frames.WaitingForLogin);
Assert.Contains("flat:terrain", rig.Calls);
// The production waiting frame: the portal cover is set, the world
// is skipped whole, and only the selection frame brackets run.
var covered = new Rig(portalVisible: true, waitingForLogin: true, clipRoot: null);
Assert.Equal(default, covered.Renderer.Render(default));
Assert.Equal(["selection:begin", "selection:complete"], covered.Calls);
}
[Fact]