# Indoor ContactPlane retention — fresh-session pickup prompt

**Status:** Indoor walkable-plane BSP port foundation shipped to main 2026-05-19 at `c6b3fd6` (8 commits between `165f67a` spec and `c6b3fd6` handoff). Visual verification FAILED — cellar descent, 2nd-floor walking, single-floor cottage regression. Root cause diagnosed deeper than originally thought: the per-frame `TryFindIndoorWalkablePlane` synthesis is a Phase 2 stop-gap retail never had; retail RETAINS `ContactPlane` across frames.

This doc is the start-of-session brief for whoever picks up the next phase.

---

## What's on main

**Foundation (kept, useful):**
- `BSPQuery.FindWalkableInternal` exposes `ref ushort hitPolyId`.
- New public `BSPQuery.FindWalkableSphere` wrapper over the retail-faithful walkable finder.
- `Transition.TryFindIndoorWalkablePlane` routes through the BSP walker with `WalkableAllowance` save/restore.
- `[indoor-walkable]` runtime-toggleable diagnostic probe at the `FindEnvCollisions` callsite.
- 5 new unit tests + 9 updated existing tests + 1 wall-poly integration test, all green.
- `dotnet build -c Debug` clean; 8 pre-existing test baseline unchanged.

**Behavioral result:** ISSUES #83 remains OPEN. Cellar descent fails ("ground blocking" — outdoor terrain backstop returns wrong Z). 2nd-floor walking gets intermittent falling-stuck. Single-floor cottage REGRESSED from stable (Phase 2) to intermittent falling-stuck. Phantom collisions persist. Probe captured 1443 MISS / 2 HIT — the foot-sphere-tangent-to-floor case is rejected by `PolygonHitsSpherePrecise`'s `|dist| > radius - epsilon` check (~0.0002 margin), which is correct retail behavior but wrong for this caller.

**Comprehensive handoff:** [`docs/research/2026-05-19-indoor-walkable-plane-bsp-port-shipped-handoff.md`](2026-05-19-indoor-walkable-plane-bsp-port-shipped-handoff.md). Read this FIRST.

---

## How to start a fresh session

Copy the block below into a fresh Claude Code session in this repo.

---

```
Pick up the acdream project. The Indoor walkable-plane BSP port shipped
to main 2026-05-19 at c6b3fd6 — 8 commits of foundation work — but
visual verification by the user FAILED to fix the indoor walking bugs
(cellars, 2nd floors, phantom collisions). Foundation is good and
stays on main; the root cause was deeper than I diagnosed.

1. Read docs/research/2026-05-19-indoor-walkable-plane-bsp-port-shipped-handoff.md
   FIRST. Long but complete: what shipped, what failed, the probe
   evidence (1443 MISS / 2 HIT), the deeper diagnosis, the recommended
   next phase target, session lessons. The "Session lessons" section
   at the bottom is important — I made specific mistakes that you
   should not repeat.

2. The recommended next phase: port retail's ContactPlane retention.
   Retail RETAINS the previous frame's ContactPlane when the BSP
   reports "no collision" — it doesn't re-synthesize per frame the way
   our Phase 2 commit eb0f772 introduced. The proper fix likely
   eliminates Transition.TryFindIndoorWalkablePlane entirely from the
   FindEnvCollisions per-frame path. Retail decomp anchors are in the
   handoff doc; key starting points:

   - acclient_2013_pseudo_c.txt:273137 — CTransition::transitional_insert
   - Search the decomp for "last_known_contact_plane" and
     "contact_plane_valid" to map the full ContactPlane lifecycle.
   - Grep our acdream code for ContactPlane writers/readers to map
     who currently sets it and when.

3. Use the brainstorming skill FIRST. But before designing a spec,
   SPIKE: add a small diagnostic probe that logs every ContactPlane
   write site with caller, old plane, new plane. Capture a log of the
   user walking around indoors. Look at the data BEFORE designing the
   fix. That's the lesson from the previous session — I designed a
   spec on a wrong hypothesis and shipped 6 commits before the
   diagnostic probe surfaced the truth. Probe-first, design-second.

4. CLAUDE.md rules apply:
   - No workarounds; fix root causes. (Specifically: do NOT add a
     sphere-offset hack to make PolygonHitsSpherePrecise accept
     tangent contact. The right answer is to stop calling find_walkable
     as a standing-still query.)
   - Use superpowers skills (brainstorming → writing-plans →
     subagent-driven-development → finishing-a-development-branch).
   - Drive autonomously — Claude picks the next step, user reviews.
   - Visual verification by the user is the acceptance test for any
     physics/collision change.

5. Foundation work to KEEP (the previous session's commits):
   - BSPQuery.FindWalkableSphere wrapper — useful for legitimate
     "find a walkable indoors" queries (spawn-placement, teleport-
     target verification), just not per-frame from FindEnvCollisions.
   - FindWalkableInternal's hitPolyId ref param.
   - The [indoor-walkable] probe (will fire less often once retention
     is in place — that's expected).
   - All 14 tests (5 new BSPQuery + 9 updated IndoorWalkablePlane).

   Foundation work to LIKELY DELETE or refactor:
   - Transition.TryFindIndoorWalkablePlane — likely deleted entirely,
     OR kept as an out-of-band synthesis path for edge cases (initial
     spawn, cell-id promotion mid-frame) but NOT called per-frame.
   - The per-frame call from FindEnvCollisions:1380.

6. The user has limited tolerance for repeated failed visual
   verifications. Be especially disciplined this time: capture
   diagnostic evidence early, validate the hypothesis against the
   probe data BEFORE designing the fix, present the smallest
   possible change that addresses the root cause.

State the milestone and your chosen phase in the first action you
take. Then begin.
```

---

## Quick reference for the user

To start the new session: open a fresh Claude Code in the acdream repo and paste the boxed prompt above. Or just say:

> "Read `docs/research/2026-05-19-contactplane-retention-pickup-prompt.md` and start on the next phase."

## Quick reference for the helper

Key files / anchors for the investigation:

- **Handoff:** `docs/research/2026-05-19-indoor-walkable-plane-bsp-port-shipped-handoff.md` — the canonical record of what just shipped and the deeper diagnosis.
- **ISSUES #83:** Updated 2026-05-19 with the deeper diagnosis. Still OPEN.
- **Foundation spec (for context, do not re-execute):** `docs/superpowers/specs/2026-05-19-indoor-walkable-plane-bsp-port-design.md`.
- **Foundation plan (for context, do not re-execute):** `docs/superpowers/plans/2026-05-19-indoor-walkable-plane-bsp-port.md`.
- **Retail decomp anchors:**
  - `acclient_2013_pseudo_c.txt:273137` — `CTransition::transitional_insert`
  - `acclient_2013_pseudo_c.txt:273099` — `CTransition::step_up`
  - `acclient_2013_pseudo_c.txt:323565` — `BSPTREE::step_sphere_up`
  - Search for `last_known_contact_plane` and `contact_plane_valid` for the retention machinery.
- **acdream code:**
  - `src/AcDream.Core/Physics/TransitionTypes.cs:1192` — `TryFindIndoorWalkablePlane` (likely to delete in the next phase).
  - `src/AcDream.Core/Physics/TransitionTypes.cs:1262` — `FindEnvCollisions` indoor branch (where the per-frame `TryFindIndoorWalkablePlane` call happens at line ~1380).
  - `src/AcDream.Core/Physics/PhysicsDiagnostics.cs` — `ProbeIndoorBspEnabled` flag (reuse for any new diagnostic probe).
  - Grep `ContactPlane` across `src/AcDream.Core/Physics/` to find all write sites.

## Visual verification scenarios (re-use for the next phase)

1. **Cellar descent** — the primary failing scenario. Walk into any building with a cellar entry, descend the stairs. Acceptance: smooth descent onto cellar floor.
2. **2nd-floor walking** — climb stairs to 2nd floor, walk around. Acceptance: no intermittent falling-stuck.
3. **Single-floor cottage regression check** — walk into a Holtburg cottage. Acceptance: stable walking, no intermittent falling-stuck (Phase 2 baseline restored).
4. **Phantom collisions** — observational. If root cause is fixed, these should improve.

## Launch command (for the user, with probes enabled)

```powershell
$env:ACDREAM_DAT_DIR   = "$env:USERPROFILE\Documents\Asheron's Call"
$env:ACDREAM_LIVE      = "1"
$env:ACDREAM_TEST_HOST = "127.0.0.1"
$env:ACDREAM_TEST_PORT = "9000"
$env:ACDREAM_TEST_USER = "testaccount"
$env:ACDREAM_TEST_PASS = "testpassword"
$env:ACDREAM_DEVTOOLS  = "1"
$env:ACDREAM_PROBE_INDOOR_BSP = "1"
dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 | Tee-Object -FilePath "launch-contactplane.log"
```
