Session-end documentation for the 2026-05-23 evening session in
which:
1. The PhysicsResolveCapture apparatus shipped (committed earlier
in fb5fba6).
2. A live capture (41K records) drove the first LiveCompare_* tests
in CellarUpTrajectoryReplayTests, two of which PASS bit-perfect.
3. The failing third test pinpointed the cap-event divergence.
4. A second capture (70K records + 16 cell dumps + per-poly probes)
identified the cottage GfxObj 0xA9B47900 as the blocker — a
landblock-baked static building whose floor polygons live in the
GfxObj's BSP, NOT in any cottage cell.
The findings doc has:
- TL;DR + chronological commits
- Apparatus inventory (PhysicsResolveCapture, comparison tests,
fixtures, launch scripts)
- The math: head sphere top at Z=foot+1.68 reaches the cottage floor
at Z=94.0 when foot Z=92.74, matching the observed cap.
- User's confirming observation (cap fires on pure-vertical jump too,
ruling out every step-up / AdjustOffset hypothesis)
- What's NOT yet known (why retail doesn't have this cap; full
cottage GfxObj polygon list)
- Next-session pickup with two ranked options
Adds:
- docs/research/2026-05-23-a6-p3-issue98-comparison-harness-findings.md
- launch-a6-issue98-capture.ps1 (capture-only launch)
- launch-a6-issue98-polydump.ps1 (capture + diagnostic probes + 16-cell dump)
- 13 new cell-dump fixtures (0xA9B40140-0xA9B40142, 0xA9B40144,
0xA9B40145, 0xA9B40148-0xA9B4014F) at 272 KB total. The harness now
has the full 0xA9B4014X neighborhood available for any future
comparison test that needs adjacent cell geometry.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The capture apparatus pays off on the FIRST iteration. Three records
sampled from a live cottage-cellar session — tick 0 (spawn at Z=92.53),
tick 376 (player on the cellar ramp at Z=91.49), and tick 1183 (first
cap event, foot Z=92.74 with cn=(0,0,-1)) — replayed against the
harness engine reveal:
- LiveCompare_Tick0_Spawn: PASSES (full round-trip).
- LiveCompare_Tick376_OnRamp: PASSES (ramp walkable
polygon hydrates correctly,
engine reproduces live).
- LiveCompare_FirstCap_HeadHitsCottageFloor: FAILS by exactly the
divergence shape that names
the missing fixture.
The cap-record divergence:
Result.Position: live=(141.3865,7.2243,92.7390)
harness=(141.3599,7.2243,92.7390) (Y slid; X stuck)
Result.CollisionNormal:live=(0,0,-1) ← downward = cottage floor from below
harness=(0,0,+1) ← upward = some other floor
Plus the LiveCompare_FirstCap_DiagnosticDump test (always passes; it's
a probe-firing scratch test) prints every cell polygon in world frame:
Cellar 0xA9B40147 — ceiling polys at world Z=93.80 cover X=133-142,
Y=-1.0-11.5 but NOT the sphere XY of (141.39, 7.03) — at the right
edge of Y=7.03 the ceiling quads are at Y<3.90 or Y>8.70.
Cottage 0xA9B40143 — floor polys at world Z=94.0 cover X=136.7-140.5,
Y=3.9-13.1 but NOT (141.39, 7.03) either — at X=141.39 we are 0.89m
east of the floor quad's rightmost vertex.
Cottage 0xA9B40146 — only 4 walls, no floor.
So both cells we have CAN'T produce the live's cn=(0,0,-1). The actual
blocking polygon must be in a cell or static object we haven't loaded
into the harness yet. The cellar is rectangularly bounded; the cottage
above has a floor that spans the cottage, but the floor polygon RIGHT
ABOVE the ramp top (which is where the freeze fires) is in some OTHER
cell — either a separate cottage-floor sub-cell or a building static
GfxObj.
This is the first evidence-driven step in the saga. Six sessions of
speculation produced ten failed fix shapes; the apparatus produced
this finding in one round trip. Next step: re-capture with
ACDREAM_PROBE_POLY_DUMP + ACDREAM_DUMP_CELLS covering 0xA9B40140-
0xA9B4014F to identify the missing fixture cell.
Adds:
- LiveCompare_Tick0_Spawn / Tick376_OnRamp / FirstCap_HeadHitsCottageFloor
- LiveCompare_FirstCap_DiagnosticDump (always passes; dumps cell polys
in world frame + enables every relevant probe so the captured stdout
shows the harness BSP query path)
- tests/AcDream.Core.Tests/Fixtures/issue98/live-capture.jsonl
(3 representative records from the 41,228-record live capture)
- AssertCallMatchesCapture helper: per-field diff with Vector3 / float
tolerances, reports every divergence not just the first.
Test baseline maintained at 1172 + 8 baseline + 5 new tests pass +
1 known-failing test that pinpoints the bug = 1178 + 9 (where the
new failure is the desired evidence-driven test).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Step 2 capture step. Launched the live client with
ACDREAM_DUMP_CELLS=0xA9B40143,0xA9B40146,0xA9B40147 and walked into a
Holtburg cottage cellar. The probe fired on first-cache of each cell
and emitted JSON dumps to tests/AcDream.Core.Tests/Fixtures/issue98/.
Cell contents (resolved polygons + portals):
- 0xA9B40143: 14 polys + 4 portals (~18.7 KB)
- 0xA9B40146: 4 polys + 2 portals (~7.0 KB)
- 0xA9B40147: 37 polys + 2 portals (~45.7 KB) — cellar, biggest
All three share worldOrigin=(130.5, 11.5, 94.0) with 180° yaw rotation
(M11=M22=-1), matching the failing-frame's local-to-world projection.
Reproduction during capture: spawn at (141.6, 8.4, 91.5) @ 0xA9B40147
— almost exactly the slice 7 handoff's failing-frame position. User
tried to walk up the cellar stair and got stuck (issue #98 reproduction
confirmed).
Surprise: 0xA9B40146 with only 4 polys + 2 portals is too sparse to be
the "cottage main floor cell" that the slice 5 handoff inferred — that
designation was a guess, not verified. 0xA9B40143 (14 polys) is the
better candidate. Step 3 (replay harness) will confirm by inspecting
the actual polygon geometry against the failing-frame sphere position.
Cells are real geometry from client_cell_1.dat, not synthetic fixtures.
The replay harness can now drive the leaf-level walkable predicates on
this exact data without launching a window.
Next: Issue98CellarUpReplayTests (Step 3).