acdream/docs/research/2026-08-04-c4-route-3-architecture-review.md
Erik e0f96a55bf fix(physics): C4 route 3 — portal placement authority (local player)
Removes a duplicate placement authority for local-player portal arrival.
Portalling worked before this change and works after it — this is not a
bug fix, EXCEPT that it found and fixed one dead-code production bug.

THE PRODUCTION BUG: TryExecuteCanonicalPortalPlacement re-read the
accepted destination at Place time, but TryBeginPortalReveal already
consumes that slot at Aim time — so the arm was 100% dead code and every
real portal Place refused with host-token-unavailable. Found only
because we refused to accept 7 skipped tests instead of chasing the
count to zero.

RETAIL IS THE GENERIC PATH FOR THE THIRD ROUTE RUNNING:
SmartBox::TeleportPlayer @0x00453910 = SetPositionSimple(dest, 1) with
flags 0x1012, followed by PlayerPositionUpdated.

BOTH INVERSIONS, WITH THEIR ANCHORS: unlike route 2, the leash IS armed
here (ConstrainTo @0x0045418A) and velocity is zeroed
(set_velocity @0x004541B4); unlike route 4b-3, the local teleport_hook
runs AFTER placement (@0x004538AE).

THE THREE-ROUND DEFECT CHAIN, HONESTLY:
- Round 1 released the player at the pre-teleport position while the
  anim stream marched on — the contract wrongly assumed Place re-fires
  (process rule 1's third occurrence this campaign).
- Round 2's fix inferred commit from a global PendingCount, which three
  non-committing paths also clear — making the SAME bug complete
  cleanly and silently. Strictly worse than round 1: round 1 at least
  tripped portal-complete-before-materialized.
- Round 3 latches the commit where it actually happens
  (ReconcileAndAcknowledgePortal), keyed on reveal generation and
  teleport sequence, via TryConsumePortalCommit. Two of the three
  required regression tests landed and are sabotage-verified on both
  hosts (ParkedPlace_ForgottenByOrdinaryMergeDoesNotLatchAsCommitted /
  HeadlessPortalPrepareDestinationForgottenByOrdinaryMergeDoesNotLatchAsCommitted).
  The third (force-arm-takes-the-slot) was judged unnecessary on review:
  with the inference gone, PendingCount is only a "don't ask yet" guard
  at both gates, so a force operation occupying or vacating the slot no
  longer changes an input the commit decision reads — the case collapses
  into what the landed test already discriminates.

THE B2/P3 RESOLUTION: both round-2 reviews were right about different
branches of the same synchronous call. RuntimePlacementProjectionSubscription
.OnPlacement acknowledges the FIFO head only when TryApply returns true;
a Place whose portal authority went stale (transit ended/superseded
while parked) used to return false, wedging every later entity's
placement receipt behind it forever. Both sinks
(RuntimePlacementPresentationSink, HeadlessRuntimePlacementProjectionSink)
now acknowledge-and-ignore a stale-authority Place instead of refusing
it. The regression test (RuntimePlacementPresentationSinkTests
.PortalPlace_StaleTransitHostOrSequenceIsAcknowledgedAndIgnored) had
been asserting the old, wrong `false` behaviour; it now asserts and
sabotage-verifies the fix.

Also lands: AP-144 (register discipline — the portal movement-event
send reuses the stricter UsePositionFromServer gate where retail's
SendMovementEvent is the looser autonomy_level != 0 test, diverging
only at level 1, currently unreachable), AP-145 + issue #318 (the
local-player collision-shadow presentation write bypasses its own
publisher's ShadowObjects write via a direct cache .Set(), self-healing
only once dedup diverges — filed, not fixed, pending a composition
test), AD-42 deleted (its last citation retired by the canonical portal
arm), AD-2 updated (the wait-cue's trigger predicate now covers a
second cause), and two documentation corrections: the enter_world
misattribution (both call sites are in SmartBox::HandleCreateObject,
only one in the player branch — portal arrival is TeleportPlayer, not
enter_world) and the stale "local player never reaches this path"
comment on the generic-remote-render-pose write.

