diff --git a/docs/research/2026-05-23-a6-p3-issue98-handoff.md b/docs/research/2026-05-23-a6-p3-issue98-handoff.md new file mode 100644 index 0000000..de53c3c --- /dev/null +++ b/docs/research/2026-05-23-a6-p3-issue98-handoff.md @@ -0,0 +1,165 @@ +# 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) + +1. **Blocking polygon identified:** polyId `0x0020` in cellar cell `0xA9B40147`'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). + +2. **The polygon's "twin":** polyId `0x0004` quad form (n=(0,-0.707,0.707) d=-0.247) is a 45° walkable INSIDE the cellar. The step-down probe's `find_walkable` converges on this polygon and lifts the sphere to world Z ≈ 93.60 (sphere center). + +3. **Cell origin (corrected):** cellar cell `0xA9B40147` has `WorldTransform.Translation = (130.5, 11.5, 94.02)`. My earlier inference of cell origin from `wpos - lpos` ignored cell rotation and was wrong. The probe's direct `worldOrigin` capture is authoritative. + +4. **Sibling cells via portal graph:** the cellar connects to `0xA9B40146` and `0xA9B40143`. Neither cell's BSP accepts the sphere placement at world Z=93.60 — both have their own geometry that rejects (cottage floor underside, walls). + +5. **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. + +6. **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 on `n=(0,-0.719,0.695)`). Sphere climbs from `cz=-1.07` to `+1.05` in 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:** + +1. **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. + +2. **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. + +3. **Add a `[step-walk]` probe** that logs sphere position + ContactPlane + WalkInterp at the start and end of each `ResolveWithTransition` call. 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 in `AdjustOffset` slope-projection, not in step-up. + +4. **Capture retail at the cellar DESCENT** via cdb. Compare to ascent. If retail's `[BP1]` `transitional_insert` reaches different polygons during descent vs ascent, that tells us what's asymmetric. + +5. **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 placement +- `src/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 of `cf3deff` (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 `cf3deff` adds `[place-fail]` probe + diagnosis correction +- Slice 5 handoff: [`docs/research/2026-05-22-a6-p3-slice5-handoff.md`](2026-05-22-a6-p3-slice5-handoff.md) +- Original A6.P3 handoff (morning, since superseded): [`docs/research/2026-05-22-a6-p3-handoff.md`](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/`