Five links traced from the named decomp: the below-push never executes (OnWalkable guard — the probe printed the wrong guard pair), the from-scratch retry is retail-identical, and validate_transition's failure path manufactures every captured field including the (0,0,1) default. Stopping dead may simply BE retail. Two validations remain: the user observing their RETAIL client at a comparable slope (the cheapest decisive test there is), and — only if retail visibly slides — the find_cell_list broadphase question via the cdb toolchain. The mechanism paragraph's wrong-cause framing is retained and corrected in place, per the register's own honesty pattern. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
13 KiB
#345 D0 — retail pseudocode pin: does transitional_insert slide on a too-steep OTHER-cell plane while already grounded?
Order: implementation-session D0, per the mechanism contract
(docs/research/2026-08-08-345-mechanism-contract.md) and the
mechanism-caught finding in docs/ISSUES.md #345. Grep-named-first,
pseudocode-before-port, per CLAUDE.md's workflow.
Verdict up front: retail does NOT slide here either. Followed by hand
through four retail functions (cross-checked against an independent C#
reference for one of them), the mechanism converges to the exact same
"0% yield, repeat forever, collN=(0,0,1), slidingNormal=(0,0,0)"
fingerprint the capture shows. This is not a carry-forward bug — see
"What the mechanism-session's framing got wrong" below. Per the session
contract's explicit fallback, this STOPS here without a D1/D2/D3 fix.
The scenario being traced
Player is grounded, walking on a nearly-flat (~6.8°) approach terrain
triangle (the PRIMARY cell). The requested horizontal offset carries the
sphere's overlap into an ADJACENT (OTHER) terrain cell whose triangle is
too steep to be walkable: N=(0.799,0.050,0.599), N.z=0.599 just under
FloorZ(≈0.664). Captured fingerprint (345-mechanism.log:279, mover
0x000F4243, and docs/ISSUES.md #345's own summary): dist=-0.34680
(a different capture in the same class logged -0.268 — same mechanism,
different exact stance), oiContact=True, spStepDown=False,
guardPassed=False, outcome=Adjusted, identical on every one of 6
attempts within the stuck tick, final resolve position byte-identical
to input, collN=(0,0,1), slidingNormal=(0,0,0), carried contact =
the flat approach terrain, transient=0x3 (Contact|OnWalkable).
1. OBJECTINFO::validate_walkable (retail 0x0050d010, pc:274479-274617)
Grep-named-first target from the contract. The "below the surface"
branch (our scenario: dist < -EPSILON) is:
zDist = dist / N.z
walkable = is_valid_walkable(N) // N.z >= FloorZ, ours: sp.WalkableAllowance
if (step_down != 0 || (state & ON_WALKABLE) == 0 || walkable != 0) {
set_contact_plane(plane, cellId)
if (step_down) { ...interpolation reject... }
AddOffsetToCheckPos(0, 0, -zDist) // THE PUSH — pc:274604-274607
}
if ((state & CONTACT) == 0 && step_down == 0) {
set_collision_normal(plane)
collided_with_environment = 1
}
return ADJUSTED_TS
Cross-checked against references/ACE/Source/ACE.Server/Physics/ObjectInfo.cs:142-170
(ObjectInfo.ValidateWalkable, independently-authored C# port of the
same algorithm) — identical structure, same three-way OR gate before
the push.
The push (AddOffsetToCheckPos) is gated behind
step_down || !OnWalkable || walkable. In our scenario: step_down
is false (confirmed by the trace's spStepDown=False), walkable is
false (0.599 < FloorZ), so the push fires only if OnWalkable is
false. Our C# (TransitionTypes.cs:3746-3769) ports this gate
verbatim: if (sp.StepDown || !oi.OnWalkable || walkable).
Is OnWalkable true here? Yes — confirmed by
PhysicsEngine.cs:2026-2047: at the start of every resolve, when the
body is in contact with a valid plane and not moving away from it
(check_contact's success branch, ported faithfully per the #32 commit
history), if (body.OnWalkable) transition.ObjectInfo.State |= OnWalkable;.
The player IS resting on the flat approach terrain — body.OnWalkable
is true — so oi.OnWalkable is true for this entire resolve.
Conclusion: the push never fires. ValidateWalkable returns
ADJUSTED_TS with ZERO state mutation — no SetContactPlane, no
AddOffsetToCheckPos, and (since !oi.Contact is false per the trace's
oiContact=True) no SetCollisionNormal either. This is retail's own
intentional design: a sphere already stably grounded elsewhere does not
get shoved around by an incidental graze against a DIFFERENT, non-walkable
patch. There is no "adjustment" to carry forward — there never was one
to begin with. The mechanism-session's framing ("push-up... the
adjustment does not carry forward between attempts") named the right
symptom (identical dist every attempt) but the wrong cause (it isn't
that a real push gets discarded; it's that the push never executes at
all, precisely as retail specifies for a grounded-elsewhere mover).
2. CTransition::transitional_insert (retail 0x0050b6f0, pc:273137-273364)
edi = INVALID_TS
for (attempt = 0; attempt < numAttempts; attempt++) {
edi = insert_into_cell(check_cell, numAttempts)
switch (edi) {
case OK_TS:
edi = check_other_cells(check_cell) // overwrites edi
if (edi != OK_TS) neg_poly_hit = 0
if (edi == COLLIDED_TS) return COLLIDED_TS
break // falls to "if edi==OK_TS" below
case COLLIDED_TS:
neg_poly_hit = 0
return edi
case ADJUSTED_TS:
neg_poly_hit = 0
break // falls straight to loop-bottom, no retry-with-state
case SLID_TS:
contact_plane_valid = 0; contact_plane_is_water = 0
neg_poly_hit = 0
break
}
if (edi == OK_TS) {
...sphere_path.collide handling (Phase 3)...
...neg_poly_hit dispatch (step_up / step_up_slide / slide_sphere)...
}
// loop-bottom: unconditional retry up to numAttempts, no early exit besides
// the explicit returns above
}
return edi
Our C# (TransitionTypes.cs:1991-2037 for the switch,
2052-2065 for the check_other_cells dispatch) matches this
line-for-line: InsertIntoCell result dispatches through the same
Collided-returns/Adjusted-clears-neg-poly-continues/Slid-clears-contact-
continues shape; OK_TS alone proceeds to RunCheckOtherCellsAndAdvance
(our name for check_other_cells), whose non-OK result also just
continues the outer loop with no special-cased state restoration —
identical to retail's break that skips the big Phase-3 block and falls
to the unconditional loop-bottom retry.
Neither retail nor our port does anything to "feed the adjusted
CheckPos forward" on an ADJUSTED_TS from check_other_cells — both
simply retry the WHOLE insert_into_cell from scratch. Since
ValidateWalkable made zero mutation (§1), retrying from scratch
necessarily reproduces the identical primary-insert-OK,
other-cell-Adjusted-with-identical-dist sequence every attempt. This
is exactly the observed fingerprint, and it is retail-faithful.
3. CTransition::check_other_cells (retail 0x0050ae50, pc:272717-272798)
Iterates the sphere's overlapping OTHER cells (find_cell_list), calling
each cell's virtual find_collisions. Its switch: COLLIDED_TS and
ADJUSTED_TS (cases 2 and 3) both return result immediately — no
further cells are tried, no retry loop of its own. SLID_TS (case 4)
clears the contact plane fields then also returns immediately. Only
OK_TS continues to the next cell. Our C# CheckOtherCells /
ApplyOtherCellResult (TransitionTypes.cs:2952-3030) halts the same
way. No divergence found here.
4. CTransition::validate_transition (retail 0x0050aa70, pc:272547-272689)
Called as validate_transition(this, transitional_insert(this, 3), &out)
directly from find_transitional_position (retail 0x0050bdf0,
pc:273743 — the ordinary per-substep walking driver, confirmed calling
exactly transitional_insert(this, 3) then validate_transition,
matching our TransitionTypes.cs:1611/1621
TransitionalInsert(3, engine) → ValidateTransition(result) pairing
byte-for-byte). On a non-OK, non-INVALID result (COLLIDED/ADJUSTED/SLID
— all three, treated identically):
if (last_known_contact_plane_valid) {
kill_velocity()
if (radius + EPSILON > |dot(N_lkcp, curr_center) + d_lkcp|) // still within
set_contact_plane(last_known_contact_plane) // reach of LKCP?
}
if (!collision_normal_valid)
set_collision_normal(UP) // the (0,0,1) DEFAULT FILL
set_check_pos(curr_pos, curr_cell) // DISCARD — revert to pre-step position
result = OK_TS // FORCE OK — the whole substep nets zero
...
if (collision_normal_valid)
set_sliding_normal(collision_normal) // sliding_normal = f(UP) below
Our C# ValidateTransition (TransitionTypes.cs:6194-6226) ports this
exactly, including the LastKnownContactPlaneValid proximity gate
(TransitionTypes.cs:6203-6219), the !CollisionNormalValid UP default
(6221-6222, the literal source of the trace's collN=(0,0,1) —
confirming the mechanism-session's own annotation that this normal
"comes from the failure path's result-filling, not from
ValidateWalkable's guard"), the SetCheckPos revert + forced OK_TS
(6224-6225), and the SetSlidingNormal(CollisionNormal) call
(6229-6230).
Because the player is still resting on the flat approach terrain,
curr_center is (by construction) essentially ON that plane, so the
LKCP-proximity check always passes — the flat terrain gets restored as
the CURRENT contact plane on every failed substep. That is why the
capture shows carried contact = the flat approach terrain, not the
steep face — the steep face never gets registered as a contact at all
(§1), and this LKCP restore keeps re-confirming OnWalkable = true
(ContactPlane.Normal.Z(0.993) >= FloorZ) at the tail of ValidateTransition
(TransitionTypes.cs:6252-6255) — which is exactly the OnWalkable
seed §1 needs to keep suppressing the push on the NEXT resolve. This
is a self-sustaining, retail-faithful attractor: stay resting on flat
ground behind you → steep OTHER-cell touch is silently ignored →
contact plane keeps re-anchoring to the flat ground → OnWalkable stays
true → the steep touch keeps being silently ignored. There is no state
transition inside this mechanism that would break the cycle.
5. COLLISIONINFO::set_sliding_normal (the "#331 absorb")
TransitionTypes.cs:553-559 projects the incoming normal to XY only
and re-normalizes:
SlidingNormal = new Vector3(normal.X, normal.Y, 0f);
if (SlidingNormal.LengthSquared() > EpsilonSq)
SlidingNormal = Vector3.Normalize(SlidingNormal);
Fed the §4 UP default (0,0,1), this produces SlidingNormal=(0,0,0)
— exactly the captured slidingNormal=(0,0,0). Per the trap
inventory (docs/research/2026-08-08-345-mechanism-contract.md +
CLAUDE.md "Current state"), this XY-projection is the retail-faithful
#331 absorb and is explicitly off-limits to touch. It is not the cause
here — it is a correct, downstream consequence of the §4 UP default,
which is itself a correct, downstream consequence of §1's guard never
firing.
What the mechanism-session's framing got wrong
The probe (ACDREAM_DUMP_TRANSIT_FAIL) correctly found WHERE the
identical-dist loop lives (ValidateWalkable's below-branch,
TransitionalInsert's retry). It inferred WHY from the symptom's shape
("push-up... doesn't carry forward") without visibility into oi.OnWalkable
or the push guard itself — the probe's trace only carries oiContact/
spStepDown (the second, SetCollisionNormal, guard), not the first
(AddOffsetToCheckPos) guard's inputs. Reading the guard from source
(sp.StepDown || !oi.OnWalkable || walkable, all three legs resolvable
statically for this scenario) shows the push is never attempted, so
there is nothing to "carry forward" in the first place.
Conclusion
Every function in the chain — ValidateWalkable, TransitionalInsert,
CheckOtherCells, ValidateTransition, SetSlidingNormal — is a
faithful, citable port, and hand-tracing them against this exact
scenario reproduces every byte of the captured fingerprint (collN=(0,0,1),
slidingNormal=(0,0,0), identical dist per attempt, carried contact =
approach terrain, byte-identical position in/out). Retail's own
algorithm, run by hand against this geometry, does not slide — it
converges to the same zero-yield stop. Per the mechanism-session
contract's explicit fallback ("If retail turns out NOT to slide here
either, STOP and report — the user's expectation would then be the
divergence, a different decision"), this session stops here. No
ValidateWalkable/TransitionalInsert/ValidateTransition change is
made; #331, #32, and AD-65 are untouched, matching the trap inventory.
Open question for whoever picks this up next
The one link in this chain NOT fully verified against retail is cell
membership: does retail's CObjCell::find_cell_list (feeding
check_other_cells's cell array) actually include this neighboring
too-steep OTHER cell from the player's exact resting position, or does
our CellTransit/other-cells construction query a cell retail's
narrower geometry test would not have reached at all? That is a
genuinely different question from anything traced above (a broadphase/
cell-array question, not a walkable-response question), and it is the
one place this D0 pass had to reason from citation rather than from a
direct retail-vs-acdream A/B. The toolchain's own guidance applies
here: this is exactly the "what does retail actually DO at runtime"
class of question the cdb toolchain
(memory/reference_retail_debugger.md) exists for — attach to a live
retail client at the identical Rithwic steep face and confirm whether
retail's player is ALSO immovable at this exact stance, or whether it
is already sliding by the time the sphere reaches this position (which
would point at the cell-array question above, not at anything in this
document).