diag(physics): remote landing-edge probe; record the two live jump defects

The user live-tested route 4a and reported two defects on player remotes: a
remote holds the falling animation after landing before finally landing, and a
remote jumping onto a house plants on the roof where retail slides off, then
blips to the slid-down position.

Neither is a route 4a regression. Do NOT revert 44830a0e — reverting would
restore the per-packet render slam 4a removed without touching either defect.

Bug B's root cause is identified and already covered by open issue #32, whose
text names both symptoms in one sentence. Both landing sites assert
TransientState |= Contact | OnWalkable unconditionally, where retail derives it
from the contact plane — CPhysicsObj::SetPositionInternal @0x00515330
(`if (contact_plane.N.z < floor_z) set_on_walkable(0) else set_on_walkable(1)`).
A steep roof is contact but NOT on_walkable; asserting both suppresses the slide
response, so the body sits until the server's positions walk 4 m away and
AP-87's threshold snaps it. That is the blip. Verified byte-identical pre-4a via
`git show 19d95094:`.

Bug B's *visible shape* IS 4a's: pre-4a every packet slammed the render entity
to the wire pose, so a stuck body flickered toward the true sliding position
5-10x per second — jitter rather than a clean hold.

Bug A stops at the goal's stop-condition rather than getting a speculative fix.
Three hypotheses with non-overlapping fixes; picking wrong means changing a
retail-ported gate on a guess. Retail's mechanism is already fully decoded, so
what is missing is OUR runtime state — no cdb trace against retail is needed.

