docs(physics): #165 diagnostic pass - rule out (a)/(b), stop at (c)

Campaign P Slice P3 item 4. Per the plan's explicit instruction, this
is diagnose-only: the research's candidate (a)/(b) mechanisms did not
confirm, so no fix lands here.

Built the dat-free/dat-backed fixtures the plan asked for (no live
client) to test the two mechanisms a physics fixture CAN discriminate:

- (b) ruled out by code reading: RuntimeRemotePhysicsUpdater.Tick's
  resolve gate reads RuntimeEntityRecord.FullCellId live. Every
  FullCellId = 0 write site (TryApplyPickup, CommitAcceptedParentCellless,
  CommitWithdrawal in RuntimeEntityObjectLifetime.cs) is a pickup/
  parent-attach/delete path, never reachable for a live, freely moving
  remote mid-session. The "one-frame grace" is genuinely first-spawn-only.

- (a) tested directly and does not reproduce, on two independent
  geometries: InterpolationManager's unclamped stall-fail "tail delta"
  snap (node_fail_counter > 3) can hand ResolveWithTransition an
  arbitrarily large single-tick targetPos. New fixture tests replace a
  proven small-step sweep (many 0.08-0.10 m ticks) with ONE resolve call
  spanning the entire distance, against both a synthetic creature sphere
  and the real Holtburg door BSP slab (Setup 0x020019FF/GfxObj
  0x010044B5, the existing door-apparatus dat fixture) already used by
  DoorCollisionApparatusTests. Both stop at the identical surface
  distance the small-step tests pin, with a valid collision normal --
  the sweep is not distance-limited and does not tunnel on a large
  single-tick delta.

Candidate (c) -- render/interpolation presentation lag on the App side --
is the remaining hypothesis and is out of scope for a physics-fixture
pass (it's a claim about what gets drawn relative to the committed
PhysicsBody.Position, not something a Core fixture observes). #165
stays OPEN with (a)/(b) struck from the candidate list by the evidence
above and (c) named as the next concrete step (an App-layer render-vs-
physics-position diff, or a fresh live ACDREAM_PROBE_RESOLVE capture).

New tests: Issue165RemoteWallPenetrationDiagnosticTests (dat-free,
3 tests) and DoorCollisionApparatusTests.
Apparatus_SingleLargeTickJump_DeadCenter_StillBlocksOnBSP (dat-backed,
1 test, skips gracefully without the local dat directory).

dotnet build + dotnet test (Core.Tests 4012/2 skip, Runtime.Tests
425/0) green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-30 10:01:11 +02:00
parent bb7b899bfe
commit bc3277a8ec
4 changed files with 392 additions and 1 deletions

View file

@ -4244,9 +4244,55 @@ NOTE: capture first — ACDREAM_PROBE_RESOLVE on the remote's guid at a
wall shows whether the resolver reports Collided-but-position-inside or
never sees the wall.
**Campaign P Slice P3 diagnostic pass (2026-07-30, no live client —
dat-free + dat-backed fixtures only, per
`docs/research/2026-07-29-remote-and-world-specials-pseudocode.md` §2.4b):**
research P3.2 re-framed the three candidates as (a) the
`InterpolationManager` unclamped stall-fail "tail delta" snap
(`node_fail_counter > 3`) committing a position on the far side of / inside
a wall in one tick and the same-tick sweep failing to catch a large
delta, (b) the remote resolve gate (`rm.CellId != 0 &&
_physics.Engine.LandblockCount > 0`) skipping the sweep entirely on some
tick other than first-spawn, and (c) render/interpolation presentation lag
on the App side. Both (a) and (b) are now RULED OUT with direct evidence:
- **(b):** code-read every `FullCellId = 0` write site
(`RuntimeEntityObjectLifetime.cs`: `TryApplyPickup`,
`CommitAcceptedParentCellless`, `CommitWithdrawal`) — all three are
pickup/parent-attach/delete paths, never reachable for a live, freely
moving remote mid-session. The gate's "one-frame grace" is genuinely
first-spawn-only.
- **(a):** three new fixture tests drive a SINGLE resolve call spanning an
entire large-tick jump (simulating the unclamped snap) instead of many
small ticks, against both synthetic sphere geometry AND the real
Holtburg door BSP slab (`Setup 0x020019FF`/`GfxObj 0x010044B5`) already
used by the door apparatus tests — both stop at the identical surface
distance the proven small-step tests already pin, with a valid collision
normal. The sweep is not distance-limited and does not tunnel on a large
single-tick delta. See
`Issue165RemoteWallPenetrationDiagnosticTests.SingleLargeTickJumpThroughObstacle_IsStillBlockedAtSurface`
and
`DoorCollisionApparatusTests.Apparatus_SingleLargeTickJump_DeadCenter_StillBlocksOnBSP`.
**Candidate (c) is therefore the remaining hypothesis** and is explicitly
OUT OF SCOPE for a physics-fixture-only pass — it is a claim about the
App-layer render/presentation frame relative to the committed
`PhysicsBody.Position`, not something a dat-free/dat-backed Core fixture
can observe. Per the campaign's own instruction ("diagnose only unless a
candidate confirms cheaply; otherwise stop"), this issue stays OPEN. The
next concrete step for whoever picks this up: an App-layer render-position
vs. physics-position diff across frames for a remote near a wall, or a
fresh `ACDREAM_PROBE_RESOLVE`/`ACDREAM_CAPTURE_RESOLVE` live capture (the
existing diagnostic recommendation in the research doc, still valid) if a
live repro becomes available.
**Where:** GameWindow remote DR tick (`TickAnimations` player-remote
pipeline + queue chase), `PhysicsEngine.ResolveWithTransition` remote
callers.
callers; `src/AcDream.Runtime/Physics/RuntimeRemotePhysicsUpdater.cs`
(resolve gate, candidate (b), ruled out); `src/AcDream.Core/Physics/
InterpolationManager.cs` (unclamped stall-fail snap, candidate (a), ruled
out); the render/presentation path (candidate (c), OPEN, App-layer, not
yet located).
**Acceptance:** a retail mover pressed against a wall shows flush at the
wall from acdream, matching the retail-observer view side-by-side.