Root cause of the "blocked at the last cellar step" wedge (the primary, ramp-climb family — 20/29 captured records). The prior session's pinned "find_walkable is never called during the step-down" was a probe artifact: a fresh [fc-dispatch]/[step-sphere-down] trace proves Path-3 StepSphereDown IS reached for both the carried cell and the iterated other-cell. The real divergence is in Transition.CheckOtherCells. Retail's check_other_cells (acclient_2013_pseudo_c.txt:272735 → (*cell+0x88)(this)) re-collides the OTHER cells against the LIVE sphere_path.global_sphere — the position AFTER the primary insert_into_cell ran. The primary collide can MOVE the sphere: a Path-5 full-hit dispatches step_sphere_up, and a successful step-up climbs the foot onto the cottage floor yet still returns OK. acdream instead reused a footCenter snapshot captured BEFORE the primary collide, so once the lip-riser step-up climbed the foot onto the floor, check_other_cells still queried 0171 at the pre-climb (sunk ~0.25 m below the floor) position → the foot spuriously near-missed the very floor it had climbed onto → neg_step_up → a doomed second step_up vs the floor normal (0,0,1) whose step_up_slide unwound the climb → validate_transition reverted → 0% advance. Fix: re-read footCenter = sp.GlobalSphere[0].Origin at the top of RunCheckOtherCellsAndAdvance (one line). Pre-fix 0/29 wedge records advanced; post-fix 20/29 climb onto Z≈94. No regression: full Core suite 1321 pass / 4 fail (the documented baseline: Apparatus_Grounded_50cmOffCenter, 2× DoorBugTrajectoryReplay LiveCompare_*, BSPStepUpTests.D4) / 1 skip. The 2 door LiveCompare divergences are byte-identical with/without the fix (the door's step_up FAILS → sphere restored → position unchanged → footCenter == live). Tests: CellarLipWedgeTests.Fix_StaleFootCenter_RampRecordClimbsCottageFloor + Fix_StaleFootCenter_MajorityOfWedgeRecordsAdvance (new, GREEN). DocumentsResidualWedge_LiveFloorCp_SlidingNormalKillsPlusY documents the remaining 9/29 (0,-1,0)-sliding-normal +Y-kill family (slide territory, deferred to the visual gate). Apparatus retained (gated on ACDREAM_PROBE_INDOOR_BSP): [fc-dispatch] in BSPQuery.FindCollisions + [step-sphere-down] in BSPQuery.StepSphereDown + CellarLipWedgeTests.Diagnostic_TraceRecordByIndex — strip once the residual is resolved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
38 KiB
P2 cellar-lip wedge — CANONICAL handoff (flat-floor contact-plane coin-flip)
✅ PRIMARY ROOT CAUSE FOUND + FIXED 2026-06-05 (START HERE — supersedes UPDATE 2 below)
The pinned "find_walkable is NEVER called during the step-down" (UPDATE 2) was a PROBE ARTIFACT.
A clean [fc-dispatch]/[step-sphere-down] trace (TEMP probes, gated on ACDREAM_PROBE_INDOOR_BSP,
in BSPQuery.FindCollisions + StepSphereDown) proved find_walkable (Path 3 / StepSphereDown)
IS reached for both 0175 (primary) and 0171 (other-cell) during the step-down — UPDATE 2 mis-read
it (the [fc-dispatch] cell logs path.CheckCellId = the carried cell 0175 even while iterating
0171's BSP, because CheckCellId is the carried cell, not the iterated one).
THE REAL ROOT CAUSE (ramp-climb family, 20/29 records): Transition.CheckOtherCells collided the
OTHER cells against a stale footCenter snapshotted at FindEnvCollisions entry (TransitionTypes.cs
~L1959) — i.e. BEFORE the primary insert_into_cell ran. The primary collide can MOVE the sphere: a
Path-5 full-hit dispatches step_sphere_up, and a successful step-up climbs the foot onto the cottage
floor yet still returns OK. Retail's check_other_cells (acclient_2013_pseudo_c.txt:272735 →
(*cell+0x88)(this)) reads the LIVE sphere_path.global_sphere (post-insert). acdream used the
pre-climb snapshot, which is sunk ~0.25 m below the floor → the foot spuriously near-misses the very
floor it just climbed onto → neg_step_up → a doomed SECOND step_up against the floor normal (0,0,1)
whose step_up_slide unwinds the climb (it slides relative to GlobalCurrCenter = the step start, low Z)
→ validate_transition reverts the whole step → 0 % advance.
FIX (shipped): in Transition.RunCheckOtherCellsAndAdvance re-read footCenter = sp.GlobalSphere[0].Origin before iterating other cells. One line + comment. Pre-fix 0/29 records
advanced; post-fix 20/29 climb onto the cottage floor (Z≈94). Zero regression — full Core suite
1321 pass / 4 fail (the documented baseline 4: Apparatus_Grounded_50cmOffCenter,
2× DoorBugTrajectoryReplay LiveCompare_*, BSPStepUpTests.D4) / 1 skip. The 2 door LiveCompare
divergences are byte-identical with/without the fix (the door's step_up FAILS → sphere restored →
position unchanged → footCenter == live). Tests: CellarLipWedgeTests.Fix_StaleFootCenter_* (2 new,
GREEN).
REMAINING RESIDUAL (9/29, OUT OF SCOPE this pass): the (0,-1,0) sliding-normal +Y-kill
(AdjustOffset slide-crease projects the into-cottage +Y onto the floor×wall crease = world X and zeroes
it → only −X survives → hits the slab −X wall → step_up fails on the flat floor → revert). 7/29 records;
record #6 is the canonical one (DocumentsResidualWedge_LiveFloorCp_SlidingNormalKillsPlusY). This is
slide-recovery territory the kickoff said NOT to re-investigate, and is suspected to be a
buggy-trajectory artifact (the stale slide accumulated only because the player was already oscillating;
once the ramp-climb advances cleanly the player should not enter the south-wall-slide-into-doorway state).
Let the VISUAL GATE decide whether it needs a follow-up before touching the slide. (Record #21 moves
−Y away from the cottage and is likely a legitimate non-advance.)
VISUAL GATE (next): run the client, walk up the Holtburg cottage cellar stairs — expect the last-step
wedge GONE (smooth ascent onto the floor). Also re-confirm the inn door BLOCKS and a generic step-up
climbs (the fix only changes check_other_cells's position reference). If the ascent still intermittently
wedges, the (0,-1,0) +Y-kill is live → investigate AdjustOffset slide-crease / the sliding-normal seed
(with the visual evidence then justifying touching the slide). Apparatus: [fc-dispatch]/[step-sphere-down]
probes + CellarLipWedgeTests.Diagnostic_TraceRecordByIndex reproduce any record in <200 ms.
▶ NEXT-SESSION KICKOFF (historical — its "find_walkable never called" framing was disproven above)
State: M1.5 / P2 cellar-lip "blocked at the last step" wedge. A FAITHFUL deterministic reproduction now
exists. The cause has been peeled through SIX evidence-disproven framings to one bounded question. No fix
landed (intentionally — the last layers were each disproven; do NOT guess, the collision code is load-
bearing). Branch claude/thirsty-goldberg-51bb9b (do NOT branch/worktree; do NOT push w/o asking; NEVER
git stash/gc). PowerShell on Windows; launch logs UTF-16. Use superpowers:systematic-debugging.
READ (in order): (1) THIS file's ## SESSION-END + UPDATE 1 + UPDATE 2 (the live captures + the
pinned root cause) and CORRECTION 1/CORRECTION 2 (CP + cull are RETAIL-FAITHFUL, proven). (2)
memory/project_p2_door_stepup_findings.md.
DONE — faithful apparatus (uncommitted in worktree; RECOMMEND committing first):
tests/AcDream.Core.Tests/Physics/CellarLipWedgeTests.cs + Fixtures/cellar-lip/0xA9B4017{1,4,5}.json +
Fixtures/cellar-lip/wedge-records.jsonl (29 real ACDREAM_CAPTURE_RESOLVE wedge calls). Replays the EXACT
captured calls (seed body-before, real climb dir −X,+Y) through the lip-cell engine — all 29 reproduce
the wedge at 0% advance in <200 ms. Tests (all GREEN as documents-the-bug/diagnostics):
DocumentsWedge_LiveFloorCp_PlayerStuckAtCottageFloorEdge, Diagnostic_ReplayLiveWedgeRecords_Advance,
Diagnostic_ReplayFloorCpRecord_StepUpProbes (→ %TEMP%/lip-wedge-stepup.log), + 2 synthetic.
DISPROVEN — do NOT re-investigate: flat-floor CP (retail also no-CP, smooth — Correction 1); the
PosHitsSphere cull sign (retail-faithful, cdb -z-verified — Correction 2); sphere radius (0.48=player
correct, 0.30=camera probe); the A6.P4 neg-poly Collided→slide_sphere shortcut (fix attempted + reverted,
didn't clear it — the slide returns offset=0 then degenerates to Collided on re-check).
PINNED ROOT-CAUSE LAYER (UPDATE 2): during the step-up's step-down (DoStepUp→DoStepDown→
TransitionalInsert(5)), BSPQuery.FindWalkableInternal is NEVER called for cell 0171 (confirmed after
a CLEAN rebuild — [fw-enter] TEMP probe fires 0×). So the cottage floor (0171 poly 0x0023, n=(0,0,1),
Z=94) is never tested as walkable → no contact plane → step-down rejects (cpValid=False) → step-up
fails → StepUpSlide=Collided → wedge. [other-cells] iter=0171 result=OK is returned WITHOUT reaching
StepSphereDown→find_walkable.
THE JOB (bounded, evidence-first — NO speculative edits):
- Trace
Transition.FindEnvCollisions(TransitionTypes.cs) →BSPQuery.FindCollisionsPATH DISPATCH for cell 0171 whenStepDown=true. Find WHYStepSphereDown/FindWalkableInternalis skipped — candidates: entryNodeIntersectsearly-OK; Path 1 (Placement) taken (DoStepDown's placement insert); the primary 0175 collision returning Collided (the −X-wall Path-5StepSphereUp,stepUp=stepDown=False= the OUTER non-step pass) short-circuiting beforeCheckOtherCells(0171); or StepDown not actually set on that call. Use the[fw-enter]/[find-walkable]TEMP probes — FORCE A CLEAN REBUILD (Remove-Item obj,bin) for any Core probe edit;dotnet test/dotnet buildincremental did NOT pick up new BSPQuery.cs probes (cost two probe rounds). - Port retail's behavior (oracle:
CEnvCell::find_collisionspc:309560 →BSPTREE::find_collisionspc:323725 Path-3 →BSPTREE::step_sphere_downpc:323665 →BSPLEAF::find_walkablepc:326793). Verify how retail's step-down reachesfind_walkableon the cottage floor where acdream's does not. - Fix → VALIDATE: flip
CellarLipWedgeTests.DocumentsWedge_LiveFloorCp_*toadvance>0.25·requested→ GREEN;Diagnostic_ReplayLiveWedgeRecordsadvance% jumps off 0%. 4. REGRESSION:DoorBugTrajectoryReplayTests- full Core suite. VISUAL GATE: cellar ascent clean (no last-step wedge) + inn door BLOCKS + generic step-up climbs.
ENABLER: cdb -z "C:\Turbine\Asheron's Call\acclient.exe" = offline static disasm + uf w/ PDB symbols
(no live attach); use it to verify any retail branch/offset (the cull-sign error was a BN parity-jump
mis-read — never trust BN if(p) for test ah,N; jp).
Apparatus (uncommitted, worktree): the test + fixtures above; TEMP probes in BSPQuery.cs
([path5-wall],[fw-enter],[find-walkable], STRIP) + TransitionTypes.cs ([neg-poly],[stepsphereup],
[stepdown-decide], CheckOtherCells cn/sn/negHit, STRIP) all gated on ACDREAM_PROBE_INDOOR_BSP; captures
lip-wedge-resolve.jsonl/lip-cells//launch-*.log; cdb scripts tools/cdb/retail-connector-collide-trace.cdb
(+ flatfloor/lip); analyzers analyze_wedge_jsonl.py/extract_wedge_records.py/analyze_v1_corr.py;
cdbz-disasm.txt/cdbz-poshits.txt. Test baseline: Core prior 1310p/4f/1s + 5 GREEN lip tests; App 177.
Canonical pickup, 2026-06-04 PM. Branch
claude/thirsty-goldberg-51bb9b(do NOT branch/worktree; do NOT push without asking; NEVERgit stash/gc). PowerShell on Windows; launch logs are UTF-16. This SUPERSEDES the membership re-diagnosis indocs/research/2026-06-04-p2-cellar-corner-stepup-handoff.md(now history) and folds in the full chain frommemory/project_p2_door_stepup_findings.md.
🧪 SESSION-END 2026-06-04 PM — deterministic repro BUILT + first fix attempt REVERTED
Apparatus shipped (uncommitted in worktree): tests/AcDream.Core.Tests/Physics/CellarLipWedgeTests.cs
- fixtures
tests/AcDream.Core.Tests/Fixtures/cellar-lip/0xA9B4017{1,4,5}.json(copied fromlip-cells/). Loads the 3 lip cells (synthetic single-leaf BSP, same asCellarUpTrajectoryReplayTests), seeds the player (r=0.48, foot bottom Z=93.456 → foot-sphere center Z=93.936 = the live wedge) carried in slab 0175, drives forward. Reproduces the wedge deterministically in <90 ms: the player FREEZES, blocked by the threshold slab's −X side wall (poly normal world (1,0,0)). Two tests, both GREEN as documents-the- bug:Diagnostic_DriveOffThreshold_DumpTrajectory(dumps trajectory+probes to%TEMP%/lip-wedge-diag.logvia Console redirect) +DocumentsWedge_PlayerFrozenAtThreshold_BlockedByMinusXWall.
FIX ATTEMPT #1 — REVERTED. Hypothesis: the A6.P4 neg-poly NegStepUp==false branch
(TransitionTypes.cs ~line 1083) returns Collided (a deliberate "simpler response" shortcut; the
comment says the slide was deferred), where retail dispatches neg_step_up==0 → slide_sphere. Replaced
it with SlideSphereInternal(NegCollisionNormal, GlobalCurrCenter[0].Origin) (mirroring the NegStepUp=
true branch). Did NOT fix the wedge → reverted. WHY: the slide returns Slid with offset=0 (the
−Y displacement is already along the crease dir=cross((1,0,0),(0,0,1))=(0,−1,0)), so the sphere
doesn't move; the loop re-checks with gDelta≈0 → SlideSphere's offset.LengthSquared<ε → Collided
branch (TransitionTypes.cs:2877) → revert. So the bug is NOT the shortcut alone — it's the
slide/loop-commit: the parallel-graze slide produces no advance, and the re-check degenerates to
Collided.
TWO GAPS for the next pass:
- Faithful repro: the synthetic drive direction (world −Y) is a GUESS and is PARALLEL to the −X
wall (keeps grazing). The real climb direction is unknown without the exact
targetPos. Get a shortACDREAM_CAPTURE_RESOLVE=<path>JSONL of the live wedge (one acdream run, wedge ~5 s) → wire aLiveCompare-style test (the provenCellarUpTrajectoryReplayTestspattern) with the exact currentPos/targetPos/body-before. That makes the RED test faithful + the fix validatable. - The real fix is in the slide/loop: why does retail's
slide_sphereadvance the sphere PAST the parallel graze where acdream's returns offset=0 then degenerates to Collided on re-check? Trace retailCSphere::slide_sphere(pc:321660) vs acdreamSlideSphere(TransitionTypes.cs:2826) for the parallel-wall + grounded case, AND why the loop re-check seesgDelta≈0. NOTE the live wedge used the NegStepUp=TRUE path (StepSphereUp→StepUpSlide=Collided) while the synthetic repro used NegStepUp=FALSE (neg-poly-dispatch→Collided) — BOTH end inSlideSphere/SlideSphereInternalreturning Collided, so the common fix point isSlideSphere's degenerate-offset handling, not the dispatch branch. DOOR REGRESSION RISK: anySlideSphere/neg-poly change touches the A6.P4 door block — regression-testDoorBugTrajectoryReplayTests+ visual-gate the inn door BLOCKS.
Test baseline unchanged: the 2 new lip tests are GREEN (documents-the-bug). Build green. The reverted
fix leaves TransitionTypes.cs functionally identical (only an explanatory comment added at the shortcut).
UPDATE (same session, later) — FAITHFUL repro BUILT + ROOT CAUSE PINNED
Got the JSONL (ACDREAM_CAPTURE_RESOLVE → lip-wedge-resolve.jsonl, 17K player records). The real climb
direction is −X,+Y (my synthetic −Y guess was backwards). Extracted 29 representative wedge records to
tests/AcDream.Core.Tests/Fixtures/cellar-lip/wedge-records.jsonl (extract_wedge_records.py).
CellarLipWedgeTests now replays the EXACT captured calls (seed body-before, replay ResolveWithTransition
through the lip-cell engine): all 29 reproduce the wedge bit-faithfully (0% advance). New tests (all
GREEN as documents-the-bug / diagnostics): Diagnostic_ReplayLiveWedgeRecords_Advance,
Diagnostic_ReplayFloorCpRecord_StepUpProbes, DocumentsWedge_LiveFloorCp_PlayerStuckAtCottageFloorEdge.
ROOT CAUSE PINNED (via Diagnostic_ReplayFloorCpRecord_StepUpProbes → %TEMP%/lip-wedge-stepup.log):
the player is at the doorway EDGE of the cottage floor. The step-up (triggered by the −X wall, normal
(1,0,0), STEEP) → step-down → multi-cell check reaches 0171 poly 0x0023 = the cottage floor (n=(0,0,1),
world Z=94). The 0.48 sphere OVERLAPS it (overlapsSphere=True, dist=−0.085) — BUT it's REJECTED
because the sphere center projects outside the floor poly's edge (insideEdges=False, gap=−0.395). So
[other-cells] iter=0171 result=OK (NOT Adjusted), no contact plane is set → [stepdown-decide] cpValid= False accept=False → step-up FAILS → StepUpSlide=Collided → wedge. Retail accepts the floor at its edge
and crosses (0175 never blocks). This is a WALKABLE-EDGE acceptance divergence, not a CP/cull/slide bug.
THE FIX (next, narrow): compare acdream's walkable-edge math vs retail for the sphere-overlaps-floor-
but-center-outside-edge case. Actual walkable test = BSPQuery.WalkableHitsSphere (254) →
PolygonHitsSpherePrecise (overlap) + AdjustSphereToPlane (351); [other-cells] result=OK means one of
them returned false for poly 0x0023. The [walkable-nearest] diagnostic uses CheckWalkable (287, the
edge/insideEdges test). Retail oracle: CPolygon::walkable_hits_sphere (pc:323006) +
CPolygon::check_walkable (pc:322811) + CPolygon::adjust_sphere_to_plane (pc:322032). Read which one
rejects the edge-overlap and why retail accepts it. Validate with CellarLipWedgeTests (flip
DocumentsWedge_LiveFloorCp_* to assert advance>0.25·requested). DOOR REGRESSION RISK: walkable changes
are global — run DoorBugTrajectoryReplayTests + visual-gate the inn door BLOCKS + generic step-up climbs.
Apparatus: lip-wedge-resolve.jsonl, Fixtures/cellar-lip/*, analyze_wedge_jsonl.py,
extract_wedge_records.py, %TEMP%/lip-wedge-stepup.log.
UPDATE 2 — deeper: find_walkable is NEVER called during the step-down (cottage floor never tested)
Drilled one layer further with TEMP probes [fw-enter]/[find-walkable] in BSPQuery.FindWalkableInternal
(gated on ACDREAM_PROBE_INDOOR_BSP, marked STRIP, uncommitted). Confirmed after a CLEAN rebuild (deleted
obj/bin) — [fw-enter] fires ZERO times while the prior probes fire. So during the step-up's step-down
(DoStepUp→DoStepDown→TransitionalInsert(5)), FindWalkableInternal is never reached for 0171 (nor
0175): the cottage floor poly 0x0023 is never tested by the walkable finder. [other-cells] iter=0171 result=OK is returned WITHOUT StepSphereDown→FindWalkableInternal. So the "walkable-edge acceptance"
framing in UPDATE 1 is one level too shallow — the floor isn't rejected by the edge test, it's never
tested at all. Root: FindEnvCollisions/BSPQuery.FindCollisions for 0171 during the step-down returns OK
on a path BEFORE Path 3 (StepDown→StepSphereDown). NEXT: trace FindEnvCollisions (TransitionTypes) → which
FindCollisions path 0171 takes during StepDown=true (entry NodeIntersects early-out? Path 1 Placement?
the primary-0175 result short-circuiting CheckOtherCells?) and why StepSphereDown/find_walkable is skipped.
The [stepsphereup] stepUpFlag=False stepDownFlag=False means the −X-wall StepSphereUp is the OUTER
(non-step) collision; the step-DOWN that should find the floor is a separate inner insert that never runs
find_walkable. NOTE: a clean dotnet build/dotnet test did NOT pick up new BSPQuery.cs probes until
Remove-Item obj,bin — force a clean rebuild when adding Core probes (cost two probe rounds this session).
HONEST STATUS: NO FIX. The collision/step path is deeper than a single-line fix — 6+ framings this
session (CP→cull→slide→neg-poly→walkable-edge→find_walkable-not-called), each disproven by evidence and the
next layer exposed. This is the systematic-debugging "question the architecture" signal. The FAITHFUL repro
(CellarLipWedgeTests, 29 records @0% advance) makes the next attempt iterable; the next move is the
FindEnvCollisions/FindCollisions-path trace above, NOT another speculative edit. The collision code is
load-bearing (every floor/wall/step) — do not guess.
⚠️ CORRECTION 2026-06-04 (next session) — THE CP IS RETAIL-FAITHFUL; v2 IS MOOT
The "decisive question" below is ANSWERED from the EXISTING v1 log — no new retail trace
needed. The v1 retail-flatfloor-trace.log was wrongly dismissed as a gu artifact. It is
real data. Proof (full-file correlation over all 5,349 records, analyze_v1_corr.py):
- sphere z ≤ 90.0 → pure ret=3 (CP set); z = 94.01 (the flat cottage floor) → pure ret=1
(NO-CP), 877 records, zero ret=3; ret mixes only in the ramp transition zone (90–93.7),
which is physical. A corrupted-
eaxartifact CANNOT produce two large pure populations at opposite Z extremes with a physical transition between — the ret tracks the input Z exactly. walk_interp = 1.0 → ret=1 (no-CP) 770×— i.e. retail, withwalk_interp=1.0on the flat floor, gets NO contact plane and is smooth. That is the exact acdream condition (walkInterp=1.000 cpValid=False).cdb -z acclient.exe(offline static disasm, symbols) confirmsBSPTREE::step_sphere_down+0x218=mov eax,3;ret(reached only after[eax+18h]=1contact_plane_valid +set_walkable) and+0x227=mov eax,1;ret(earlyjewhenfind_walkablefound nothing). So ret3↔CP-set, ret1↔no-CP is certain.
ANSWER: retail's step_sphere_down returns NO-CP (ret 1) on the flat cottage floor —
exactly like acdream — and retail crosses smoothly. The contact plane is NOT the divergence.
Both "if NO-CP → trace set_contact_plane callers" and "if SET-CP → divergence in StepSphereDown"
branches below rest on a FALSE premise (that retail establishes a flat-floor CP somewhere). It
does not. Do NOT run the v2 trace; do NOT hunt a retail flat-floor CP path.
REDIRECTED diagnosis (back to the connector recovery — the RE-DIAGNOSIS 2 / SLIDE LOCALIZED
line in memory, which the flat-floor-CP finding had wrongly sidelined): the wedge is the
per-cell collide on connector 0175 returning Slid during the recovery, which reverts the
good floor landing. Static comparison this session confirms the recovery structures ALL MATCH
retail: find_collisions Contact full-hit → step_sphere_up; step_up fail → step_up_slide
→ slide_sphere (retail CSphere::step_sphere_up pc:321611–321638, step_up_slide pc:273930);
check_other_cells halts on Slid (4) clearing CP (pc:272717, cdb -z jump-table on (result-1));
acdream TransitionalInsert continues (no revert) on Slid (TransitionTypes.cs:881). The SOLE
open question: does retail's per-cell CEnvCell::find_collisions return Slid (recover & slide)
or OK (never hits) for connector 0175 at the lip?
- OK in retail → acdream's connector Slid is SPURIOUS (over-detect / over-step-up 0175) → fix there.
- Slid in retail → retail slides+continues; acdream's wedge is the substep REVERT upstream
(
FindTransitionalPosition/ResolveWithTransition), not the collide.
NEW decisive trace (READY, robust, no gu): tools/cdb/retail-connector-collide-trace.cdb
breaks CEnvCell::find_collisions+0x1e (the SINGLE exit; esi=this, eax=result; cell id
poi(esi+0x28)), logs ret per lip cell 0xA9B4017X. Built + offset-verified entirely offline via
cdb -z (no live attach). ENABLER: cdb -z "C:\Turbine\Asheron's Call\acclient.exe" does
offline static disassembly with full PDB symbols — verify any trace offset without a running client.
Everything below this banner is RETAINED FOR HISTORY (the flat-floor-CP hypothesis, now disproven).
⚠️ CORRECTION 2 — 2026-06-04 PM (live retail + acdream captures; the REAL mechanism)
Two live captures this session settled it. Retail-connector trace (tools/cdb/retail-connector-collide-trace.cdb
→ retail-connector-collide-trace.log, breaking CEnvCell::find_collisions+0x1e, single nesting-safe exit):
over ~85K samples the connector cell 0175 returns 2692 OK + 94 Adjusted + 0 Collided + 0 Slid — it
never blocks. (Floor 0171 and 0174 DO block — real cottage-room walls — so the trace is working.) So
the connector is a pure pass-through / successful-step-up in retail; acdream spuriously blocks it.
acdream live capture at the wedge (launch-lip-capture.log, ACDREAM_PROBE_INDOOR_BSP=1 + the 4 TEMP
probes + cell dumps lip-cells/0xA9B4017{1,4,5}.json) — the stuck state is:
[indoor-bsp] cell=0xA9B40175 lpos=(8.523,-2.251,-0.064) lprev=(8.520,-2.251,-0.064) r=0.480 result=OK
[stepdown-decide] cell=0xA9B40175 insert=OK cpValid=False cpNz=1.000 walkableZ=0.664 accept=False pos=(...,93.456)
[stepsphereup] cell=0xA9B40175 stepUpFlag=False stepDownFlag=False n=(1.00,0,0) stepped=False
[stepsphereup] cell=0xA9B40175 StepUpSlide=Collided
[indoor-bsp] cell=0xA9B40175 r=0.480 result=Collided
Decoded mechanism (this is NOT the memory's "connector Slid" — that was a pre-B1-fix state):
- 0175 is a 0.364 m-tall threshold SLAB (dump: 4 solid side walls at local X=7/9, Y=−2.85/1.15; open floor/ceiling portals poly4→0171, poly5→0174; WorldTransform 180°-rot at (161.929,7.503,94)).
- The wedge uses the r=0.48 body sphere (Ø0.96 — bigger than the slab is tall), centered at world Z=93.936 (local Z=−0.064, i.e. SUNK into the threshold, ~0.5 m below resting-on-floor Z≈94.48).
- That oversized sphere genuinely full-hits the −X wall (poly 3, X=9; sphere at X=8.523 reaches
X=9.003 — a 3 mm graze;
moveDot<0so retail would keep it too) →BSPQuery.StepSphereUp(Path 5, BSPQuery.cs:1849/1380) →DoStepUpfails (its internal step-down finds no CP on the flat floor —[stepdown-decide] cpValid=False, retail-faithful per Correction 1) →StepUpSlide→SlideSphereInternalreturnsCollided→FindEnvCollisionsreturns Collided → wedge. The 3 mm graze is hair-trigger → explains the intermittency.
CULL SIGN = RED HERRING (verified faithful). Mid-session I believed acdream's PosHitsSphere cull
(if moveDot>=0 return false) was OPPOSITE retail. WRONG — cdb -z uf acclient!CPolygon::pos_hits_sphere
shows test ah,5; jp +0x46. jp is a parity jump; the cull branch is taken on EVEN parity = {dot>=0}.
So retail keeps the hit when dot<0, culls when dot>=0 — IDENTICAL to acdream + ACE (if dist>=0 return false). Movement convention also matches (both check−curr: acdream BSPQuery.cs:1663, retail
find_collisions). Do NOT touch the cull. The Binary Ninja pseudo-C renders test ah,5; jp as
if (p) return 0 which READS like "cull when dot<0" — it is not; the parity decode is inverted. LESSON:
verify any cull/branch sign against cdb -z, never the BN if(p) rendering of a parity jump.
ENABLER: cdb -z "C:\Turbine\Asheron's Call\acclient.exe" does offline static disasm + uf with full
PDB symbols — used to build/verify the connector trace AND to catch the cull-sign error. Ghidra patchmem
addresses do NOT match the PDB/BN addresses (0x005394f0 → CPolygon::UnPack in Ghidra); use cdb -z.
THE SHARP REMAINING QUESTION: at the thin slab, why does retail's step-up SUCCEED (climb onto the
cottage floor, find_collisions returns OK) where acdream's DoStepUp FAILS (no CP → StepUpSlide=Collided)?
Sub-leads: (a) RULED OUT — r=0.48 vs r=0.30 is two DIFFERENT movers, not a bug. r=0.48 = the PLAYER
(PlayerMovementController.cs:1116, "human player radius from Setup"); r=0.30 = the CAMERA collision
probe (PhysicsCameraCollisionProbe.cs:18 ViewerSphereRadius=0.3, single sphere). The smooth r=0.30
crossings are the camera spring-arm; the wedge is the player. Player radius 0.48 is correct. So the
question is purely the player step-up, NOT the sphere. Open: why is the player SUNK to Z=93.936 (0.5 m
below resting-on-floor Z≈94.48) at the threshold — is that retail-faithful (it's mid-climb from the
cellar) or a position error? (b) does retail even full-hit 0175's wall, or does its sphere clear it
(position)? (c) the
flat-floor step-up success path (Correction 1's open question — retail's step_up establishes the floor
CP via some path acdream lacks). NEXT: either build a deterministic harness test from lip-cells/*.json
(place the r=0.48 sphere at the captured wedge pos, assert FindCollisions returns OK not Collided — RED→
GREEN), or one targeted retail trace of CSphere::step_sphere_up/CTransition::step_up at 0175 (does it
return 1/OK or fall to step_up_slide?). Apparatus committed-in-worktree: tools/cdb/retail-connector-collide-trace.cdb,
lip-cells/0xA9B4017{1,4,5}.json, launch-lip-capture.log, cdbz-disasm.txt, cdbz-poshits.txt,
analyze_v1_corr.py. TEMP [path5-wall] probe added to BSPQuery.cs Path 5 (STRIP; was NOT in the stale
--no-build binary, so it didn't fire — rebuild to use it).
State both altitudes
- Milestone: M1.5 — Indoor world feels right.
- Effort: P2 of the verbatim spatial-pipeline port
(
docs/superpowers/specs/2026-06-03-verbatim-spatial-pipeline-port-master-plan.md). - Symptom (user words): "run up the cellar stairs, get blocked at the last step; sometimes through, sometimes not." Retail is always smooth there.
- This session's outcome: NO fix landed. The diagnosis was corrected three times with
evidence; the wedge is now precisely localized; the FINAL decisive question is still open
because the retail trace tooling (
guin a bp action) produced an artifact. One clean v2 retail trace pins it. Everything is saved; resume cold.
The corrected diagnosis (evidence chain — all three prior theories DISPROVEN)
-
NOT membership / cell-resolver ping-pong (the prior handoff's claim). A live retail cdb trace (
tools/cdb/retail-lip-trace.cdb→retail-lip-trace.log, breakingCTransition::step_up, loggingsphere_path.check_pos.objcell_id) proved retail's carried cell ALSO alternates0xA9B40174/0175/0171at the lip (181/40/17 over 238 step_ups), yet retail crosses smoothly. So the carried-cell flip is retail-faithful — a "keep the cell stable" /ResolveCellId-stickiness fix would DIVERGE from retail. Also: the production[cell-transit] reason=resolveris the SWEPTfind_cell_listpick (RunCheckOtherCellsAndAdvance→CellTransit.FindCellSet), NOTPhysicsEngine.ResolveCellId(which is only the cache-null test fallback).result.cellIdis STABLE in runs of 100s of ticks inacdream-corner-capture.jsonl(154K recs). -
NOT a reverted landing (the M1 guess). In
acdream-corner-capture.jsonlthe player reaches the floor (Z=94.0, cpz 0.78→1.00) and WALKS ON into the cottage (idx 7215→7244); the landing commits fine. -
IT IS: a step-up coin-flip on the FLAT cottage floor. The
[stepdown-decide]probe (inTransition.DoStepDown) shows the trigger unambiguously:accept=True (1845×): insert=OK cpValid=Trueon the RAMP (cpNz=0.781, Z≈93.3, walkInterp≈0)accept=False ( 849×): insert=OK cpValid=False cpNz=1.000 walkInterp=1.000on the FLAT floor (Z=94.0)
The step-up's acceptance check (
insert==OK && ContactPlaneValid && cpNz>=walkableZ,TransitionTypes.cs:3147) rejects ONLY whencpValid=False, which happens ONLY on the FLAT floor: the sphere is already settled →adjust_sphere_to_planeis a no-op →FindWalkableInternalrecords no poly (its gate iswalkable && adjusted,BSPQuery.cs:736) →StepSphereDown(BSPQuery.cs:1216) sets no contact plane → reject. On the RAMP the sphere is always sliding (adjusted=true) so the CP is set → accept. Ramp = adjusting = works; flat floor = settled = no CP = fails. The[stepsphereup]probe corroborates: lip-riser step-up (cell 0171, n=(0,-1,0)) = 443 success / 445 fail; connector +X corner wall (cell 0175, n=(1,0,0)) = 74 fail → recursiveStepSphereUp→StepUpSlide= 401 Slid / 203 Collided overall.
Why the OBVIOUS fix is WRONG (do not ship it)
"Just set the contact plane whenever a walkable poly is found, even without adjustment" — this DIVERGES from retail. Verified against the decomp:
BSPLEAF::find_walkable(acclient_2013_pseudo_c.txt:326793) gates BOTH the poly AND the changed-flag onwalkable_hits_sphere && adjust_sphere_to_plane— IDENTICAL to acdream'sFindWalkableInternal.CPolygon::adjust_sphere_to_plane(:322032) updateswalk_interpand returns 1 only whennew_interp = (1-t)*walk_interp < walk_interp, i.e.t>0(the sphere must move toward the plane). For a SETTLED sphere (t≈0) retail ALSO returns 0 → records no poly → sets no step-down CP. So acdream'sStepSphereDown+AdjustSphereToPlaneare FAITHFUL. Retail must establish the flat-floor contact plane through a DIFFERENT path during the climb — that path is what's still unknown.
THE DECISIVE OPEN QUESTION + the v2 trace protocol
Does retail's BSPTREE::step_sphere_down SET the contact plane (ret 3) or NOT (ret 1) on the
flat floor cell (0xA9B40171)?
- v1 trace FAILED:
guinside a cdb bp action ("commands skipped … target execution inside an event handler") corrupted eax → perfect1,3,1,3alternation artifact (run-length=1; the 4216/1133 histogram is meaningless). NEVER useguin a cdb bp action. - v2 trace READY:
tools/cdb/retail-flatfloor-trace.cdb— stashes the cell in$t3at entry via@@c++, counts at the two RETURN addresses (nogu). STEP 0: verify the +0x218 (ret 3) / +0x227 (ret 1) offsets against theu acclient!BSPTREE::step_sphere_downdisassembly the script logs, fix if needed, re-attach, THEN have the user wedge ~10s. - Interpretation: if floor cell 0171 is mostly NO-CP → retail establishes the floor CP via a
DIFFERENT path → next trace breaks
COLLISIONINFO::set_contact_planeand logs the CALLER (poi(@esp)) for normal≈(0,0,1) to find that path, then port it. If mostly SET-CP → the divergence is inside acdream'sStepSphereDown/AdjustSphereToPlaneafter all (re-read thewalk_interp/tmath vs ACE).
Leading hypothesis (UNCONFIRMED, pending v2)
Retail's step-up ALSO "fails" on the settled flat floor (step_sphere_down no-CP) but recovers
via step_up_slide smoothly, where acdream wedges — so the divergence may be in the SLIDE
RECOVERY (SpherePath.StepUpSlide → Transition.SlideSphereInternal, the B1/slide_sphere
area, commits abbd761/0935a31) and/or the connector-cell-0175 StepSphereUp interference,
NOT the contact plane itself. The B1/slide fixes are correct FOR THE DOOR; re-investigation is
warranted FOR THE CELLAR recovery only.
Retail decomp anchors (verified this session)
CTransition::step_up pc:273099 (clears CP @273103, calls step_down) · CTransition::step_down
pc:272946 (the if (step_up==0) lower-gate @272954; transitional_insert(5); accept iff
!cond:0 && contact_plane_valid @272968) · BSPTREE::step_sphere_down pc:323665 (sets
contact_plane_valid=1 UNCONDITIONALLY when a poly is found @323711; return 3) ·
BSPLEAF::find_walkable pc:326793 · CPolygon::adjust_sphere_to_plane pc:322032 ·
CTransition::transitional_insert pc:273137 (neg_poly_hit → slide_sphere @273350) ·
CTransition::validate_transition pc:272547 · CTransition::check_other_cells pc:272717.
acdream code map (where the fix will likely go)
BSPQuery.StepSphereDown (:1216) · FindWalkableInternal gate (:736) · AdjustSphereToPlane
(:351) · FindCollisions StepDown dispatch (:1753) · StepSphereUp (:1372) · StepUpSlide
(TransitionTypes.cs:472) / SlideSphereInternal · DoStepUp (:3269) / DoStepDown (:3089) ·
step-up acceptance (:3147) · neg_poly dispatch gated !StepDown && !StepUp (:1040) ·
CheckOtherCells (:1632) · RunCheckOtherCellsAndAdvance (:2158).
Apparatus inventory
TEMP probes (UNCOMMITTED in worktree, gated on ACDREAM_PROBE_INDOOR_BSP, marked STRIP):
BSPQuery.NegPolyHitDispatch → [neg-poly]; BSPQuery.StepSphereUp → [stepsphereup];
Transition.CheckOtherCells → cn/sn/negHit added to [other-cells]; Transition.DoStepDown
→ [stepdown-decide].
Existing env probes: ACDREAM_PROBE_INDOOR_BSP=1 (→ [indoor-bsp]+[other-cells]+the 4 TEMP),
ACDREAM_DUMP_STEPUP=1 (→ stepup:), ACDREAM_PROBE_CELL=1 (→ [cell-transit]),
ACDREAM_PROBE_STEP_WALK=1 (→ [step-walk], very high volume), ACDREAM_CAPTURE_RESOLVE=<path>.
cdb scripts: tools/cdb/retail-lip-trace.cdb (carried cell — DONE), tools/cdb/retail-flatfloor-trace.cdb
(v2, READY). Binary C:\Turbine\Asheron's Call\acclient.exe MATCHES refs/acclient.pdb.
Logs (worktree root, UTF-16/big — do NOT commit): acdream-corner-capture.jsonl (321MB),
launch-corner-{innerflow,slidepoly,negpoly,ssu,decide}.log, retail-lip-trace.log,
retail-flatfloor-trace.log (artifact), corner-cells-audit.txt. Analyzers: analyze_corner.py.
DO NOT
- Re-diagnose as membership / add
ResolveCellIdstickiness (RULED OUT by retail cdb). - Ship "set the step-down CP without adjustment" (DIVERGES from retail — verified vs decomp).
- Use
guinside a cdb bp action (corrupts eax — v1 trace artifact). - Re-investigate B1/
slide_sphereAS THE DOOR FIX (correct); but the cellar SLIDE RECOVERY is a legitimate new suspect. - Flip
Apparatus_Grounded_50cmOffCentertoAssert.True(synthetic-floor artifact). - Guess the fix — the divergence is genuinely subtle (
walk_interp/slide-recovery), pin it first.
Test baseline
Core 1310 pass / 4 fail / 1 skip (the 4: Apparatus_Grounded_50cmOffCenter [synthetic-floor],
2× DoorBugTrajectoryReplay LiveCompare_* [captured-buggy-live], BSPStepUpTests.D4 [airborne
Path 6, separate]); App 177 green. Branch HEAD 664101f + this session's UNCOMMITTED probes/docs.
FRESH-SESSION KICKOFF PROMPT (copy-paste)
Continue the P2 cellar-lip wedge fix for acdream. Branch claude/thirsty-goldberg-51bb9b (do NOT
branch/worktree; do NOT push without asking; NEVER git stash/gc). PowerShell on Windows; launch
logs are UTF-16. Use superpowers:systematic-debugging.
READ FIRST (in order):
1. docs/research/2026-06-04-p2-cellar-lip-flatfloor-cp-handoff.md (THIS handoff — canonical).
2. memory/project_p2_door_stepup_findings.md (full chain: RE-DIAGNOSIS 2 + SLIDE LOCALIZED +
FAILING CONDITION PINNED + RETAIL trace ATTEMPT #1 entries).
STATE: M1.5. The cellar "blocked at the last step, sometimes through" wedge is RE-DIAGNOSED with
live retail cdb evidence: NOT membership (retail's carried cell flips the same way + is smooth),
NOT a reverted landing. It IS a step-up coin-flip on the FLAT cottage floor — the step-up's
internal step-down sets NO contact plane on the settled flat floor (cpValid=False, walkInterp=1.0)
so the acceptance check rejects, while it works on the ramp slope. acdream's StepSphereDown +
AdjustSphereToPlane are FAITHFUL to retail (verified vs find_walkable pc:326793 + adjust_sphere_to_plane
pc:322032), so the obvious "set the CP anyway" fix is WRONG — retail establishes the flat-floor CP
via a DIFFERENT path that is still unknown.
THE JOB (evidence-first; do NOT guess):
1. Run the READY v2 retail trace tools/cdb/retail-flatfloor-trace.cdb (user relaunches the retail
client + walks to the cellar lip; STEP 0 = verify the +0x218/+0x227 return offsets against the
`u` disassembly the script logs BEFORE driving; NO `gu` in bp actions). Answer: does retail's
step_sphere_down set the CP (ret 3) or not (ret 1) at floor cell 0xA9B40171?
2. If mostly NO-CP → trace COLLISIONINFO::set_contact_plane callers (poi(@esp)) for normal≈(0,0,1)
to find retail's flat-floor CP path; port it. If mostly SET-CP → the divergence is in acdream's
StepSphereDown/AdjustSphereToPlane walk_interp/t math vs ACE. Leading hypothesis: retail's
step-up also "fails" on the flat floor but RECOVERS via step_up_slide smoothly where acdream
wedges → the divergence may be the SLIDE RECOVERY (StepUpSlide/SlideSphereInternal) +
connector-0175 StepSphereUp interference, NOT the CP.
3. RED→GREEN deterministic test + STRIP the 4 TEMP probes once the fix lands. USER VISUAL GATE:
cellar ascent clean (no last-step wedge); inn door still BLOCKS; generic step-up climbs.
DO NOT: re-diagnose as membership / add ResolveCellId stickiness; ship "set the step-down CP
without adjust" (diverges from retail); use `gu` in a cdb bp action; guess.
TEST BASELINE: Core 1310 pass / 4 fail / 1 skip (documented); App 177 green. Branch HEAD 664101f +
UNCOMMITTED TEMP probes (BSPQuery.NegPolyHitDispatch [neg-poly], BSPQuery.StepSphereUp
[stepsphereup], CheckOtherCells cn/sn/negHit, DoStepDown [stepdown-decide]) gated on
ACDREAM_PROBE_INDOOR_BSP.