diff --git a/docs/ISSUES.md b/docs/ISSUES.md
index 88e52a17..5f2dd459 100644
--- a/docs/ISSUES.md
+++ b/docs/ISSUES.md
@@ -201,9 +201,32 @@ reasoned-from-source diagnoses.
---
+## #346 — `PortalProjectionTests.ProjectToClipLease_ReusesPooledWorkWithoutResultArrays` is a SIXTH load-sensitive flake
+
+**Status:** OPEN. LOW. Allocation-count assertion, passed in isolation and on
+two subsequent full runs. Same FILE as #302 but a DIFFERENT test — filed
+separately per the never-conflate rule.
+**Filed:** 2026-08-08, observed during #344's suite runs.
+
+---
+
## #344 — Mid-teleport crash: world-frame owners disagree during a long portal into a dungeon
-**Status:** OPEN — HIGH, user-hit during live play 2026-08-07 evening.
+**Status:** FIXED 2026-08-08 — defer-don't-crash, discriminated on the
+canonical transit authority. `TryEnsureAgreesWithRuntimeFrame` defers (the
+materializer's existing "not yet" outcome) when
+`RuntimeWorldTransitState.IsTeleportActive`, and STILL THROWS otherwise —
+the #283 invariant stays loud for genuine corruption, and the sabotage run
+proved the discriminator's removal reddens the original #283 tests, not
+just the new ones. The retry ride is `OnLandblockLoaded`'s re-attempt loop,
+whose ordering GUARANTEES agreement on retry: the recenter coordinator
+calls `Recenter` before `TryCommitOriginRecenter` unblocks new landblock
+loads (verified at source at landing). Entity projected exactly once,
+never dropped. Clean-room suite 11,261/6/0.
+
+**Original filing:**
+
+**Status (original):** OPEN — HIGH, user-hit during live play 2026-08-07 evening.
**Filed:** 2026-08-07 (`339-fix-gate.log`, full stack).
During a long-distance portal into dungeon landblock `0x5A48`, entity
diff --git a/src/AcDream.App/Composition/SessionPlayerComposition.cs b/src/AcDream.App/Composition/SessionPlayerComposition.cs
index 40c12694..160fae44 100644
--- a/src/AcDream.App/Composition/SessionPlayerComposition.cs
+++ b/src/AcDream.App/Composition/SessionPlayerComposition.cs
@@ -461,7 +461,8 @@ internal sealed class SessionPlayerCompositionPhase
live.AnimationPresenter,
live.StaticAnimationScheduler,
d.WorldOrigin,
- d.UpdateClock);
+ d.UpdateClock,
+ d.Runtime.TransitOwner);
var originCoordinator = new LiveEntityWorldOriginCoordinator(
d.WorldOrigin,
streaming,
diff --git a/src/AcDream.App/Rendering/DatLiveEntityProjectionMaterializer.cs b/src/AcDream.App/Rendering/DatLiveEntityProjectionMaterializer.cs
index 1a78c234..665d757c 100644
--- a/src/AcDream.App/Rendering/DatLiveEntityProjectionMaterializer.cs
+++ b/src/AcDream.App/Rendering/DatLiveEntityProjectionMaterializer.cs
@@ -13,6 +13,7 @@ using AcDream.Core.Plugins;
using AcDream.Core.World;
using AcDream.Runtime.Entities;
using AcDream.Runtime.Physics;
+using AcDream.Runtime.World;
using DatReaderWriter;
using DatReaderWriter.DBObjs;
using DatReaderWriter.Types;
@@ -48,6 +49,14 @@ internal sealed class DatLiveEntityProjectionMaterializer
private readonly RetailStaticAnimatingObjectScheduler _staticAnimations;
private readonly LiveWorldOriginState _origin;
private readonly IPhysicsScriptTimeSource _gameTime;
+ ///
+ /// #344: Runtime's authoritative "is a portal/teleport transit currently
+ /// in flight" signal (the same field App's
+ /// LocalPlayerTeleportController.IsActive already exposes) — the
+ /// discriminator between the ordinary #283 corruption case (throw) and
+ /// the legitimate mid-transit ordering race (defer).
+ ///
+ private readonly RuntimeWorldTransitState _transit;
private int _received;
private int _hydrated;
@@ -79,7 +88,8 @@ internal sealed class DatLiveEntityProjectionMaterializer
LiveEntityAnimationPresenter animationPresenter,
RetailStaticAnimatingObjectScheduler staticAnimations,
LiveWorldOriginState origin,
- IPhysicsScriptTimeSource gameTime)
+ IPhysicsScriptTimeSource gameTime,
+ RuntimeWorldTransitState transit)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
_dats = dats ?? throw new ArgumentNullException(nameof(dats));
@@ -101,6 +111,7 @@ internal sealed class DatLiveEntityProjectionMaterializer
_staticAnimations = staticAnimations ?? throw new ArgumentNullException(nameof(staticAnimations));
_origin = origin ?? throw new ArgumentNullException(nameof(origin));
_gameTime = gameTime ?? throw new ArgumentNullException(nameof(gameTime));
+ _transit = transit ?? throw new ArgumentNullException(nameof(transit));
}
public void ResetSessionState()
@@ -164,12 +175,26 @@ internal sealed class DatLiveEntityProjectionMaterializer
CreateObject.ServerPosition position = canonicalSpawn.Position.Value;
int lbX = (int)((position.LandblockId >> 24) & 0xFFu);
int lbY = (int)((position.LandblockId >> 16) & 0xFFu);
- // #283: permanent invariant - the two world-frame owners must agree
- // before their conversions can be mixed. Proven unreachable by the
- // 2026-08-03 probe run; this keeps it that way.
- _origin.EnsureAgreesWithRuntimeFrame(
- _runtime.Physics.WorldFrameCenterLandblockId,
- position.LandblockId);
+ // #283/#344: permanent invariant - the two world-frame owners must
+ // agree before their conversions can be mixed. Outside an in-flight
+ // portal/teleport transit a disagreement has no legitimate
+ // explanation and still throws loudly (proven unreachable there by
+ // the 2026-08-03 probe run; this keeps it that way). DURING a
+ // transit, Runtime can legitimately rebase to the destination before
+ // this owner observes old-window retirement
+ // (LiveWorldOriginState.EnsureAgreesWithRuntimeFrame's doc comment on
+ // the two rebase edges) - that is the #344 ordering race, not
+ // corruption, so this is the existing "not yet" outcome: the
+ // projection parks here and the caller's existing spatial-recovery
+ // retry re-attempts it once streaming recentres and the origins
+ // agree again.
+ if (!_origin.TryEnsureAgreesWithRuntimeFrame(
+ _runtime.Physics.WorldFrameCenterLandblockId,
+ position.LandblockId,
+ transitInFlight: _transit.IsTeleportActive))
+ {
+ return false;
+ }
if (AcDream.Core.Physics.PhysicsDiagnostics.ProbeWorldFrameEnabled)
ProbeWorldFrameAgreement(position.LandblockId);
var worldOrigin = new Vector3(
diff --git a/src/AcDream.App/World/LiveWorldOriginState.cs b/src/AcDream.App/World/LiveWorldOriginState.cs
index e74290e7..7a36b2fa 100644
--- a/src/AcDream.App/World/LiveWorldOriginState.cs
+++ b/src/AcDream.App/World/LiveWorldOriginState.cs
@@ -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.
+ ///
+ /// #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
+ /// TeleportAdvanced 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
+ /// .
///
public void EnsureAgreesWithRuntimeFrame(
uint runtimeCenterLandblockId,
- uint projectingLandblockId)
+ uint projectingLandblockId) =>
+ TryEnsureAgreesWithRuntimeFrame(
+ runtimeCenterLandblockId,
+ projectingLandblockId,
+ transitInFlight: false);
+
+ ///
+ /// #344: the discriminated form of .
+ /// The agreement check itself is UNCHANGED — the guard is correct and stays
+ /// correct; only the response to a genuine disagreement now depends on
+ /// , the authoritative signal for
+ /// "a portal/teleport transit is currently in flight"
+ /// (RuntimeWorldTransitState.IsTeleportActive, the same field
+ /// LocalPlayerTeleportController.IsActive 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
+ /// catches up, not crash. Outside a transit, a
+ /// disagreement has no legitimate explanation and still throws exactly as
+ /// before.
+ ///
+ ///
+ /// if the owners agree (or there is nothing yet to
+ /// agree on); if they disagree while
+ /// is — the
+ /// caller's existing "not yet" outcome, so the projection parks and
+ /// retries on the same cadence it already uses.
+ ///
+ ///
+ /// The owners disagree and is
+ /// — the #283 invariant failure, unchanged.
+ ///
+ 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 "
diff --git a/tests/AcDream.App.Tests/World/LiveWorldOriginStateTests.cs b/tests/AcDream.App.Tests/World/LiveWorldOriginStateTests.cs
index 722c0a36..0953f7c0 100644
--- a/tests/AcDream.App.Tests/World/LiveWorldOriginStateTests.cs
+++ b/tests/AcDream.App.Tests/World/LiveWorldOriginStateTests.cs
@@ -168,4 +168,99 @@ public sealed class LiveWorldOriginStateTests
state.EnsureAgreesWithRuntimeFrame(0xF682FFFFu, 0xF6820033u);
}
+
+ // #344: the discriminated overload. During an in-flight portal/teleport
+ // transit, Runtime rebasing ahead of this owner is the ordinary shape of
+ // the race documented on EnsureAgreesWithRuntimeFrame's doc comment, not
+ // corruption — the caller gets back its existing "not yet" outcome (a
+ // false return, matching every other "not yet" case in
+ // DatLiveEntityProjectionMaterializer.TryMaterialize) instead of a thrown
+ // exception. Outside a transit the guard is unchanged: it still throws.
+
+ [Fact]
+ public void DisagreeingWorldFrameOwners_WhileTransitInFlight_DefersInsteadOfThrowing()
+ {
+ var state = new LiveWorldOriginState();
+ Assert.True(state.TryInitialize(0x09, 0x04));
+
+ bool agree = state.TryEnsureAgreesWithRuntimeFrame(
+ 0xF682FFFFu,
+ 0xF6820033u,
+ transitInFlight: true);
+
+ Assert.False(agree);
+ // The disagreement did not mutate the streamed origin — only
+ // Recenter (driven by StreamingOriginRecenterCoordinator) may do
+ // that.
+ Assert.Equal(0x09, state.CenterX);
+ Assert.Equal(0x04, state.CenterY);
+ }
+
+ ///
+ /// The full #344 round trip: a spawn arrives mid-portal (disagreement,
+ /// transit in flight) and parks; streaming then recentres to the same
+ /// destination Runtime already rebased to, and the exact same query that
+ /// deferred a moment ago now agrees — the caller's existing retry re-
+ /// attempts materialization and this is what lets it proceed. Passing
+ /// transitInFlight:false on the retry too shows agreement no longer
+ /// depends on the discriminator once the origins actually match.
+ ///
+ [Fact]
+ public void DisagreeingWorldFrameOwners_WhileTransitInFlight_ThenAgreeing_RetrySucceeds()
+ {
+ var state = new LiveWorldOriginState();
+ Assert.True(state.TryInitialize(0x09, 0x04));
+
+ bool firstAttempt = state.TryEnsureAgreesWithRuntimeFrame(
+ 0xF682FFFFu,
+ 0xF6820033u,
+ transitInFlight: true);
+ Assert.False(firstAttempt);
+
+ // Streaming recentres: old window fully retires, the streamed
+ // origin adopts the destination Runtime already rebased to.
+ state.Recenter(0xF6, 0x82);
+
+ bool retry = state.TryEnsureAgreesWithRuntimeFrame(
+ 0xF682FFFFu,
+ 0xF6820033u,
+ transitInFlight: false);
+ Assert.True(retry);
+ }
+
+ [Fact]
+ public void DisagreeingWorldFrameOwners_NotInTransit_StillThrowsWithTheOffsetInMetres()
+ {
+ var state = new LiveWorldOriginState();
+ Assert.True(state.TryInitialize(0x09, 0x04));
+
+ InvalidOperationException error =
+ Assert.Throws(() =>
+ state.TryEnsureAgreesWithRuntimeFrame(
+ 0xF682FFFFu,
+ 0xF6820033u,
+ transitInFlight: false));
+
+ Assert.Contains("World-frame owners disagree", error.Message);
+ Assert.Contains("45504m", error.Message);
+ Assert.Contains("0xF6820033", error.Message);
+ }
+
+ [Fact]
+ public void AgreeingWorldFrameOwners_TryVariantPassesRegardlessOfTransitFlag()
+ {
+ var state = new LiveWorldOriginState();
+ Assert.True(state.TryInitialize(0xA9, 0xB6));
+
+ Assert.True(
+ state.TryEnsureAgreesWithRuntimeFrame(
+ 0xA9B6FFFFu,
+ 0xA9B60001u,
+ transitInFlight: true));
+ Assert.True(
+ state.TryEnsureAgreesWithRuntimeFrame(
+ 0xA9B6FFFFu,
+ 0xA9B60001u,
+ transitInFlight: false));
+ }
}