The pinned contract plus the four review documents behind 6dc7ba51:
round 1 (retail FAIL 3 MAJOR / architecture FAIL 2 MAJOR) and round 2
(both PASS on the fixed diff).
Process findings worth carrying into the remaining routes:
1. The contract's 13 explicit "what must REMAIN true" invariants were the
fix for 4b-2's round-1 defect (a contract that said what must change but
not what must stay). They did NOT prevent a round-1 FAIL here. What the
round-1 MAJORs actually shared was a STRUCTURAL cause the invariant list
could not express: two parallel inline copies of the same routing tail.
An invariant list constrains behaviour; it cannot see duplication.
2. Both reviews independently found the same NPC synth-velocity defect
(retail R3 = architecture A2). Independent convergence on one finding is
the strongest signal this process produces — weight it accordingly.
3. The specified two-client gate could not have observed three of the four
MAJORs: it teleported a player character, and all three live on the NPC
arm. Caught by both reviewers before the gate ran, not after. Check that
a gate can structurally see the defect class it is gating.
4. A reviewer named a symbol that does not exist (RuntimeCollisionReportingState
.ForceEnd is a private helper, not the public entry point). The implementer
silently substituted the correct one (LeaveWorld) while reporting "no
disagreements with either review". Verify implementer claims against source
even when they report full agreement.
5. A new test asserted only what must NOT happen, so an emptied
ApplyWireAirborneLeftoverBookkeeping passed every test in the tree. Caught
in round 2 and closed with positive assertions, sabotage-verified. Negative
assertions alone cannot detect a deleted write.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
299 lines
17 KiB
Markdown
299 lines
17 KiB
Markdown
# C4 route 4b-3 — architecture / adversarial DELTA review, round 2 (2026-08-04)
|
|
|
|
Reviewer lens: **adversary**. Round 1's findings are
|
|
[`2026-08-04-c4-route-4b-3-architecture-review.md`](2026-08-04-c4-route-4b-3-architecture-review.md);
|
|
the retail lane's are
|
|
[`2026-08-04-c4-route-4b-3-retail-review.md`](2026-08-04-c4-route-4b-3-retail-review.md).
|
|
|
|
Subject: the same uncommitted working tree on
|
|
`claude/acdream-physics-divergence-5aa784` at base `3e002993`, after the round-1
|
|
fix pass. This review re-attacks the **fixes**, not the whole slice — the
|
|
round-1 "verified sound" list is carried forward except where a fix touched it.
|
|
|
|
## Verdict: **PASS**
|
|
|
|
Both round-1 MAJORs (A1, A2) are fixed, and I verified each fix produces the
|
|
retail-correct outcome rather than merely silencing the symptom. The retail
|
|
lane's R1/R2/R3 are fixed. **The `RunRemoteArmTail` /
|
|
`ApplyWireAirborneLeftoverBookkeeping` extraction — the thing most likely to
|
|
introduce a new defect — is behaviour-identical at all five call sites**; I
|
|
walked each one against the pre-fix code and found no reordering, no dropped
|
|
step, and no widened or narrowed guard. Six MINORs below, none blocking.
|
|
|
|
Build `dotnet build AcDream.slnx -c Release`: **succeeded, 0 warnings**.
|
|
Focused suites at Release `--no-build`: **Runtime 1,125 / 0 skips**,
|
|
**App 4,081 / 3 skips** (up 3 from round 1's 4,078 — the three new App tests).
|
|
|
|
---
|
|
|
|
## Part 1 — the extraction, call site by call site
|
|
|
|
The blast radius of the fix pass is small and I confirmed it: only
|
|
`LiveEntityNetworkUpdateController.cs`, one new method on `LiveEntityRuntime.cs`,
|
|
the App teleport test file, and three docs carry round-2 markers.
|
|
|
|
### `RunRemoteArmTail` — 3 call sites
|
|
|
|
Signature returns `RemoteContactRouting?`; `null` means "the currency guard
|
|
tripped, write nothing further". The guard inside it is
|
|
`(Arm is FarSnapPlacement or TeleportPlacement) && (!isCurrentPositionOwner() || !ReferenceEquals(positionRecord.RemoteMotionRuntime, remote))`.
|
|
|
|
| site | pre-fix sequence | post-fix | verdict |
|
|
|---|---|---|---|
|
|
| player teleport dispatch (`:2333`) | routing → **unconditional** guard → return | routing → **arm-gated** guard → return | **identical.** `ApplyRemoteContactRouting` returns `TeleportPlacement` iff `OwnsTeleportPlacement(route)`, which the caller has already evaluated on the *same* `earlyRemoteRoute` with the same pure static predicate. The arm at this site is provably always `TeleportPlacement`, so arm-gating the guard cannot weaken it. |
|
|
| player grounded routing (`:2566`) | routing → arm-gated guard → return | same, via helper | **identical**, including the R5 guard-before-arm order (`TryArmConstraintAfterOperation` is still the first statement after the null check, `:2596`). |
|
|
| NPC dispatch (`:2818`) | routing → arm-gated guard → `return` from `OnPosition` | routing → helper returns `null` → `if (npcRoutingResult is null) return;` inside the same `if (!snapSuppressedByStick \|\| isTeleportRoute)` block | **identical**, same lexical position, same effect. |
|
|
|
|
Specific things I checked for and did **not** find:
|
|
|
|
- **`willBeDrTicked` moved inside the helper.** The player grounded site used to
|
|
hoist it into a local (`HEAD:2317`). I grepped every use in both the HEAD and
|
|
current file: its only consumer was ever the routing call itself. Nothing
|
|
downstream reads it. No loss.
|
|
- **Delegate identity.** `runTeleportHook` now closes over `canonical`/`remote`
|
|
and reuses the caller's `isCurrentPositionOwner` for both the hook's per-step
|
|
currency checks and the post-routing guard. Previously two separately
|
|
allocated but semantically identical lambdas. No change in what is tested.
|
|
- **Guard-before-arm (R5) at all three sites.** Held. The helper cannot arm — it
|
|
has no access to `ToConstraintArm` and its doc says so — and all three callers
|
|
arm immediately after the null check.
|
|
- **The NPC sticky-suppressed path still arms.** `npcArm` is initialised to
|
|
`UnroutedCatchUp` and `TryArmConstraintAfterOperation` sits *outside* the
|
|
`if (!snapSuppressedByStick || isTeleportRoute)` block, exactly as at HEAD.
|
|
The extraction did not pull it inside.
|
|
|
|
### The LANDING TRANSITION block — confirmed untouched and non-conflicting
|
|
|
|
`:2445-2532` still gates on `!rmState.Body.InContact`, still `return`s, and
|
|
still arms with its own hard-coded `NearInterpolate`. It therefore cannot
|
|
double-run with the shared tail, and — importantly — it is what makes
|
|
`playerArm` provably never `AirborneSnap` at the grounded-routing site
|
|
(the free-flight case has already returned). The only edit is its comment,
|
|
which round 1 flagged as false (A5) and which is now correct **and complete**:
|
|
it enumerates `SetPositionSimple` / `null` / `Rejected*` as classifications
|
|
that also reach the block, and states why `NearInterpolate` is the right arming
|
|
value for every one of them.
|
|
|
|
### `ApplyWireAirborneLeftoverBookkeeping` — 2 call sites
|
|
|
|
The helper writes exactly three fields: `remote.CellId`, `remote.LastServerPos`,
|
|
`remote.LastServerPosTime`.
|
|
|
|
- **NPC site (`:2717-2722`)** — new, and the R1 fix. Correctly gated
|
|
`!update.IsGrounded && !isTeleportRoute`, placed after the
|
|
`IsAirborneNoOperation` return (so `NoPositionOperation` never reaches it)
|
|
and before the synth-velocity block, the sticky probe, and routing. I
|
|
confirmed the gate is exhaustive: for `RuntimeAcceptedPositionSource.PositionEvent`
|
|
a wire-airborne packet can only classify `NoPositionOperation` (handled above),
|
|
`null`, or `Rejected*` — the classifier's `effectiveContact` widening applies
|
|
only to `SameIncarnationCreate`, which this path never carries.
|
|
- **Player site (`:2390-2395`)** — the helper adds a `remote.CellId` write the
|
|
hand-rolled block did not have. **I chased this specifically as the classic
|
|
extraction hazard and it is benign**:
|
|
`RuntimePhysicsState.CommitCanonicalCell:2145` short-circuits on
|
|
`fullCellId == record.FullCellId` *before* `SetFullCell` and before raising
|
|
`CellCommitted`, and the player arm wrote the identical `p.LandblockId` ~180
|
|
lines earlier with no placement in between. The redundant write is a true
|
|
no-op — no spurious rebucket event, no version bump.
|
|
|
|
---
|
|
|
|
## Part 2 — the individual fixes
|
|
|
|
### A1 — `ToConstraintArm(AirborneSnap) → NearInterpolate`, switch made total
|
|
|
|
Correct, and correct for the right reason: `AirborneSnap` is acdream's
|
|
*body*-contact carve-out for a packet whose **wire** contact bit said grounded,
|
|
so retail's `MoveOrTeleport` returns nonzero and `HandleReceivedPosition` arms
|
|
@0x00454272. Mapping it to an arming value restores the 1-arm count and makes
|
|
the App-layer partition exactly the contract's D4 table.
|
|
|
|
**The throwing default cannot be reached in production.** `RemoteContactArm`
|
|
has exactly five members (`AirborneSnap`, `SteadyStateInterpolate`,
|
|
`FarSnapPlacement`, `TeleportPlacement`, `UnroutedCatchUp`) and all five have
|
|
explicit cases; `default(RemoteContactArm)` is `AirborneSnap` (value 0), which
|
|
is handled. The only two producers of the argument are
|
|
`ApplyRemoteContactRouting`'s returns and the NPC arm's
|
|
`RemoteContactArm.UnroutedCatchUp` initialiser. Reaching `_` requires an
|
|
out-of-range cast, which nothing performs. The throw is a genuine
|
|
"can't-happen" guard, not a live hazard — this was the right call over a silent
|
|
zero-arm fallback.
|
|
|
|
**The test genuinely discriminates.**
|
|
`NpcAirborneSnap_LandingPacket_StillArmsTheLeash` asserts
|
|
`host.PositionManager.Constraint` goes from `null` to non-null across the
|
|
packet. I verified `PositionManager.Constraint` is lazily created *only* inside
|
|
`ConstrainTo` (`PositionManager.cs:27-28`, `:62`), so its presence is direct
|
|
proof of an arm rather than an inference. Under the pre-fix mapping the packet
|
|
arms zero times and `Constraint` stays null — the test fails.
|
|
|
|
### A2 / R3 — NPC synth-velocity and cycle-apply gated on `!isTeleportRoute`
|
|
|
|
Correct. `isTeleportRoute` is hoisted above both the D2 check and the velocity
|
|
block, and both the install (`:2741`) and the `RemoteServerControlledVelocityCycle.Apply`
|
|
call (`:2886`) carry it. The fix's own claim that leaving `ServerVelocity`
|
|
stale is safe holds up: its only consumers are the now-excluded cycle-apply and
|
|
`RuntimeRemotePhysicsUpdater`'s stale-velocity watchdog, which only *zeroes*.
|
|
|
|
Two incidental changes in the same block are behaviour-neutral and I checked
|
|
them rather than assumed: the `!IsPlayerGuid(update.Guid)` guards were dropped
|
|
from the synth condition and the `else if` collapsed to `else`. Both were
|
|
already dead — the whole NPC section sits after `if (IsPlayerGuid(update.Guid)) { … }`
|
|
and every path inside that block `return`s (the last statement before its
|
|
closing brace at `:2666` is `return;`), so the section is unreachable for
|
|
player guids.
|
|
|
|
`NpcTeleport_DoesNotInstallASynthesizedVelocity` seeds `LastServerPos`/
|
|
`LastServerPosTime` so a broken implementation has a real distance and interval
|
|
to synthesise from. It fails pre-fix (`HasServerVelocity` would be `true`).
|
|
|
|
### R1 — the D2 shape on the NPC arm
|
|
|
|
Correct and now genuinely shared. The AP-137 sentence *"unifies player and NPC
|
|
remotes on one behaviour"* is true against the code as of this round — I
|
|
re-read the row and the two call sites.
|
|
|
|
`NullClassifiedNpc_WireAirbornePacket_WritesOnlyBookkeepingNoBodyOrShadow`
|
|
discriminates: pre-fix the packet reaches `ApplyRemoteContactRouting`'s
|
|
free-flight carve-out and hard-snaps `Body.Position = worldPos`, which the
|
|
test's `Assert.Equal(spawnBodyPose, …)` catches.
|
|
|
|
### R2 — the teleport hook's collision-end action → `ForceEndCollisionReporting`
|
|
|
|
**This was the fix I was asked to attack hardest, and it does not carry any of
|
|
this family's failure modes.** `RuntimeCollisionReportingState.LeaveWorld` is
|
|
named for the *collision-reporting* state machine's own leave transaction, not
|
|
the entity lifecycle's. I traced it end to end:
|
|
|
|
- `LeaveWorld:870-887` → `_admissionBlocked.Add(key)` → `ForceEnd:1435-1454` →
|
|
`EndExpiredObjectCollisions(force: true)` → `TrimEmptyOwner`. **The only
|
|
mutations are the owner's collision table, the reverse-owner index, and the
|
|
report queue.** Nothing writes `body.InWorld`, `TransientStateFlags.Active`,
|
|
`record.ObjectClock`, `FullCellId`, spatial residency, or visibility.
|
|
**Invariant 3 is not at risk.**
|
|
- `_admissionBlocked` is released in a `finally`, so the subsequent placement's
|
|
`TryPrepareSetPositionBatch:230-235` — which *does* refuse while a key is in
|
|
`_leaving` or `_admissionBlocked` — is not blocked by the hook that ran
|
|
immediately before it.
|
|
- `_mutationRevision` is bumped by `LeaveWorld`, but the placement's batch
|
|
captures `expectedMutation` *after* the hook (`:238`) and the
|
|
prepare→install window is entirely inside the placement, so the bump cannot
|
|
invalidate the teleport's own batch.
|
|
- `Publish` swallows observer exceptions (`:1489-1494`), and `_leaving` guards
|
|
re-entrancy, so a force-end cannot escape as a throw into the packet path.
|
|
- `TrimEmptyOwner` runs on the exit path, so `CaptureOwnership`'s owner count
|
|
cannot leak an empty entry — no ledger regression.
|
|
|
|
Dropping the old `ShadowObjects.Suspend` is also safe and is arguably the
|
|
better half of the fix: the far-snap arm (shipped, user-accepted) has never
|
|
suspended the shadow before its own placement, so the teleport arm is now
|
|
*consistent* with it rather than uniquely different, and the arm tail's
|
|
`TryPublishRemote` → `SyncRemoteShadowToBody` (ungated at this call site) still
|
|
re-seeds the registry at the resolved pose. See MINOR B2 for the one thing
|
|
about R2 that should be stated rather than left implied.
|
|
|
|
---
|
|
|
|
## MINOR findings
|
|
|
|
### B1 (MINOR) — contract test-plan item 11 is still unwritten, and it is now the *only* thing guarding the #42 class
|
|
|
|
`NullClassifiedNpc_WireAirbornePacket_…` asserts what must NOT happen (no body
|
|
write, no shadow republish) but never asserts what MUST happen: that
|
|
`ApplyWireAirborneLeftoverBookkeeping` actually wrote `remote.CellId` and
|
|
`LastServerPos`/`LastServerPosTime`. A regression that emptied the helper body
|
|
would pass every test in the tree. Those writes are exactly AP-135 — the
|
|
free-fall sweep gates on `rm.CellId != 0` and without it "an airborne remote
|
|
falls through the floor" (#42), and the first grounded packet after an arc
|
|
would synthesise its velocity across the whole jump. Two `Assert.Equal`s on the
|
|
existing test close it.
|
|
|
|
### B2 (MINOR) — R2's fix is correct plumbing, but its *observable* half still goes nowhere; say so before someone records it as closed
|
|
|
|
`IRuntimeCollisionReportObserver` has **zero production implementations** —
|
|
`git grep OnCollisionReport` returns the interface, the dispatch loop, and four
|
|
test doubles. `CollisionReports.Subscribe` has no production caller. So the
|
|
bidirectional `DoCollisionEnd` notification retail fires at @0x00514620 still
|
|
reaches no gameplay consumer; what the fix actually delivers today is the
|
|
**table clear** (real, and it does prevent the later ~1 s stale-end and any
|
|
mis-attribution) plus a correctly-wired channel for when a consumer appears.
|
|
The hook's new doc doesn't overclaim, but the retail review's phrasing
|
|
("neither side receives the immediate `ObjectCollisionEnd`") will read as
|
|
closed. State the residual — it is a pre-existing gap in the collision-report
|
|
plumbing, wider than this slice, and it deserves one sentence rather than a
|
|
silent inheritance.
|
|
|
|
### B3 (MINOR, disclosed) — no test for R2
|
|
|
|
Judged **acceptable but worth filing**. A test would assert against a channel
|
|
nothing production reads (B2), so its value is pinning the retail *mapping*,
|
|
not a behaviour. The cheap version is one assertion that the teleporting
|
|
owner's collision table is empty after an `OnPosition` teleport packet — that
|
|
would fail if a future edit reverted the action to `ShadowObjects.Suspend`,
|
|
which is the actual regression risk. Not blocking.
|
|
|
|
### B4 (MINOR, disclosed) — the per-packet `runTeleportHook` closure
|
|
|
|
Two delegates + two display classes per remote accepted Position (the outer
|
|
`runTeleportHook` lambda and the caller's `isCurrentPositionOwner`), allocated
|
|
whether or not the packet is a teleport. The implementer's stated blocker —
|
|
that `ApplyRemoteContactRouting`'s `Func<bool>` parameter is injected by
|
|
existing tests — is real but the parameter is `internal`, so it is a
|
|
refactor cost, not a compatibility one. Judged **acceptable to defer**: this is
|
|
the per-packet network path (5-10 Hz per remote), not Slice I's per-frame
|
|
resolve path where the 0-B target applies, and the objects are gen0-transient.
|
|
File it with the probe-family cleanup rather than churning the seam now.
|
|
|
|
### B5 (MINOR, disclosed) — the stress test's teleport step
|
|
|
|
Round 1's A3 stands as written and is judged **acceptable to leave**. The
|
|
scenario it covers (Hidden → DeferredShadowRestore → landblock churn → UnHide)
|
|
no longer has any teleport-specific machinery to interact with, because this
|
|
slice deletes `_activePlacementOwners` and the placement is now synchronous
|
|
inside `OnPosition`. The hand-built step is honestly documented as reproducing
|
|
the arm tail's observable state, and the arm tail itself is directly covered by
|
|
`LiveEntityNetworkRemoteTeleportPresentationTests`. The residual loss — the
|
|
*interaction* between a mid-teleport Hidden edge and the placement — is a
|
|
degenerate case now, not an untested one.
|
|
|
|
### B6 (MINOR, carried) — proof obligation 1 is still unstated
|
|
|
|
Unchanged from round 1's A9. The contract requires the
|
|
`ParkCollisionResidents`-overlap-throw unreachability argument (with 4b-1's B2
|
|
caveat that the guarded property is
|
|
`TryAcquireCollisionPrefixMutationPermission`'s `HasOldPrefixPlacementDebt`
|
|
refusal — a stall, not a throw) in the implementation commit's
|
|
contract-conformance section. The work is still uncommitted so I cannot verify
|
|
it; the property itself holds by reading (the teleport arm adds packets to the
|
|
same one-operation-per-key machinery and opens no new operation shape).
|
|
|
|
---
|
|
|
|
## Round-1 MINORs — spot-check
|
|
|
|
Verified fixed, not re-derived: **A4** (`TeleportRefused_…` now arms sticky
|
|
before the packet and asserts `GetStickyObjectId() == 0` afterward — a real
|
|
discriminator, since only the teleport arm's hook calls `UnStick`, so the
|
|
`UnroutedCatchUp` look-alike I identified can no longer pass it); **A5** (the
|
|
landing-block comment is now correct *and* complete); **A7** (R1, above);
|
|
**A8** (`wasCellless` deleted). **A10** was accepted and restated correctly.
|
|
The retail lane's **R4** (the prologue comment's `CommittedCellId` claim) and
|
|
**R5** (`acdream-architecture.md` / `code-structure.md` still describing the
|
|
deleted classes) are both fixed in the diff.
|
|
|
|
---
|
|
|
|
## Gate status observed
|
|
|
|
- `dotnet build AcDream.slnx -c Release` → **succeeded, 0 warnings, 0 errors**.
|
|
- `tests/AcDream.Runtime.Tests -c Release --no-build` → **1,125 / 0 / 0**.
|
|
- `tests/AcDream.App.Tests -c Release --no-build` → **4,081 / 3 skipped / 0**.
|
|
- Complete Release suite: **still not run and not recorded.** The contract is
|
|
explicit that the new figure must be measured, not inherited from 11,027.
|
|
Outstanding.
|
|
- Two-client connected teleport gate: outstanding. **It must use an NPC
|
|
target** (`@teleto` a creature into view), not a second player character —
|
|
both round-1 MAJORs lived on the NPC arm, and
|
|
`RemoteServerControlledVelocityCycle.Apply` early-returns for `0x50xxxxxx`
|
|
guids, so a player-remote teleport exercises neither fix. Confirm at least
|
|
one `[remote-teleport]` line per teleport with the expected `cause`.
|