Suite: 11,090 passed / 4 skipped / 0 failed. No new skips, nothing
weakened.

STILL OWED: the connected two-client gate, with
ACDREAM_PROBE_LOCAL_TELEPORT=1, scored only if [local-tp] lines
actually appear in the capture — and explicitly NOT scored as covering
issue #318 (no composition test yet asserts PhysicsEngine.ShadowObjects
directly).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 03:57:37 +02:00

29 KiB

C4 route 3 — architecture / adversarial review (2026-08-04)

Verdict: FAIL.

Reviewed: the uncommitted working-tree diff (git diff HEAD + untracked) on claude/acdream-physics-divergence-5aa784 at HEAD cd3129e9 (route 7's commit, "child cell propagation moves from a render tick into Runtime"). 16 files, +1,573/-216.

Reference documents read in full: the route-3 contract (2026-08-04-c4-route-3-contract.md), the route-3 scoping, the route-2 contract, and the route-5/route-7 review defect classes.

Independent verification performed against source, not against the implementer's summary: RuntimeWorldTransitState, RuntimeSetPositionState's commit tail, RuntimeEntityObjectEventStream/ RuntimePlacementProjectionSubscription (publication synchronicity), RuntimePlacementPresentationSink + LiveEntityRuntime .TryApplyRuntimePlacementPlace, LocalPlayerShadowSynchronizer, LocalPlayerProjectionController, TeleportAnimSequencer, and both hosts' Advance() pump sites. dotnet build AcDream.slnx -c Debug exits 0.

The _pendingDestination fix — the item flagged as highest risk — is correct, and is not the reason for the FAIL. See §"Judgment on the _pendingDestination lifetime" at the end.

The FAIL rests on A1 and A2: the slice adds five new ways for the Place edge to refuse, and the refusal path it hands them to does not stop the teleport animation stream. One of those five (DeferredCell) additionally commits the placement out of band after the transit has ended, which both splits the body from presentation and leaves a placement receipt nothing can consume — proof obligations P3 (graphical half) and P4 are undischarged, and D-T2.4's "the wake path must re-validate the portal authority before committing" is not implemented at all.


MAJOR

A1 — A refused canonical Place does not stop the teleport animation; the player is released into the world without ever having been placed

Severity: MAJOR (FAIL basis).

src/AcDream.Core/World/TeleportAnimSequencer.cs:134-142:

case TeleportAnimState.Tunnel:
    if (worldReady)
    {
        evts.Add(TeleportAnimEvent.Place);
        Advance(TeleportAnimState.TunnelContinue, enterTunnel: false);
        _continueElapsed = 0f;
    }
    break;

TeleportAnimEvent.Place is emitted exactly once, and the sequencer advances to TunnelContinue in the same statement block, unconditionally and with no knowledge of whether the consumer's handler succeeded. There is no path back to Tunnel.

src/AcDream.App/Streaming/LocalPlayerTeleportController.cs:505-526:

case TeleportAnimEvent.Place:
    if (!_worldReveal.CanPlacePortalDestination(...)) return;
    if (!TryExecuteCanonicalPortalPlacement(sequence))
        return;                                   // <- new in this slice
    ...
    _placement.Place(_pendingRotation);
    ...
    _worldReveal.ObserveMaterialized(...);

The return exits Tick, but the sequencer has already left Tunnel. Every subsequent Tick therefore runs the rest of the stream with no placement and no materialization:

next event what runs
TunnelContinueTunnelFadeOut
PlayExitSound (:532-542) _worldReveal.RevealWorldViewport() + _presentation.ExitTunnel()
FireLoginComplete (:543-554) _mode.EnterWorld(), _session.SendLoginComplete(), _worldReveal.Complete(), ResetTransit(clearSession: false)

WorldRevealCoordinator.RevealWorldViewport only needs a live host projection (WorldRevealCoordinator.cs:258-266) — present. Complete() reaches RuntimeWorldTransitState.Complete (:701-706), which hits FailInvariant("portal-complete-before-materialized") and returns false; FailInvariant (:934-946) only increments a counter and logs — it does not throw and does not stop the caller. ResetTransit then runs EndTeleport() + _worldReveal.Cancel().

Concrete failure scenario. A Contention outcome (route 2's force arm, a route-7 parent drive, or an earlier park still owns the entity's placement token at the Place edge) makes TryExecuteAcceptedPortalArrival return Contention at RuntimeAcceptedPositionDriveController.cs:492-501. The player watches the portal tunnel finish normally, the world viewport is revealed, LoginComplete is sent to ACE — and the player is standing at the pre-teleport position in the pre-teleport cell. ACE has them at the destination. Every subsequent server broadcast fights the client. Nothing in the client logs above [world-reveal] event=invariant-failure (a SafeLog line), and the D-T8 probe never emits because ReconcileAndAcknowledgePortal never ran.

Why this is the slice's problem and not inherited. The pre-existing CanPlacePortalDestination early return (:506-512) has the same shape, but it fires only when the transit no longer owns this reveal — a case where marching on is at worst redundant, because a newer transit owns the world. This slice adds five new refusal causes that all fire while the transit is perfectly healthy: host-token-unavailable, NotApplicable, Rejected, Contention, and DeferredCell (LocalPlayerTeleportController.cs:596-625, which treats everything except Committed as a refusal at :619).

Contract obligations violated. §4 item 4 ("on every refusal … the transit remains coherent … never a half-state … no path leaves the player permanently in portal space with a dead operation"); §4 item 5 ("a refused placement must NOT … RevealWorldViewport, must NOT advance the anim-event stream's terminal events"); D-T5's Begin-refusal row ("the anim stream stays where it is, so the NEXT Tick re-attempts the Place edge … if the Place anim event is one-shot, the re-attempt must be driven by the same Tick predicate that produced it, and THAT mechanism must be stated in the commit"); and proof obligation P4 verbatim. P4 was to be discharged by reading TeleportAnimSequencer. It is one-shot. No re-attempt driver exists.

Fix direction. Two shapes are available without touching the sequencer (stop condition 2 forbids sequencer timing changes):

  1. Make the Place edge idempotent-and-latched at the controller: keep a _placementCommitted flag; on a refusal, do NOT let the stream reach PlayExitSound/FireLoginComplete — gate those two cases on the latch and drive a bounded re-attempt from the same ready predicate that produced the Place event (the contract's stated fallback). A refusal that never converges must then take the existing transit cancellation (ResetTransit(clearSession: false) — which already cancels the reveal and restores presentation) rather than a silent world release.
  2. Or treat a refusal as an immediate transit cancellation and let the existing supersession path own recovery. Louder, smaller, and it satisfies D-T5's "never a silent wedge" — but it needs the user's eyes because it is user-visible (the portal fails and the player stays put) rather than a silent desync.

Either way this needs a test: refused arm → the anim stream does not reach RevealWorldViewport/FireLoginComplete with an unplaced body.


A2 — A DeferredCell portal park splits the body from presentation and leaves a placement receipt nothing can consume (P3 undischarged on the graphical host; D-T2.4's re-validation missing)

Severity: MAJOR.

RuntimeAcceptedPositionDriveController.SubmitAndResolvePortal:614-645 parks a DeferredCell outcome into _pending carrying the portal authority. LocalPlayerTeleportController.TryExecuteCanonicalPortalPlacement:619 returns false for it, so A1's march runs: the stream reaches FireLoginComplete, ResetTransit calls _transit.EndTeleport() and _worldReveal.Cancel().

The park is still live. Advance() is pumped by the graphical host at src/AcDream.App/Net/GraphicalSessionEventRoute.cs:117 and src/AcDream.App/World/LiveEntityHydrationController.cs:416. When the destination landblock's collision generation eventually commits:

  • Advance:763-771 runs ReconcileAndAcknowledgePortal — the body moves, the leash re-arms, autorun cancels, and one outbound movement event is sent — seconds after the player was already released into the world at the old position. Presentation is never told: _placement.Place and ObserveMaterialized are unreachable (the anim event is one-shot, A1).
  • The commit publishes a Place receipt whose Token.Portal still names the ended reveal. RuntimeWorldTransitState.IsCurrentPlacementAuthority:258-275 requires IsCurrentPortalDestination (:870-882), which requires _teleportActive — cleared by EndTeleport (:547-556). It returns false forever.
  • RuntimePlacementPresentationSink.TryApply:100-106 therefore returns false; RuntimePlacementProjectionSubscription.OnPlacement:134-136 leaves the receipt at the FIFO head. Every later placement receipt for every entity is blocked behind it, and AcceptedPositionDrivePendingCount never returns to zero, so GameWindowLifetime.DisposeGameRuntime throws on shutdown.

That is precisely the failure mode P3 exists to rule out ("A receipt nothing can ever consume or retire is a FIFO wedge"). P3 was discharged only for the headless happy path; the graphical park was not walked.

Independently, D-T2.4's explicit requirement is not implemented: "its wake path must re-validate the portal authority before committing". Neither Advance's AwaitingCommitWake branch (:763-771) nor its IsPlacementCurrent re-submit branch (:813-819) re-checks the portal authority — they pass pending.Portal straight through.

Fix direction. (a) Re-validate the portal authority at both wake points (_entityObjects has no transit handle today — the drive needs a Func<bool>-style currency predicate or the authority passed back through the transit owner); on failure take AbandonPending's exact shape (restoreCancelledPark: true + PublishCancellation) so the park is retired rather than committed. (b) Independently, A1's fix must prevent the transit from ending while a portal park is outstanding.


MEDIUM

A3 — Headless discards the arm's status entirely; a failed placement is silent

src/AcDream.Headless/Hosting/HeadlessSessionWorldProjection.cs:768-780:

if (_acceptedPositionDrive is not null)
{
    var authority = new RuntimePortalPlacementAuthority(...);
    _ = _acceptedPositionDrive.TryExecuteAcceptedPortalArrival(destination, authority);
}

Two problems. First, the status is discarded: any non-Committed outcome leaves the body unmoved while TryCompletePortal (RuntimeLiveEntitySessionController.cs:530-585) proceeds through AcknowledgeDestinationReadinessAcknowledgePortalMaterializedCompleteTerminalProjectedLoginCompleteEndTeleport — asserting a materialization that did not happen (§4 item 5) and telling ACE the login completed. The deleted ResynchronizeLocalPlayerForPortalArrival was unconditional and could not fail this way. Second, the is not null guard means a composition regression that fails to wire the drive silently disables headless portal placement with no signal at all; the previous code had no such mode.

Fix direction. Treat a non-Committed status as a hard failure on this path (TryCompletePortal already throws on every other Runtime refusal — match that), and make the drive a required constructor dependency for the production projection.

A4 — Both inversions are hardcoded; the classifier route facts that encode them are never read

ReconcileAndAcknowledgePortal(RuntimeEntityRecord, in RuntimeAuthoritativePositionRoute route, in RuntimePortalPlacementAuthority) (RuntimeAcceptedPositionDriveController.cs:667-698) never references route. PlayerMovementController.CommitCanonicalTeleportFrame:1987-2035 unconditionally zeroes velocity, runs StopCompletelyAtPhysicsObjectBoundary, UnStick/UnConstrain, and RearmConstraintLeashAtCurrentPosition.

So route.ZeroVelocity, route.ConstrainPhase, and route.TeleportHookPhase are recorded-not-consumed, even though D-T2.3 pinned "route.ZeroVelocity is honored at the commit". The visible behaviour is correct today only because the classifier's LocalPlayer-teleport branch happens to agree with the hardcoded method.

Consequence for test quality: the contract's own §8 item 11 sabotage — "hardcode the force route onto the portal arm (ConstrainPhase.None) → test 5a fails" — cannot fail, because no code path reads ConstrainPhase. No test discriminates the classifier from the executor. A future classifier edit (the classifier is a shared surface routes 2/4b-2/4b-3 also consume) diverges from behaviour silently.

Fix direction. Either consume the route facts in the frame commit (branch on ZeroVelocity/ConstrainPhase) and add the discriminating test, or delete the unused route parameter and state explicitly, in the class doc and in AD-2, that the inversions are enforced by CommitCanonicalTeleportFrame and NOT by the classifier — so the next reader does not trust a route fact that nothing reads.

A5 — Contract §8 item 8's committed-receipt presentation suite is missing; invariant 6's "the local-player collision shadow agrees" is asserted nowhere

No test in this diff drives a committed portal placement through the real RuntimePlacementPresentationSink plus the suffix. tests/AcDream.App.Tests/World/RuntimePlacementPresentationSinkTests.cs is untouched; its only portal test (PortalPlace_RequiresExactCurrentTransitHostAndSequence:467) drives a synthetic token, not a local-player placement. The App teleport tests assert harness.Placement.Called against a fake placement.

That missing suite would have surfaced the following latent inconsistency, which route 3 newly makes reachable on the portal path:

  • RuntimePlacementPresentationSink.TryPublishPlace:226-232 writes _localPlayerShadow.Set(entity.Position, entity.Rotation, record.FullCellId). LocalPlayerShadowState.Set updates only the cache — it never touches PhysicsEngine.ShadowObjects.
  • LocalPlayerShadowSynchronizer.SyncPose:59-70 dedups against that same cache (cellId equal AND position within 1 cm AND orientation within tolerance ⇒ return without publishing).
  • LocalPlayerProjectionController.Project:102 early-returns for PlayerState.PortalSpace, so the sink's cache write is the last word until the player re-enters the world.

Net: the first post-arrival SyncShadow sees a cache that already claims the resolved pose and resolved cell, skips, and the player's collision shadow row is not published at the destination. It self-heals the first time the player moves more than ~1 cm, so the window is short — but during it, other entities have no collider for the player at the destination. (The shape is pre-existing from route 2's force arm, where Project runs every frame so the window is one frame; route 3's portal-space skip widens it.)

Fix direction. Write the §8 item 8 suite. Independently, either have the suffix re-publish the shadow through LocalPlayerShadowSynchronizer (force: true) after writing the resolved entity pose, or stop the sink from writing a "last published" cache entry it did not publish.

A6 — The one test that discriminated which destination gets placed lost its discriminator

tests/AcDream.App.Tests/Streaming/LocalPlayerTeleportControllerTests.cs, superseded-teleport scenario:

-        Assert.Equal(new Vector3(2f), harness.Placement.Position);
+        Assert.True(harness.Placement.Called);

The old assertion proved the second destination (2,2,2) was placed and not the first (1,1,1). Assert.True(Called) cannot distinguish them. That is exactly the property the _pendingDestination caching change puts at risk (caching an Aim-time value instead of re-reading). Two sibling tests lose the same class of assertion, and one now contradicts its own name: SameLandblockDestination_DoesNotRecenterAndKeepsTranslatedPosition no longer asserts any position or cell.

This is the route-5 "tests that assert only negatives"/weakened-successor defect class. The replacement assertion is available: the harness now owns a real Runtime RuntimeLocalPlayerMovementState, so Assert.Equal(expected, movement.Controller!.Position) and .CellId are reachable; the harness simply does not expose movement.

Fix direction. Expose the Runtime controller on the harness and restore a positive position/cell assertion in each of the three tests, at minimum in the superseded-teleport one.

A7 — Dual-host parity (§8 item 6) is not met; the headless flip is untested

tests/AcDream.Headless.Tests/HeadlessSessionHostTests.cs:413-424 now documents that the fixture's projection is built without a drive controller, so "the canonical portal arm this method now calls is a no-op here by construction", and defers the headless committed-portal test as "an open item, not attempted here given this session's time budget".

The contract states plainly: "The headless arm reuses the identical Runtime entry — dual-host parity is a test obligation, not an aspiration (§8)." Combined with A3, the entire headless production placement flip — the deletion of ResynchronizeLocalPlayerForPortalArrival, the new portal parameter, the new call — has zero behavioural coverage. The only surviving assertion change is CenterCount 3→2.


MINOR

A8 — Portal-test cleanup runs at the end of the test body, so the first assertion failure is masked by a teardown throw

ConvergePortalHost is invoked as the last statement of each portal test (RuntimeAcceptedPositionDriveControllerTests.cs:1273/1380/1423/1519). If any earlier Assert throws, cleanup is skipped, StartedRuntime.Dispose() throws during unwinding, and C# using/try…finally lets the finally-exception replace the in-flight one.

The implementer diagnosed their own instance of this correctly (claim 1 — verified: the mechanism is real and the two corrected assertions were genuine test bugs, since an accepted TeleportAdvanced merge rebases the world frame onto the destination per #283, and ReconcileAndAcknowledgePortal does legitimately send one movement event). But the pattern remains in the shipped tests, and it is exactly how a genuine host-projection leak would also present — which is why it is worth removing rather than remembering.

Fix direction. try { … } finally { ConvergePortalHost(…); }, or make StartedRuntime.Dispose record non-convergence and assert it explicitly.

ConvergePortalHost itself is otherwise sound: it cannot double-release — AcknowledgeHostProjection's TerminalProjected branch removes the record (RuntimeWorldTransitState.cs:343-355) and a second call returns false — and it cannot leak, because a forgotten call throws at Dispose.

A9 — Two sources for one teleport sequence

LocalPlayerTeleportController.cs:613 builds the authority's TeleportSequence from _transit.ActiveTeleportSequence (passed in as sequence), while ClassifyPortalArrival (RuntimeAcceptedPositionDriveController.cs:514-535) derives its accepted/prior pair from destination.TeleportSequence. They agree today — OfferTeleportDestination:490-497 refuses a second destination for an already-accepted active sequence — but two sources for one fact is the campaign's "mapping written against one caller's reachable set" shape.

Fix direction. Use destination.TeleportSequence in both, or assert equality at the producer.

A10 — Two documentation statements assert behaviour the code does not have

(a) The new class doc on LocalPlayerTeleportPlacement (LocalPlayerTeleportController.cs:188-193) says the sink "snapshots whatever the entity already holds and writes no pose itself — this is the render entity's mover". TryPublishPlace writes no pose, but the sink's own upstream call chain does: RuntimePlacementPresentationSink.TryApply:108LiveEntityRuntime.TryApplyRuntimePlacementProjection:1301TryApplyRuntimePlacementPlace:1386-1420, which performs entity.SetPosition(projection.WorldPosition), entity.Rotation = …, entity.ParentCellId = token.ExactCellId, and RebucketLiveEntity — all before TryPublishPlace snapshots. The suffix's entity writes and rebucket are therefore redundant repeats of a mutation the canonical receipt already made.

This is harmless at runtime today, but it is the "a doc asserting behaviour the code does not have" class — and the contract carries the same misreading (§3.4, D-T4, §12.5(b)), so correcting the code comment alone is not enough.

(b) The plan correction in docs/plans/2026-08-02-placement-cutover.md says "RuntimeAcceptedPositionDriveController's portal arm reading it — was already live before route 3 (from route 2's shared drive controller)". The portal arm was added by this slice. A correction that itself asserts a false fact is worse than the line it corrects.

A11 — PhysicsDiagnostics.LocalTeleportHostKind is a process-global mutable set from a host

src/AcDream.Core/Physics/PhysicsDiagnostics.cs + HeadlessSessionHost.cs:625. Correct under K3/K4 (all sessions in a headless process are headless), and the doc comment says so — noted only so it is not later mistaken for per-session state. No action required this slice.

A12 — AddSyntheticIndoorCell is representative enough to pass the gate, and no more

The helper registers a CellPhysics with an empty Resolved polygon dictionary, one PortalInfo(0,0,0), and a leaf-only BSP root. It is not shaped to make a specific assertion pass — it mirrors RuntimeSetPositionStateTests.AddSyntheticCell and its only effect is to make PhysicsEngine.IsSpawnCellReady return true for an indoor cell, which is a genuine fixture gap (a bare AddLandblock passes an empty CellSurface list, so indoor destinations parked DeferredCell forever). Accepted.

The caveat: because the destination cell has no geometry, the App-layer tests prove "the arm returned Committed", not "the destination resolved somewhere sane". That makes A6's missing position assertions more load-bearing, not less.


Verified correct (checked against source, not taken on report)

  • P1 (the D-T3 duty map). RuntimeSetPositionState.cs:5036-5058 calls PhysicsObjUpdate.CommitSetPositionContactTransition unconditionally inside the canonical commit, and CommitSetPositionContactPrefix (PhysicsObjUpdate.cs:153-175) derives Contact/OnWalkable/ WaterContact from the placement result's own InContact/OnWalkable. Not re-seeding TransientState in CommitCanonicalTeleportFrame is correct and is more faithful than SetPositionCore's unconditional Contact|OnWalkable|Active overwrite, exactly as claimed.
  • P3, happy path, both hosts. RuntimeEntityObjectEventStream .PublishPlacement:164-171EnqueueAndDrainRuntimePlacementProjectionSubscription.OnPlacement:122-150 is synchronous, inside CommitCanonical. Headless's placement therefore commits and its receipt is consumed inside PrepareDestination, strictly before AcknowledgePortalMaterialized/Complete/EndTeleport. The receipt-past-EndTeleport hazard is discharged for the committed path. (The residual is A2's park.)
  • Trap T7 / route-2 blast radius. No portal pending reaches SettlePending or _newestForce: the three pending.Portal.Present guards at :763, :794, and :820 fence every terminal path, and SubmitAndResolvePortal is a genuine sibling of SubmitAndResolve rather than an overload of it. git diff shows zero expectation changes in any force-arm test — the contract's §4 item 8 tripwire is clean.
  • Implementer claim 1 (the teardown throw was a test bug). Mechanism verified. Both corrected assertions were genuinely wrong for the stated reasons, and the using-finally exception-replacement is real. See A8 for the residual.
  • Sabotage B's asymmetry. Verified structurally: PortalProducerInvalidAuthority_ArmDoesNotRunAndNothingMutates builds an authority with RevealGeneration: 0, which fails RuntimePortalPlacementAuthority.IsValid at TryExecuteAcceptedPortalArrival:459before ClassifyPortalArrival is reached. Forcing the classifier to reject cannot change that test's outcome, so the 4-of-5 asymmetry is exactly what the code shape predicts. Good evidence.
  • Register bookkeeping. AD-42's deletion is justified (its last citation was D2's two-call Resolve+ResolvePlacement, which is gone); AD-2's amendment states the deferred-place adaptation, the T8 tolerance, and the leash-anchor nuance as D-T9 required; the :2276 stale comment correction landed; the 2026-07-16 pseudocode enter_world correction landed. Row count 49→48 is consistent.
  • Build. dotnet build AcDream.slnx -c Debug exit 0 at the reviewed tree.

Judgment on the _pendingDestination lifetime

The cached destination's lifetime is correct. I found no way to Place against a superseded destination, and the Place-time re-read it replaced protected against nothing.

The reasoning, checked against source:

  1. The bug was real and total. RuntimeWorldTransitState .TryBeginPortalReveal:159-183 clears _hasAcceptedDestination and _acceptedDestination at :180-181 on success. TryGetAcceptedTeleportDestination:522-527 returns _teleportActive && _hasAcceptedDestination. Since AimDestination drives TryBeginPortalReveal through WorldRevealCoordinator.TryBeginPortal (:742), the slot is empty at every Place edge. The old re-read could never succeed — every real portal placement would have refused with cause=host-token-unavailable. Not a stale-destination guard; a hard failure.

  2. Write/clear is in exact lockstep with _pendingCell. _pendingRotation/_pendingCell/_pendingDestination/ _hasPendingDestination are written together at :780-783 and cleared together at :801-805 in ResetTransit. _pendingCell != 0u is itself the haveDestination predicate (:481), so the two cannot diverge. _pendingDestination.Position.ObjCellId is _pendingCell by construction (Position position = destination.Position; at :715).

  3. A second Aim cannot produce a mismatched pair. Supersession by a new F751 goes through OnTeleportStartedResetTransit(clearSession: false), which clears all four fields and bumps _lifetimeGeneration. Supersession by a second destination on the same sequence is impossible: OfferTeleportDestination:490-497 returns false once _destinationAccepted is set, and TryBeginPortalReveal clears only _hasAcceptedDestination, leaving _destinationAccepted latched for the life of the reveal. So the destination is pinned from Aim to terminal, by the transit itself.

  4. The one torn window fails closed. _pendingRevealGeneration is written at :749, before the IsCurrentLifetime/recenter guards at :750, :757, :764, while the other three are written at :780-783. A false return from any of those guards leaves a NEW generation paired with an OLD cell/destination. Both Place-edge gates then refuse: CanPlacePortalDestination(newGen, seq, oldCell) fails IsCurrentPortalDestination's destinationCell == _snapshot.DestinationCell check, and TryRegisterHostProjection(newGen, oldCell) fails the same comparison at RuntimeWorldTransitState.cs:197-209. Neither can commit a stale pair. (This tearing predates the slice — _pendingCell already had it; _pendingDestination does not worsen it.)

  5. Terminal clearing. Commit → FireLoginCompleteResetTransit. Session reset / generation reset → ResetSession / ResetGenerationPresentationResetTransit. Cancellation through ResetTransit(clearSession: false). A refused Place leaves the fields set — but so does _pendingCell, and both Place-edge gates are keyed on the reveal generation, so a retained value is inert until a new Aim overwrites it or a reset clears it.

The one thing the caching genuinely costs is test coverage, not correctness: A6 removed the only assertion that could have distinguished a stale cached destination from a fresh one. Restore it.


Summary

# Severity Finding
A1 MAJOR Refused Place does not stop the anim stream; player released into the world unplaced. P4 undischarged.
A2 MAJOR DeferredCell park commits after EndTeleport: body/presentation split + unconsumable Place receipt (P3 graphical half, D-T2.4 re-validation missing).
A3 MEDIUM Headless discards the arm's status; is not null guard silently disables placement.
A4 MEDIUM route.ZeroVelocity/ConstrainPhase/TeleportHookPhase never read; inversions hardcoded; contract sabotage 3 cannot fail.
A5 MEDIUM §8 item 8 presentation suite missing; local-player shadow invariant unasserted, and a real cache/publish desync sits behind it.
A6 MEDIUM Superseded-teleport test lost its destination discriminator; two sibling tests weakened, one now contradicts its name.
A7 MEDIUM Dual-host parity test obligation (§8 item 6) not met; headless flip untested.
A8 MINOR Portal-test cleanup outside finally masks the first failure behind a Dispose throw.
A9 MINOR Two sources for the teleport sequence (transit vs destination).
A10 MINOR Class doc and plan correction each assert behaviour the code does not have.
A11 MINOR Process-global LocalTeleportHostKind (accepted, noted).
A12 MINOR Synthetic indoor cell is geometry-free — fine as a gate, weak as a placement oracle.