acdream/tests/AcDream.App.Tests/World/LiveWorldOriginStateTests.cs
Erik 89cf1e66d0 fix(physics): guard the world-frame agreement proven unreachable by measurement
Closes #283 (plan S3) - as UNREACHABLE, not by restructuring ownership.

acdream has two owners that convert a landblock-local network origin into the
streamed world frame: LiveWorldOriginState for presentation/streaming, and
RuntimePhysicsState.TryGetWorldFrameOffset for placement. They rebase on
different edges - Runtime the instant an accepted Position carries
TeleportAdvanced, App only once StreamingOriginRecenterCoordinator observes
old-window retirement completion, many frames later. A one-landblock
disagreement places an entity 192 m from the geometry around it: the same
failure family as the zero-offset bug 670f307c fixed, with a wrong origin
instead of a missing one.

The plan's first step was to prove or disprove reachability BEFORE moving
ownership, because a restructure on a hypothesis is churn. The probe added in
898ff18b answered it: a connected Release session recorded ZERO disagreements
across 11 completed reveals and six destination landblocks (0x0904, 0x1134,
0x3032, 0x8763, 0xA9B4, 0xF682) spanning roughly 45 km. A gap of even one
frame would have printed an offset in the tens of thousands of metres.

Cause of the safety: BeginOriginRecenter detaches EVERY resident landblock
before the new origin is adopted, so the two rebases are serialized and no
conversion can observe the gap. Ownership is therefore left exactly as it is.

What lands instead is the invariant that keeps it true.
LiveWorldOriginState.EnsureAgreesWithRuntimeFrame is checked at the
landblock->world conversion and is terminal on disagreement, converting a
silent 192 m-multiple misplacement into a loud failure with the offset in
metres and the landblock being projected. Six focused tests pin it, including
the cross-world portal case (0x09 -> 0xF6 = 45,504 m). Disagreement can no
longer reach the probe, so ACDREAM_PROBE_WORLD_FRAME now emits a verbose
per-conversion agreement trace - useful when a placement looks displaced for
some reason OTHER than a frame disagreement.

Complete Release solution: 10,844 passed / 4 skipped / 0 failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 14:33:46 +02:00

171 lines
5.7 KiB
C#