Adds ACDREAM_PROBE_REMOTE_LANDING (PhysicsDiagnostics, read once at startup per
the diagnostic-owner rule, one bool check when off). It logs both landing sites
immediately before HitGround, and — the most diagnostic signal — emits a
separate line when a site is reached but the gravity gate is about to no-op,
which is hypothesis 1 (a wholesale Body.State write wiping the transient Gravity
bit mid-air, exactly AP-81's stated risk). Temporary instrumentation, marked for
stripping once the evidence is in.

Evidence recorded rather than new bugs filed: #32 gains the observation, the
root cause and the #173/AD-10 dependency caveat; AP-87 gains a live instance of
its stated risk; AD-10's stale file:line is corrected to RemoteMotionCombiner
with a note that its terrain-only normal cannot see a house roof at all.

Also files #308 — a SECOND flaky test, distinct from #302, which was twice
misattributed to it before being written down. #302 is a GC-allocation assertion
in App.Tests; #308 is a wall-clock deadline loop in Core.Net.Tests that fails
only under full-suite CPU contention (0 failures in 4 isolated runs). Conflating
them hides one, and an agent told to "ignore the known flake" would wave through
a real transport regression.

Gates: complete Release solution 10,938 passed / 4 skipped / 0 failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-04 01:10:03 +02:00
parent dda1e2a03a
commit eeec4fb42a
6 changed files with 366 additions and 2 deletions

View file

@ -582,6 +582,28 @@ it. Do #297 FIRST — #298 depends on it.
allocation count, matching how the other allocation gates in the repo are
written. Found while independently verifying the #297 gate.
- **#308 — OPEN — `NakEmissionTests.LossSoak_TwoPercentBidirectional_ZeroMessageLoss_LedgersConverge`
is a SECOND, load-sensitive flake — distinct from #302. LOW.**
`tests/AcDream.Core.Net.Tests/Transport/` — a wall-clock-driven randomized
packet-loss soak with a `DateTime.UtcNow < deadline` loop. Observed failing
twice on 2026-08-03/04, **both times only inside a full-solution run**, and
0 failures in 4 consecutive isolated runs of `AcDream.Core.Net.Tests` alone.
That profile points at CPU contention starving the deadline loop under the
full suite, not at transport logic.
**Filed because it was twice misattributed to #302 before being written
down.** They are different tests in different assemblies with different
mechanisms: #302 is a `GC.GetAllocatedBytesForCurrentThread()` assertion in
`AcDream.App.Tests` sensitive to JIT tiering; this one is a wall-clock
deadline in `AcDream.Core.Net.Tests` sensitive to machine load. Conflating
them hides one of the two, and an agent instructed to "ignore the known flake"
will wave through a real transport regression.
Fix shape: drive the soak from a virtual/injected clock or an iteration count
rather than wall-clock, matching how the deterministic transport suites are
written. Do not simply widen the deadline — that hides load regressions
instead of removing the dependency. Note Campaign N's transport work is the
SSOT here; read `claude-memory/project_network_transport_digest.md` before
touching it.
- **#303 — OPEN — `LiveEntityPvpBitfieldSync` lives in App but touches only
Runtime-owned state. INFO/shape.**
`src/AcDream.App/Physics/LiveEntityPvpBitfieldSync.cs` reads
@ -9333,6 +9355,63 @@ anchors include `CTransition::edge_slide`, `CTransition::cliff_slide`,
**Acceptance:** Synthetic and real-DAT tests cover wall-slide, roof-edge slide,
cliff/precipice slide, failed step-up/step-down, and the jump-clears-edge case.
**2026-08-04 live route 4a test — Bug B (remote roof-plant half-state, one of
the two symptoms this row already named) confirmed and root-caused:** the
user's two-client test reproduced exactly the "lands on roof in falling
animation, can't slide off" half-state this row already describes, and this
time as a REMOTE jumping onto a house: it plants on the roof, then blips to a
slid-down position after drifting away rather than sliding smoothly.
Root cause: the player-remote landing block
(`src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs`, the
`if (rmState.Airborne)` transition) and its per-tick twin
(`src/AcDream.Runtime/Physics/RuntimeRemotePhysicsUpdater.cs:~493-551`) both
assert `Body.TransientState |= Contact | OnWalkable` UNCONDITIONALLY on
landing. Retail derives `on_walkable` from the contact plane instead —
`CPhysicsObj::SetPositionInternal` (named symbol @0x00515330, pseudo-C
:283501-283509):
```
if (contact_plane.N.z < floor_z)
set_on_walkable(0);
else
set_on_walkable(1);
```
A steep roof is Contact (the sphere is touching it) but NOT on_walkable (its
normal.Z is below `floor_z`) — retail keeps sliding it. Forcing both bits true
suppresses the slide response outright; the body then sits planted on the
roof until AP-87's 4 m drift-snap backstop (`docs/architecture/retail-
divergence-register.md` row AP-87) fires and blips it to the server's
already-slid-down position — the visible "plant, then teleport" the user
reported. This code is byte-identical to the pre-C4-route-4a version (verified
via `git show 19d95094:src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs`,
which shows the identical unconditional `TransientState |= Contact |
OnWalkable` at the same landing site) — **this is not a route 4a regression;
do not revert `44830a0e`.**
Fixing `OnWalkable` alone at the landing block may not be sufficient to
reproduce retail's slide, because retail's slide response also depends on two
other pieces that are either incomplete or unverified for remotes:
- **#173** (this file) shipped the remote collision-velocity reflect
(`CPhysicsObj::handle_all_collisions` pc:282699-282715) but its dedicated
visual gate was folded into the Campaign P matrix scenario 8 and that gate
has not actually been run/confirmed yet — the reflect path this fix needs
is unverified in practice, not just untested in isolation.
- **AD-10** (`docs/architecture/retail-divergence-register.md`) — remote
slope projection samples ONLY the terrain normal
(`PhysicsEngine.SampleTerrainNormal`, consumed by
`src/AcDream.Core/Physics/RemoteMotionCombiner.cs`), which cannot see
building/EnvCell geometry at all. A house roof has no terrain normal to
project against, so even a corrected `OnWalkable` would need a real
contact-plane-derived slide, not the terrain-only approximation AD-10
already flags as a divergence.
No fix has been applied for this observation — the investigation stopped
here per project policy (no workarounds without approval) and instrumented a
probe (`ACDREAM_PROBE_REMOTE_LANDING`, `PhysicsDiagnostics.cs`) instead. See
`docs/research/2026-08-04-remote-landing-investigation.md` for the companion
Bug A (falling-animation-lingers) hypothesis set and the probe's decision
table.
---
## #35 — [DONE 2026-04-30] Retail debugger toolchain (cdb + PDB GUID matching)