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>
11 KiB
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.FindWalkableSphere → FindWalkableInternal →
walkable_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.0–0.2 m | 18 |
| 0.2–0.4 m | 7 |
| 0.4–0.5 m | 792 |
| 0.5–1.0 m | 141 |
| 1.0–2.0 m | 427 |
| > 2.0 m | 370 |
| negative | 0 |
The massive 792-event spike at 0.4–0.5 m is the standing-on-the-floor position. The 1.0–2.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:
CPolygon::walkable_hits_sphere—acclient_2013_pseudo_c.txt:323006-323028. Slope test +polygon_hits_sphere_slow_but_sureoverlap test.CPolygon::adjust_sphere_to_plane—acclient_2013_pseudo_c.txt:322032. Sphere-to-plane projection with sweep-distance budget.BSPLEAF::find_walkable—acclient_2013_pseudo_c.txt:326793. Iterates polys; requires BOTHwalkable_hits_sphereANDadjust_sphere_to_planenon-zero.
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.0–0.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.
Recommended next step
Phase: design + ship the H3 fix.
-
Decomp comparison (~1 hour, no code change):
- Read
acclient_2013_pseudo_c.txt:322032-322110(adjust_sphere_to_plane) and our equivalent insideBSPQuery.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 ourFindWalkableInternaltraversal. - Document any divergences in a follow-up findings note.
- Read
-
Unit test for the 2 cm boundary (~30 min):
- Synthetic
CellPhysicswith a horizontal floor at local Z=0. - Foot sphere centered at
Z=0.46, then again atZ=0.48. Assert both HIT. - Mirrors the IndoorWalkablePlaneTests fixture pattern.
- Expected: both fail at HEAD; pass after the fix.
- Synthetic
-
Fix the divergence found in step 1 (size unknown — could be a one-line epsilon adjustment or a structural mismatch).
-
Re-run this capture with the fix in place. Expected outcome:
[indoor-walkable] HITrate goes from 0.38 % to >95 % during ground-contact frames;[walk-miss]H3 bucket collapses; H1 (the 59 doorway-edge events) remains. -
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. -
Delete the spike when both H3 and H1 fixes ship: revert
27c7284..a2e7a87plus 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_sphereoverlap 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.