Commit graph

7 commits

Author SHA1 Message Date
Erik
fcea816391 test(core): commit doorway-threshold fixture for DoorwayMembershipReplayTests (portable)
T0 test-hygiene pass (2026-06-02): DoorwayMembershipReplayTests previously loaded
doorway-capture.jsonl from the repo root — a 719 MB untracked file that only
exists on the developer's machine after a specific live capture run. On any other
machine (CI, fresh worktree, other developers) the tests would silently SKIP instead
of running.

Fixes:
- Extract the 57 doorway-seam records (Y∈[15.5,17.5], ticks 17392-17448) from the
  large capture into committed fixture
  tests/AcDream.Core.Tests/Fixtures/issue98/doorway-threshold-capture.jsonl (110 KB).
- Update DoorwayMembershipReplayTests to use FixturePath() (same SolutionRoot walk
  pattern as CellarUpTrajectoryReplayTests) instead of FindCapturePath().
- Change from silent-skip-if-absent to Assert.True(File.Exists) with a clear error
  message — the committed fixture must be present.
- Both DoorwaySeam_FindCellSet_StableNoStrobe and
  OutdoorSeamRecords_FindCellSet_ReturnsCorrectOutdoorCell pass against the fixture.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 15:22:57 +02:00
Erik
82781c272b test(phys): A6.P5 fixture — 3 ticks from live door-stuck capture
over-penetration-capture.jsonl is 3 records extracted from
door-stuck-capture.jsonl: the cell-crossing over-penetration tick
(0xA9B4013F -> 0xA9B40150, sphere committed 0.27m INTO slab), a
stuck-position hit=yes tick, and a stuck-position hit=no tick. Drives
the A6.P5 replay tests that prove the cellSet gate removal closes both
the over-penetration and the intermittent-visibility bugs.

extract-records.ps1 is a one-shot extractor; reusable if we capture more.
Source captures (door-stuck-*.jsonl, door-stuck-*.launch.log) gitignored.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 12:43:51 +02:00
Erik
28cd97be62 fix(phys): A6.P4 door bug — AddAllOutsideCells coord convention + replay apparatus
CellTransit.AddAllOutsideCells assumed sphere coords were absolute world
coords (subtracting lbXf = 0xA9 * 192 = 32448 from the sphere position).
Production has used landblock-local coords since Phase A.1
(streaming-center landblock at world origin), so the subtraction
produced localX = -32316, gridX = -1346 → out-of-range → early return
→ ZERO outdoor cells added.

For outdoor primary cells the bug was masked by GetNearbyObjects's
radial sweep. For indoor primary cells (where #98 gates the outdoor
sweep), the door's outdoor cell 0xA9B40029 never reached
portalReachableCells, the door's BSP was never queried, and the player
walked through Holtburg cottage doors unimpeded.

Fix: AddAllOutsideCells treats worldSphereCenter as landblock-local
directly. Matches retail CLandCell::add_all_outside_cells which uses
the per-cell 6-byte landblock-relative position struct.

Existing CellTransitAddAllOutsideCellsTests + CellTransitFindCellSetTests
updated to use landblock-local sphere coords (they were the only callers
using the world-coord convention; production never did).

Apparatus shipped:
- DoorBugTrajectoryReplayTests — live-capture-driven replay harness
  that pinpointed the bug per-field at unit-test speed (<500ms iteration)
- AddAllOutsideCells_LandblockLocalSphere_AddsDoorOutdoorCell — direct
  unit test that demonstrates the fix
- FindTransitCellsSphere_IndoorExitPortal_AddsOutsideForCapturedSpherePos
  — verifies cell-portal traversal at the captured sphere position
- DoorSetupGfxObjInspectionTests.HoltburgCottage_CellPortals_DatInspection
  — dat-direct EnvCell + Environment.Cells + portal-poly inspector
