acdream/docs/research/2026-07-31-271-stair-side-slide-capture.md

3.8 KiB
Raw Permalink Blame History

#271 — Stair-side uphill reversal capture

Date: 2026-07-31

Status: closed; retail control flow restored and user live gate passed

Symptom

When the local player ran diagonally uphill while pressing into the side of an outdoor staircase, the character could suddenly move backward and rapidly slide to the bottom. The symptom was intermittent because it required the forward candidate to hit the side wall while the step-down recovery crossed a tread edge.

This is not an RDP, render-rate, animation, or gravity symptom. It reproduced inside the pure Core collision resolver from one captured input frame.

Live evidence

The bounded capture is under the ignored local artifact pointer:

artifacts/issue271-stair-side/LATEST.txt

It contains 677 local-player physics quanta plus the matching resolver stream. The first decisive frame is quantum 310:

current = (133.03775, 75.53931, 59.608147)
target  = (133.33783, 76.42308, 59.608147)
input   = forward + run
result  = (133.18779, 75.19872, 59.316677)
normal  = (-1, approximately 0, approximately 0)

The X side-wall collision was valid, but the tangential Y component reversed: an uphill request of +0.88377 produced -0.34059. Three frames later, quantum 313 snapped from Z 59.52598 to terrain Z 58.005. A second attempt reproduced the same family at quanta 479482, falling from Z 60.96376 to 58.005.

Retail oracle

Named retail:

  • CTransition::edge_slide at 0x0050B3D0
  • current-walkable branch at 0x0050B44A
  • no-walkable back-probe at 0x0050B4580x0050B50F
  • SPHEREPATH::precipice_slide at 0x0050CC80

Retail tests only the current SPHEREPATH::walkable pointer. If it is null, retail:

  1. offsets the failed candidate back to the current sphere center;
  2. runs step_down there to rediscover the surface actually under the mover;
  3. restores the failed candidate;
  4. runs precipice_slide against the newly discovered polygon; or
  5. returns COLLIDED_TS when the back-probe found no walkable polygon.

Retail has no substitution of an older saved walkable polygon in either null case.

ACDream divergence and root cause

EdgeSlideAfterStepDownFailed previously called SpherePath.RestoreLastWalkable():

  • before deciding whether to enter the retail back-probe; and
  • again when the back-probe found no current walkable polygon.

LastWalkable is a separate ACDream history used by the still-open CliffSlide compatibility path. At a staircase side wall it could describe the preceding tread rather than the surface below the current player position. Promoting it into the current slot bypassed retail's back-probe. PrecipiceSlide then projected the failed forward candidate along the stale tread edge, producing the backward/downhill displacement seen in the capture.

The fix removes both stale-history promotions from the edge-slide dispatch. Current walkable state still takes retail's direct precipice path; absent state now always takes retail's current-position back-probe.

Deterministic regression

Issue185OutdoorStairsSeamReplayTests reuses the captured 0x01000AC5 staircase collision fixture and the exact quantum-310 position, contact plane, movement delta, player flags, and 1.5 m Setup step-down height.

Pre-fix:

out = (133.187790, 75.346481, 59.430882)

Fixed:

out = (133.187790, 76.078186, 60.016247)

The regression requires meaningful positive uphill progress and forbids a downhill Z displacement. The complete Core Release suite passes 4,108 tests / 2 skips; the complete Release solution passes 10,062 tests / 5 skips.

Live acceptance

The user repeatedly ran uphill while pressing into both sides of the affected staircase. Movement remained stable and the former rapid downhill reversal did not recur. The client then closed through the normal logout path, with ACE confirming graceful logout.