acdream/docs/research/2026-06-02-phase-w-w2a-shipped-baseline-handoff.md
Erik 3622a658fd docs(render): Phase W — W2a shipped+verified + baseline handoff
W2a (render reads physics CurrCell) visually verified: indoor world-from-below fixed (cellar/stairs seal). Baseline scopes the residuals: W2b (doorway ping-pong 0170<->0031, confirmed) + W3 (one-gate seal: roof, entity bleed, openings) + the EnvCellRenderer GL_BLEND fix (transparent walls). Membership (W2) done.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 10:55:21 +02:00

153 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase W (Unified Cell Graph) — W2a shipped + baseline handoff (2026-06-02)
> **Canonical pickup for the next session.** This session pivoted the indoor render work
> to a full retail `CObjCell` cell-graph migration (Phase W), shipped **W1** (scaffold) and
> **W2a** (render reads physics membership), visually verified W2a (the indoor "world from
> below" is fixed), and captured a scoped baseline of the remaining residuals. Read this
> first, then the W2 spec/plan + the evidence doc.
## 0. Git / safety state
- **Branch `claude/thirsty-goldberg-51bb9b` — UNPUSHED.** Do not push without the user.
- **Two git stashes preserved — do NOT drop:** `stash@{0}` (#98/#101/A8-culling WIP),
`stash@{1}` (issue98 backup).
- Working tree clean except throwaway untracked `baseline-w2a-*.png` / `shot-*.png` /
`launch*.log` (the baseline evidence — ephemeral, do not commit; delete freely).
- HEAD = `02acac5`.
## 1. What shipped this session (commit ledger, oldest→newest)
| SHA | What |
|---|---|
| `e8c7164` | Pivot decision: evidence model + W1 (ObjCell scaffold) spec |
| `bd0244f` | W1 implementation plan |
| `9cb1571` | W1 T1 — `ObjCell` base + `CellPortal` |
| `76c9e2f` | W1 T2 — `EnvCell` + `PointInCell` (AABB/BSP) |
| `5bc72d5` | W1 T3 — `EnvCell.FromDat` (mirrors `BuildLoadedCell`) |
| `03f08f0` | W1 T3 fix — `ResolvePortalPolygon` all-or-nothing (review caught a real latent Stage-3 bug) |
| `b4c4318` | W1 T4 — `LandCell` synthesized from `TerrainSurface` |
| `cf5d60d` | W1 T5 — `CellGraph` resolver + registry + inert `CurrCell` |
| `1aede3d` | W1 T6 — real cottage-cell fixture grounding test |
| `8e703be` | W1 T7 — populate `CellGraph` from `CacheCellStruct` + `AddLandblock` (inert) |
| `f2663b7` | W1 final-review polish (Opus review: VisibleCells null-guard + Neighbor doc) |
| `07e68e0` | Roadmap — register Phase W; W1 shipped |
| `83c452b` | W2 (one membership) spec + plan |
| `0e27a6c` | **W2 T1**`ResolveCellId` writes `CellGraph.CurrCell` (additive/write-only) |
| `02acac5` | **W2 T2** — render root from physics `CurrCell` (`FindCameraCell` fallback) |
Specs/plans: `docs/superpowers/specs/2026-06-02-unified-cell-graph-stage1-design.md`,
`.../2026-06-02-unified-cell-graph-stage2-design.md`,
`docs/superpowers/plans/2026-06-02-unified-cell-graph-stage1.md`,
`.../2026-06-02-unified-cell-graph-stage2.md`. Evidence: `docs/research/2026-06-02-render-cell-membership-evidence.md`.
## 2. The program (Phase W, 5 stages — see roadmap)
W1 ObjCell scaffold (**shipped**) → **W2 one membership** (W2a shipped+verified; **W2b next**) →
W3 render on the graph / one gate → W4 collision on the graph → W5 streaming → ObjCells.
The architecture: ONE retail `CObjCell` cell graph (`AcDream.Core.World.Cells`) shared by
physics + render (+ later collision + streaming). Membership is physics-owned (`ResolveCellId`
`CellGraph.CurrCell`); render reads it.
## 3. W2a — VERIFIED result
Render now reads the physics membership answer (`CellGraph.CurrCell`) as its visibility root,
with a `FindCameraCell` fallback (so it can't regress below baseline). **Visually verified
2026-06-02** at the Holtburg cottage:
- **The indoor "world from below" is fixed.** Spawning directly in the cellar and standing
still: `[vis]=15, [shell]=19448` (baseline spawn-in was **0/0** = render never engaged →
terrain/world drawn). The cellar/stairs now seal walls+floor; render follows physics
through the cottage.
- Tests: W2 T1 + T2 spec-reviewed; 166+ Core/App tests green; App builds 0/0.
- W2a is **membership only** — it does NOT seal the full interior (that's W3).
## 4. Baseline of the W2a residuals (scoped by owner — the next-work map)
Captured across cellar / stairs / room / doorway (screenshots `baseline-w2a-*.png`, ephemeral).
**None of these are W2 membership** — that's done.
| Residual | Where | Probe-grounded cause | Owner |
|---|---|---|---|
| Missing ceiling / open roof | cellar, stairs | ceiling not capped by the drawn shells | **W3** (seal) |
| Entities bleed through (NPCs / doors / smoke pillars / particles) | everywhere indoors | entities drawn **ungated** — not clipped to the visible cells | **W3** (entity gate) |
| Openings show "bluish world" | cellar entrance, doorway | openings reveal clear-color/sky instead of the adjacent cell | **W3** (clip) |
| Transparent interior walls | room | opaque shells (`[shell] tr=0 zh=0`) render transparent → `EnvCellRenderer` inherits a leftover `GL_BLEND`; opaque texels composite against the bluish clear color | **Render GL-state fix** (memory `render-self-contained-gl-state`) |
| **Doorway ping-pong `0170↔0031`** | threshold | physics cell flips indoor↔outdoor at a near-static position; **no stab-list prune** | **W2b** (confirmed needed) |
**Key cross-cutting observation:** the PView *builder* (`PortalVisibilityBuilder`) computes
sensible visible-cell sets (15 cells depending on root) AND non-empty `OutsideView` clip
regions at exit portals (`[vis] root=0171 outside(polys=1,planes=4)` from the room's front
door). The problem is the render **gates don't all obey** that output — entities draw
ungated, the ceiling isn't drawn/capped, openings show the background. **That is exactly
W3's "compute visibility once, enforce it once for ALL geometry."**
## 5. Ping-pong evidence (W2b is needed, not optional)
At the doorway threshold, `[cell-transit]` shows the physics cell flipping at a near-static
position:
```
0xA9B40170 -> 0xA9B40031 pos=(155.054,16.569,94.000)
0xA9B40031 -> 0xA9B40170 pos=(155.075,16.522,94.000)
0xA9B40170 -> 0xA9B40031 pos=(155.035,16.610,94.000)
0xA9B40031 -> 0xA9B40170 pos=(155.129,16.403,94.000)
```
`0170` (indoor) ↔ `0031` (outdoor) at ~(155.1, 16.5). W2b's stab-list prune (hold the indoor
cell unless the outdoor candidate is in `CurrCell.StabList`) is the retail-faithful fix the
#98 saga never tried. Plan: W2 plan **Task 3** (`docs/superpowers/plans/2026-06-02-unified-cell-graph-stage2.md`).
## 6. Apparatus / how to reproduce
- Launch (per CLAUDE.md "Running the client") with
`ACDREAM_PROBE_SHELL=1 ACDREAM_PROBE_VIS=1 ACDREAM_PROBE_CELL=1 ACDREAM_PROBE_ENVCELL=1`.
Pipe to a log via `Tee-Object`**note the log is UTF-16**; read it with the ripgrep-based
Grep tool or PowerShell `Get-Content`, NOT GNU `grep` (silently matches nothing).
- Screenshots: PowerShell `System.Drawing` `CopyFromScreen` on the `AcDream.App`
`MainWindowHandle` → PNG → `Read` the PNG. (Capture loop used this session; works.)
- Probes: `[vis]` (root + visible cells + OutsideView poly/plane counts), `[shell]` (per-cell
shell render + `tr`/`zh` flags), `[cell-transit]` (physics CellId changes + reason),
`[envcells]`. ACE respawns at last logout position (likely the cellar `0xA9B40171/0174`).
- Cottage cells: `0171` room (Z94), `0175` stairs (Z93), `0174` cellar (Z90), `0172/0173`
room sub-cells, `0170` vestibule; outdoor neighbours `0031/0032`.
## 7. Do-NOT-repeat / settled facts
- **W2a (membership) is done** — the residuals are W2b/W3/GL-state, NOT membership. Don't
re-investigate "why doesn't render engage" — it does now.
- The transparent walls are NOT translucent geometry (`tr=0`) — it's the `EnvCellRenderer`
inherited-`GL_BLEND` bug (memory `render-self-contained-gl-state`, item 3). Mirror
`WbDrawDispatcher`'s per-pass `Disable/Enable(Blend)` + `DepthMask`.
- The PView builder works; don't rebuild it. W3 makes the GATES obey it.
- Disproven earlier (do not revisit): camera/eye as root, cull mode, shell geometry/texture
missing, stencil-mask-breaks-outdoors, flag-based per-entity gate routing.
## 8. Pickup prompt (copy-paste for the next session)
```
PHASE W (Unified Cell Graph) — continue on branch claude/thirsty-goldberg-51bb9b
(do NOT branch/worktree). Preserve the 2 git stashes — do not drop. Branch UNPUSHED — ask
before pushing. HEAD = 02acac5.
READ FIRST, in full: docs/research/2026-06-02-phase-w-w2a-shipped-baseline-handoff.md, then
the W2 spec docs/superpowers/specs/2026-06-02-unified-cell-graph-stage2-design.md + plan
docs/superpowers/plans/2026-06-02-unified-cell-graph-stage2.md, then the evidence doc
docs/research/2026-06-02-render-cell-membership-evidence.md.
STATE: M1.5 "indoor world feels right." Phase W = full retail CObjCell cell-graph migration,
5 stages. W1 (ObjCell scaffold) SHIPPED. W2a (render reads physics CurrCell) SHIPPED +
visually verified — the indoor "world from below" is FIXED (cellar/stairs seal walls+floor).
W2 membership is done. Remaining residuals are scoped in the handoff §4.
DO NEXT (in order):
1. W2b — stab-list doorway hysteresis (CONFIRMED needed: ping-pong 0170<->0031 at the
threshold, handoff §5). Implement W2 plan Task 3 (port retail find_cell_list do_not_load_cells
prune into PhysicsEngine.ResolveCellId; hold indoor cell unless the outdoor candidate is in
CurrCell.StabList). Behavior-changing -> visual-verify the ping-pong stops, then W2 T4
(flip W2 shipped in roadmap). Subagent-driven per the plan.
2. W3 — render on the graph / ONE gate (spec it first via superpowers:brainstorming, grounded
in the handoff §4). Make ALL geometry obey the PView output: draw the ceiling/cap cell,
CLIP ENTITIES to the visible cells (kills the NPC/door/smoke bleed), clip the outside to
exit-portal openings (kills "bluish world" through openings). The PView builder already
produces sensible visible sets + OutsideView regions — W3 makes the gates obey them.
Fold in the EnvCellRenderer inherited-GL_BLEND fix (transparent walls; memory
render-self-contained-gl-state) here or as a standalone render-GL-state fix.
EVIDENCE-FIRST for any render/visual question: launch with ACDREAM_PROBE_SHELL/VIS/CELL/ENVCELL,
screenshot (PowerShell CopyFromScreen on AcDream.App), read the UTF-16 log with ripgrep/PowerShell
(NOT GNU grep). Cottage cells: 0171 room, 0175 stairs, 0174 cellar, 0170 vestibule, 0031/0032
outdoor. Visual verification at the cottage is the acceptance gate for W2b + W3.
DO NOT REPEAT: W2a membership is done (render engages now); transparent walls = EnvCellRenderer
inherited GL_BLEND (not translucent geometry); the PView builder works (W3 fixes the GATES, not
the builder); camera/eye-as-root + stencil-mask-breaks-outdoors + flag-based gate routing are
all evidence-disproven.
```