acdream/docs/research/2026-08-04-c4-route-5-architecture-review.md
Erik 36255af0f6 fix(physics): C4 route 5 — projectile authoritative placement (#276 partial)
Ports retail's missile Position handling into the canonical Runtime
placement owner instead of the deleted ApplyAuthoritativePosition
short-circuit. The Create/residence-window halves of the projectile
pipeline (RuntimeProjectile binding, TryBind's adopted-body branch,
the collision/shadow registration) were already canonical from prior
slices; this closes the remaining gap — how an ACCEPTED Position for
an in-flight missile is classified, placed, and presented.

Byte-decode (Step 1 hard gate, before any code was written):
CPhysicsObj::MoveOrTeleport @0x00516330-0x00516438 disassembled from
the PDB-paired binary (Capstone, x86 32-bit thiscall). `ret 0x10`
establishes four stack args; [esp+0x7c] (arg5, the velocity pointer)
is never referenced in any of the three branches (teleport/near/far).
The retail reviewer independently reproduced this by searching the
whole function body for the `24 7c` mod/rm+disp8 encoding a
`[esp+0x7c]` read would require and found zero occurrences. This
retired a fabricated `?? Vector3.Zero` fallback in the deleted method
— retail's PositionPack::UnPack initializes an absent velocity to
zero and MoveOrTeleport never installs it; the projectile's Vector
channel (RuntimeProjectilePhysicsUpdater.ApplyAuthoritativeVector)
remains the sole velocity authority for a missile. D-P5 in the
contract; the Runtime seam commits no velocity from the Position
packet at all.

The unbound-missile fix: RuntimeEntityObjectLifetime's
ClassifyRemoteAcceptedPosition now derives ProjectileAuthoritative
from a CONJUNCTIVE predicate — the Missile bit AND a bound
RuntimeProjectile whose Body is the canonical PhysicsBody — never the
bit alone. Retail places every non-player CPhysicsObj unconditionally
(there is no missile-specific placement gate in MoveOrTeleport or its
callers), so an unbindable or not-yet-bound missile taking the
ordinary remote tail is retail-faithful, not a fallback: the earlier
bit-only discriminator would have silently frozen it instead.

AP-141 records this as a deliberate, recorded divergence, not
fidelity. Retail mechanically WOULD arm a missile's ConstrainTo leash
on any nonzero MoveOrTeleport return: HandleReceivedPosition
@0x00453FD0's only kind test is player-vs-not, ConstrainTo
@0x00454272 has no kind test of its own, and CPhysicsObj::ConstrainTo
@0x00510520 creates a PositionManager on demand via
MakePositionManager @0x00510523 if one doesn't exist. acdream
deliberately does not construct that EntityPhysicsHost/
PositionManager/InterpolationManager chain for a ballistic body — the
route-5b split the C4 route 5 contract rejected — so a live missile
never shows an armed leash and never catches up via the near/
UnroutedCatchUp policy. This divergence is safe specifically because
ACE never sends UpdatePosition for a missile
(references/ACE/Source/ACE.Server/WorldObjects/WorldObject_Tick.cs:
333-334, SendUpdatePosition() commented out inside the
PhysicsState.Missile branch at :265) — every half of this row is
deterministic-test-gated only, never exercised against a real server.

AP-141 also records the surviving ConstrainTo re-anchor divergence
under clause (b): for the adopted-body case (TryBind's shared-body
branch — an ordinary remote whose Missile bit is set by a later
State packet, so it still carries a live RemoteMotion), acdream now
ports retail's teleport-branch and far-branch StopInterpolating
action (Interp.Clear()), but never re-arms or re-anchors the
inherited ConstrainTo leash the way retail's HandleReceivedPosition
@0x00454254/@0x00454272 does on every nonzero return. The risk
column's earlier wording — that a stale leash "would drag the body
toward a stale anchor" — was wrong and is retracted in this same
commit: ConstraintManager.ConstraintPos is write-only in both retail
and the port (never read by AdjustOffset), and
ConstraintManager::adjust_offset @0x00556180 only tapers or zeroes an
already-composed per-tick offset while InContact — a leash brakes
motion the interp/sticky chain already produced, it cannot pull
anything toward the anchor. The real residual is one tick of un-reset
brake accumulator, contact-gated, and it cannot move an airborne
far-snapped missile at all (the clamp branch does not run while
airborne).

NO CONNECTED GATE EXISTS for this route, by design: ACE never sends a
missile UpdatePosition (see above), so retail's own server never
exercises this code path in play. Every proof obligation here is
test-gated only — Runtime and App-level fixtures constructing the
packet directly — never a live client/server capture.

Three review rounds closed 8 MAJOR findings before this landed:
round 1 (A1 App discarded the seam's status; A2/R1 silent swallow on
an unbound missile; A3/R2 the adopted-body teleport_hook never
wired; A4/A5 zero Runtime/App test coverage); round 2 (a
ParentCellId regression introduced by round 1's own R6 finding,
which the retail reviewer retracted the following round as factually
wrong — the fix here is the REVERT to record.FullCellId, not the
relocation round 1 shipped; B2 the far-branch StopInterpolating skip
never extended to the adopted-body case; residual App/Runtime store-
path coverage; a per-packet closure contradicting the file's own
#315 cached-delegate pattern). Round 3 closed on coverage alone (no
defect): the Advance() retry arm's projectile branch — added at
round 2, semantically reordered at round 2's B5 fix (skip prediction
invalidation on a re-parked Contention, since it writes nothing) —
had never been executed by any test; two new tests drive it directly
and are sabotage-verified against both the reordering and the
retry-arm's own SyncProjectilePresentation call site. The one
recorded defect this campaign produced (the ParentCellId regression)
was caused by complying with a review finding that its own author
later retracted — the standing lesson recorded for future rounds is
that review findings are evidence to re-verify against the code, not
commands to obey unconditionally.

