feat(runtime): bridge executor completion to the placement stream
Cutover slice C0 (docs/plans/2026-08-02-placement-cutover.md): the seam work that lets C3 flip hosts onto a complete receipt stream instead of growing one mid-cutover. The executor's Released exit now publishes an acknowledge-only ExecutorCompleted receipt through the one placement projection stream — registered before observer dispatch, correlated to the full execution receipt, reaped exactly once on acknowledgement/ discard/session-clear, and counted in the convergence ledger. All three production placement sinks acknowledge-and-ignore the new kind via early returns proven behavior-preserving for every existing kind; without them the first such receipt at cutover would permanently wedge the exact-head FIFO behind sinks that return false. Provably inert today: the publisher has no production caller. Execute's live inputs now derive from Runtime's own owners bound at GameRuntime construction: UsePositionFromServer is retail's exact autonomy_level != 2 (CommandInterpreter::UsePositionFromServer 0x006B3B40, startup-only knob), and PlayerDistance uses the live movement controller's position with a null-safe fallback to the caller struct — never a fabricated origin. TryPrepareAndSubmitAuthoredPlacement chains the prepared-collision Setup read through PrepareMover to submission with zero validation-semantics changes. TryCommitParent and CommitWithdrawal gain the sibling cancellation flow (residence + ordinary placement family); TryCommitParent deliberately omits LeaveWorld — retail's set_parent performs its single gated leave_world (0x00515A90) and a second would have no counterpart. Not fully dormant: the two cancellation fixes change Runtime paths production already calls (today as no-op-adjacent hardening, since nothing upstream begins a residence yet); everything else is reachable only by tests. Reviewed: retail-conformance PASS + architecture/ adversarial PASS after one fix round (sink wedge, completion-receipt lifecycle, null-controller distance). Runtime 921/921; complete Release solution 10,716 passed / 4 intentional skips. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
27e05b99e4
commit
67f63e85e5
14 changed files with 1639 additions and 11 deletions
|
|
@ -2379,6 +2379,82 @@ public sealed class RuntimeInitialCreateResidenceStateTests
|
|||
Assert.Single(retained.Continuations).Kind);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// C0-4: TryCommitParent/CommitWithdrawal cancellation asymmetries
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
[Fact]
|
||||
public void TryCommitParent_CancelsActiveInitialResidenceAndItsPendingPlacement()
|
||||
{
|
||||
var engine = new PhysicsEngine { DataCache = new PhysicsDataCache() };
|
||||
engine.AddLandblock(
|
||||
Landblock,
|
||||
new TerrainSurface(new byte[81], new float[256]),
|
||||
Array.Empty<CellSurface>(),
|
||||
Array.Empty<PortalPlane>(),
|
||||
worldOffsetX: 0f,
|
||||
worldOffsetY: 0f);
|
||||
using var lifetime = new RuntimeEntityObjectLifetime(engine);
|
||||
Bind(lifetime, 200UL);
|
||||
const uint guid = 0x70004001u;
|
||||
RuntimeEntityRecord canonical = lifetime
|
||||
.RegisterEntityWithInitialResidence(
|
||||
Spawn(guid, 1, setupId: null),
|
||||
isLocalPlayer: false)
|
||||
.Canonical!;
|
||||
Assert.True(lifetime.TryGetInitialCreateResidence(
|
||||
canonical,
|
||||
out RuntimeInitialCreateResidenceLease lease));
|
||||
// Unparented -> the classifier's route performs SetPosition, so
|
||||
// Own() has already begun the lease's own placement operation.
|
||||
// Submit it (a live Place receipt now sits unacknowledged) so
|
||||
// cancellation has an ACTUAL outstanding receipt to discard, not
|
||||
// merely an unpublished AwaitingPreparation operation.
|
||||
Assert.True(lease.Placement.IsValid);
|
||||
AttachDormantBody(lifetime, canonical);
|
||||
RuntimeSetPositionOutcome outcome = lifetime.Physics.SetPosition
|
||||
.SubmitPreparedPlacement(
|
||||
lease.Placement,
|
||||
Prepare(lifetime, lease, RuntimeSetPositionMoverSetup.ResolvedAbsent));
|
||||
Assert.Equal(
|
||||
RuntimeSetPositionStatus.CommittedHostAcknowledgementPending,
|
||||
outcome.Status);
|
||||
Assert.Equal(1, lifetime.Physics.SetPosition.PendingProjectionCount);
|
||||
|
||||
var discards = new List<RuntimePlacementProjectionSnapshot>();
|
||||
using IDisposable subscription = lifetime.Events.SubscribePlacement(
|
||||
new PlacementObserver(delta =>
|
||||
{
|
||||
if (delta.Placement.Kind is RuntimePlacementProjectionKind.Discard)
|
||||
discards.Add(delta.Placement);
|
||||
}));
|
||||
|
||||
var relation = new ParentAttachmentRelation(
|
||||
ParentGuid: 0x70004100u,
|
||||
ChildGuid: guid,
|
||||
ParentLocation: 1u,
|
||||
PlacementId: 1u,
|
||||
ParentInstanceSequence: 1,
|
||||
ChildPositionSequence: 1);
|
||||
Assert.True(lifetime.TryCommitParent(relation, null, out _));
|
||||
|
||||
Assert.Equal(0, lifetime.CaptureOwnership()
|
||||
.InitialCreateResidenceLeaseCount);
|
||||
Assert.Equal(0, lifetime.Physics.SetPosition.CaptureOwnership()
|
||||
.ActiveOperationCount);
|
||||
// The old Place receipt is REPLACED by a Discard at the same
|
||||
// sequence, not removed outright - still awaiting host ack.
|
||||
Assert.Equal(1, lifetime.Physics.SetPosition.PendingProjectionCount);
|
||||
Assert.False(lifetime.Physics.SetPosition.IsPlacementCurrent(
|
||||
lease.Placement));
|
||||
RuntimePlacementProjectionSnapshot discard = Assert.Single(discards);
|
||||
Assert.Equal(canonical.Key, discard.Token.Entity);
|
||||
Assert.Equal(outcome.Projection.Sequence, discard.Token.Sequence);
|
||||
Assert.True(lifetime.Physics.SetPosition.AcknowledgeProjection(
|
||||
discard.Token));
|
||||
Assert.Equal(0, lifetime.Physics.SetPosition.PendingProjectionCount);
|
||||
}
|
||||
|
||||
private static RuntimeSetPositionCommand Prepare(
|
||||
RuntimeEntityObjectLifetime lifetime,
|
||||
in RuntimeInitialCreateResidenceLease lease,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue