Tonight's slice 6 session attempted 6 variations of placement-insert
bypass in Transition.FindEnvCollisions + Transition.DoStepUp. None
unstuck the player at the cellar ramp top despite mechanically firing
the bypass up to 72 times per session. Reverted all variants; nothing
shipped tonight beyond this handoff.
The hard finding: the placement-insert path is a SYMPTOM, not the
cause. Bypassing it (in 6 ways) doesn't make the sphere climb the
cellar ramp. The first-order question — why doesn't the sphere
progress UP the ramp via normal slope-walking? — wasn't addressed.
User's most actionable clue (not yet investigated): "outside ground
covers only the open path down into the cellar" → suggests a missing
hole in the outdoor terrain mesh over the cellar entry. That's a
terrain-generation bug, completely separate from BSPQuery.FindCollisions.
Handoff doc captures:
- The 3-session diagnosis evolution (each previous session's
confident diagnosis was wrong)
- All 6 slice-6 bypass variants tried and why each failed
- What we KNOW (data-confirmed) vs what we DON'T KNOW (open
questions)
- Specific next-step investigation order with terrain-mesh as #1
- Pickup prompt with strong "don't re-attempt placement-insert
bypass" guard
Test baseline 1148 + 8 unchanged. Slice 5 probe (cf3deff) remains
committed as the durable diagnostic infrastructure.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
14 KiB
A6.P3 issue #98 handoff — 2026-05-23 (early morning)
Worktree: C:\Users\erikn\source\repos\acdream\.claude\worktrees\strange-albattani-3fc83c
Branch: claude/strange-albattani-3fc83c
HEAD at handoff: 467a81f (this doc) on top of cf3deff (slice 5 probe + diagnosis)
Status: Cellar-up still broken. Tonight's slice 6 attempt at placement-insert bypass (multiple variations) did not converge. Worktree code is at the slice 5 baseline (commit cf3deff); none of tonight's bypass variations landed. Investigation direction needs to pivot — the placement-insert path is not the right place to fix this.
Pasteable session-start prompt at the bottom of this doc.
TL;DR
Three sessions on this bug. Each previous session was confident about the diagnosis; each one was wrong:
| Session | Diagnosis | Outcome |
|---|---|---|
| 2026-05-22 morning | BSPQuery.FindCollisions Path 5 vs Path 6 path-selection |
Wrong — slice 5 probe + retail BP4 data proved every retail find_collisions hit has collide=0, so retail enters the same Contact branch we do. |
| 2026-05-22 evening (slice 5) | Cellar ceiling polygon 0x0020 blocks placement_insert; cell-promotion would unstick the player | Sharpened but incomplete — the probe identified the polygon correctly, but cell-promotion alone doesn't fix it. |
| 2026-05-22 late evening (slice 6 attempts, this handoff) | Bypass placement_insert when blocker is a downward-facing cell-boundary polygon | 6+ variations tried, none unstuck the player. Each variation produced "bypass fires, player still stuck." |
The CLEAN finding from tonight: the placement-insert path is NOT the root cause. Bypassing it (in 6 different ways) doesn't unstick the player. The actual blocker is somewhere else in the resolve chain, OR in the geometry pipeline (terrain mesh hole missing).
User's most actionable clue (not yet investigated): "Looking down to the cellar I can see that the entry is covered with outside ground. Like the ground continues and covers only the open path down into the cellar." → suggests a missing hole in the outdoor terrain mesh over the cellar entry. That's a terrain-generation bug, not a physics bug.
What's committed
-
cf3deff(slice 5) —[place-fail]+[place-fail-obj]probe + side-channel polygon attribution + the corrected diagnosis in ISSUES.md #98. This is the durable value from this work. It rules out the morning's Path 5/6 hypothesis with hard data and gives any future investigator the diagnostic infrastructure to identify which polygon blocks any placement check. -
The two captures at
docs/research/2026-05-21-a6-captures/scen4_cottage_cellar_place_fail/:acdream.log(probe pass 1)acdream_v2_with_obj_probe.log(probe pass 2 with object-id emit)
What did NOT work tonight (reverted)
All six variations of placement-insert bypass in Transition.FindEnvCollisions + Transition.DoStepUp:
| Variant | What it tried | Failure mode |
|---|---|---|
| Sibling fallback | If primary cell's Path 1 placement returns Collided, try other cells via portal-graph BFS. Accept if ANY sibling cell's BSP accepts the sphere. | All siblings (0xA9B40143, 0xA9B40146) also returned Collided. No cell accepts the sphere position. |
| Cell-boundary bypass (no lift) | When primary's blocker is a downward-facing polygon (N.Z < -0.5), return OK from FindEnvCollisions without modifying CheckPos. | Sphere stayed where the step-down probe left it (cellar walkable at world Z=93.22). Next tick re-runs same logic. Player oscillates at one Z. |
Bypass + ceiling-clearance lift (+0.05) |
Same as above, but also lift CheckPos to ceiling_world_z + 0.05 (sphere foot just above ceiling). | Sphere foot stuck at 93.87 across 72 events. Cell-resolver did not promote to cottage cell (cottage CellBSP volume might not extend down to sphere center at world Z=94.35, or rotation makes the check fail). |
Bypass + aggressive lift (+ diameter + 0.05) |
Lift CheckPos by ceiling + 0.96m so sphere clearly clears the cottage floor thickness layer. | 0 bypass events captured. Possibly client-side issue or geometry placement diverged enough to skip the bypass branch entirely. |
| Override DoStepDown false result via flag | When DoStepDown returns false AND CellBoundaryBypassActive=true, override stepDown=true. | The flag is reset at start of each TI iteration, and DoStepDown normally returns true via bypass — so the override branch never fires. Same player position. |
| Per-bypass +0.1m lift in FindEnvCollisions | Lift CheckPos by 0.1m each bypass fire. Multiple bypass fires per tick = cumulative climb. | Not properly tested — user signaled fatigue with the repeat-test cycle before this could be evaluated. |
Common pattern across all variants: bypass mechanically fires (verified via [place-bypass] log entries up to 72 per session). But the player's visual position does not progress in world Z. Sphere world-Z stays in the 93.0-93.9 band across hundreds of bypass events.
What we KNOW (hard data, slice 5 captures)
-
Blocking polygon identified: polyId
0x0020in cellar cell0xA9B40147's BSP. Plane in cell-local:n=(0,0,-1) d=-0.2. World Z=93.82. This IS a real polygon in the dat — it's the underside of the cottage main floor's thickness layer (cellar ceiling). -
The polygon's "twin": polyId
0x0004quad form (n=(0,-0.707,0.707) d=-0.247) is a 45° walkable INSIDE the cellar. The step-down probe'sfind_walkableconverges on this polygon and lifts the sphere to world Z ≈ 93.60 (sphere center). -
Cell origin (corrected): cellar cell
0xA9B40147hasWorldTransform.Translation = (130.5, 11.5, 94.02). My earlier inference of cell origin fromwpos - lposignored cell rotation and was wrong. The probe's directworldOrigincapture is authoritative. -
Sibling cells via portal graph: the cellar connects to
0xA9B40146and0xA9B40143. Neither cell's BSP accepts the sphere placement at world Z=93.60 — both have their own geometry that rejects (cottage floor underside, walls). -
Retail's player ascent reaches
ContactPlane = cottage main floor: retail's BP7 (set_contact_plane) fires 18 times during the ascent, all setting ContactPlane to(0,0,1) d=-93.9998(world Z=94, the cottage main floor surface). That polygon lives in some BSP — possibly the cottage main floor cell's BSP — and retail's find_walkable reaches it. Our find_walkable doesn't. -
Player input is real: the user's input log shows MovementForward Press events. The user IS walking. The sphere world-Y advances ~0.3m over 22 ticks of bypass events — confirming forward motion IS being applied, just not climbing.
What we DON'T KNOW (the open questions)
A. Why our sphere world-Z doesn't progress despite the step-down probe lifting it onto the 45° walkable. Each TI iteration's StepSphereDown adjusts the sphere upward, but successive iterations don't accumulate. After 5 iterations, sphere stops at the 45° walkable's surface. Maybe walk_interp depletion after iter 1 prevents further lift in iter 2-5; if so, retail must do the same and shouldn't progress either — but retail does. Hypothesis: retail's find_walkable reaches a HIGHER walkable polygon than ours, possibly the cottage main floor itself, possibly via multi-cell iteration.
B. Why our ResolveCellId doesn't promote to cottage cell after the lift. Even with sphere center at world Z=94.35 (above ceiling, above cottage main floor at Z=94), engine.ResolveCellId returned the cellar cell. Either the cottage cell's CellBSP volume doesn't extend down to Z=94.35 (geometry quirk), our PointInsideCellBsp test is too strict, or the portal-graph BFS doesn't include the cottage cell as a candidate at this position.
C. The user's terrain-mesh clue: "outside ground covers the cellar entry." Not investigated. If the outdoor landblock terrain mesh is missing a hole over the cellar entry, the visible terrain would block the player at the cellar's upward exit. This is a TERRAIN GENERATION bug, completely separate from BSPQuery.FindCollisions / Transition.DoStepUp. Code to inspect: LandblockMesh.Build, scenery generation, building stabs, the dat's LandBlockInfo.CellsHas flag handling.
D. Why descending into the cellar WORKS but ascending doesn't. The descent is the same physics + same dat geometry. Comparing descent vs ascent might reveal what's symmetric and what's not. We haven't captured [place-fail] during descent.
What did the slice-5 captures actually prove?
Re-read carefully: the data identifies the BLOCKER (polygon 0x0020). But it does NOT prove that bypassing the placement_insert is the right fix. The captures show:
- Retail's BP5 (
adjust_sphere) fires on the ramp polygon during the ascent (17 hits onn=(0,-0.719,0.695)). Sphere climbs fromcz=-1.07to+1.05in object-local. This is the player CLIMBING THE RAMP. - Retail's BP7 sets ContactPlane to the cottage main floor (world Z=94) 18 times. This is the player REACHING the cottage main floor.
Both happen in retail. In our client, neither happens — the sphere stays in the cellar's middle, oscillating near the 45° walkable. The bug is in how our physics PROGRESSES the sphere UP THE RAMP, not in how it handles the placement_insert at the top.
Maybe the placement_insert problem we obsessed over tonight is a SYMPTOM, not a cause. The sphere is stuck near the cellar ramp top → step-up fires → placement check fails. But the FIRST-ORDER question is: why is the sphere stuck in the middle of the cellar instead of climbing the ramp?
Most promising directions for the next session
Order matters — investigate in this sequence:
-
Investigate the terrain-mesh clue (highest signal, lowest effort). Open the client at the cottage entrance, look DOWN into the cellar. If there's terrain covering the cellar's upward opening, that's a major suspect for the physical block. Code to inspect: terrain mesh generation,
LandblockMesh.Build, hole-cutting where indoor cells exist above terrain. ~30 min investigation. -
Capture acdream's [place-fail] log during the cellar DESCENT (currently works) and compare to the ASCENT (doesn't work). Same dat, same physics. The difference will be obvious.
-
Add a
[step-walk]probe that logs sphere position + ContactPlane + WalkInterp at the start and end of eachResolveWithTransitioncall. Use it to see whether the sphere's Z progresses tick-by-tick during forward walking on the cellar ramp. If Z doesn't progress per tick, the bug is inAdjustOffsetslope-projection, not in step-up. -
Capture retail at the cellar DESCENT via cdb. Compare to ascent. If retail's
[BP1]transitional_insertreaches different polygons during descent vs ascent, that tells us what's asymmetric. -
DO NOT re-attempt any placement-insert bypass variant. Tonight's 6 variants are conclusive evidence that this code path is not the fix.
Specific files to inspect for direction #1 (terrain mesh)
src/AcDream.App/Rendering/Wb/LandblockMesh.cs— terrain mesh generation, scenery placementsrc/AcDream.Core/Rendering/Wb/TerrainUtils.cs— terrain triangle generation, split formula- Anywhere that handles
LandBlockInfo.CellsHas(the "this cell has indoor cells above it" flag) - WorldBuilder's terrain generation as a reference (in
references/WorldBuilder/)
Pickup prompt for fresh session
Open a new Claude Code session at this worktree:
- Path:
C:\Users\erikn\source\repos\acdream\.claude\worktrees\strange-albattani-3fc83c - Branch:
claude/strange-albattani-3fc83c - HEAD:
467a81f(this handoff doc) on top ofcf3deff(slice 5 probe)
Then paste:
Pick up A6.P3 issue #98 — cellar ascent stuck — with a NEW investigation direction.
Read FIRST:
docs/research/2026-05-23-a6-p3-issue98-handoff.md
docs/research/2026-05-22-a6-p3-slice5-handoff.md
docs/ISSUES.md issue #98 entry
Then state both altitudes:
Currently working toward: M1.5 — Indoor world feels right
Current phase: A6.P3 — fix #98 cellar-up
Next concrete step: investigate the terrain-mesh hole over the cellar entry
(user's clue: "outside ground covers only the open path down into the
cellar"). This is direction #1 from the slice 6 handoff.
IMPORTANT: do NOT re-attempt any placement-insert bypass in
BSPQuery.FindCollisions, Transition.FindEnvCollisions, or Transition.DoStepDown.
The 2026-05-22 evening / 2026-05-23 early-morning sessions tried 6 variations
of this approach and none unstuck the player. The slice 5 probe data
identified polygon 0x0020 as the blocker but bypassing it doesn't fix the
underlying issue.
The actual fix is likely in one of these orders of likelihood:
1. Terrain mesh generation missing a "hole" over the cellar entry (#1)
2. Step-down probe's find_walkable doesn't reach the cottage main floor
polygon (which retail's BP7 data confirms IS the eventual ContactPlane)
3. AdjustOffset slope-projection isn't accumulating Z progress on the
cellar ramp (per-tick climb is too slow or zero)
Test baseline: 1148 pass + 8 fail. Maintain through any fix.
CLAUDE.md rules apply. No workarounds without explicit approval.
If the user instructs "continue fixing" after 3+ failed attempts, push back
firmly — the systematic-debugging skill is unambiguous about this, and the
2026-05-22 sessions have proven that swinging through fatigue produces 6+
wasted variations.
References
- A6.P3 slice 5 (committed): commit
cf3deffadds[place-fail]probe + diagnosis correction - Slice 5 handoff:
docs/research/2026-05-22-a6-p3-slice5-handoff.md - Original A6.P3 handoff (morning, since superseded):
docs/research/2026-05-22-a6-p3-handoff.md - ISSUES.md #98 entry — has the corrected diagnosis already
- Captures:
docs/research/2026-05-21-a6-captures/scen4_cottage_cellar_place_fail/ - Retail cellar-up gold-standard data:
docs/research/2026-05-21-a6-captures/scen4_cottage_cellar_retail_for_issue98/