Complete Release suite: 11,063 passed / 4 skipped / 0 failed
(baseline 11,036 at 30d3d114, +27 new tests across this campaign).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 21:03:41 +02:00

26 KiB

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

Verdict: FAIL.

Scope reviewed: the uncommitted working tree at HEAD 30d3d114, branch claude/acdream-physics-divergence-5aa784git diff HEAD over 8 files plus the untracked tests/AcDream.Runtime.Tests/Entities/RuntimeProjectilePositionKindTests.cs. docs/research/2026-08-04-c4-route-5-contract.md is the contract, not under review. Line numbers below are as-of the working tree and will go stale; every citation also names the symbol (process rule 6).

Independent verification performed for this review: dotnet build AcDream.slnx -c Release (succeeded, 0 warnings / 0 errors), focused Runtime suites 58/58 green, focused ProjectileControllerTests 41/41 green. The complete Release suite was NOT run here.

The design is sound and the Runtime seam is largely a faithful, well-argued reproduction. The FAIL rests on four things: two real defects in the ~35 lines of App dispatch glue (A1, A2), one pinned contract obligation left unwired with a concrete failure scenario (A3), and the fact that the presentation invariant (§5 item 2, "#312's layer — tests must assert it") and the entire App dispatch have zero test coverage (A4, A5) — which is also the direct answer to the scoping-gap question at the end.


MAJOR findings

A1 — the App projectile ack ignores the seam's status and writes cell identity on the outcomes the design pins as "write nothing"

Severity: MAJOR. src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs:2137-2144 (OnPosition, the D-P6 projectile arm):

if (earlyRemoteRoute is { } route)
{
    _remotePlacementDrive.ApplyAcceptedProjectilePosition(
        acceptedPositionCanonical,
        route);
    _projectileController?.SyncPresentationFromResolvedBody(
        acceptedPositionRecord);
}
return;

The returned RuntimeRemotePlacementExecutionStatus? is discarded. The Runtime half is deliberately selective — RuntimeRemotePlacementDriveController.ApplyAcceptedProjectilePosition:975-983 skips SyncProjectilePresentation for Deferred/RejectedByPlacement ("Invariant 2: presentation advances on every committed/stored outcome only") and returns null without touching anything for Interpolate, NoPositionOperation, RejectedAuthority, RejectedData, and every ownership mismatch. App re-projects presentation for all of them.

Concrete failure scenario (the near no-op, D-P2's pinned Interpolate row):

  1. An in-flight arrow's canonical body sits in cell A at world P_A.
  2. A grounded, <96 m accepted Position for cell B arrives. RuntimeEntityObjectLifetime.TryApplyPosition merges it; the merge's RefreshDerivedStateSetFullCell (RuntimeEntityRecord.cs:230-251) stamps canonical.FullCellId = B before any classification runs.
  3. The classifier returns Interpolate — a pinned no-op. The Runtime seam writes nothing: body stays at cell A / P_A, prediction version unchanged.
  4. App nevertheless runs ProjectileController.SyncPresentationFromResolvedBody:505-520, which does entity.SetPosition(runtime.Body.Position) (= P_A, correct) and entity.ParentCellId = record.FullCellId (= B, wrong — LiveEntityRecord.FullCellId is Canonical.FullCellId, LiveEntityRuntime.cs:189-191).

The render entity is now parented into a cell it is not geometrically inside, with a position from the other cell. If B is an indoor EnvCell the arrow has not entered, the arrow renders through the wall or is culled. The same write happens on RejectedByPlacement, where the Runtime comment says in as many words that the body must be left "at its prior (already-synced) pose".

This is a genuine regression, not parity: the deleted ApplyAuthoritativePosition had no disposition concept — it always moved the body to the wire cell and wrote the same cell into the entity, so position and cell were always consistent. Splitting the body write out by disposition without splitting the presentation write out with it is what creates the divergence.

Fix direction: return the status through the App boundary and call SyncPresentationFromResolvedBody only on the outcomes SyncProjectilePresentation itself covers (non-null status that is neither Deferred nor RejectedByPlacement) — or move the render-entity projection into the same gate inside the Runtime seam and have App acknowledge, not decide.


A2 — a record carrying the Missile bit with no bound RuntimeProjectile now has every accepted Position silently dropped, where it previously fell through to the remote tail

Severity: MAJOR (silent, permanent). Discriminator: LiveEntityNetworkUpdateController.cs:2122-2146 (isMissilePacket); refusal: RuntimeRemotePlacementDriveController.ApplyAcceptedProjectilePosition:930-936 (record.Projectile is not RuntimeProjectile projectilereturn null).

isMissilePacket keys purely on the canonical record's Missile bit. It does not require that a projectile component exists. The old short-circuit did: the deleted ProjectileController.ApplyAuthoritativePosition returned false when TryGetCurrent found no bound RuntimeProjectile, and == true failing meant the packet fell through to the generic remote tail.

record.Projectile has exactly one producer: ProjectileController.TryBindLiveEntityRuntime.BindProjectileRuntimeRuntimePhysicsState.BindProjectile (verified by grep — no other writer of Entities.SetProjectile(record, component)). TryBind has several ordinary, non-exceptional failure returns, e.g. ProjectileController.cs:160-166:

"Missile 0x… Setup 0x… does not have the supported retail one-sphere collision shape."

Scenario: ACE spawns a missile whose Setup does not reduce to the supported one-sphere shape (a diagnosed, expected case — it has its own log line). TryBind returns false; record.Projectile stays null; FinalPhysicsState & Missile stays set. Every subsequent accepted Position for that guid now returns at :2146 having done nothing at all — no TryApplyGenericRemoteRenderPose, no RebucketLiveEntity, no GetOrCreateRemoteMotionRuntime. The object freezes at its create pose for the rest of its life and never follows the server. Before this diff it tracked, via the remote tail.

The contract's D-P6 does pin "dispatch the projectile arm and RETURN", so this is a defect in the design as implemented rather than a slip against it — but it is still a new, silent, permanent freeze, and the same defect class (the frozen entity) that the 4b-family reviews have been hunting. Reachability caveat, stated honestly: ACE never sends a missile UpdatePosition (WorldObject_Tick.cs:333-334), so like every other half of this route it is test-reachable only.

Fix direction: make the discriminator conjunctive — a packet takes the projectile arm only when the arm can actually own it (Missile bit and a bound projectile whose Body is the canonical PhysicsBody); otherwise let it take the ordinary tail, which is what the record's shape actually is. If the swallow is intended, it needs its own register row and a test that pins it, and neither exists.


A3 — D-P4's teleport-hook reduction is unwired for the adopted-body case, which the codebase explicitly supports

Severity: MAJOR (contract obligation unmet; concrete scenario). RuntimeRemotePlacementDriveController.ApplyAcceptedProjectilePosition:944 runs exactly one of retail's six teleport_hook @0x00514ED0 actions:

case RuntimeAuthoritativePositionDisposition.SetPosition:
    _entityObjects.Physics.CollisionReports.LeaveWorld(record);

The contract pins more than that: "The other five actions execute iff their owning component exists — for the adopted-body case (a missile that also carries a RemoteMotion), the existing hook actions' per-manager guards already express retail's shape; the implementer wires this without per-packet closures" (D-P4). Nothing wires them, and no note records the omission.

The adopted-body case is not hypothetical. ProjectileController.TryBind's shared-body branch exists precisely for it — "If a non-missile incarnation already created its MovementManager or entered the Physics-Static animation workset, classification adopts that same body" — and RuntimePhysicsState.BindProjectile:757-830 does not exclude a record that has a RemoteMotion. RuntimePhysicsState.cs:697-708 shows the same key can sit in both _spatialRemotes and _spatialProjectiles.

Scenario: an object is a live remote with a populated RemoteMotion.Interp queue and a ConstrainTo leash armed by route 4a's RuntimeRemoteSteadyStatePosition.TryArmConstraintAfterOperation. ACE then sets the Missile bit (a State packet); TryBind adopts the shared body. The next teleport/cell-less Position takes the projectile arm: collisions are force-ended and the body is teleported, but StopInterpolating, UnConstrain, CancelMoveTo, and UnStick never run. The RemoteMotion survives in the remote workset with a stale waypoint and a live leash anchored at the pre-teleport position, and drags the newly-placed missile body back. Retail @0x00514EFD/@0x00514F31 runs all six, each guarded on its own manager, so retail's own guards would no-op for a pure arrow and would fire here.

Note this is not a regression from HEAD — the old short-circuit did not run the hook either — but D-P4 made wiring it an explicit obligation of this slice, and the faithful port (RemoteTeleportHook.Execute + RemoteTeleportHookActions, src/AcDream.App/Physics/RemoteTeleportHook.cs) is sitting in-tree unused for this arm. That is exactly the 4b-3 round-2 R2 defect class the contract cited by name.

Fix direction: drive the projectile teleport arm through the same six-action bundle (cached delegates, #315 pattern), letting each action's per-component guard decide — for an ordinary arrow all five extra actions are no-ops, and the adopted-body case gets retail's shape for free.


A4 — SyncProjectilePresentation, the highest-risk reproduced code in the diff, has no test that would fail if it were deleted

Severity: MAJOR (test gap on the invariant the contract singles out). RuntimeRemotePlacementDriveController.SyncProjectilePresentation:987-1039.

Contract §5 invariant 2: "Presentation still advances… the shadow registry is synced (spatial+visible) or suspended (hidden/non-spatial) exactly per the current tail's semantics. A projectile is never left rendered a packet behind its body (#312's layer — tests must assert it)."

Across all seven new Runtime tests, the only assertion that even touches this method is Assert.True(body.InWorld) in ApplyAcceptedProjectilePosition_Refused_StillAdvancesPoseNoParkPredictionInvalidated. That assertion is vacuous with respect to the sync: the fixture's AttachBody (RuntimeRemotePlacementDriveControllerTests.cs:2860-2880) calls body.SnapToCell(...), and PhysicsBody.SnapToCell sets InWorld = true (PhysicsBody.cs:201-205). Nothing in the Refused path clears it. So the assertion passes with SyncProjectilePresentation entirely removed.

Unasserted, at any layer: the shadow-registry publication (ShadowObjects.UpdatePosition), the spatial+hidden Suspend, the non-spatial InWorld = false + Active clear + Suspend, the !body.InWorld activation edge, and the three currency guards at the method's head. The committed-outcome tests (…TeleportCommit…, …FarCommit…) assert status, position, prediction version, velocity, RemoteMotion is null, and collision-owner count — none of which the sync produces.

Fix direction: one test per branch of the sync, keyed on the observable the old tail produced: shadow row present at the resolved pose (spatial+visible), Suspend called (spatial+hidden and non-spatial), Active cleared (non-spatial). These are cheap; the fixture already registers shadows in SeedCollisionOwner.


A5 — no App-layer test exercises OnPosition with a missile packet at all; §7 items 8 and 9 are unwritten

Severity: MAJOR (this is the scoping-gap answer).

grep -rn "Missile" tests/AcDream.App.Tests/Physics/LiveEntityNetwork*.cs returns zero hits. The only App file mentioning Missile at all is ProjectileControllerTests.cs, which never calls OnPosition.

So none of the following is covered anywhere:

  • the D-P1/D-P6 discriminator itself in its production call site;
  • invariant 8's mutual exclusion (Missile-set ⇒ projectile arm and no RemoteMotion afterward; Missile-clear ⇒ remote tail and no projectile effect);
  • the null-classification swallow (earlyRemoteRoute is null with the Missile bit set) and its positive half (timestamps consumed, merge advanced);
  • the "no early wire-pose write / no RebucketLiveEntity" pins;
  • the presentation ack the App owns — i.e. #312's layer at the layer it renders.

Worse, the retired App test MalformedFreshUpdates_DoNotPoisonCanonicalBodyOrPose justifies its Position half's deletion by pointing at "LiveEntityNetworkUpdateController's own 'invalid-payload swallow' test". That test does not exist. The underlying claim (the shared CanAcceptPositionPayload gate rejects the payload upstream) is correct and I verified it independently — but the cited successor coverage is not there, so the assertion was retired against a coverage claim that is false.

Both A1 and A2 live inside the ~35 lines the implementer argued were "thin glue between two well-tested layers". That is the empirical refutation of the argument.


MINOR findings

A6 — the !body.InWorld gate is read after the placement, where the deleted tail captured wasInWorld before it

SyncProjectilePresentation:1012-1018 reads body.InWorld after TryExecuteAcceptedRemotePosition has run. The canonical commit calls body.SnapToCell(...) (RuntimeSetPositionState.cs:4974), which sets InWorld = true. The deleted tail captured bool wasInWorld = body.InWorld; before its SnapToCell. Consequence: on every committed outcome the re-activation branch (body.LastUpdateTime = clock + TransientState |= Active) is now dead — a projectile that had left the world and comes back through a committed accepted Position is marked InWorld but never re-flagged Active, and its legacy LastUpdateTime is not rebased. It self-heals on the next tick because RetailObjectActivityGate.Evaluate re-sets the flag (RetailObjectActivityGate.cs:61-67), which is the only reason this is MINOR rather than a frozen body. Fix: capture body.InWorld before dispatching the placement and pass it in.

A7 — the spatial+hidden branch silently drops body.LastUpdateTime = currentTime

Deleted tail: else if (spatial) { body.InWorld = true; body.LastUpdateTime = currentTime; Suspend(); }. New (SyncProjectilePresentation:1031-1035): the LastUpdateTime write is gone. ProjectileController.TryBind's equivalent branch documents why the write exists — "consume the hidden clock so UnHide cannot replay a time backlog". Bounded by TryBegin refusing Hidden and by the RetailObjectQuantumClock being canonical post-R6, but it was a deliberate write and its removal is unremarked.

A8 — the shadow publication is silently skipped when the Runtime world frame is unavailable

SyncProjectilePresentation:1019-1030 wraps the shadow update in if (physics.TryGetWorldFrameOffset(...)) and does nothing on false. The deleted ShadowPositionSynchronizer.Sync always published, using App's live centre, and returned early only for cellId == 0. TryGetWorldFrameOffset additionally returns false when _worldFrameCenterLandblockId == 0 (RuntimePhysicsState.cs:613-632). Two methods away, StoreAcceptedDestinationPose:1113-1119 treats exactly this case as ThrowIfWorldFrameUnreachable — #284's "a frame that can never arrive is terminal, never silent" policy. The new code neither publishes nor escalates.

A9 — the null-route fallback is not fenced off the local player

LiveEntityNetworkUpdateController.cs:2122-2126: when earlyRemoteRoute is null, isMissilePacket falls back to a bare FinalPhysicsState & Missile test. earlyRemoteRoute is always null for update.Guid == _playerServerGuid. A local-player record that ever carried the Missile bit would therefore swallow its own accepted Position and freeze the player. Currently impossible only because ACE never sets Missile on a player — a one-token update.Guid != _playerServerGuid && would make it structurally impossible.

A10 — OwnsFarSnap's doc is now false in the kind dimension

src/AcDream.Runtime/Physics/RuntimeRemoteFarSnapPosition.cs:78-79 still states this predicate is "a strict narrowing of OwnsPlacement to its far half". After the widening it narrows only OwnsPlacement's remote far half. RuntimeRemoteTeleportPosition.cs:33-35 hedges correctly ("OwnsPlacement's remote scope"); the far-snap doc does not. D-P3 asked for exactly this correction where a comment would otherwise mislead (process rule 6).

A11 — the cutover route ledger still lists the deleted methods as live routes

docs/research/2026-08-02-cutover-route-inventory.md:666-694 still describes ProjectileController.ApplyAuthoritativePositionRuntimeProjectilePhysicsUpdater.ApplyAuthoritativePosition as a live route with SnapToCell + CommitProjectileCell. D-P7 scoped the re-point grep to src/ and docs/architecture/, so this is outside the letter of the obligation — but that file is the C4 route ledger this campaign reads from, and it is now wrong about route 5.


Verified — no finding

These were hunted and came back clean; recorded so the next round does not re-litigate them.

  • P3 (RuntimeSetPositionState kind-agnosticism) is CORRECT, and I verified it independently rather than accepting the argument. TryBeginExclusiveAuthoredPlacement:1444-1472 returns default (invalid token → Contention) whenever _operations.ContainsKey(key) or HasRetainedCompletion(key). Both constructors that stamp Kind = RemoteAuthoritativeParkCollisionResidents's window-departure park (:3833/:3866, which itself continues past any record already in _operations) and CreateWithdrawalOperation (:5338/:5350, reached only from Cancel after CancelCoreDeferred) — install an operation into _operations under the record's key. A projectile accepted Position arriving while one is live cannot capture or be relabelled by it; it refuses with Contention, which StoresAcceptedDestination() puts on the storing side, so the pose still advances and no ledger column is mislabelled. The two kind-conditional stage sites (IsExactDormantLocalActivationCurrent:5445-5446, IsDormantLocalActivationPrephaseCurrent:2554-2600) additionally require InitialLogin/LocalAuthoritative and record.Projectile is null, and the family has zero production callers. Residual, benign and pre-existing: a park operation created for a projectile record carries Kind = RemoteAuthoritative, but it never reaches the drive controller's ledger.
  • The three ownership fences hold. OwnsPlacement has exactly one production reader — TryExecuteAcceptedRemotePosition:640 (verified by grep across src/; every other hit is a doc comment or a test). OwnsFarSnap and OwnsTeleportPlacement keep their RemoteAuthoritative gate, and a projectile route cannot reach ApplyAcceptedRemoteFarSnap / ApplyAcceptedRemoteTeleport / TryArmConstraintAfterOperation: the App returns before the remote tail whenever isMissilePacket, and isMissilePacket is derived from route.OperationKind whenever a route exists, so the two cannot disagree. The throwing guards stay unreachable, and no RemoteMotion is ever created on this arm.
  • The remote route is unchanged. Moving the ClassifyRemoteAcceptedPosition call earlier hops only a pure-read guard block (TryGetRecord / ReferenceEquals / IsCurrentPositionAuthority) with no reentrancy in between; classification itself is side-effect-free. Zero remote classifier tests changed expectation, which is the contract's own tripwire.
  • StoreAcceptedDestinationPose never writes a cell, so on Refused/Contention/RejectedPreparation the projectile body's CellPosition stays at the source cell while record.FullCellId is the wire cell. This is identical to the accepted remote behaviour (AP-138's residual) and the quantum stepper takes the cell from record.FullCellId explicitly (RuntimeProjectilePhysicsUpdater.TryBegin), so it is parity, not a new defect. Recorded, not filed.

Judgment on the four implementer claims

Claim 1 — both ApplyAuthoritativePosition overloads and the Runtime updater's copy deleted; nothing else called them; no behaviour lost. Deletions and callers: VERIFIED. No code reference survives anywhere in src/ or tests/ (only comments, the contract, and the two research docs noted in A11); Release build green with 0 warnings. "No behaviour lost": PARTIALLY FALSE. Three deliberate behaviours went with them and only one is accounted for: the origin-translated world-position finiteness check (genuinely redundant — worldPos is a finite wire triple plus an integer landblock offset, so it cannot be non-finite when CanAcceptPositionPayload passed); the _lastFiniteGameTime rebase on a Position packet (App tick clock — unremarked, low impact); and the wasInWorld activate edge plus the hidden-branch LastUpdateTime write (A6, A7 — unremarked).

Claim 2 — 7 call sites modified, 2 assertions retired as obsolete. Mostly legitimate, with one false coverage claim. The velocity assertions in FreshVectorAndPositionCorrectionsMutateSameBody are genuinely obsolete under D-P5 and have a real positive successor (…TeleportCommit… / …FarCommit… assert body.Velocity bit-identical after a placement). The AuthoritativeMutation.Position retirement has a genuine, load-bearing successor I read and checked — ApplyAcceptedProjectilePosition_DuringOpenQuantum_CompleteAbortsAfterPredictionInvalidated opens a real quantum, runs the arm, and asserts Complete returns false with the committed pose intact. The rewritten SyncPresentation_ReentrantGuidReuseNeverTouchesTheReplacement is an improvement, not a dilution: it correctly notes that RebucketLiveEntity self-suppresses its own guid's visibility callback and switches to a genuine spatial edge. But the malformed-payload retirement in MalformedFreshUpdates_DoNotPoisonCanonicalBodyOrPose cites a successor test in LiveEntityNetworkUpdateController that does not exist (A5). The upstream gate does cover the scenario; the citation does not.

Claim 3 — OwnsPlacement_FalseWhenOperationKindIsNotRemoteAuthoritative legitimately changed its expected outcome. TRUE, not a test bent to fit the code. The widening makes ProjectileAuthoritative a positively-owned kind by construction, so leaving it in a "these kinds are refused" list would assert the opposite of the design. The positive case is separately and explicitly asserted (OwnsPlacement_TrueForProjectileAuthoritative_…, including the Create exclusion), and the two remaining negatives (InitialLogin, LocalAuthoritative) still pin the predicate's kind dimension. The rename is accurate.

Claim 4 — the new tests use airborne destinations to remove a contact-response confound. Legitimate confound removal, with a named residual. The claim is accurate: the shared placement pipeline's contact response is retail landing behaviour, shared verbatim with the remote arms, and outside route 5's scope; D-P5's pin is specifically "no velocity from the packet", which an airborne destination isolates cleanly. It is not a test dodging a defect. The residual worth stating: no test now places a projectile into ground contact at all, so the interaction between the projectile arm and contact response — including whether the resulting velocity change is the right one for a ballistic body — is entirely unexercised. That is a gap, not a dishonesty.


Judgment on the known scoping gap (§7 item 8, the dual-kind OnPosition matrix)

It is a FAIL-level gap. Definite answer: not acceptable.

The implementer's two arguments are (a) the collapse's LiveEntityNetworkOnPositionCollapseMatrixTests fixture unconditionally constructs a RemoteMotion a projectile lacks, and (b) the D-P6 dispatch is ~35 lines of thin glue between two well-tested layers.

(a) is a fixture limitation, and a fixture limitation is a reason to extend the fixture, not to ship zero coverage. The projectile half of the matrix needs a record with the Missile bit, a bound projectile, and no RemoteMotion — which is precisely the assertion the matrix exists to make.

(b) is refuted by this diff itself. Two of the five MAJORs above (A1, A2) are defects inside those 35 lines, and neither is visible from either well-tested layer: A1 is an App/Runtime disagreement about which outcomes may write presentation, and A2 is a discriminator whose reachable set is wider than the arm that consumes it. This is the same shape as 4b-3's three MAJORs — a mapping written against one caller's reachable set, and an invariant satisfied on one arm only — and a dual-kind matrix was the structural fix there for the same reason it is here.

Additionally, the gap is broader than §7 item 8 alone: item 9 (the App-level invalid-payload swallow) is also unwritten, and was cited as existing coverage in a retired assertion's justification.

The minimum this needs before landing: a dual-kind theory over OnPosition covering at least far-commit, teleport-commit, near, airborne, and null-classification, asserting on the projectile half that no RemoteMotion exists afterward, no generic wire-pose write occurred, and the render entity's position and ParentCellId agree with the resolved body — that last assertion alone would have caught A1.