feat(physics): C4 route 4b-1 — remote placement infrastructure (dormant)

Builds the machinery route 4b-2 and 4b-3 will flip on, and changes no remote
behaviour: it has no production caller, so RemotePlacementDrivePendingCount is
provably 0 and IsConverged is unchanged.

Five pieces: a per-entity remote placement owner (RuntimeRemotePlacementDriveController),
a Position-time service-window guard with a Runtime interface plus BOTH host
implementations, N3's headless RetryPending pump, parked-count observability in
the ownership ledger, and the service-window optimisation that avoids parks we
can cheaply predict.

Landed alone because it is where the park-withdraws-the-entity failure was
decided; that decision is fixed at the source in the preceding commit and must
not share a review signal with a behaviour flip.

Two parts of route 2's controller are deliberately NOT ported, both verified
against retail rather than assumed. There is no ack: SendPositionEvent is called
only inside HandleReceivedPosition's local-player FORCE_POSITION gate
@0x0045400C-@0x00454091, and the remote arm @0x0045414D has no equivalent. There
is no re-issue funnel: retail never re-attempts a position it could not apply —
stale timestamps merely bump error_count @0x004542AC — and re-issuing packet N
after N+1 has merged would apply a pose the newer packet already superseded,
which is correct for a one-shot ForcePosition and wrong for a 5-10 Hz stream.

The service-window guard is an OPTIMISATION, not the correctness mechanism. The
original contract had it the other way round, justified by a claim that retail
cannot represent "arrived but not placeable" — false, and corrected in the
review findings: retail's GotoLostCell/reenter_visibility path represents it
exactly. A pre-flight guard also cannot be complete, because Core defers on the
entity's CURRENT cell, on the swept QueriedCellIds footprint spanning
neighbouring landblocks, and on residency evaluated after AdjustToOutside —
conditions only Core can see.

Review found and this commit fixes: DetachRoute cleared two maps of LIVE Core
operations without cancelling them (route 2's AbandonPending is the correct
mirror, not the first-entry controller) and its test asserted that blindness as
convergence; the headless predicate answered "can ever publish" rather than "is
published", and after the first fix still matched only 1 of the 9 landblocks
this host publishes; OwnsPlacement admitted remote top-level Creates until
gated on the Teleport flag as well as the disposition; Advance re-submitted
without re-checking the window; and four comments cited a report that did not
exist.

Contract item 6 is met by the structural proof, not the earlier test:
HasOldPrefixPlacementDebt refuses collision-prefix mutation permission before
ParkCollisionResidents is ever entered, so its overlap throw is unreachable.
That same mechanism is the unbounded stall filed as #310, which 4b-1 does not
bound — it only avoids widening it.

#311 files the remaining per-tick allocation in RetryPendingProjections; the
early-out for the empty-FIFO case landed via a new HasPendingReceipts accessor
so hosts still never touch .Placements. directly.

Gates: complete Release solution 10,973 passed / 4 skipped / 0 failed (baseline
10,938). Four review rounds; every fix discrimination-verified by revert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-04 04:08:19 +02:00
parent 634bc5513a
commit 2e8e09acd0
14 changed files with 3151 additions and 6 deletions

View file

@ -88,7 +88,20 @@ public readonly record struct RuntimeEntityObjectOwnershipSnapshot(
/// <see cref="RuntimeEntityObjectLifetime.RegisterAcceptedPositionDriveOwnership"/>.
/// Gated by <see cref="IsConverged"/> — a leaked pending ack cannot hide.
/// </summary>
int AcceptedPositionDrivePendingCount = 0)
int AcceptedPositionDrivePendingCount = 0,
/// <summary>
/// C4 route 4b-1: outstanding
/// <c>AcDream.Runtime.Session.RuntimeRemotePlacementDriveController</c>
/// preparation-retry entries (a not-yet-resolved
/// <c>RetrySetupUnavailable</c>/<c>RetryWorldFrameUnavailable</c> for a
/// remote), summed over every drive registered against this lifetime via
/// <see cref="RuntimeEntityObjectLifetime.RegisterRemotePlacementDriveOwnership"/>.
/// Gated by <see cref="IsConverged"/>, mirroring
/// <see cref="AcceptedPositionDrivePendingCount"/> — steady-state
/// remotes hold no operations, and this count proves it at every
/// convergence checkpoint the same way.
/// </summary>
int RemotePlacementDrivePendingCount = 0)
{
public bool IsConverged =>
IsDisposed
@ -114,6 +127,7 @@ public readonly record struct RuntimeEntityObjectOwnershipSnapshot(
&& RemoteFirstEntryActiveCount == 0
&& FirstEntryDrivePendingCount == 0
&& AcceptedPositionDrivePendingCount == 0
&& RemotePlacementDrivePendingCount == 0
&& StreamSubscriberCount == 0
&& PlacementStreamSubscriberCount == 0
&& PendingDispatchCount == 0
@ -163,6 +177,8 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
private readonly List<Func<int>> _firstEntryDriveOwnership = [];
/// <summary>C4 route 2: see <see cref="RegisterAcceptedPositionDriveOwnership"/>.</summary>
private readonly List<Func<int>> _acceptedPositionDriveOwnership = [];
/// <summary>C4 route 4b-1: see <see cref="RegisterRemotePlacementDriveOwnership"/>.</summary>
private readonly List<Func<int>> _remotePlacementDriveOwnership = [];
/// <summary>
/// C4 route 4a: captured by <see cref="BindEventContext"/> alongside the
/// other generation-consuming children so
@ -486,7 +502,8 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
LocalPlayerFirstEntry.CaptureOwnership().ActiveCount,
RemoteFirstEntry.CaptureOwnership().ActiveCount,
CaptureFirstEntryDrivePendingCount(),
CaptureAcceptedPositionDrivePendingCount());
CaptureAcceptedPositionDrivePendingCount(),
CaptureRemotePlacementDrivePendingCount());
}
private int CaptureFirstEntryDrivePendingCount()
@ -505,6 +522,14 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
return total;
}
private int CaptureRemotePlacementDrivePendingCount()
{
int total = 0;
for (int i = 0; i < _remotePlacementDriveOwnership.Count; i++)
total = checked(total + _remotePlacementDriveOwnership[i]());
return total;
}
/// <summary>
/// C3c-R1 review F5: registers one host first-entry drive controller's
/// pending-count provider into this lifetime's ownership snapshot, so
@ -535,6 +560,22 @@ public sealed class RuntimeEntityObjectLifetime : IDisposable
_acceptedPositionDriveOwnership.Add(pendingCount);
}
/// <summary>
/// C4 route 4b-1: registers one host
/// <c>RuntimeRemotePlacementDriveController</c>'s pending-count provider
/// into this lifetime's ownership snapshot, mirroring
/// <see cref="RegisterAcceptedPositionDriveOwnership"/> — a leaked
/// remote preparation retry must not sit outside every ledger. The drive
/// controller registers itself at construction; multiple registrations
/// sum (one per host route sharing this lifetime).
/// </summary>
public void RegisterRemotePlacementDriveOwnership(Func<int> pendingCount)
{
ArgumentNullException.ThrowIfNull(pendingCount);
EnsureNotDisposed();
_remotePlacementDriveOwnership.Add(pendingCount);
}
public void BindEventContext(
Func<RuntimeGenerationToken> generation,
Func<ulong> frameNumber)