using System.Numerics;
using AcDream.App.World;
namespace AcDream.App.Tests.World;
public sealed class LiveWorldOriginStateTests
{
[Fact]
public void Placeholder_IsNotAuthoritativeUntilFirstInitialization()
{
var state = new LiveWorldOriginState();
state.SetPlaceholder(42, 43);
Assert.Equal(42, state.CenterX);
Assert.Equal(43, state.CenterY);
Assert.False(state.IsKnown);
Assert.True(state.TryInitialize(10, 11));
Assert.Equal(10, state.CenterX);
Assert.Equal(11, state.CenterY);
Assert.True(state.IsKnown);
Assert.False(state.TryInitialize(20, 21));
Assert.Equal(10, state.CenterX);
Assert.Equal(11, state.CenterY);
}
[Fact]
public void Recenter_ReplacesKnownOriginAndResetRetainsItAsPlaceholder()
{
var state = new LiveWorldOriginState();
Assert.True(state.TryInitialize(1, 2));
state.Recenter(3, 4);
state.Reset();
Assert.Equal(3, state.CenterX);
Assert.Equal(4, state.CenterY);
Assert.False(state.IsKnown);
Assert.True(state.TryInitialize(5, 6));
}
[Fact]
public void RecenterBeforeInitialization_PreservesUnknownAndResetIsIdempotent()
{
var state = new LiveWorldOriginState();
state.SetPlaceholder(20, 21);
state.Recenter(30, 31);
state.Reset();
state.Reset();
Assert.Equal(30, state.CenterX);
Assert.Equal(31, state.CenterY);
Assert.False(state.IsKnown);
Assert.True(state.TryInitialize(40, 41));
state.Recenter(50, 51);
Assert.True(state.IsKnown);
Assert.Equal(50, state.CenterX);
Assert.Equal(51, state.CenterY);
}
[Fact]
public void CellLocalForSeed_UsesTheCurrentLandblockOrigin()
{
var state = new LiveWorldOriginState();
state.SetPlaceholder(0x30, 0x32);
Vector3 local = state.CellLocalForSeed(
new Vector3(200f, -300f, 5f),
0x3130_0001u);
Assert.Equal(new Vector3(8f, 84f, 5f), local);
}
// #283: acdream has TWO owners that convert a landblock-local network
// origin into the streamed world frame - this one for presentation and
// streaming, RuntimePhysicsState.TryGetWorldFrameOffset for placement.
// They rebase on different edges (Runtime on the accepted teleport
// Position; this owner only once StreamingOriginRecenterCoordinator
// observes old-window retirement), so a one-landblock disagreement places
// an entity 192 m from the geometry around it - the same failure family
// as the zero-offset bug 670f307c fixed, with a wrong origin rather than
// a missing one.
//
// A 2026-08-03 connected run with ACDREAM_PROBE_WORLD_FRAME=1 (11 reveals
// across six landblocks spanning ~45 km) recorded ZERO disagreements:
// detaching every resident landblock before adopting the new origin
// serializes the two rebases. These pin the permanent guard.
[Fact]
public void AgreeingWorldFrameOwners_Pass()
{
var state = new LiveWorldOriginState();
Assert.True(state.TryInitialize(0xA9, 0xB6));
state.EnsureAgreesWithRuntimeFrame(0xA9B6FFFFu, 0xA9B60001u);
}
[Fact]
public void BeforeEitherWorldFrameOwnerIsEstablished_ThereIsNothingToAgreeOn()
{
var state = new LiveWorldOriginState();
// No accepted origin yet; placement is gated separately (#284).
state.EnsureAgreesWithRuntimeFrame(0xA9B6FFFFu, 0xA9B60001u);
// An accepted origin with no Runtime frame yet is equally not a
// disagreement.
Assert.True(state.TryInitialize(0xA9, 0xB6));
state.EnsureAgreesWithRuntimeFrame(0u, 0xA9B60001u);
}
[Theory]
[InlineData(0xAAB6FFFFu, "192m")]
[InlineData(0xA8B6FFFFu, "-192m")]
[InlineData(0xA9B7FFFFu, "192m")]
[InlineData(0xA9B5FFFFu, "-192m")]
public void DisagreeingWorldFrameOwners_FailLoudlyWithTheOffsetInMetres(
uint runtimeCenter,
string expectedOffset)
{
var state = new LiveWorldOriginState();
Assert.True(state.TryInitialize(0xA9, 0xB6));
InvalidOperationException error =
Assert.Throws<InvalidOperationException>(() =>
state.EnsureAgreesWithRuntimeFrame(
runtimeCenter,
0xA9B60001u));
Assert.Contains("World-frame owners disagree", error.Message);
Assert.Contains(expectedOffset, error.Message);
Assert.Contains("0xA9B60001", error.Message);
}
/// <summary>
/// The exact case the guard exists for: Runtime has rebased on a portal
/// destination while the streamed origin still holds the departure
/// landblock. A cross-world portal makes the offset enormous rather than
/// subtle - 0xF6 - 0x09 = 237 landblocks east = 45,504 m.
/// </summary>
[Fact]
public void ARuntimeRebaseAheadOfTheStreamedOrigin_IsCaught()
{
var state = new LiveWorldOriginState();
Assert.True(state.TryInitialize(0x09, 0x04));
InvalidOperationException error =
Assert.Throws<InvalidOperationException>(() =>
state.EnsureAgreesWithRuntimeFrame(
0xF682FFFFu,
0xF6820033u));
Assert.Contains("45504m", error.Message);
}
[Fact]
public void AfterBothRebaseToTheSameDestination_TheyAgreeAgain()
{
var state = new LiveWorldOriginState();
Assert.True(state.TryInitialize(0x09, 0x04));
// The streamed origin adopts the destination once old-window
// retirement completes; Runtime is already there.
state.Recenter(0xF6, 0x82);
state.EnsureAgreesWithRuntimeFrame(0xF682FFFFu, 0xF6820033u);
}
}