Commit graph

2 commits

Author SHA1 Message Date
Erik
ec29a732f5 test(physics): settle #331 — the uphill "refusal" is the #137 anti-parallel absorb, not a defect
#331 reported that `PhysicsEngine.ResolveWithTransition` refuses ALL uphill
motion whenever a `body:` is supplied. It does not. It refuses a step whose
sub-step offset is exactly anti-parallel to a live sliding normal — the
#137-family absorb this project already recorded as retail-faithful.

Measured on the same fixture, same gradient, same body, varying only the
heading relative to the slope gradient:

  (0,     -0.1, 0)  cross-slope 0        -> zero movement, latched
  (0.0001,-0.1, 0)  cross-slope 0.0001 m -> zero movement, latched
  (0.001, -0.1, 0)  cross-slope 0.001 m  -> climbs 0.176 m in 5 ticks
  (0.01,  -0.1, 0)  cross-slope 0.01 m   -> climbs 0.176 m in 5 ticks

The threshold is retail's own F_EPSILON small-offset abort (0.0002 m): about
0.11 degrees off the exact gradient at a 0.1 m step. `RemoteRampHarness`
builds a ramp whose gradient is exactly along Y and the original probe pushed
exactly along -Y, so it hit the measure-zero case with probability 1.

The latch itself is production-real in mechanism — a pure gravity fall under
the production RuntimeRemotePhysicsUpdater, with no fixture settle seam
involved, lands leaving Contact|OnWalkable|Sliding with slidingNormal (0,1,0)
— but every link is faithful to retail, verified in the PDB-paired binary
rather than Binary Ninja (BN typed find_transitional_position `void` and
dropped the load-bearing return value):

  validate_walkable sets collision_normal from the terrain plane when
    OBJECTINFO CONTACT is clear      0x0050d251 / 0x0050d261 / 0x0050d26c
  validate_transition converts it unconditionally  0x0050ac19-0x0050ac30
  set_sliding_normal zeroes Z AND re-normalizes    0x0050a060
  SetPositionInternal persists SLIDING_TS          0x005154c2 / 0x005154e1
  get_object_info re-seeds it next frame           0x00511d44 / 0x00511d4f
  find_transitional_position returns
    `i != 0 && state == OK` on the step-0 abort     0x0050c0ed -> 0x0050c089

ACE agrees (Transition.cs:1027, CollisionInfo.cs:58). No production code
changed; no divergence introduced, so no register row.

What lands is the coverage whose absence made this invisible — nothing in the
suite asserted that a body-bearing mover makes uphill progress on a walkable
slope, and the test that found #331 passed vacuously because the body never
moved:

  RuntimeRemoteUphillProgressTests.ARemoteWithABodyClimbsAWalkableSlopeAndKeepsItsFeetOnIt
    per-tick climb + surface tracking under a realistic off-gradient heading.
    SAB-A1 AdjustOffset -> Vector3.Zero            reddens at tick 1
    SAB-A2 fixture gradient -> 0 (flat)            reddens at tick 1
  RuntimeRemoteUphillProgressTests.AnExactlyUpSlopeOffsetIsAbsorbedByThePersistedSlidingNormal
    characterization pin for the absorb, with the retail anchors inline.
    SAB-B1 delete the get_object_info sliding seed  reddens (climbs to 57.7544)
    SAB-A1                                          reddens
    SAB-A2                                          reddens
    NON-discriminating, measured and documented: making the final tick
    exactly up-slope leaves it green — by then the latch is already cleared.

RemoteRampHarness gains a warning block naming the axis-alignment trap so the
next vacuous uphill assertion is caught at authoring time.

Suite re-measured from a full clean (43 bin/obj removed): 11,198 passed /
4 skipped / 0 failed, against the 11,196/4/0 baseline at 0d62a5ff — exactly
the two tests added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 14:08:22 +02:00
Erik
fe6ee877d1 test(physics): measure whether the remote sweep alone tracks surface Z (AD-10 Stage 0)
AD-10 claims the remote slope projection is "relocated" out of the sweep
because "remote bodies don't run a full local transition sweep". That
justification is false at HEAD: RuntimeRemotePhysicsUpdater.Tick calls
PhysicsEngine.ResolveWithTransition with the remote's own body, and that
sweep runs acdream's verbatim port of CTransition::adjust_offset
(0x0050a370, pc:272271-272393) once per sub-step. So the boundary
projection is an EXTRA layer, not a relocation — and whether it is doing
anything the sweep does not is a measurement, never an argument.

This commit builds the fixture for that measurement and changes no
production code.

RuntimeRemoteSteepContactSlideTests' private Harness is extracted to
RemoteRampHarness so the new tests share it instead of cloning ~180 lines.
The extraction is behaviour-preserving; its only additions are the
fixture's own TerrainSurface (so an assertion about "is the body on the
surface" is answered by the surface geometry rather than by
re-implementing what the code under test computed), a SurfaceZ helper, and
a Tick overload that supplies a per-frame body-local root displacement —
the locomotion-cycle push a running remote actually carries. All ten Bug B
tests pass unchanged against it.

RuntimeRemoteSlopeProjectionTests then drives the production tick 30 ticks
down a 31-degree walkable ramp and asserts, on EVERY tick rather than at
the end, that the body's root stays within 5 mm of its settled offset from
the terrain beneath it. A staircase catching up on the final tick would
pass a start/end comparison; 30 unprojected ticks accumulate ~1.8 m.

Sabotage results, all from clean builds (bin/obj deleted), reported in
both directions:

  * Discard the sweep's answer (Body.Position = postIntegratePos instead
    of resolveResult.Position): RED at tick 1, body 0.05999 m off the
    surface. This is the tracking test's discriminating sabotage.
  * Flatten the ramp to gradient 0: RED on the anti-vacuity guard
    (dz = 0.0000 m). That guard exists because the tracking assertion
    passes trivially on flat ground, where Z never has to move.
  * Short-circuit Transition.AdjustOffset to `return offset;`: GREEN.
    Recorded, not hidden — it is the reason the contract's proposed T1
    sabotage was rejected. On terrain the sweep has a SECOND independent
    way to plant Z: ValidateWalkable's push-out re-seats the sphere at its
    natural resting distance from the terrain plane every sub-step.
    Removing the step-down probe as well does not change it either
    (measured). The tests therefore assert the OUTCOME the projection
    exists for, and say in their own doc comments that they are not unit
    tests of adjust_offset and must not be cited as such.

One test the contract asked for is deliberately absent. An uphill
counterpart was written, passed, and was then found VACUOUS: on this
fixture ResolveWithTransition returns ok=False for uphill motion and the
body does not move at all, so it "tracked the surface" by standing still.
That finding is filed separately rather than shipped as a green test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 09:34:56 +02:00