# L.2a shipped — L.2d direction confirmed — Cold-Start Handoff

**Created:** 2026-05-12 evening, immediately after the L.2a-slice-1/2/3 work landed and visual-verified.
**Audience:** the next agent picking up Phase L.2 (Movement & Collision Conformance).
**Purpose:** give you everything you need to start L.2d brainstorming cold, without spelunking through this session's transcript.

---

## TL;DR

Phase L.2a (Truth & Diagnostics) shipped three slices tonight. They surfaced **three concrete L.2 findings** with reproducible evidence — converting "we should look at this someday" theories into "here is the entity id, here is the wall normal, here is the cell id." With those findings in hand, the next concrete physics work in the L.2 roadmap is **L.2d slice 1 — port `CBuildingObj` collision so doorway gaps are walkable.** Brainstorm + spec, then port.

**Three slices shipped to `claude/intelligent-poitras-b2c4f9`:**

| Commit | What | Why |
|---|---|---|
| [`ebef820`](.) | L.2a slice 1: `[resolve]` + `[cell-transit]` probes + DebugPanel mirror | Foundation for every later L.2 change to be evidence-driven |
| [`e0c08bc`](.) | L.2a slice 2: surface hit object guid in `[resolve]` line | Tell us WHICH entity is the wall, not just the wall normal |
| [`a068292`](.) | L.2a slice 3: populate the previously-stub `CollisionInfo.CollideObjectGuids` / `LastCollidedObjectGuid` | Slice 2 found these fields were declared but never written — fixed the structural gap |

---

## Three findings from the L.2a probes

All produced by walking around Holtburg + pushing W into a Town doorway with `ACDREAM_PROBE_RESOLVE=1 ACDREAM_PROBE_CELL=1`.

### Finding 1 — L.2e cell-id format gap (DEFINITIVE)

The player's tracked `CellId` is being recorded as a **bare low byte** (`0x00000029`), with no landblock prefix. AC cell ids are normally `0xLLLLCCCC` — landblock id (4 hex digits) + cell-within-landblock (4 hex digits, `0x0001-0x00FF` outdoor or `0x0100+` indoor).

Evidence from a tonight log:

```
[cell-transit] 0x00000001 -> 0x00000029 pos=(132.585,21.015,94.000) reason=resolver
```

NPCs in the same area show MIXED forms in their resolve lines:
- `cell=0xA9B3000E` ← full landblock-prefixed (correct)
- `cell=0x00000032` ← bare low byte (matches the bug shape)

Likely source: `ResolveOutdoorCellId(...)` at [src/AcDream.Core/Physics/PhysicsEngine.cs:687](src/AcDream.Core/Physics/PhysicsEngine.cs:687) — that's the function that ResolveWithTransition routes the output cell id through before returning. Worth grepping for its body.

This is the L.2e blocker per the plan-of-record:
> *"Update low outdoor cell id across 24m cell boundaries and landblock seams. Port the retail adjacent-cell search: `find_cell_list`, `check_other_cells`, and `adjust_check_pos`."*

### Finding 2 — L.2c wall-slide is working

The transition layer at this spot does the retail-faithful thing:

```
[resolve] ent=0x000F4240 in=(132.067,17.567,94.000) cell=0x00000029
          tgt=(132.239,17.172,94.000)
          out=(131.938,17.567,94.000) cell=0x00000029
          ok=True groundedIn=True cp=valid hit=yes n=(0.00,1.00,0.00)
          obj=0xA9B47900 walkable=True
```

- Wall normal `(0, 1, 0)` — vertical wall facing +Y, captured correctly.
- `out` shows the position clamped along the wall: X slid back from 132.067 → 131.938, Y preserved.
- `ok=True` — resolver completed normally (no `ok=False` anywhere in the trace, 0/140).

