acdream/docs/research/2026-08-08-345-pseudocode.md
Erik 18289f95f8 docs: #345 D0 verdict — the stuck-tick fingerprint is retail's own algorithm; fix attempt correctly stopped
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>
2026-08-07 11:11:19 +02:00

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).