fix #137 (corridor phantom resolved): slide_sphere opposing branch returns Collided; the 'wall' was synthetic

The mechanism-1 theory (PortalSide portal polys solid in our physics set)
is REFUTED for the corridor repro, and the remaining half of the phantom
is fixed — no cdb session needed:

- The live hit normal (-1.00,0.03,-0.03) matches NO dat polygon: a
  world-space sweep of both seam cells + every portal-adjacent neighbor
  (CorridorSeam_FindPolygonMatchingLiveHit) returns zero candidates. The
  normal is the negated movement direction — the SYNTHETIC value
  slide_sphere's opposing-normals branch records (reversed = -gDelta).
- Cell 0x8A02016E has IDENTITY rotation (the prior session's 'rotation
  maps the portal planes into the -X wall' was a misattribution). The
  PortalSide polys to 0x011E are +-Y planes 1.4 m beside the player's
  track, perpendicular to the +X run — pos_hits_sphere's directional
  cull rejects them for that movement. They ARE referenced by the dat's
  physics-BSP leaves (CorridorCell_PhysicsBspLeafMembership), so retail
  tests them too when approached into their plane; the dat's
  keep-PortalSide / strip-ExactMatch asymmetry reads as intentional
  (solid window/grate-class portals). No portal-poly filter — exactly
  the blanket-skip the pickup warned against.
- Port fix: CSphere::slide_sphere's opposing-normals branch
  (0x005375d7-0x0053762c) records the reversed displacement and returns
  COLLIDED_TS; our port returned OK ('retail returns OK here' was a
  decomp misread), letting the step complete as-is with the synthetic
  collision normal that validate's epilogue then persisted as the
  sliding normal the wedge absorbed on. TransitionTypes opposing branch
  now returns Collided; pinned by
  SlideSphere_OpposingNormals_ReturnsCollided_WithReversedDisplacementNormal
  (RED->GREEN).
- Dat-backed replay (Issue137CorridorSeamReplayTests) reproduces the
  live hit frame verbatim (same in/out to the millimeter, same 016E->017A
  transit, same +8mm settle) and runs the corridor CLEAN: hit=no, no
  sliding normal persisted, six further forward frames advance freely.
- Inspection tests extended: physics-BSP leaf membership walk +
  hit-normal candidate sweep + downward-poly sweep (all report-style,
  dat-gated). Pickup prompt banner'd SUPERSEDED; ISSUES #137 updated
  (door half stays open); audit doc extended with the resolution.

Suites: Core 2551 / App 713 / UI 425 / Net 385, 0 failures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-05 18:27:40 +02:00
parent a11df5b8d3
commit e8651b3819
7 changed files with 581 additions and 14 deletions

View file

@ -1183,8 +1183,27 @@ walls** in particular. (Symptoms not fully characterized yet: likely walking thr
openings that should block / blocking at openings that should pass, and door collision not
matching the door's open/closed state.)
**CORRIDOR PHANTOM FIXED 2026-07-06 (both mechanisms resolved; visual gate
pending — see `docs/research/2026-07-06-137-sliding-normal-lifecycle-audit.md`
for the full audit):** mechanism 2 = BSPQuery Contact-branch stub slide
responses leaked sliding normals retail's BSP layer never writes (fixed:
real `slide_sphere` routing + success-gated body writeback). Mechanism 1 as
theorized is REFUTED: the recorded wall normal `(1.00,0.03,0.03)` matches
NO dat polygon (world-space sweep of both seam cells + all portal-adjacent
neighbors) — it is the SYNTHETIC negated movement direction from
`slide_sphere`'s opposing-normals branch, which our port let survive by
returning OK where retail returns COLLIDED_TS (0x0053762c; second fix). The
PortalSide polys to 0x011E were a red herring: cell 0x8A02016E has IDENTITY
rotation, the polys are ±Y planes perpendicular to the run (directionally
culled), retail's physics-BSP leaves reference them too, and the dat's
keep-PortalSide/strip-ExactMatch asymmetry reads as intentional (solid
window/grate-class portals) — NO portal-poly filter needed, no cdb session
needed for this repro. Dat-backed replay
(`Issue137CorridorSeamReplayTests`) reproduces the live frame exactly and
runs the corridor clean. The issue's DOOR half remains open.
**CHARACTERIZED 2026-07-05 (Facility Hub corridor repro, probe + dat evidence)
— two stacked mechanisms:**
— two stacked mechanisms (historical; see the 2026-07-06 resolution above):**
1. **PortalSide portal polygons are IN the physics polygon set and we treat
them as solid.** Live: running the corridor, the seam crossing
`0x8A02016E → 0x8A02017A` (x≈85.25) records a wall hit with normal