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>
This commit is contained in:
Erik 2026-05-24 20:52:53 +02:00
parent 163a1f0d35
commit 6a2c432e5a

View file

@ -0,0 +1,188 @@
# 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.
```