# Issue #269 — slope-stop capture and retail correction **Date:** 2026-07-31 **Status:** implemented; user live gate passed **Scope:** landing-bounce follow-up, `CTransition::validate_transition` ## Symptom After the retail 5%-elasticity landing reflection was restored for #265, the character could retain too much downhill speed after landing on a walkable slope. The user described the residual as “slides too far on landing.” ## ACDream live capture `ACDREAM_CAPTURE_PLAYER_QUANTA=` records the local player's complete admitted object quantum without changing simulation order: 1. quantum start; 2. root/PositionManager composition; 3. pre- and post-`UpdatePhysicsInternal`; 4. transition result; 5. final collision-response commit. The accepted repro contained 2,184 quanta. The clearest landing was: | Quantum | Event | Velocity | |---|---|---| | 1740 | final airborne quantum | `(-12.316, 8.187, -26.266)` | | 1741 | slope collision, normal `(-0.236, 0.236, 0.943)` | | | 1741 post-response | correct 5% reflect | `(-17.391, 13.262, -6.576)` | | 1742–1758 | still Contact + OnWalkable, no new collision normal | velocity unchanged | | 1759+ | contact relationship changes | friction finally begins decaying | The reflected velocity had `dot(v, normal) = +1.0252`: it pointed away from the slope. Retail `calc_friction` correctly skips while this value is at least `0.25`, so friction was not the defect. ACDream was repeatedly restoring the remembered slope plane and re-grounding the body without performing retail's accompanying velocity stop. ## Retail oracle Named-retail: - `CPhysicsObj::check_contact` `0x0050F5B0` - `CPhysicsObj::get_object_info` `0x00511CC0` - `CTransition::validate_transition` `0x0050AA70` - `OBJECTINFO::kill_velocity` `0x0050CFE0` The exact `validate_transition` order at `0x0050AAED–0x0050AB42` is: 1. enter only for a non-OK collision/adjusted/slid result; 2. if `last_known_contact_plane_valid`, call `OBJECTINFO::kill_velocity`; 3. test the current sphere center against the remembered plane using `radius + 0.0002`; 4. restore the contact plane only when still within that distance; 5. later, at `0x0050ACFF`, overwrite last-known validity with final contact-plane validity. `OBJECTINFO::kill_velocity` calls `CPhysicsObj::set_velocity({0,0,0}, 0)`. ACDream had ported the proximity test and plane restore but omitted this call. It also allowed the last-known plane to re-ground clean accepted moves, although retail only consumes it in the non-OK recovery branch. ## Correction `Transition.ValidateTransition` now: - calls `ObjectInfo.StopVelocity()` before the remembered-plane proximity/restore test on a non-OK recovery; - performs that restore only in the retail branch; - overwrites last-known validity from final contact validity, so a clean move away cannot be re-grounded from stale memory. The existing `PhysicsEngine.ResolveWithTransition` consumption of `VelocityKilled` applies the zero to the canonical `PhysicsBody` before the collision-response tail. The initial 5% landing reflection remains; only a following collision recovery performs the retail stop. ## Gates - New focused pins: - collision recovery with a remembered plane kills velocity; - clean advance with a remembered plane neither kills nor re-grounds. - Full `AcDream.Core.Tests`: 4,107 passed / 2 skipped. - Full `AcDream.Runtime.Tests`: 439 passed. - `AcDream.App` Release build: 0 warnings / 0 errors. - Complete Release suite: 10,061 passed / 5 skipped / 0 failed. - User live gate: **PASS** — repeated slope jumps now settle correctly (“Perfect! Works great!”). ## Diagnostic tools retained - `tools/analyze_269_slope_stop_capture.py` - `tools/cdb/run-issue269-slope-stop.ps1` - `tools/cdb/issue269-slope-stop.cdb` The cdb runner refuses to attach unless the live retail executable matches the Sept 2013 named PDB. The locally installed 2015 retail executable does not match; the static named-retail decode above is therefore the retail oracle used for this correction.