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:
Erik 2026-08-02 05:22:37 +02:00
parent 27e05b99e4
commit 67f63e85e5
14 changed files with 1639 additions and 11 deletions

View file

@ -946,6 +946,19 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
return true;
}
if (projection.Kind is RuntimePlacementProjectionKind.ExecutorCompleted)
{
// F1: acknowledge-and-ignore, same as Discard. Must NOT fall
// through to the record-lookup/spatial-load gates below - those
// legitimately reject for reasons unrelated to this receipt (no
// sidecar yet, destination backend not loaded), and a false
// return here wedges the whole ordered placement stream at the
// FIFO head (RuntimePlacementProjectionSubscription's contract).
// Provably inert today: PublishExecutorCompletion has zero
// production callers.
return true;
}
RuntimePlacementProjectionToken token = projection.Token;
if (!TryGetRuntimePlacementProjectionRecord(
token,

View file

@ -76,8 +76,21 @@ internal sealed class RuntimePlacementPresentationSink
if (!_liveEntities.TryApplyRuntimePlacementProjection(in projection))
return false;
if (projection.Kind is RuntimePlacementProjectionKind.Discard)
if (projection.Kind is RuntimePlacementProjectionKind.Discard
or RuntimePlacementProjectionKind.ExecutorCompleted)
{
// F1: ExecutorCompleted is acknowledge-and-ignore like Discard -
// no world/presentation mutation by definition. Must NOT fall
// through to the record-lookup gate below (that gate legitimately
// rejects for OTHER reasons, and this sink's caller
// (RuntimePlacementProjectionSubscription) treats a false return
// as "leave at the FIFO head" - a rejected ExecutorCompleted
// would permanently wedge the whole ordered stream). Provably
// inert today: PublishExecutorCompletion has zero production
// callers - see
// RuntimePlacementPresentationSinkTests.ExecutorCompleted_IsAckOnlyNoOpEvenWhenTokenIsStaleOrSidecarIsGone.
return true;
}
if (!_liveEntities.TryGetRecord(
projection.Token.Entity,
out LiveEntityRecord record)