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
|
|
@ -479,6 +479,56 @@ public sealed class HeadlessSessionHostTests
|
|||
Assert.True(projection.TryApply(in discard));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExecutorCompletedReceiptIsAcknowledgeOnlyRegardlessOfRecordValidity()
|
||||
{
|
||||
// F1: mirrors PlacementReceiptUsesExactIncarnationAndDiscardIsAckOnly's
|
||||
// stale-token half - proves ExecutorCompleted is acknowledged
|
||||
// unconditionally (never gated by the record-lookup/portal-shape
|
||||
// checks Place/Withdraw depend on), so a genuinely stale/mismatched
|
||||
// token can never wedge the FIFO behind it.
|
||||
var operations = new FixtureSessionOperations();
|
||||
using var credential = new HeadlessCredentialSecret(
|
||||
"fixture",
|
||||
"password");
|
||||
using var host = new HeadlessSessionHost(
|
||||
Descriptor(),
|
||||
credential,
|
||||
new HeadlessDiagnosticWriter(TextWriter.Null),
|
||||
operations);
|
||||
GameRuntime runtime = host.Runtime;
|
||||
RuntimeEntityRecord record = runtime.EntityObjects
|
||||
.RegisterEntity(Spawn(0x50000006u))
|
||||
.Canonical!;
|
||||
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
|
||||
record,
|
||||
record.CreateIntegrationVersion,
|
||||
record.Snapshot,
|
||||
replaceGeneration: false));
|
||||
var sink = new HeadlessRuntimePlacementProjectionSink(runtime);
|
||||
RuntimePlacementProjectionSnapshot completion = Placement(
|
||||
runtime,
|
||||
record,
|
||||
RuntimePlacementProjectionKind.ExecutorCompleted,
|
||||
Vector3.One,
|
||||
Quaternion.Identity);
|
||||
RuntimePlacementProjectionSnapshot stale = completion with
|
||||
{
|
||||
Token = completion.Token with
|
||||
{
|
||||
Entity = completion.Token.Entity with
|
||||
{
|
||||
Incarnation = unchecked((ushort)(
|
||||
completion.Token.Entity.Incarnation + 1)),
|
||||
},
|
||||
SessionLifetimeVersion = ulong.MaxValue,
|
||||
},
|
||||
};
|
||||
|
||||
Assert.True(sink.TryApply(in completion));
|
||||
Assert.True(sink.TryApply(in stale));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SessionEventRouteOwnsOneObserverAndUnsubscribesBeforeNetworkDetach()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue