feat(runtime): C3c - production placement cutover: both hosts on the residence conductors (routes 1+8)

Campaign P remaining-physics-divergence, placement cutover slice C3c
(docs/plans/2026-08-02-placement-cutover.md). Both production hosts now
register every initial Create through the residence + continuation-
executor + first-entry-conductor machinery (C0-C3b):

- Graphical (route 1): RegisterEntityWithInitialResidence at Create; the
  shared RuntimeFirstEntryDriveController pumps both conductors from the
  placement-receipt flow; MaterializeProjection and RebucketLiveEntity
  are presentation-only while a residence is ACTIVE (ExecutorCompleted is
  the presentation-binding receipt); post-residence entities take the
  full legacy path including the prepare_to_enter_world clock edges.
  PlayerModeController attaches presentation to the Runtime-published
  controller; its legacy resolve/step-heights/host-construction path is
  deleted; presentation-only rollback (retail has no entry-flow rollback).
- Headless (route 8): OnSpawned registers with residence when a drive
  exists; content-less sessions keep the pre-flip direct registration;
  SynchronizeLocalPlayer/CreateController/ApplySetupStepHeights deleted;
  prepared-collision read failure is a typed AwaitingCollisionSource
  retry; far remotes outside the service window complete celless.
- RuntimeLocalPlayerMovementState.Controller setter sealed internal; all
  controller mutation flows through the publication lifecycle.

Fix slices landed within this cutover, each dual-gated:
- F1: live movement-stat/server-physics application routed through the
  Runtime ownership seam (post-logout ingest crash on the retired
  controller eliminated; RuntimeMovementSkillProjection deleted).
- F2: login activation wedge - collision-admission prefix gate factored
  out of the seal (reentrant-commit RejectedAuthority), rearm generation
  identity corrected, PlayerModeAutoEntry requires the Runtime-published
  controller (world reveal can no longer seal unmaterialized).
- F3: landblock-prefix 0-sentinel replaced by explicit absent-id guards;
  map-corner landblocks (grid row/col 0) fully legal through admission,
  park/rearm/retire, quiescence, and outdoor shadow seeds.
- F5: local-player first-entry ground contact seeded by the shared
  SpawnPlacementSettler (moved App->Core) at FinalizeActivation - the
  retail first-gravity-frame touch (enter_world 0x00516170 carries no
  seed); the legacy unconditional force-seed is overwritten by a real
  floor-found contact; airborne spawns stay airborne; outbound contact
  bit verified end-to-end. Fixes the standing-cast 'You can't do that
  while in the air!' rejections.
- R1 (dual-review round): login constraint leash armed at the committed
  placement (HandleReceivedPosition 0x00453FD0 analog); register rows
  AD-61 (settle-timing compression now covering the local player) and
  AD-42 (repointed off the deleted resolve split) in this commit;
  residence-conversion owner API; wire-landblock guards; drive-pending
  ledger in IsConverged; route attach/detach latch; executor-drain drift
  model documented + source-pinned.

Gates: Runtime 1,003, App 4,039/3 skips, Headless 79, complete solution
10,816/0 failed/4 skips (Release, -m:1); connected lifecycle/reconnect
gate PASS (logs/connected-world-gate-20260802-175401; graceful exits,
world-visible, zero airborne rejections). The nine-stop soak remains red
for the pre-existing 6b28ff99 whole-world collision-clone throughput
regression (attributed with evidence; scheduled as its own slice before
C5). Dual Opus reviews (retail-conformance + adversarial): delta PASS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-02 18:10:33 +02:00
parent 78f1eb1896
commit 529e0e9d88
68 changed files with 5977 additions and 831 deletions

View file

