acdream/docs/research/2026-08-07-s4b-tangent-rest-contract.md
Erik e1beb7d31f docs: S4b contract — port the retail resting pair (tangent walkable rest + bare push-out + AD-69)
The suspect line is pinned at scoping: our ValidateWalkable measures the
sphere's VERTICAL bottom against the plane (planted rest, perp = r*N.z)
while our AdjustSphereToPlane is already a faithful tangent port — we
mix the two geometries today and the planted one wins on terrain. D0
byte-pins retail's validate_walkable distance basis with an explicit
STOP if it refutes the premise; D2 retests the #341 harness flip ten
ways under the mechanism's stability prediction; the gate teaches the
user that slightly hovering feet on steep slopes is the CORRECT retail
look. Queued behind S1B and S2 — one physics slice in flight at a time.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 07:21:07 +02:00

99 lines
5.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# S4b contract (Campaign S) — port the retail resting pair: tangent walkable rest + bare-radius push-out
**Date:** 2026-08-07. **User decision, same day: "port the retail pair."**
**Implementer:** one Sonnet agent, AFTER S1B and S2 have landed (one physics
slice in flight at a time; build slots). **Review:** dual Opus. **Gate:** the
user's eyes on a slope — feet are EXPECTED to hover slightly (authentic
retail): ~3 cm at 30°, up to ~20 cm near the walkable limit.
## The mechanism, settled by measurement + two decompilers (#341)
Retail's walkable placement (`CPolygon::adjust_sphere_to_plane` @0x00538210,
BN pseudo-C 322032 + Ghidra cross-confirm) solves
`t = (dist ∓ r) / dot(N, stepDir)` — the sphere rests TANGENT to the slope,
perpendicular distance = radius. Its `adjust_offset` push-out uses the BARE
radius (AD-66's byte evidence) and is therefore structurally inert at rest.
acdream rests PLANTED (perp = r·N.z) and its substituted r·N.z trigger is
inert here by the same algebra. The user's live capture: bare trigger vs our
rest would fire on 84% of grounded slope ticks (2,471/2,955), lifts 288 mm.
**The pair ports together or not at all.**
## The suspect line, pinned at scoping
`Transition.ValidateWalkable` (TransitionTypes.cs ~3652) computes
`lowPoint = sphereCenter (0,0,radius)` — the sphere's VERTICAL bottom — and
`dist = dot(lowPoint, N) + D + waterDepth`, pushing up by `dist/N.z` until
the FEET clear the plane. Resting identity: `dot(center,N)+D = r·N.z`.
Meanwhile our `AdjustSphereToPlane` (BSPQuery.cs:364 and its FlatBspQuery
twin) is ALREADY a faithful tangent port of @0x00538210 — so acdream today
mixes tangent (BSP walk solve) with planted (ValidateWalkable) and the
planted one wins the resting height on terrain.
## Deliverables, in order
**D0 — byte-pin retail's `OBJECTINFO::validate_walkable` FIRST.** Grep the
named pseudo-C; disassemble the distance basis from the PDB-paired binary if
BN is ambiguous (the flag-idiom artifact class). The ONE question: does
retail measure the perpendicular sphere clearance
(`dot(center,N)+D radius` — tangent semantics) or a vertical foot point?
Cross-check ACE's `ObjectInfo.ValidateWalkable`. Write the pseudocode doc.
**If retail's validate_walkable turns out to ALSO use a vertical foot point,
STOP — the whole slice premise changes and the session lead re-decides.**
The waterDepth term's exact placement in retail's expression must be pinned
too (AP-10's sink-in behaviour must survive byte-for-byte).
**D1 — port the pair, one commit:**
1. `ValidateWalkable`'s distance basis → retail's (per D0's pin).
2. `AdjustOffset`'s push-out → bare radius in trigger AND numerator (the
exact diff that was withheld — its two `[Skip]`-ed conformance tests in
`S4AdjustOffsetConformanceTests` un-skip and must pass unchanged).
3. **AD-69 rides along:** the same block's `dist` gains retail's
`LandDefs::get_block_offset` cell-relative correction (the plane's cell
frame vs the mover's), per that row's citations.
**D2 — the #341 harness anomaly retest.** With the pair in, run
`RuntimeRemoteUphillProgressTests` TEN times (mixed single/class filters,
one full bin/obj clean-room among them) and report every outcome. The
mechanism predicts the absorbed-tick latch becomes STABLE at the tangent
rest (no lift — the settle leaves perp = r, bare trigger inert). If the
flip persists, capture per-tick positions inside the test (temporary
prints) and report the matrix — do NOT recalibrate goldens on a flipping
measurement.
**D3 — conformance + regression:**
- Exact-value tests for the new resting identity on a tilted plane
(perp = r), the flat-ground case (unchanged: N.z=1 makes planted and
tangent identical — this is why the suite never saw the difference), and
the water sink-in cases (AP-10's 0.1/0.45/0.9 depths, unchanged
behaviourally per D0's waterDepth pin).
- The uphill no-flap guard (`Uphill_NoContactFlapAcrossTicks`) must stay
green — the mechanism predicts it does (tangent rest + bare trigger =
retail's own stable pair).
- Sabotage: revert ONLY the ValidateWalkable half — the un-skipped AD-66
exact-value tests stay green but the new resting-identity test reds AND
a re-run of the user's capture analysis script over a synthetic planted
rest shows the 84% fire pattern returning. Report verbatim.
**D4 — bookkeeping (session lead does the register/ISSUES edits):** AD-66
retires with the pair; AD-69 retires; #341 closes; the AD-65 register
retirement gains a sibling note.
## Scope — OUT
The sliding/crease arm, the #331 absorb semantics (crease arm — untouched
by this pair), any scaling change (AP-156's question is separate), indoor
EnvCell walkable paths beyond what D0 proves shares the same
validate_walkable, S1B's files.
## Acceptance
Full suite clean-room green (all bin/obj deleted first — this family has
burned three verdicts on stale artifacts); D2's ten-run matrix reported;
nothing committed. Absolute paths, no subagents, contradictions → STOP.
## The gate (user, ~3 min)
Same slope run as this morning's G1, plus: stand still on a steep slope and
LOOK DOWN — feet slightly above the surface is CORRECT (retail's look).
Downhill speed must remain the post-AD-65 feel. Any per-tick jitter,
bouncing, or Falling-animation flicker on slopes = FAIL, revert the slice.