Commit graph

2 commits

Author SHA1 Message Date
Erik
163a1f0d35 diag(phys): [bsp-test] probe + grounded apparatus test + handoff
Visual verification of Task 7 ship: doors block at dead-center (the
small Cylinder catches) but the BSP slab doesn't catch off-center
or inside-walking-out approaches. Probe-instrumented live capture
proves multi-part registration is correct — every door spawns with
shapes=cyl1+bsp1, and the BSP part is visited 135 times for a single
door at player approaches as close as 0.42 m, with cacheHit=True.
But zero [resolve-bldg] attributions for the BSP shape.

Three artifacts added:

1. TransitionTypes.cs — new [bsp-test] probe in the BSP collision
   dispatch, fires BEFORE the cache lookup. Mirrors [cyl-test] on
   the Cylinder branch. Distinguishes "cache miss → silent skip"
   from "queried but no hit" (the latter doesn't show up in
   [resolve-bldg] which only fires on attributed hits).

2. DoorCollisionApparatusTests.cs — new grounded test
   (Apparatus_Grounded_50cmOffCenter_*) attempts to reproduce the
   production bug via a seeded PhysicsBody (Contact + OnWalkable
   + ContactPlane + WalkablePolygon). Currently doesn't reproduce
   because the apparatus's stub-terrain + synthetic-floor setup
   diverges from production's real Holtburg geometry. Captured as
   "documents-the-bug" — flip the assertion shape when the fix
   lands.

3. docs/research/2026-05-24-door-collision-task7-shipped-but-bug-remains.md
   — full session handoff. Identifies the remaining bug as a Path 5
   (Contact branch + StepSphereUp) misbehavior at thin tall
   obstacles, not in the multi-part registration we just shipped.
   Leading hypothesis: DoStepUp's downward probe finds the same
   flat floor on the OTHER side of the door (Holtburg cottages have
   no Z change between exterior and interior floor), declares
   step-up success, BSP collision returns OK, sphere walks through.
   Recommended next move: relaunch with ACDREAM_DUMP_STEPUP=1 to
   verify the hypothesis.

What this commit DOES NOT do: fix the remaining step-up bug. The
A6.P4 multi-part registration foundation is correct and stays.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 19:22:45 +02:00
Erik
3b7dc46219 fix(phys): GetNearbyObjects dedup-by-entityId silently drops multi-part shadows
Apparatus test (DoorCollisionApparatusTests) loads door GfxObj 0x010044B5
from the real dat, builds the door entity's shape list via
ShadowShapeBuilder, registers via RegisterMultiPart, and sweeps a player
sphere into the door from three angles. Pre-fix: all three assertions
fail — the sphere walks straight through. The [cyl-test] probe fires
every tick (the small Sphere shape is queried) but no [resolve-bldg] —
the per-Part BSP entry is never reached.

Root cause: ShadowObjectRegistry.GetNearbyObjects deduplicates on
entry.EntityId via HashSet<uint>. Pre-RegisterMultiPart each entity had
exactly one shadow row, so dedup-by-entityId correctly suppressed
multi-cell duplication. After Task 4's RegisterMultiPart introduced
multi-shape rows (1 Sphere + 1 per-Part-BSP for doors; potentially more
for creatures + items), the dedup silently drops everything after the
first. ShadowShapeBuilder emits Sphere shapes before Part-BSPs, so the
Sphere wins and the BSP is dropped — exactly the "Task 7 produced zero
[resolve-bldg] hits" finding from the 2026-05-24 evening handoff.

Fix: dedup on the full ShadowEntry. record-struct equality compares
all fields (EntityId, GfxObjId, Position, Rotation, Radius,
CollisionType, CylHeight, Scale, State, Flags, LocalPosition,
LocalRotation). Distinct shapes of the same entity are not equal and
make it through; the same shape registered in multiple cells (its
fields identical across calls) dedups exactly as before.

Apparatus verification post-fix: all 4 tests pass.
  - Dead-center front approach: BLOCKED at Y=11.5 normal=(0,-1,0).
  - 50 cm off-center: BLOCKED at Y=11.5 normal=(0,-1,0).
  - Back approach from inside: BLOCKED at Y=12.8 normal=(0,+1,0).
  - Diagnostic dump: BSP fires at tick 5.

What this fix DOES NOT do: switch live RegisterLiveEntityCollision to
use ShadowShapeBuilder + RegisterMultiPart. That's Task 7 of the
original plan, still reverted. With this foundation fix in place,
Task 7 should now actually deliver door blocking in production.

Test impact: 44/44 in the shape/registry/door scope pass. The broader
Physics suite shows the pre-existing PhysicsResolveCapture
static-state flakiness documented in CLAUDE.md — 6 baseline failures
without my new tests, 10 with them (4 extra are my apparatus tests'
IsPlayer-flag resolves getting captured by a concurrent Capture-test
race). Independent of this fix; verified by isolating each test
class.

Findings + apparatus reasoning:
docs/research/2026-05-24-door-dat-inspection-findings.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 18:47:04 +02:00