- Fixture: tests/AcDream.Core.Tests/Fixtures/door-bug/live-capture.jsonl
  (tick 13558 walkthrough + tick 22760 outdoor block)

Visual verification (user-driven at Holtburg cottage door, ~50cm off-center):
- outside→inside RUN: now BLOCKS (was: walks through)
- outside→inside WALK: presumed blocks (not retested)
- inside→outside RUN: PARTIAL — body intersects door, sphere slides through
- inside→outside WALK: same partial behavior

The remaining inside→outside asymmetry is a SEPARATE bug in BSP
collision response for two-sided polygons. The [bsp-test] probe now
fires 245 times for the door entity from indoor (was 0 pre-fix) —
door IS being queried; the BSP polygon-level collision response is
the new bug. Handoff at
docs/research/2026-05-25-door-bug-partial-fix-shipped.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 07:53:34 +02:00
Erik
97fec19dbb test(phys): A6.P3 #98 — comparison harness reproduces cottage-floor cap
Apparatus convergence. With the cottage GfxObj 0x01000A2B registered as
a ShadowEntry in BuildEngineWithCellarFixtures, the harness now reproduces
the live cap-event collision normal (cn=(0,0,-1)) exactly, ending the
"harness doesn't reproduce" divergence the prior session's findings doc
identified.

Concretely:
  * Adds a minimum-stub landblock (TerrainSurface at z=-1000) so
    TryGetLandblockContext succeeds at the cellar XY — production's
    FindObjCollisions early-returns without a landblock and would skip
    the cottage shadow query.
  * Adds RegisterCottageGfxObj that loads the 74-polygon cottage fixture
    via GfxObjDumpSerializer.Hydrate, then registers it at the cottage's
    world transform (translation (130.5, 11.5, 94.0) + 180° around Z,
    derived from the cellar cell's WorldTransform), matching
    GameWindow.cs:5893's landblock-baked-static registration shape.
  * LiveCompare_FirstCap_HarnessMissesCottageFloorBecauseCottageGfxObjNotRegistered
    flips: the cap-normal reproduction is now enforced by
    LiveCompare_FirstCap_HarnessReproducesCottageFloorCapNormal.
  * The full per-field round-trip uncovered ONE residual divergence:
    live preserves +0.0266m of +X motion through the cap event (edge-
    slide along the floor in XY); harness blocks ALL motion at the cap.
    Captured by LiveCompare_FirstCap_ResidualXMotionDivergence_Docs...
    in documents-the-bug form so the next session has a concrete next
    target.

Fixture: tests/AcDream.Core.Tests/Fixtures/issue98/0x01000A2B.gfxobj.json
(74 polygons, 6 downward-facing cottage-floor triangles at object-local
Z=0, BSP radius 13.989m matching the live [resolve-bldg] bspR=13.99).
Captured via launch-a6-issue98-cottage-gfxobj-dump.ps1.

In-isolation: all 12 CellarUpTrajectoryReplayTests + 4 GfxObjDumpRoundTripTests
+ 1 new PhysicsDiagnosticsTests pass.

Note on full-suite baseline: the full xUnit serial run shows 8–19
failures depending on order (pre-existing test interaction with shared
statics across PlayerMovementControllerTests, MotionInterpreterTests,
PositionManagerTests, etc.). The flakiness is independent of this
change — confirmed by stashing the harness changes and observing the
same flaky range. Investigating the static-state isolation problem is
out of scope for issue #98; tracked as a follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 20:44:50 +02:00
Erik
f29c9d5e61 docs(research): A6.P3 #98 — comparison harness findings + neighborhood fixtures
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>
2026-05-23 20:12:43 +02:00
Erik
44614ab591 test(phys): A6.P3 #98 — comparison harness + first evidence-driven finding
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>
2026-05-23 19:58:51 +02:00
Erik
3f56915bc6 capture(phys): A6.P3 #98 — cellar/cottage cell fixtures from live capture
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).
2026-05-23 15:21:44 +02:00