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>
This commit is contained in:
Erik 2026-08-07 11:11:19 +02:00
parent 2098fa6690
commit 18289f95f8
2 changed files with 292 additions and 1 deletions

View file

@ -178,7 +178,32 @@ position. Zero yield. (`oiContact=True, spStepDown=False, guardPassed=False`
on every line — the morning's `collN=(0,0,1)` comes from the failure path's on every line — the morning's `collN=(0,0,1)` comes from the failure path's
result-filling, not from ValidateWalkable's guard, which never passes here.) result-filling, not from ValidateWalkable's guard, which never passes here.)
**The fix contract's question is now precise:** what does RETAIL's ### D0 VERDICT, same day — the fingerprint IS retail's own algorithm; the fix attempt STOPPED itself
The fix implementer's mandatory pseudocode pass traced all five links from
the named decomp (addresses in
`docs/research/2026-08-08-345-pseudocode.md`) and found the mechanism
paragraph above named the right symptom with the WRONG cause: the below-push
never executes at all (its guard is `step_down || !OnWalkable || walkable`,
and the player IS OnWalkable on the flat approach — the probe printed the
SetCollisionNormal guards, not this one); `Adjusted` retrying the whole
insert from scratch is retail-identical (`transitional_insert` @0x0050b6f0);
and `validate_transition` @0x0050aa70 on failure kills velocity, restores
the flat plane, DEFAULTS the collision normal to (0,0,1), reverts CheckPos,
and forces OK — producing every field of the captured fingerprint from
retail's own code. **Stopping dead here may simply BE retail.**
**Two open validations before this closes either way:**
1. **The cheapest decisive test needs no debugger: the USER walks their
RETAIL client into a comparable just-too-steep hillside at ~45° and
reports slide vs dead stop.** Their expectation of sliding is currently
the only evidence against retail-faithfulness.
2. If retail visibly slides: the remaining suspect is UPSTREAM of the
walkable response — whether retail's `find_cell_list` broadphase even
queries the steep cell from this position (the pseudocode doc's open
question) — a runtime question for the cdb toolchain, not code-reading.
**The fix contract's question (superseded by the verdict above, retained):** what does RETAIL's
transitional_insert do with validate_walkable's Adjusted on a non-walkable transitional_insert do with validate_walkable's Adjusted on a non-walkable
plane — does the adjusted CheckPos feed the NEXT attempt (convergence), or plane — does the adjusted CheckPos feed the NEXT attempt (convergence), or
does retail take a different branch entirely (slide/collision) instead of does retail take a different branch entirely (slide/collision) instead of

View file

@ -0,0 +1,266 @@
# #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
`continue`s 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:
```csharp
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).