acdream/docs/research/2026-05-24-door-collision-session-end-handoff.md
Erik 6a2c432e5a docs(handoff): door collision session end — honest accounting
Replaces the puffed-up framing in the prior task7-shipped handoff.
Honest summary: no user-visible bug fixed this session. Off-center
and inside-out door walk-through still 100% reproducible. The 4
commits shipped real infrastructure (multi-part registration + the
GetNearbyObjects dedup fix that would have silently broken any
future multi-part feature) but no observed behavioral change.

Also explicitly retracts the "step-up is the bug" hypothesis from
the prior handoff doc — ACDREAM_DUMP_STEPUP=1 in the apparatus
produced no stepup: ENTER lines, so DoStepUp wasn't even being
called. That hypothesis was over-reach from an inference I should
not have inflated to a conclusion.

Recommends the apparatus-replay pattern (same one that closed issue
#98 after 6+ speculation rounds): live capture via
ACDREAM_CAPTURE_RESOLVE → harness replay test → first per-field
divergence names the broken assumption.

DO-NOT list for the next session: do not redo the multi-part work,
do not speculate-and-fix, do not relaunch with more probes hoping
for an obvious signal.

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

8.4 KiB
Raw Blame History

Door collision — end-of-session handoff (2026-05-24, late)

Branch: claude/strange-albattani-3fc83c Worktree: C:\Users\erikn\source\repos\acdream\.claude\worktrees\strange-albattani-3fc83c

TL;DR — what was actually accomplished

No user-visible bug was fixed this session. The door bug the user reported at the start (center blocks, off-center walks through, inside-out walks through) is identically reproducible after the 4 commits as it was before them.

What changed: infrastructure. Server-spawned doors now register multi-part shadow shapes (cylinder + BSP slab) instead of one cylinder approximation. The BSP slab is queried 135 times per door near approach but produces zero collision hits, so observed behavior is unchanged.

Don't re-do the infrastructure. It's correctly built and necessary for any future fix. The remaining work is downstream of it.

Commits landed (4)

163a1f0 diag(phys): [bsp-test] probe + grounded apparatus test + handoff
ca9341c feat(phys): A6.P4 Task 7 — RegisterLiveEntityCollision uses ShadowShapeBuilder + RegisterMultiPart
3b7dc46 fix(phys): GetNearbyObjects dedup-by-entityId silently drops multi-part shadows
e1d94d7 test(phys): door setup + GfxObj dat-inspection — Hypothesis A falsified

Real-but-latent value from these:

  • The dedup-by-entityId issue (3b7dc46) was a latent footgun: any future attempt at multi-part shadows (NPCs with hit-region capsules, multi-part creatures, props with separated collision) would have silently dropped all but the first shape. Now safe.
  • The dat-inspection (e1d94d7) proved part 0 (0x010044B5) has a real 1.9×0.26×2.5 m BSP slab in the dat. A future fix doesn't have to question whether the data exists.
  • The Task 7 wiring (ca9341c) puts the right architecture in place — doors now register the shapes retail expects (cyl per CylSphere + cyl per Sphere + BSP per Part-with-BSP).
  • The [bsp-test] probe (163a1f0) fires before the cache lookup, distinguishing "cache miss → silent skip" from "queried but no hit" — neither of which [resolve-bldg] ever showed.

Brutally clear: zero of these commits change observed door behavior.

What we now know vs. what we don't

Known (from this session's probes)

  • 0x010044B5 PhysicsBSP has 6 collision-bearing polygons forming a 1.925 × 0.261 × 2.490 m door slab. All SidesType=Landblock (two-sided). Bounding sphere radius 1.975 m. Verified by direct dat read.
  • 0x010044B6 (the two leaf parts) have HasPhysics=false, PhysicsBSP=null, PhysicsPolygons.Count=0. Visual-only by retail design — our skip matches retail's CPhysicsPart::find_obj_collisions:275051.
  • Live Holtburg doors register with shapes=cyl1+bsp1. Cache is populated. BSP entries are visited (135x for one door at player approaches as close as 0.42 m).
  • The BSP traversal produces ZERO attributed hits during live walking (all 19 [resolve-bldg] lines show gfxObj=0x00000000, which is the Cylinder shape). Whatever is happening inside SphereIntersectsPolyInternal or the dispatch around it is swallowing the hit silently.

NOT known (don't speculate further)

  • Whether DoStepUp is involved. The prior handoff doc (2026-05-24-door-collision-task7-shipped-but-bug-remains.md) asserted "step-up incorrectly succeeds" as the leading hypothesis. That was over-reach. In the apparatus, ACDREAM_DUMP_STEPUP=1 produced no stepup: ENTER lines — DoStepUp was never called. So the apparatus shows hit=yes n=(0,0,1) from some OTHER path (terrain step-down? walkable poly preservation?). It does not confirm step-up is the production bug.
  • Whether the production hit happens at the BSP polygon edge test, the BSP node traversal, or some other layer.
  • Whether the production code path is the same as the apparatus path 5 in the first place.

The earlier framing of "step-up is the bug" was a guess I inflated into a conclusion. Treat it as a candidate, not a finding.

Proper next move

Same pattern that closed issue #98 after 6+ failed speculation rounds: live capture + apparatus replay.

The infrastructure for this already exists in the codebase:

  1. ACDREAM_CAPTURE_RESOLVE=<path> env var (see src/AcDream.Core/Physics/PhysicsResolveCapture.cs) captures every player-side PhysicsEngine.ResolveWithTransition call as a JSON Lines record with full PhysicsBody before-and-after snapshots.
  2. CellarUpTrajectoryReplayTests.LoadCapturedRecord + AssertCallMatchesCapture replay a captured record through a harness engine and emit the first per-field divergence between live and harness outputs.

The plan:

  1. Launch with ACDREAM_CAPTURE_RESOLVE=door-walkthrough.jsonl (no other probes — capture is independent).
  2. Walk into a closed Holtburg cottage door 50 cm off-center.
  3. Close gracefully. Save the JSONL.
  4. Write a new test LiveCompare_DoorOffCenterWalkthrough that loads the failing-tick record and replays it through a harness with the real 0x010044B5 BSP hydrated + registered via RegisterMultiPart. Compare per-field.
  5. The first divergent field names the broken assumption. Fix that.

This is concrete, deterministic, and doesn't ask you to relaunch multiple times for each fix attempt. The harness round-trip is <500 ms; a fix iteration is ~3 seconds.

What NOT to do

  1. Do NOT re-do the multi-part registration. It's correct. The dedup fix is correct. Task 7 is correct. Verified by 53/53 tests in the targeted scope.
  2. Do NOT speculate-and-fix. This session burned cycles on a "step-up is the bug" hypothesis that wasn't supported by the evidence. The apparatus-first rule (feedback_apparatus_for_physics_bugs.md) exists for exactly this. Build the apparatus before the fix.
  3. Do NOT re-investigate whether the door has BSP polygons. It does. 6 of them. Forming a full door slab. Cached. Visited.
  4. Do NOT relaunch with more probes hoping for an obvious signal. The probes we have already say "BSP visited 135 times, no hits." More log lines won't tell us WHY it doesn't hit. The apparatus replay will.

Files to read first

  • This doc (you're in it).
  • docs/research/2026-05-24-door-dat-inspection-findings.md — the dat data, polygon layout, bounding sphere center vs frame offset.
  • docs/research/2026-05-24-door-collision-task7-shipped-but-bug-remains.md — the prior end-of-session handoff. Read with skepticism — its "leading hypothesis" section overstates confidence in the step-up theory (corrected here).
  • tests/AcDream.Core.Tests/Physics/CellarUpTrajectoryReplayTests.cs — the capture+replay pattern to mirror for the door bug. See LiveCompare_* tests.

State of the M1.5 milestone

Doors at Holtburg cottages: center blocks, off-center walks through, inside-out walks through. Same as it was 24 hours ago. The walking- through case is the actual user pain point. Until the apparatus replay names the divergence, treat M1.5 indoor-world as still incomplete on the door front.

The infrastructure is in place for the eventual fix. The fix itself remains future work.

Pickup prompt for the next session

Door collision investigation. Previous session shipped infrastructure
(multi-part registration + GetNearbyObjects dedup fix) but did NOT fix
the user-visible bug: off-center / inside-out approaches still walk
through closed Holtburg cottage doors.

  Read docs/research/2026-05-24-door-collision-session-end-handoff.md

  State both altitudes:
    Currently working toward: M1.5 — Indoor world feels right
    Current phase: A6.P4 door bug — apparatus replay phase.
                   Multi-part registration shipped; need live capture
                   + per-field divergence comparison to identify why
                   the door's BSP slab fires zero attributed hits
                   despite being visited 135x per approach.

  First move: launch the client with ACDREAM_CAPTURE_RESOLVE=<path>,
  walk into a closed Holtburg cottage door 50 cm off-center, close
  gracefully. Then write a LiveCompare_* test in CellarUpTrajectoryReplayTests
  that loads the captured failing tick + replays through a harness
  with the door BSP hydrated via the existing 0x010044B5 dat read
  pattern and registered via RegisterMultiPart.

  DO NOT redo the multi-part registration. DO NOT speculate about
  step-up without evidence — the apparatus tested DoStepUp and it
  didn't fire. The bug is upstream of step-up. The replay will name
  the actual divergence.