@ -466,6 +466,7 @@ public sealed class EquippedChildProjectionWithdrawalTests
ChildInstanceSequence: 1,
ChildPositionSequence: 1);
fixture.CompleteFirstEntry();
Assert.True(fixture.Live.TryApplyCreateParent(update, out _));
fixture.Controller.OnCreateParentAccepted(update);
@ -509,13 +510,20 @@ public sealed class EquippedChildProjectionWithdrawalTests
LiveEntityRecord parent = fixture.Spawn(0x70000270u, generation: 1);
WorldSession.EntitySpawn childSpawn = ControllerFixture.SpawnData(
0x70000271u,
generation: 1) with
generation: 1);
childSpawn = childSpawn with
{
Position = null,
ParentGuid = parent.ServerGuid,
ParentLocation = 0,
PlacementId = null,
PositionSequence = 0,
Physics = childSpawn.Physics!.Value with
{
Position = null,
Parent = new PhysicsAttachment(parent.ServerGuid, 0u),
AnimationFrame = null,
},
};
fixture.Live.RegisterLiveEntity(childSpawn);
fixture.Controller.OnSpawn(childSpawn);
@ -558,13 +566,20 @@ public sealed class EquippedChildProjectionWithdrawalTests
LiveEntityRecord parent = fixture.Spawn(0x70000272u, generation: 1);
WorldSession.EntitySpawn childSpawn = ControllerFixture.SpawnData(
0x70000273u,
generation: 1) with
generation: 1);
childSpawn = childSpawn with
{
Position = null,
ParentGuid = parent.ServerGuid,
ParentLocation = 0,
PlacementId = 0,
PositionSequence = 0,
Physics = childSpawn.Physics!.Value with
{
Position = null,
Parent = new PhysicsAttachment(parent.ServerGuid, 0u),
AnimationFrame = 0,
},
};
fixture.Live.RegisterLiveEntity(childSpawn);
fixture.Controller.OnSpawn(childSpawn);
@ -577,13 +592,20 @@ public sealed class EquippedChildProjectionWithdrawalTests
Assert.Null(entity.PaletteOverride);
WorldSession.EntitySpawn grandchildSpawn = ControllerFixture.SpawnData(
0x70000274u,
generation: 1) with
generation: 1);
grandchildSpawn = grandchildSpawn with
{
Position = null,
ParentGuid = child.ServerGuid,
ParentLocation = 0,
PlacementId = 0,
PositionSequence = 0,
Physics = grandchildSpawn.Physics!.Value with
{
Position = null,
Parent = new PhysicsAttachment(child.ServerGuid, 0u),
AnimationFrame = 0,
},
};
fixture.Live.RegisterLiveEntity(grandchildSpawn);
fixture.Controller.OnSpawn(grandchildSpawn);
@ -734,6 +756,8 @@ public sealed class EquippedChildProjectionWithdrawalTests
Position = null,
PositionSequence = 1,
PlacementId = 0,
ParentGuid = parent.ServerGuid,
ParentLocation = 0,
Physics = physics,
};
@ -1192,6 +1216,50 @@ public sealed class EquippedChildProjectionWithdrawalTests
private const uint Cell = 0x01010001u;
private readonly DeferredLiveEntityRuntimeComponentLifecycle _lifecycle = new();
private readonly Setup _setup;
private readonly AcDream.Runtime.Session.RuntimeFirstEntryDriveController _firstEntry;
private sealed class NullCollisionSource
: AcDream.Content.IPreparedCollisionSource
{
public AcDream.Content.PreparedAssetPresence ProbeCollision(
AcDream.Content.Pak.PakAssetType type,
uint sourceFileId) =>
AcDream.Content.PreparedAssetPresence.Available;
public AcDream.Content.PreparedCollisionReadResult<
AcDream.Core.Physics.FlatSetupCollision> ReadSetupCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
AcDream.Content.PreparedCollisionReadResult<
AcDream.Core.Physics.FlatSetupCollision>.Missing;
public AcDream.Content.PreparedCollisionReadResult<
AcDream.Core.Physics.FlatGfxObjCollisionAsset>
ReadGfxObjCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public AcDream.Content.PreparedCollisionReadResult<
AcDream.Core.Physics.FlatCellStructureCollisionAsset>
ReadCellStructureCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public AcDream.Content.PreparedCollisionReadResult<
AcDream.Core.Physics.FlatEnvCellTopology> ReadEnvCellTopology(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public AcDream.Content.PreparedCollisionSourceStats CollisionStats =>
default;
public void Dispose()
{
}
}
internal ControllerFixture(
Func<LiveEntityRecord, ulong, ulong, ExactProjectionWithdrawalOutcome>
@ -1201,10 +1269,24 @@ public sealed class EquippedChildProjectionWithdrawalTests
(Cell & 0xFFFF0000u) | 0xFFFFu,
new LandBlock(),
Array.Empty<WorldEntity>()));
Live = LiveEntityRuntimeFixture.Create(
EntityObjects = new RuntimeEntityObjectLifetime();
EntityObjects.BindEventContext(
static () => new AcDream.Runtime.RuntimeGenerationToken(1UL),
static () => 1UL);
_firstEntry = new AcDream.Runtime.Session.RuntimeFirstEntryDriveController(
EntityObjects,
new AcDream.Runtime.GameRuntimeClock(),
new NullCollisionSource(),
() => AcDream.Runtime.Gameplay.PlayerMovementConstructionOptions.Fallback,
static _ => new AcDream.Runtime.Gameplay.RuntimeLocalPlayerPhysicsActivationPreparation(
0.48f,
1.835f,
AcDream.Runtime.Gameplay.RuntimeLocalPlayerShadowDisposition.ProvenShapeless));
Live = new LiveEntityRuntime(
Spatial,
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }),
_lifecycle);
_lifecycle,
EntityObjects);
_setup = new Setup
{
HoldingLocations =
@ -1231,6 +1313,21 @@ public sealed class EquippedChildProjectionWithdrawalTests
}
internal GpuWorldState Spatial { get; } = new();
internal RuntimeEntityObjectLifetime EntityObjects { get; }
/// <summary>
/// C3c: completes fresh residences through the first-entry
/// conductors (a celless route performs no SetPosition, so its drain
/// completes synchronously), releasing the lease so legacy direct
/// CreateParent/Parent application stays valid post-flip. The
/// controller is constructed lazily but binds no notification of its
/// own tracking value until first use, so it sweeps active leases
/// directly instead.
/// </summary>
internal void CompleteFirstEntry()
{
_firstEntry.DriveAll();
}
internal ClientObjectTable Objects { get; } = new();
internal EntityEffectPoseRegistry Poses { get; } = new();
internal LiveEntityRuntime Live { get; }
@ -1254,7 +1351,13 @@ public sealed class EquippedChildProjectionWithdrawalTests
{
WorldSession.EntitySpawn spawn = SpawnData(guid, generation);
if (!hasPosition)
spawn = spawn with { Position = null };
{
spawn = spawn with
{
Position = null,
Physics = spawn.Physics!.Value with { Position = null },
};
}
if (!hasSetup)
spawn = spawn with { SetupTableId = null };
return Assert.IsType<RuntimeEntityRecord>(
@ -1288,21 +1391,59 @@ public sealed class EquippedChildProjectionWithdrawalTests
return record;
}
internal static WorldSession.EntitySpawn SpawnData(uint guid, ushort generation) => new(
guid,
new CreateObject.ServerPosition(
Cell, 0f, 0f, 0f, 1f, 0f, 0f, 0f),
0x02000001u,
Array.Empty<CreateObject.AnimPartChange>(),
Array.Empty<CreateObject.TextureChange>(),
Array.Empty<CreateObject.SubPaletteSwap>(),
BasePaletteId: null,
ObjScale: null,
Name: "attached fixture",
ItemType: null,
MotionState: null,
MotionTableId: null,
InstanceSequence: generation);
internal static WorldSession.EntitySpawn SpawnData(uint guid, ushort generation)
{
// C3c: residence admission freezes the raw create and requires
// the flattened parser projections to agree with the nested
// PhysicsDesc block (HasConsistentCreateIdentityAndParent).
var position = new CreateObject.ServerPosition(
Cell, 0f, 0f, 0f, 1f, 0f, 0f, 0f);
var physics = new PhysicsSpawnData(
RawState: 0u,
Position: position,
Movement: null,
AnimationFrame: null,
SetupTableId: 0x02000001u,
MotionTableId: null,
SoundTableId: null,
PhysicsScriptTableId: null,
Parent: null,
Children: null,
Scale: null,
Friction: null,
Elasticity: null,
Translucency: null,
Velocity: null,
Acceleration: null,
AngularVelocity: null,
DefaultScriptType: null,
DefaultScriptIntensity: null,
Timestamps: new PhysicsTimestamps(
Position: 0,
Movement: 0,
State: 0,
Vector: 0,
Teleport: 0,
ServerControlledMove: 0,
ForcePosition: 0,
ObjDesc: 0,
Instance: generation));
return new WorldSession.EntitySpawn(
guid,
position,
0x02000001u,
Array.Empty<CreateObject.AnimPartChange>(),
Array.Empty<CreateObject.TextureChange>(),
Array.Empty<CreateObject.SubPaletteSwap>(),
BasePaletteId: null,
ObjScale: null,
Name: "attached fixture",
ItemType: null,
MotionState: null,
MotionTableId: null,
InstanceSequence: generation,
Physics: physics);
}
internal void InstallAttached(
LiveEntityRecord parent,

View file

@ -33,7 +33,7 @@ public sealed class LiveAppearanceAnimationTests
ItemType: null,
MotionState: null,
MotionTableId: null,
InstanceSequence: 1);
InstanceSequence: 1).WithConsistentPhysics();
LiveEntityRecord record = runtime.RegisterAndMaterializeProjection(
spawn,
id => Entity(id, 0x01000001u, guid));
@ -175,7 +175,7 @@ public sealed class LiveAppearanceAnimationTests
Assert.Equal(1, registry.RetainedRegistrationCount);
}
private static WorldSession.EntitySpawn Spawn(uint guid, uint cell, ushort instance) => new(
private static WorldSession.EntitySpawn Spawn(uint guid, uint cell, ushort instance) => new WorldSession.EntitySpawn(
guid,
new CreateObject.ServerPosition(cell, 1f, 1f, 1f, 1f, 0f, 0f, 0f),
0x02000010u,
@ -188,7 +188,7 @@ public sealed class LiveAppearanceAnimationTests
ItemType: null,
MotionState: null,
MotionTableId: null,
InstanceSequence: instance);
InstanceSequence: instance).WithConsistentPhysics();
private static WorldEntity Entity(
uint id,

View file

@ -74,7 +74,22 @@ public sealed class LiveEntityCreateSupersessionRecoveryTests
publishAppearance: _ =>
{
operations.Add("appearance");
runtime.RegisterLiveEntity(Spawn() with { Name = "fresher" });
// C3c: a fresher same-generation CreateObject no longer
// advances create authority at registration — while a
// residence is active it is FIFO-staged and its authority
// advance lands at the executor drain's WeenieDescription
// stage (AdvanceCreateAuthority). Model that exact advance
// directly so the between-stage revalidation guard stays
// covered.
// C3c-R1 F3: honest MODEL of the executor drain's advance
// (ApplyWeenieDescriptionAction — the sole production site,
// source-pinned by C3cR1F3DriftModelSourcePinTests); a
// nested production OnCreate can no longer reach it —
// post-residence registration is description-only
// (RuntimeEntityObjectLifetime :660-665,
// !beginInitialResidence gate) and ConsumeExecuted already
// removed the completed residence entry.
record.Canonical.AdvanceCreateAuthority();
return true;
},
publishCurrentSnapshot: _ => operations.Add("current"),
@ -315,7 +330,7 @@ public sealed class LiveEntityCreateSupersessionRecoveryTests
return record;
}
private static WorldSession.EntitySpawn Spawn() => new(
private static WorldSession.EntitySpawn Spawn() => new WorldSession.EntitySpawn(
Guid,
new CreateObject.ServerPosition(
Cell,
@ -336,7 +351,7 @@ public sealed class LiveEntityCreateSupersessionRecoveryTests
ItemType: null,
MotionState: null,
MotionTableId: null,
InstanceSequence: 1);
InstanceSequence: 1).WithConsistentPhysics();
private static LiveEntityAnimationState AnimationState(
WorldEntity entity,

View file

@ -232,7 +232,7 @@ public sealed class LiveEntityLightControllerTests
InstanceSequence: 1,
MovementSequence: 1,
ServerControlSequence: 1,
PositionSequence: 1);
PositionSequence: 1).WithConsistentPhysics();
}
}