acdream/docs/research/2026-05-21-walk-miss-capture-findings.md
Erik bb1e919ef2 docs(physics): spec + plan + findings for ISSUES #83 walk-miss probe spike
Three docs from the indoor walk-miss probe spike landed in commits
27c7284..a2e7a87:

- Spec: design of the [walk-miss] + [floor-polys] diagnostic emissions
  with the H1/H2/H3 disambiguation matrix.
- Plan: 3-task TDD implementation plan (flag, aggregator, emissions).
- Findings: live-capture analysis showing H3 (walkable_hits_sphere /
  adjust_sphere_to_plane synthesis rejection) is the dominant defect.
  817 of 876 ground-contact misses (93%) cluster at dz~0.48 m, while
  the 7 HITs all sit at dz~0.46 m — a 2 cm boundary between working
  and broken that points at the sphere-overlap math, not the probe
  distance. H1 (multi-cell iteration missing) is real but only 3%
  of misses, secondary. H2 (probe distance) ruled out.

Next step: line-by-line decomp comparison of FindWalkableInternal /
walkable_hits_sphere / adjust_sphere_to_plane against retail at
acclient_2013_pseudo_c.txt:322032 / :323006 / :326793, then design
the fix in a follow-up session.

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

11 KiB
Raw Blame History

Indoor walk-miss probe — capture findings (ISSUES #83)

Date: 2026-05-21 Session: lucid-goldberg-1ba520 Spec: docs/superpowers/specs/2026-05-21-indoor-walk-miss-probe-design.md Plan: docs/superpowers/plans/2026-05-21-indoor-walk-miss-probe.md Capture log: launch-walk-miss.utf8.log (9,401 lines, this branch — uncommitted)

TL;DR

H3 is the dominant defect. The indoor walkable-plane synthesis (BSPQuery.FindWalkableSphereFindWalkableInternalwalkable_hits_sphere + adjust_sphere_to_plane) rejects floor polygons it should accept ~98 % of the time the player is standing on a horizontal indoor floor. The HIT zone is razor-thin: misses cluster at dz=0.48 m (cell-local foot-above-floor) while the only 7 HITs in the entire capture all sat at dz=0.46 m — a 2 cm boundary between working and broken.

H1 (multi-cell iteration missing) is real but secondary: 59 events (3 %) at doorway-threshold cells where the player stepped past a small indoor floor poly and the LandCell terrain would have grounded them.

H2 (probe distance 0.5 m too short) is not the issue. The bulk of H3 misses sit well within the probe envelope.

Numbers

Metric Count
Total [walk-miss] events 1,814
[indoor-walkable] result=HIT (synthesis succeeded) 7
[indoor-walkable] result=MISS (synthesis failed) 1,814
Synthesis HIT rate 0.38 %
[floor-polys] cell dumps (one per cached indoor cell) 527

Hypothesis classification (per spec disambiguation matrix)

Class Filter Count % of total
H3 candidate containsFootXY=True AND |dz| ≤ 0.5 m 817 45.0 %
Airborne / jump containsFootXY=True AND |dz| > 0.5 m 938 51.7 %
H1 candidate containsFootXY=False AND landcell.hasTerrain=true 59 3.3 %
H1+H3 combo containsFootXY=False AND landcell.hasTerrain=false 0 0.0 %

The 938 "airborne" events are not a defect — they correspond to the test session's jump arc (the user jumped through the doorway during capture). The probe correctly reports containsFootXY=True with a large dz because the foot is XY-over a floor poly but vertically too far above it. Setting these aside: of 876 ground-contact misses, 93 % are H3.

nearest.dz distribution (containsFootXY=True only)

dz bucket Count
0.00.2 m 18
0.20.4 m 7
0.40.5 m 792
0.51.0 m 141
1.02.0 m 427
> 2.0 m 370
negative 0

The massive 792-event spike at 0.40.5 m is the standing-on-the-floor position. The 1.02.0 m and >2.0 m buckets are the jump arc.

The 2 cm hit/miss boundary

The only 7 synthesis HITs in the capture share a precise property:

HIT example foot.W.Z world floor Z dz
cell=0xA9B40125 wpos=(104.263, 140.893, 66.480) 66.480 66.020 +0.46
cell=0xA9B40125 wpos=(104.272, 141.275, 66.480) 66.480 66.020 +0.46
cell=0xA9B40123 wpos=(108.430, 134.116, 69.485) 69.485 69.020 +0.47
cell=0xA9B40123 wpos=(108.443, 134.162, 69.485) 69.485 69.020 +0.47
cell=0xA9B40123 wpos=(109.702, 133.700, 69.485) 69.485 69.020 +0.47

The MISS lines from the same cottage, same physics tick rate:

MISS example foot.W.Z world floor Z dz
cell=0xA9B40125 foot.W=(104.263, 140.893, 66.500) 66.500 66.020 +0.48
cell=0xA9B40121 foot.W=(104.254, 140.441, 66.500) 66.500 66.020 +0.48

The 20 mm difference in foot.W.Z (66.480 → 66.500) flips the synthesis from HIT to MISS. This matches the +0.02 m Z-bump mentioned in TransitionTypes.cs:1511 ("the +0.02f Z-bump applied for render z-fight prevention"). When the foot's world Z is at exactly the rendered floor + foot-height (world_floor + 0.46), synthesis HITs. When it's 2 cm higher, synthesis MISSES.

That's not a probe-distance issue. The probe distance is 0.5 m and dz=0.48 < 0.5. The geometry is well within reach.

The defect is in the sphere-overlap test or sphere-plane-adjustment math inside FindWalkableInternal. Retail anchors to compare against:

Our port lives in BSPQuery.FindWalkableInternal (called by FindWalkableSphere). Direct line-by-line comparison against the retail oracle is the next step.

H1 evidence (secondary, doorway-edge cases)

59 [walk-miss] events where the foot XY left the indoor floor poly but the LandCell underneath would have been walkable. All concentrated in cell 0xA9B40125, whose floor poly is a tiny 1.5 m × 0.5 m strip (bbox=(-0.40,-5.65)..(1.10,-5.15)) — this is a doorway-threshold cell. The player crosses it; the foot XY exits the strip before they reach the next cell.

Sample (last 3 walk-miss lines):

[walk-miss] cell=0xA9B40125 foot.W=(104.400,147.409,66.480)
            foot.L=(0.100,-11.909,0.460) ...
            containsFootXY=False
            landcell.hasTerrain=true landcell.terrainZ=66.000 landcell.dz=+0.480

foot.L.Y = -11.909, well outside the strip's Y range [-5.65, -5.15]. Outdoor LandCell terrain at world Z = 66.000 would have grounded the foot at dz = 0.480. This is the case the prior handoff (docs/research/2026-05-20-indoor-walking-bug-a-handoff.md) diagnosed as "doorway threshold has no floor poly." It's real — but 3 % of the total miss volume, not the primary defect.

H2 ruled out

Of 817 in-bbox candidate misses, 792 sit at dz between 0.4 m and 0.5 m, well within the 0.5 m probe distance. Only 25 events fall in the 0.00.4 m range (a few cm above plane — already touching). Bumping INDOOR_WALKABLE_PROBE_DISTANCE will not help — the geometry is reachable; the rejection is in the sphere-overlap math.

Cells of interest

Cell ID Walk-misses Floor polys (local-XY bboxes) Role
0xA9B40121 1,453 1 @ Z=0, bbox (-5.7,-5.15)..(5.7,4.55) Cottage main room (1st floor)
0xA9B40123 283 5 @ Z=3.0 (multiple connected panels) Cottage 2nd floor
0xA9B40125 67 1 @ Z=0, bbox (-0.4,-5.65)..(1.1,-5.15) Doorway threshold strip
0xA9B40126 11 (no [floor-polys] dump captured at start) Adjacent

Cell 0xA9B40123's floor polys all sit at planeZ@center=3.000 — that's 3 m above the cell origin, i.e. a 2nd-story floor. The HITs in this cell at world Z 69.485 match: cell origin Z 66.020 + local floor Z 3.0 = world floor 69.020, foot 0.46 above → world Z 69.485. ✓

This confirms our 2nd-floor handling is being exercised by the synthesis; it's just rejecting at the same 2 cm boundary as the 1st floor.

Disambiguation matrix verdict (per spec)

Matrix entry Spec condition This capture
H1 confirmed landcell.hasTerrain==true AND |landcell.dz| < 0.2 m 59 events at doorway threshold
H2 confirmed containsFootXY==true AND 0.5 m < nearest.dz < 5 m 0 events qualify (all "candidates" turned out to be jump-arc)
H3 candidate containsFootXY==true AND nearest.dz ≤ 0.5 m AND normalZ ≥ FloorZ 817 events — the bulk
H1+H3 combo containsFootXY==false AND landcell.hasTerrain==false 0 events

Spec matrix entry H3 is flagged as "next step: cdb attach to retail." Given the 2 cm hit-vs-miss boundary and the matched normalZ + FloorZ + in-bbox + in-probe signatures, we can attempt the retail decomp side-by-side comparison first without cdb — the discrepancy is narrow enough that the decomp + a focused unit test should expose it. cdb is a fallback if that fails.

Phase: design + ship the H3 fix.

  1. Decomp comparison (~1 hour, no code change):

    • Read acclient_2013_pseudo_c.txt:322032-322110 (adjust_sphere_to_plane) and our equivalent inside BSPQuery.FindWalkableInternal (BSPQuery.cs) line-by-line.
    • Read acclient_2013_pseudo_c.txt:323006-323028 (walkable_hits_sphere) and our equivalent.
    • Read acclient_2013_pseudo_c.txt:326793-326816 (BSPLEAF::find_walkable) and our FindWalkableInternal traversal.
    • Document any divergences in a follow-up findings note.
  2. Unit test for the 2 cm boundary (~30 min):

    • Synthetic CellPhysics with a horizontal floor at local Z=0.
    • Foot sphere centered at Z=0.46, then again at Z=0.48. Assert both HIT.
    • Mirrors the IndoorWalkablePlaneTests fixture pattern.
    • Expected: both fail at HEAD; pass after the fix.
  3. Fix the divergence found in step 1 (size unknown — could be a one-line epsilon adjustment or a structural mismatch).

  4. Re-run this capture with the fix in place. Expected outcome: [indoor-walkable] HIT rate goes from 0.38 % to >95 % during ground-contact frames; [walk-miss] H3 bucket collapses; H1 (the 59 doorway-edge events) remains.

  5. Then design H1 fix as a separate, smaller phase — porting retail's CTransition::check_other_cells (acclient_2013_pseudo_c.txt:272717) for multi-cell BSP iteration. Lower priority since 3 % of total misses and only manifests at threshold strips.

  6. Delete the spike when both H3 and H1 fixes ship: revert 27c7284..a2e7a87 plus this findings doc.

Anti-patterns to avoid (from prior handoffs)

  • Don't increase INDOOR_WALKABLE_PROBE_DISTANCE. The data shows probe distance is not the blocker.
  • Don't delete TryFindIndoorWalkablePlane ("Bug A" from 2026-05-20) — once H3 is fixed, the synthesis path will work correctly and is the right call (not removable until retail's multi-cell iteration is also ported).
  • Don't bypass walkable_hits_sphere overlap rejection with a looser epsilon without first verifying retail's exact behavior at this boundary. The 2 cm difference is suspiciously close to the rendered Z-bump (+0.02 f) used to prevent z-fighting on indoor floors. There may be a coordinate-space mismatch where the player's foot world Z is computed in the rendered (bumped) frame but the synthesis expects the dat-stated (unbumped) frame, or vice versa. Investigate before "fixing."

Acceptance review

The probe spike's acceptance criteria from 2026-05-21-indoor-walk-miss-probe-design.md:

  • Build green, tests green
  • Live capture produced [walk-miss] lines at the cottage doorway
  • Live capture produced [walk-miss] lines on the cottage 2nd floor
  • Aggregated counts classify each MISS per the disambiguation matrix
  • Zero [walk-miss] / [floor-polys] lines when env var unset (verified by code inspection; runtime verification deferred)

Spike concluded. Ship findings, design the H3 fix.