fix(world): #344 — a mid-teleport world-frame disagreement defers the projection instead of crashing
Some checks are pending
Headless portability / portable-headless (ubuntu-latest) (push) Waiting to run
Headless portability / portable-headless (windows-latest) (push) Waiting to run
Headless portability / linux-graphical (push) Waiting to run
Headless portability / linux-vulkan (push) Waiting to run
Some checks are pending
Headless portability / portable-headless (ubuntu-latest) (push) Waiting to run
Headless portability / portable-headless (windows-latest) (push) Waiting to run
Headless portability / linux-graphical (push) Waiting to run
Headless portability / linux-vulkan (push) Waiting to run
During a portal transit the two world-frame owners legitimately rebase on different edges (Runtime at TeleportAdvanced, streaming only after old-window retirement), and a spawn projection landing in that window hit the #283 invariant as an unhandled render-path throw — the crash the user hit entering a dungeon. The guard's check is unchanged; only the disagreement RESPONSE is discriminated on the canonical transit authority (RuntimeWorldTransitState.IsTeleportActive, the same field the App layer already reads for portal-in-flight): in transit -> the materializer's existing "not yet" return, parking the projection on its established retry rides (OnLandblockLoaded's re-attempt loop, whose ordering guarantees agreement on retry because the recenter coordinator adopts the new origin BEFORE unblocking new landblock loads — verified at source; plus OnPosition recovery and OnAppearance). Outside transit -> still throws: genuine corruption stays loud. The implementer explicitly ruled out riding the Runtime placement pump, which would have acknowledged-and-discarded the completion receipt and silently dropped the entity forever. Sabotage: removing the discriminator reddened the pre-existing #283 throw tests as well as the new not-in-transit test — the sabotage defeats the original contract, not merely the new coverage. Four new tests cover defer, defer-then-agree-then-succeed (projected exactly once), throw-outside-transit, and the agreeing pass-through. Clean-room suite: 11,261 passed / 6 skipped / 0 failed. #346 filed for a sixth, distinct load-sensitive allocation flake observed during the runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
3f2b2dc3ed
commit
52bdf4df71
5 changed files with 205 additions and 12 deletions
|
|
@ -62,20 +62,69 @@ internal sealed class LiveWorldOriginState
|
|||
/// so no conversion can observe the gap. This is the permanent guard that
|
||||
/// keeps that true — it converts a silent 192 m-multiple misplacement into
|
||||
/// a loud failure if a future change ever reopens the window.</para>
|
||||
///
|
||||
/// <para>#344 found the one window where the two rebase edges CAN
|
||||
/// legitimately observe the gap: a long-distance portal, where Runtime
|
||||
/// already rebased to the destination (the accepted Position's
|
||||
/// <c>TeleportAdvanced</c> edge) while this owner is still mid-flight
|
||||
/// toward the same destination (old-window retirement not yet observed).
|
||||
/// That is an ordering race, not corruption, so it must not crash the
|
||||
/// render thread. Always throws here — this overload keeps its original
|
||||
/// unconditional-throw contract for every existing caller and test; the
|
||||
/// discriminated form a caller can defer on is
|
||||
/// <see cref="TryEnsureAgreesWithRuntimeFrame"/>.</para>
|
||||
/// </summary>
|
||||
public void EnsureAgreesWithRuntimeFrame(
|
||||
uint runtimeCenterLandblockId,
|
||||
uint projectingLandblockId)
|
||||
uint projectingLandblockId) =>
|
||||
TryEnsureAgreesWithRuntimeFrame(
|
||||
runtimeCenterLandblockId,
|
||||
projectingLandblockId,
|
||||
transitInFlight: false);
|
||||
|
||||
/// <summary>
|
||||
/// #344: the discriminated form of <see cref="EnsureAgreesWithRuntimeFrame"/>.
|
||||
/// The agreement check itself is UNCHANGED — the guard is correct and stays
|
||||
/// correct; only the response to a genuine disagreement now depends on
|
||||
/// <paramref name="transitInFlight"/>, the authoritative signal for
|
||||
/// "a portal/teleport transit is currently in flight"
|
||||
/// (<c>RuntimeWorldTransitState.IsTeleportActive</c>, the same field
|
||||
/// <c>LocalPlayerTeleportController.IsActive</c> already exposes to the
|
||||
/// App layer). While a transit is in flight, Runtime rebasing ahead of
|
||||
/// this owner is the ordinary, expected shape of the race documented
|
||||
/// above — the caller should park the projection and retry once
|
||||
/// <see cref="Recenter"/> catches up, not crash. Outside a transit, a
|
||||
/// disagreement has no legitimate explanation and still throws exactly as
|
||||
/// before.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the owners agree (or there is nothing yet to
|
||||
/// agree on); <see langword="false"/> if they disagree while
|
||||
/// <paramref name="transitInFlight"/> is <see langword="true"/> — the
|
||||
/// caller's existing "not yet" outcome, so the projection parks and
|
||||
/// retries on the same cadence it already uses.
|
||||
/// </returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The owners disagree and <paramref name="transitInFlight"/> is
|
||||
/// <see langword="false"/> — the #283 invariant failure, unchanged.
|
||||
/// </exception>
|
||||
public bool TryEnsureAgreesWithRuntimeFrame(
|
||||
uint runtimeCenterLandblockId,
|
||||
uint projectingLandblockId,
|
||||
bool transitInFlight)
|
||||
{
|
||||
// Before either owner is established there is nothing to agree on;
|
||||
// the placement itself is gated separately (#284).
|
||||
if (!IsKnown || runtimeCenterLandblockId == 0u)
|
||||
return;
|
||||
return true;
|
||||
|
||||
int runtimeCenterX = (int)((runtimeCenterLandblockId >> 24) & 0xFFu);
|
||||
int runtimeCenterY = (int)((runtimeCenterLandblockId >> 16) & 0xFFu);
|
||||
if (runtimeCenterX == CenterX && runtimeCenterY == CenterY)
|
||||
return;
|
||||
return true;
|
||||
|
||||
if (transitInFlight)
|
||||
return false;
|
||||
|
||||
throw new InvalidOperationException(
|
||||
"World-frame owners disagree: Runtime centre "
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue