C4 route 4b-3 collapse (docs/research/2026-08-04-onposition-collapse-contract.md).
Behaviour-preserving: the ~640-line duplicated player-guid and NPC-guid
copies of the remote routing tail in LiveEntityNetworkUpdateController.OnPosition
become one guid-blind tail, reached by every remote guid through the single
ApplyRemoteContactRouting/RunRemoteArmTail seam.
Two guid-conditionals survive, both named and justified:
- Row 8 (TS-44 sticky suppression, creature-only): retail's sticky is
independent of this acdream-only steady-state gate; the register row
already describes it as NPC-only and this collapse does not widen it.
- The AirborneSnap arm's interp-clear + shadow-publish (rows 2a/2b,
player-only preserve): unifying either way would be an unauthorized
behaviour change. #316 (shadow publish) is a real, unmeasured
pre-existing defect, deliberately preserved not fixed. The interp-clear's
equivalence could not be proven for the steep-non-walkable-landing edge
case (AdjustOffset's CONTACT-keyed gate vs. AP-139's WALKABLE-keyed
per-tick clear) — preserved per contract stop condition 2 rather than
shipped on an incomplete proof.
Category-(c) resolutions (contract §2.1-2.5), each with its evidence:
- Row 2a (interp clear): PRESERVED — AdjustOffset's `if (!inContact) return`
proves inertness on flat landings, but not on the steep-contact edge case.
- Row 2b (shadow publish / #316): PRESERVED — no design note ever sanctioned
the player-guid skip; the file's own #184 Slice 2b comments contradict it.
- Row 2c (EnsureRemoteMotionBindings): UNIFIED — the method is idempotent
(`if (rm.Host is not null) return rm.Sink;`), so "always ensure" is safe.
- Row 3 (wire-cell adopt ordering): UNIFIED — RebucketLiveEntity already
commits the wire cell before either guid branch runs, so the deleted
player-guid pre-write was a proven no-op.
- Row 4 (LastServerPos/Time sample timing): UNIFIED — on a genuine first UP,
InterpolationManager.Enqueue's already-close branch and the Snapped branch
both converge on the same body pose/orientation for a zero-distance target.
- Row 12 (wall-clock capture): UNIFIED — one shared `nowSec`, a
microsecond-scale skew in acdream-only bookkeeping/diagnostics.
Sabotage check (contract §5, performed and reverted, not committed):
deleting the one remaining TryArmConstraintAfterOperation call failed
10/16 dual-guid matrix tests, spanning BOTH guid halves of every
arming-dependent scenario (teleport, landing, near, far, sticky) — proof
the matrix discriminates a defect regardless of which guid range exercises
it, closing the class of bug that let 4b-3's A1/A2/R3 findings survive
review when only one copy's tests were green.
New tests/AcDream.App.Tests/Physics/LiveEntityNetworkOnPositionCollapseMatrixTests.cs
drives 8 scenarios x 2 guid ranges (0x50xxxxxx player, 0x8xxxxxxx creature)
through the complete production OnPosition entry point. Doc comments on
ApplyRemoteContactRouting, RunRemoteArmTail, ApplyWireAirborneLeftoverBookkeeping,
TryAdoptWireCellAfterRouting, and the AirborneNoOperation throw guard
updated to describe the collapsed one-path world (the "two callers stay
one decision" claim was true before this commit and false after — fixed
in the same commit that makes it false). One branch-routing source-text
pin (LiveEntityNetworkBranchRoutingTests.cs) updated to follow the AP-140
CONTACT gate to its new address inside ApplyRemoteContactRouting.
#316 stays OPEN, deliberately not fixed here — see its updated ISSUES.md
entry.
dotnet build AcDream.slnx -c Release: 0 errors. Verified independently
bisectable at this exact commit: AcDream.App.Tests 4104/4107 (3 pre-existing
skips), AcDream.Runtime.Tests 1125/1125.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>