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:
parent
a11df5b8d3
commit
e8651b3819
7 changed files with 581 additions and 14 deletions
|
|
@ -1,5 +1,16 @@
|
|||
# Pickup prompt — #137 corridor phantom collision (paste into a fresh session)
|
||||
|
||||
> **SUPERSEDED 2026-07-06.** The corridor phantom is FIXED (visual gate
|
||||
> pending) — see `docs/research/2026-07-06-137-sliding-normal-lifecycle-audit.md`.
|
||||
> Mechanism 2 was real (BSPQuery stub slide responses leaked sliding
|
||||
> normals; fixed). Mechanism 1's framing was WRONG: the recorded wall
|
||||
> normal was SYNTHETIC (slide_sphere's opposing branch + a `return OK` vs
|
||||
> retail's COLLIDED_TS misport — fixed); the PortalSide polys are ±Y
|
||||
> planes perpendicular to the run, directionally culled, tested by
|
||||
> retail's own BSP leaves too, and plausibly legitimately solid
|
||||
> (window/grate class). The step −1 cdb session below is NOT needed for
|
||||
> this repro. Kept for the audit trail only.
|
||||
|
||||
Read `claude-memory/project_physics_collision_digest.md` FIRST (binding
|
||||
DO-NOT-RETRY table), then **ISSUES #137** (the 2026-07-05 CHARACTERIZED
|
||||
section — the full evidence chain lives there), then this file. The 2026-07-05
|
||||
|
|
|
|||
|
|
@ -69,14 +69,47 @@ engine-level wall lifecycle pin (persist-on-block via validate →
|
|||
absorbed exactly-anti-parallel frame → oblique escape CLEARS the body
|
||||
state). Full solution suite green (Core 2545 / App 713 / UI 425 / Net 385).
|
||||
|
||||
## What this does and does not fix in the corridor
|
||||
## Mechanism 1 RESOLVED the same session — the "phantom wall" never existed
|
||||
|
||||
The wedge (mechanism 2) is fixed at its entry: a full-advance hit can no
|
||||
longer persist a phantom normal, so the corridor dead-stop degrades to
|
||||
whatever mechanism 1 actually produces — a momentary stutter if the portal
|
||||
poly only face-hits in the crossing window, or an honest (re-tested,
|
||||
strafe-escapable) wall if it keeps colliding. **Mechanism 1 — PortalSide
|
||||
portal polygons being solid in our physics set — is still open**; the
|
||||
pickup's step −1 cdb session (trace whether retail's BSP test chain ever
|
||||
TESTS those polys, or membership order never reaches them from the passable
|
||||
side) remains the next action, and needs the user to run retail.
|
||||
Follow-up dat + decomp work (same day) dissolved the PortalSide-poly theory
|
||||
entirely; **no cdb session needed for this repro**:
|
||||
|
||||
1. **The recorded hit normal matches NO polygon.** A world-space sweep of
|
||||
both seam cells + every portal-adjacent neighbor
|
||||
(`Issue137CorridorSeamInspectionTests.CorridorSeam_FindPolygonMatchingLiveHit`)
|
||||
found zero physics polygons within 18° of `(−1.00,0.03,−0.03)` near the
|
||||
hit point. The normal is the player's **negated movement direction** — a
|
||||
SYNTHETIC value from `slide_sphere`'s opposing-normals branch
|
||||
(`reversed = −gDelta` → `set_collision_normal`).
|
||||
2. **The PortalSide polys were a red herring for this hit.** Cell
|
||||
0x8A02016E has IDENTITY rotation (the prior session's "rotation maps
|
||||
them into the −X wall" was wrong); polys 1/3/5 are ±Y-normal planes at
|
||||
world y≈−38.33, 1.4 m beside the player's track and PERPENDICULAR to
|
||||
the +X run — `pos_hits_sphere`'s directional cull (dot ≥ 0 → culled,
|
||||
0x005394f0 tail) rejects them for that movement outright. They ARE
|
||||
referenced by a physics-BSP leaf (`CorridorCell_PhysicsBspLeafMembership`),
|
||||
so retail tests them too when approached INTO their plane — most likely
|
||||
they are legitimately solid one-way/window-class geometry (which is why
|
||||
the dat keeps PortalSide-only portal polys in the physics set while
|
||||
removing every ExactMatch one). The pickup's warning against a blanket
|
||||
"skip portal polys" filter stands — no filter is needed at all.
|
||||
3. **A second slide_sphere port bug found and fixed:** the opposing-normals
|
||||
branch returned OK where retail returns COLLIDED_TS
|
||||
(0x005375d7-0x0053762c: `*normal = −gDelta; normalize;
|
||||
set_collision_normal; return 2`). Our OK let the step complete as-is
|
||||
while carrying the synthetic reversed-movement collision normal —
|
||||
`validate_transition`'s epilogue then converted it into the sliding
|
||||
normal the wedge absorbed on. Fixed at the same TransitionTypes site;
|
||||
pinned by `SlideSphere_OpposingNormals_ReturnsCollided_WithReversedDisplacementNormal`.
|
||||
4. **The dat-backed corridor replay reproduces the live frame and runs
|
||||
clean** (`Issue137CorridorSeamReplayTests`): same input, same full
|
||||
advance to (85.253, −39.776, −5.992), same 016E→017A transit — now
|
||||
`hit=no`, no sliding normal persisted, and six further forward frames
|
||||
advance freely. (The pre-fix code did NOT reproduce the wedge in the
|
||||
replay — the live entry chain involved session state beyond the
|
||||
replay's reach — so the replay is the CLEAN-corridor pin, not a
|
||||
red/green falsification; the site-level pins in
|
||||
`Issue137SlidingNormalLifecycleTests` are the red→green proof.)
|
||||
|
||||
Remaining for #137: the user's corridor re-run (visual gate) + the issue's
|
||||
door half (doors block/pass per open state — separate acceptance).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue