fix(session): acknowledge login after first placement

ACE intentionally creates the local player Hidden and releases that materialization state on LoginComplete. Sending LoginComplete from raw F746 receipt raced canonical placement and left the login haze visible. Route one one-shot completion callback from Runtime's local first-entry terminal edge to graphical and prepared headless hosts; retain a guarded accepted-Create edge only for content-less headless sessions. Focused Runtime login tests, all 79 Headless tests, the connected user gate, and the Release build pass.
This commit is contained in:
Erik 2026-08-03 12:10:42 +02:00
parent f24532adf3
commit 175ad6b0d0
10 changed files with 107 additions and 48 deletions

View file

@ -61,6 +61,7 @@ internal sealed class RuntimeFirstEntryDriveController
private bool _driving;
/// <summary>C3c-R1 review F6: see <see cref="AttachRoute"/>.</summary>
private object? _routeOwner;
private Action<RuntimeEntityRecord>? _localPlayerCompleted;
internal RuntimeFirstEntryDriveController(
RuntimeEntityObjectLifetime entityObjects,
@ -155,7 +156,9 @@ internal sealed class RuntimeFirstEntryDriveController
/// before the prior route detached would otherwise let the OLD route's
/// dispose wipe the NEW route's tracked entries.
/// </summary>
internal void AttachRoute(object route)
internal void AttachRoute(
object route,
Action<RuntimeEntityRecord>? localPlayerCompleted = null)
{
ArgumentNullException.ThrowIfNull(route);
if (_routeOwner is not null && !ReferenceEquals(_routeOwner, route))
@ -166,6 +169,7 @@ internal sealed class RuntimeFirstEntryDriveController
+ "precedes a new route) before a replacement attaches.");
}
_routeOwner = route;
_localPlayerCompleted = localPlayerCompleted;
}
/// <summary>
@ -181,6 +185,7 @@ internal sealed class RuntimeFirstEntryDriveController
if (!ReferenceEquals(_routeOwner, route))
return;
_routeOwner = null;
_localPlayerCompleted = null;
_pending.Clear();
}
@ -198,6 +203,7 @@ internal sealed class RuntimeFirstEntryDriveController
bool terminal;
bool awaitingContinuationPlacement;
bool localPlayerCompleted = false;
if (pending.IsLocalPlayer)
{
RuntimeLocalPlayerFirstEntryStatus status =
@ -214,6 +220,8 @@ internal sealed class RuntimeFirstEntryDriveController
is RuntimeLocalPlayerFirstEntryStatus.Completed
or RuntimeLocalPlayerFirstEntryStatus.RejectedToken
or RuntimeLocalPlayerFirstEntryStatus.RejectedAuthority;
localPlayerCompleted = status
is RuntimeLocalPlayerFirstEntryStatus.Completed;
awaitingContinuationPlacement = status
is RuntimeLocalPlayerFirstEntryStatus
.AwaitingContinuationPlacement;
@ -241,6 +249,8 @@ internal sealed class RuntimeFirstEntryDriveController
if (terminal)
{
_pending.Remove(key);
if (localPlayerCompleted)
_localPlayerCompleted?.Invoke(pending.Record);
return;
}
if (!awaitingContinuationPlacement)