**No L.2c work needed at this site.** Edge-slide / wall-slide port from earlier (per the plan-of-record's L.2c "Current shipped slice" note) is doing its job here.

### Finding 3 — L.2d sub-direction = CBuildingObj port (NOT door-toggle)

All 140 hit=yes lines in the doorway-push test came back with the **same dominant `obj=` attribution**:

| obj | hits | range | what it is |
|---|---|---|---|
| **`0xA9B47900`** | **126** | `0xLLLLxxxx` (landblock-baked static) | The Holtburg building itself — its baked collision mesh |
| `0x000F4245` | 14 | `0x000Fxxxx` (local-spawn entity) | An NPC standing near the doorway |

`0xA9B4` matches the Holtburg landblock prefix we logged at startup (`loading world view centered on 0xA9B4FFFF`). The `0x7900` low bytes is its landblock-local entity id. **It's the building's baked collision shape — not a door entity, not a creature.**

**Implication:** the "doorway is blocked" symptom is NOT a door-collision-not-toggled bug (which would have shown a door-range entity id, typically `0xCC0Cxxxx`). It's a **building-mesh fidelity issue**: the building's baked collision data we're loading represents the building as a solid block with no walkable opening where the visual doorway is.

Two non-mutually-exclusive interpretations:
1. **Collision-mesh extraction is wrong** — we load building geometry but don't respect the BSP nodes that encode doorway openings.
2. **`CBuildingObj` + per-cell walkability is not ported** — retail uses a per-cell `CObjCell` structure that maps "this interior cell is reachable" / "this exterior cell connects to those interior cells." Without that, we treat the building as one opaque collision volume.

The plan-of-record's L.2d goal:
> *"Preserve enough building identity to model `CBuildingObj` collision and `bldg_check` behavior."*

points at interpretation 2 as the canonical fix.

---

## What this session deliberately did NOT do

- **Other L.2a slices** (contact-plane probe, ShadowObject hit log, water probe, real-DAT fixture-capture pipeline). Slice 1 + 2 + 3 cover the most-load-bearing case (resolver outcomes + cell transits + entity attribution). The remaining diagnostics serve future L.2 work and can ship opportunistically.
- **L.2d implementation or brainstorm.** Deliberately parked for a fresh session with this evidence as cold-start context.
- **L.2e implementation.** The cell-id format finding is filed but not investigated.
- **Pre-existing test failures.** 8 tests fail at the branch base (none from these slices — verified by stash + rerun on every test cycle). Not from this slice. See "Open concerns" below.

---

## Branch state at handoff

- Branch: `claude/intelligent-poitras-b2c4f9`
- Three slice commits ahead of `eab347d` (the C.1.5b merge into main), plus a docs commit that adds this handoff + the next-session prompt + plan-of-record / CLAUDE.md updates.
- Tonight's last code commit was `a068292` (L.2a slice 3); docs commit follows.
- Worktree clean post-docs-commit; merge to main is the user's planned next operation.

## What's now in the diagnostic surface

Live env vars (both can be flipped at runtime via the DebugPanel "Diagnostics" section if `ACDREAM_DEVTOOLS=1`):

- **`ACDREAM_PROBE_RESOLVE=1`** — one `[resolve]` line per `PhysicsEngine.ResolveWithTransition` call:
  ```
  [resolve] ent=0xEEEEEEEE in=(x,y,z) cell=0xCCCCCCCC tgt=(x,y,z) out=(x,y,z) cell=0xCCCCCCCC ok=Y/N groundedIn=Y/N cp=valid|lastKnown|none hit=yes n=(nx,ny,nz) obj=0xOOOOOOOO env nObj=N walkable=Y/N
  ```
  Heavy: fires for every entity's resolve per physics tick.
- **`ACDREAM_PROBE_CELL=1`** — one `[cell-transit]` line per `PlayerMovementController.CellId` change:
  ```
  [cell-transit] 0xOLD -> 0xNEW pos=(x,y,z) reason=resolver|teleport
  ```
  Low volume — only fires on actual cell crossings.

Both backed by `AcDream.Core.Physics.PhysicsDiagnostics` static class (initial from env var, set/get from anywhere at runtime).

## Files changed in this session

```
src/AcDream.Core/Physics/PhysicsDiagnostics.cs              (new)
src/AcDream.Core/Physics/PhysicsEngine.cs                   (modified — probe emission)
src/AcDream.Core/Physics/TransitionTypes.cs                 (modified — entity attribution plumbing)
src/AcDream.App/Input/PlayerMovementController.cs           (modified — UpdateCellId chokepoint)
src/AcDream.UI.Abstractions/Panels/Debug/DebugVM.cs         (modified — Probe* forwarder props)
src/AcDream.UI.Abstractions/Panels/Debug/DebugPanel.cs      (modified — two new checkboxes)
docs/plans/2026-04-29-movement-collision-conformance.md     (modified — shipped-slice note + L.2d sub-direction)
```

## Open concerns flagged but NOT addressed in this session

- **8 pre-existing test failures** on the branch base, verified by stash+rerun: `MotionInterpreterTests.GetMaxSpeed_*` (3), `PositionManagerTests.ComputeOffset_BothActive_Combined`, `PlayerMovementControllerTests.Update_ForwardInput_MovesInFacingDirection`, `DispatcherToMovementIntegrationTests.Dispatcher_W_held_produces_forward_motion`, `BSPStepUpTests.{D4_AirborneMover_TallWall_PersistsSlidingNormalAcrossFrames,C3_Path6_AirborneMoverHitsSteepSlope_SetsCollide}`. Most touch movement/physics code we're about to evolve in L.2b/L.2c/L.2d — **triage before further L.2 work** is recommended.
- **Player entity id quirk.** Local player physics entity id observed as `0x000F4240` in the resolve probe, not the server guid `0x5000000A`. This is presumably the dat/local-spawn entity id — fine for diagnostic, worth keeping in mind for any future "is this the player?" check.

## Cold-start checklist for L.2d brainstorm

1. Read this handoff.
2. Read [docs/plans/2026-04-29-movement-collision-conformance.md](docs/plans/2026-04-29-movement-collision-conformance.md) — focus on L.2d section.
3. Read the L.2d named-retail anchors:
   - `CCellStruct::point_in_cell`, `CCellStruct::sphere_intersects_cell`, `CCellStruct::box_intersects_cell`
   - `CBuildingObj::find_building_collisions`
   - `CObjCell::find_cell_list` (already shared with L.2e)
   Grep `docs/research/named-retail/acclient_2013_pseudo_c.txt` by `class::method`.
4. Read [src/AcDream.Core/Physics/TransitionTypes.cs:1386](src/AcDream.Core/Physics/TransitionTypes.cs:1386) — current `FindObjCollisions` loop, where building objects currently route through generic BSP/Cylinder paths.
5. Read [src/AcDream.Core/Physics/PhysicsDataCache.cs](src/AcDream.Core/Physics/PhysicsDataCache.cs) — how we currently load BSP / GfxObj data; figure out if building-specific data (interior cells, `CBuildingObj`) is loaded but not consumed.
6. Cross-reference WorldBuilder (`references/WorldBuilder/`) for any building-cell handling already present.
7. Brainstorm the slice (`superpowers:brainstorming` if useful) — scope, named-retail anchors, conformance tests, real-DAT fixtures.
8. Write a spec at `docs/superpowers/specs/2026-05-13-l2d-cbuildingobj-collision-design.md`.
9. Implement in slices with conformance citations in each commit.

## Reproducing the doorway evidence

In case you want to re-capture the trace:

```powershell
# In the project worktree
$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_CELL = "1"
$env:ACDREAM_PROBE_RESOLVE = "1"
dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 | Tee-Object -FilePath "launch.log"
```

Walk acdream up to a Holtburg building doorway. Hold W into it for ~2 seconds. Close. Grep `launch.log` for:
- `cell-transit` — cell tracking
- `\[resolve\].*hit=yes` — wall hits with object attribution

Wall entity should appear as `obj=0xA9B47XXX` for the same Holtburg building, OR a different `0xA9Bxxxxx` for other buildings in the area.
