# Phase A8 — Render-Frame Restructure to WB-Faithful Order Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Replace the R3.5 v2 "frankenstein" render frame (initial terrain + depth-clear-if-inside + stencil pipeline, three workarounds stacked) with WorldBuilder's `RenderInsideOut` order verbatim. Close R4 Issue B (sky doesn't render through windows). Match the proven reference. Pre-restructure falsification spike (RR0) determines whether R4 Issues A + C are pre-existing on `main` (out of A8 scope) or A8-caused (re-brainstorm before continuing). **Architecture:** Skip initial sky + terrain at the start of the render frame when the camera is inside a cell; delete the depth-clear-if-inside block entirely; inside the indoor branch insert a stencil-gated `_skyRenderer.RenderSky` step (DepthMask off) between `EnableOutdoorPass` and the terrain re-draw so windows show real sky; unify the two-flag asymmetry (`cameraInsideCell` lenient + `cameraReallyInside` strict) into a single strict `cameraInside` flag computed via `PointInCell`. Grace mechanism in `CellVisibility` stays alive for non-render consumers. **Tech Stack:** C# .NET 10, Silk.NET (OpenGL 4.3 + GL_ARB_bindless_texture + GL_ARB_shader_draw_parameters), xUnit. **Predecessor context (REQUIRED reading before starting):** - [docs/superpowers/specs/2026-05-26-phase-a8-restructure-design.md](../specs/2026-05-26-phase-a8-restructure-design.md) — the approved design this plan implements - [docs/research/2026-05-26-a8-r3.5-restructure-handoff.md](../../research/2026-05-26-a8-r3.5-restructure-handoff.md) — full handoff covering the R3.5 v1+v2 saga and architectural mismatch - [references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/VisibilityManager.cs:73-239](../../../references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/VisibilityManager.cs) — the proven WB reference; the restructure must match this verbatim through Step 4. Step 5 (3-stencil-bit cross-building) stays deferred. **Infrastructure preserved (consume as-is — these are already shipped + tested):** - `src/AcDream.App/Rendering/IndoorCellStencilPipeline.cs` — `UploadPortalMesh` / `MarkAndPunch` / `EnableOutdoorPass` / `DisableStencil` - `src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs` — `EntitySet.{IndoorPass, OutdoorScenery, LiveDynamic, All}` partition (R2) - `src/AcDream.Core/World/WorldEntity.cs` — `IsBuildingShell` flag (R1) - `src/AcDream.App/Rendering/CellVisibility.cs` — `PointInCell` static, `ComputeVisibility`, `FindCameraCell` with grace mechanism **HEAD at start of session:** `2bfeafd` (R3.5 v2) **Clean revert points:** `60f07bc` (R3 baseline) or further back to `55f26f2` (R2) --- ## File Structure | File | What changes | Why | |---|---|---| | `docs/research/2026-05-26-a8-rr0-falsification-findings.md` | NEW doc capturing RR0 outcome on three branches | Decision evidence for whether A+C are A8-caused or pre-existing | | `src/AcDream.App/Rendering/GameWindow.cs` | Render-frame block, lines ~7011–7260: gate-flag rename + skip-sky+terrain when inside + delete-depth-clear + add stencil-gated sky inside indoor branch | The restructure itself | | `src/AcDream.App/Rendering/SkyRenderer.cs` | READ ONLY in RR3; possibly a small wrapper invocation in `GameWindow.cs` if dirty | Pre-flight verify stencil state contract | | `docs/ISSUES.md` | Move #78 to "Recently closed"; file new follow-ups (cross-cell-portal, cellar Z-fight from outside, and A/C if RR0 confirms pre-existing on main) | Ship docs | | `CLAUDE.md` | Update A8 paragraph: `PAUSED` → `SHIPPED 2026-05-2X` with the restructure commit list | Roadmap discipline | **Decomposition rationale:** the restructure is localized to one render-frame block in one file. The other files are docs. Six tasks because of the mandatory pre-spike (RR0) and the SkyRenderer verification (RR3); the core restructure is one commit (RR2). --- ## Task RR0: Falsification spike — are Issues A + C pre-existing or A8-caused? **Goal:** Determine whether R4 Issues A ("objects through ground + walls missing on exit") and C ("transparent floor showing cellar on entry") reproduce on `main` (no A8 work) and on `60f07bc` (R3 baseline, before R3.5 patches). This is the decision gate for whether the restructure as designed is sufficient or whether scope must expand. **Files:** - Create: `docs/research/2026-05-26-a8-rr0-falsification-findings.md` **Method:** three side-by-side launches. Human visual observation per scenario. Findings doc records what was seen on each branch and the decision outcome. - [ ] **RR0-S1: Launch HEAD (2bfeafd) and observe Issues A + C** Build + launch in the foreground (the human watches the client window): ```powershell $proc = Get-Process -Name AcDream.App -ErrorAction SilentlyContinue if ($proc) { $proc.CloseMainWindow() | Out-Null if (-not $proc.WaitForExit(5000)) { $proc | Stop-Process -Force } } Start-Sleep -Seconds 3 $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" dotnet build src\AcDream.App\AcDream.App.csproj -c Debug --nologo dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 | Tee-Object -FilePath "launch-a8-rr0-head.log" ``` Human walks `+Acdream` through these scenarios: 1. Stand outside Holtburg cottage. Walk into cottage. Watch the entry transition for ~3 seconds. Observe: does the cottage floor go transparent showing cellar below, with "wrong texture" flicker? 2. Stand inside cottage. Walk back outside. Watch the exit transition for ~3 seconds. Observe: do objects appear visible through the ground? Do walls of other buildings (adjacent cottages) appear missing? Record per-scenario: - Issue C (entry transparent floor): YES / NO / INTERMITTENT - Issue A (exit through-ground): YES / NO / INTERMITTENT Graceful close (use `$proc.CloseMainWindow()` pattern). - [ ] **RR0-S2: Test against R3 baseline by checking out 60f07bc's GameWindow.cs only** `60f07bc` is the R3 baseline (before R3.5 v1+v2 patches). It includes R1+R2 infrastructure (which we want), but the render-frame block is pre-patch. Single-file checkout keeps all other R1+R2 code intact: ```bash git checkout 60f07bc -- src/AcDream.App/Rendering/GameWindow.cs dotnet build src\AcDream.App\AcDream.App.csproj -c Debug --nologo ``` Expected: build green (R1+R2 deps unchanged between 60f07bc and HEAD). Launch + repro the same two scenarios from S1, logging to `launch-a8-rr0-r3.log`: ```powershell dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 | Tee-Object -FilePath "launch-a8-rr0-r3.log" ``` Record per-scenario: Issue C, Issue A outcomes. Graceful close. Restore HEAD's `GameWindow.cs`: ```bash git checkout HEAD -- src/AcDream.App/Rendering/GameWindow.cs dotnet build src\AcDream.App\AcDream.App.csproj -c Debug --nologo ``` Expected: build green; working tree clean. - [ ] **RR0-S3: Test against main using a side worktree** Main has no A8 work at all. Need a separate worktree to test it without disturbing the current worktree: ```bash git fetch origin main git worktree add ../tmp-main-baseline main ``` Expected: new worktree created at `../tmp-main-baseline` checked out to `main`. Build + launch from the side worktree: ```powershell Push-Location ..\tmp-main-baseline $proc = Get-Process -Name AcDream.App -ErrorAction SilentlyContinue if ($proc) { $proc.CloseMainWindow() | Out-Null if (-not $proc.WaitForExit(5000)) { $proc | Stop-Process -Force } } Start-Sleep -Seconds 3 dotnet build src\AcDream.App\AcDream.App.csproj -c Debug --nologo dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 | Tee-Object -FilePath "launch-a8-rr0-main.log" Pop-Location ``` Record per-scenario: Issue C, Issue A outcomes. Graceful close. Remove the side worktree: ```bash git worktree remove ../tmp-main-baseline ``` - [ ] **RR0-S4: Write findings doc and commit** Create `docs/research/2026-05-26-a8-rr0-falsification-findings.md` with this template (fill in the actual observations from S1–S3): ```markdown # A8 RR0 falsification — are Issues A and C pre-existing or A8-caused? **Date:** 2026-05-26 **Method:** three-branch launch + visual repro at Holtburg cottage entry / exit transitions. ## Observations | Branch | Commit | Issue A (exit through-ground) | Issue C (entry transparent floor) | |---|---|---|---| | HEAD | `2bfeafd` (R3.5 v2) | [YES / NO / INTERMITTENT] | [YES / NO / INTERMITTENT] | | R3 baseline | `60f07bc` | [YES / NO / INTERMITTENT] | [YES / NO / INTERMITTENT] | | main | [current main SHA] | [YES / NO / INTERMITTENT] | [YES / NO / INTERMITTENT] | ## Decision Based on the table: - [ ] **Outcome 1:** All three reproduce → A + C are pre-existing on main. Restructure proceeds RR1→RR5 unchanged. RR5 files A + C as new ISSUES.md entries. - [ ] **Outcome 2:** Only R3 + HEAD reproduce → A and/or C caused by R3 work specifically. **PAUSE** the plan. Re-brainstorm via `superpowers:brainstorming` to address them; update the design doc; resume. - [ ] **Outcome 3:** Only HEAD reproduces → R3.5 v1/v2 patches caused them. Revert in RR1 clears them. Restructure proceeds; RR4 confirms cleanup. Selected: [outcome #] ## Logs - `launch-a8-rr0-head.log` - `launch-a8-rr0-r3.log` - `launch-a8-rr0-main.log` ``` Commit the findings: ```bash git add docs/research/2026-05-26-a8-rr0-falsification-findings.md git commit -m "$(cat <<'EOF' docs(research): Phase A8 RR0 — falsification findings (A + C pre-existing?) Side-by-side launch on HEAD (2bfeafd) / R3 baseline (60f07bc) / main. Visual repro at Holtburg cottage entry + exit transitions. Records whether Issues A and C are A8-caused or pre-existing. Decision gate for whether the restructure as designed is sufficient or whether RR2 scope must expand. Co-Authored-By: Claude Opus 4.7 (1M context) EOF )" ``` - [ ] **RR0-S5: Decision gate — proceed or pause** If selected outcome is 1 or 3 → proceed to RR1. If selected outcome is 2 → **STOP**. Re-invoke `superpowers:brainstorming` to expand the design. Do NOT proceed to RR1. --- ## Task RR1: Revert R3.5 v1 + v2 as two new commits **Goal:** Clean diff against R3 baseline for the restructure that follows. The v1+v2 patches are subsumed by RR2 (the stencil branch will use `cameraInside`; depth-clear gets deleted entirely). **Files:** - Modify (via `git revert`): `src/AcDream.App/Rendering/GameWindow.cs` - [ ] **RR1-S1: Revert R3.5 v2 (depth-clear gate)** ```bash git revert 2bfeafd --no-edit ``` Expected: one new commit lands. `git log -1` shows `Revert "fix(render): Phase A8 R3.5 v2 — gate depth-clear on cameraReallyInside too"`. - [ ] **RR1-S2: Revert R3.5 v1 (stencil branch gate)** ```bash git revert 38d5374 --no-edit ``` Expected: one new commit lands. `git log -1` shows `Revert "fix(render): Phase A8 R3.5 — gate stencil branch on PointInCell containment"`. - [ ] **RR1-S3: Verify the working tree matches the R3 baseline render frame** ```bash git diff 60f07bc HEAD -- src/AcDream.App/Rendering/GameWindow.cs ``` Expected: empty diff. The render-frame block at HEAD now matches `60f07bc`'s GameWindow.cs verbatim. If the diff is NOT empty, investigate — likely a non-A8 commit landed between 60f07bc and 2bfeafd that touched GameWindow.cs unrelated to R3.5 (uncommon but possible). - [ ] **RR1-S4: Build + test green** ```bash dotnet build -c Debug --nologo dotnet test --nologo ``` Expected: build green; test failures within the documented 14–23 flaky window (PhysicsResolveCapture/Diagnostics static-leak issues, pre-existing). --- ## Task RR2: Restructure render frame to WB-faithful order **Goal:** Re-wire `GameWindow.cs`'s render-frame block to match `VisibilityManager.RenderInsideOut` Steps 1–4 verbatim, unify the two-flag asymmetry, and add the stencil-gated sky step. **Files:** - Modify: `src/AcDream.App/Rendering/GameWindow.cs` — render-frame block, lines ~7011–7260 The exact line numbers below are approximations from the worktree state at the time this plan was written (HEAD = `2bfeafd`). After RR1 reverts the line numbers shift; locate each edit by the exact `old_string` content, not by line number. - [ ] **RR2-S1: Rename `cameraInsideCell` → `cameraInside` with strict semantics** In `src/AcDream.App/Rendering/GameWindow.cs`, find this line (currently ~7012): ```csharp bool cameraInsideCell = visibility?.CameraCell is not null; ``` Replace with: ```csharp // Phase A8 restructure (2026-05-26): SINGLE source of truth for // "rendering as if camera is inside a cell." Strict PointInCell // check, no grace. Drives sky, terrain, stencil branch, weather, // sky-PES debug. `playerInsideCell` (line below) STAYS unchanged // — it tracks player position, not camera, for lighting. // // The grace mechanism in CellVisibility.FindCameraCell stays // alive; non-render consumers (IsInsideAnyCell, etc.) may still // benefit. Only the render-frame consumers use this strict flag. // // See: docs/superpowers/specs/2026-05-26-phase-a8-restructure-design.md bool cameraInside = visibility?.CameraCell is not null && CellVisibility.PointInCell(camPos, visibility.CameraCell); ``` Note: the `—` em-dash in the comment above is just for the doc renderer; in the actual file write em-dashes directly (or hyphens; not load-bearing). - [ ] **RR2-S2: Update sky-PES debug call to use cameraInside** Find this line (currently ~7032): ```csharp if (_options.EnableSkyPesDebug) UpdateSkyPes((float)WorldTime.DayFraction, _activeDayGroup, camPos, cameraInsideCell); ``` Replace with: ```csharp if (_options.EnableSkyPesDebug) UpdateSkyPes((float)WorldTime.DayFraction, _activeDayGroup, camPos, cameraInside); ``` - [ ] **RR2-S3: Update sky pre-scene gate to use cameraInside** Find this line (currently ~7090): ```csharp if (!cameraInsideCell) { _skyRenderer?.RenderSky(camera, camPos, (float)WorldTime.DayFraction, _activeDayGroup, kf, environOverrideActive); if (_particleSystem is not null && _particleRenderer is not null) _particleRenderer.Draw(_particleSystem, camera, camPos, AcDream.Core.Vfx.ParticleRenderPass.SkyPreScene); } ``` Replace with: ```csharp if (!cameraInside) { _skyRenderer?.RenderSky(camera, camPos, (float)WorldTime.DayFraction, _activeDayGroup, kf, environOverrideActive); if (_particleSystem is not null && _particleRenderer is not null) _particleRenderer.Draw(_particleSystem, camera, camPos, AcDream.Core.Vfx.ParticleRenderPass.SkyPreScene); } ``` - [ ] **RR2-S4: Gate initial terrain draw on `!cameraInside`** Find this block (currently ~7111–7123): ```csharp // Phase N.5b: wrap Draw in CPU stopwatch for [TERRAIN-DIAG] rollup // (gated on ACDREAM_WB_DIAG=1, same env var as [WB-DIAG]). Stopwatch // is cheap; only the periodic Console.WriteLine is gated. _terrainCpuStopwatch.Restart(); _terrain?.Draw(camera, frustum, neverCullLandblockId: playerLb); _terrainCpuStopwatch.Stop(); ``` Replace with: ```csharp // Phase N.5b: wrap Draw in CPU stopwatch for [TERRAIN-DIAG] rollup // (gated on ACDREAM_WB_DIAG=1, same env var as [WB-DIAG]). Stopwatch // is cheap; only the periodic Console.WriteLine is gated. // // Phase A8 restructure: skip initial terrain when cameraInside. // WB renders terrain ONLY at the stencil-gated step inside the // indoor branch (see line ~7215). Drawing terrain unconditionally // here would require a depth-clear-if-inside workaround (deleted // by this restructure). _terrainCpuStopwatch.Restart(); if (!cameraInside) _terrain?.Draw(camera, frustum, neverCullLandblockId: playerLb); _terrainCpuStopwatch.Stop(); ``` The diag stopwatch + sample buffer + MaybeFlushTerrainDiag below stay unchanged — they record sub-microsecond when skipped, which is correct. - [ ] **RR2-S5: Delete the R3.5 long comment block + cameraReallyInside declaration + depth-clear-if-inside** Find this entire block (currently ~7125–7155): ```csharp // Phase A8 R3.5 — transition-flicker fix. `cameraInsideCell` // stays true for ~3 grace frames after the camera physically // exits a cell (see CellVisibility._cellSwitchGraceFrames). // The grace mechanism prevents sky/lighting flicker at the // doorway threshold, but the render-frame mechanisms that // touch depth (depth-clear AND the stencil pipeline) MUST be // gated on the stricter PointInCell containment so they don't // fire during grace frames when the camera is actually outside. // // cameraInsideCell — lenient, grace-aware → sky, lighting // cameraReallyInside — PointInCell, no grace → depth-clear, // stencil pipeline branch // // R3.5 v1 only gated the stencil branch on `cameraReallyInside`; // depth-clear stayed on `cameraInsideCell`. Result: during grace // frames the depth-clear ran but the outdoor branch ran (because // !cameraReallyInside), so terrain depth was destroyed AND // everything below terrain (cellars, basement geometry) won the // depth test in the outdoor pass → "objects visible through // ground." R3.5 v2 unifies the depth-related gates on // `cameraReallyInside` so terrain depth is preserved during // grace, eliminating the through-ground artifact. bool cameraReallyInside = visibility?.CameraCell is not null && CellVisibility.PointInCell(camPos, visibility.CameraCell); // Conditional depth clear: when camera is ACTUALLY inside a cell // volume (not just in the grace window), clear depth (not color) // so interior geometry writes fresh Z values on top of the // terrain color buffer. Matches ACME GameScene.cs pattern. if (cameraReallyInside) _gl!.Clear(ClearBufferMask.DepthBufferBit); ``` Delete the entire block. No replacement — the depth-clear was a workaround for the now-skipped initial terrain. RR2-S4 (terrain gated on `!cameraInside`) replaces both functions. Note: after RR1 reverts have run, the `cameraReallyInside` declaration is GONE (it was added by R3.5 v1). The remaining lines you need to delete in this step are smaller — just the depth-clear-if-inside block. The full block above is what HEAD looks like BEFORE RR1 reverts; after RR1 the matching `old_string` shrinks to roughly: ```csharp // Conditional depth clear: when camera is ACTUALLY inside a cell // volume (not just in the grace window), clear depth (not color) // so interior geometry writes fresh Z values on top of the // terrain color buffer. Matches ACME GameScene.cs pattern. if (cameraInsideCell) _gl!.Clear(ClearBufferMask.DepthBufferBit); ``` (Note: post-RR1, the variable name is `cameraInsideCell` again — but RR2-S1 already renamed it to `cameraInside`. So at this step's execution time, the gate is `cameraInside`. Locate by the `_gl!.Clear(ClearBufferMask.DepthBufferBit)` line and the comment above it; delete the whole 4-line block.) - [ ] **RR2-S6: Modify the indoor branch — switch condition to cameraInside, prepare for stencil-gated sky insertion** Find the indoor branch condition (currently ~7174): ```csharp // The `visibility?.CameraCell is not null` repeat is for the // compiler's null-flow analysis: `cameraReallyInside` already // implies it, but flow doesn't propagate through a separate // local. Restating it inside the if condition lets the branch // body use the un-`?`d form without null-forgiving. if (cameraReallyInside && _indoorStencilPipeline is not null && visibility?.CameraCell is not null) { ``` Replace with: ```csharp // The `visibility?.CameraCell is not null` repeat is for the // compiler's null-flow analysis: `cameraInside` already implies // it, but flow doesn't propagate through a separate local. // Restating it inside the if condition lets the branch body use // the un-`?`d form without null-forgiving. if (cameraInside && _indoorStencilPipeline is not null && visibility?.CameraCell is not null) { ``` (Post-RR1, the variable is `cameraInsideCell` and is then renamed by RR2-S1 to `cameraInside`. Locate this step's edit by the `_indoorStencilPipeline is not null` text — that's stable across the renames.) - [ ] **RR2-S7: Insert stencil-gated sky step between EnableOutdoorPass and the terrain re-draw** Find this block (currently ~7209–7215): ```csharp // 5. Stencil-gated outdoor pass. _indoorStencilPipeline.EnableOutdoorPass(); // 5a. Re-draw terrain — at portal-silhouette pixels only, // terrain Z (with the f48c74a -0.01 nudge) wins over the // punched 1.0 depth. Color writes through window. _terrain?.Draw(camera, frustum, neverCullLandblockId: playerLb); ``` Replace with: ```csharp // 5. Stencil-gated outdoor pass. _indoorStencilPipeline.EnableOutdoorPass(); // 5a. Stencil-gated SKY. DepthMask OFF so sky color writes // through the punched depth=1.0 but depth STAYS at the // punch value, letting the next step's terrain re-draw // win the depth test wherever closer terrain exists. // EnableOutdoorPass left stencil at Equal(1, 0x01) so // sky color only writes where bit 1 is set (portal // silhouettes). This is acdream's enhancement over WB // (which shows fog clear color through windows); see // design doc §Q2 + brainstorm outcomes. // // PRE-FLIGHT (RR3): SkyRenderer.RenderSky must NOT // toggle stencil state internally. Verified in commit // . _gl!.DepthMask(false); _skyRenderer?.RenderSky(camera, camPos, (float)WorldTime.DayFraction, _activeDayGroup, kf, environOverrideActive); _gl!.DepthMask(true); // 5b. Re-draw terrain — at portal-silhouette pixels only, // terrain Z (with the f48c74a -0.01 nudge) wins over the // punched 1.0 depth. Color writes through window, // overwriting the sky's color writes where terrain is // closer (near-field landscape through the window). _terrain?.Draw(camera, frustum, neverCullLandblockId: playerLb); ``` The step numbering in the comments shifts: what was "5a" terrain re-draw is now "5b" with sky as "5a." Outdoor scenery below stays as "5c" (was "5b"). Update consistently below: Find the OutdoorScenery comment immediately following: ```csharp // 5b. Outdoor scenery — same stencil gating. _wbDrawDispatcher!.Draw(camera, _worldState.LandblockEntries, frustum, neverCullLandblockId: playerLb, visibleCellIds: visibility.VisibleCellIds, animatedEntityIds: animatedIds, set: AcDream.App.Rendering.Wb.WbDrawDispatcher.EntitySet.OutdoorScenery); ``` Replace the comment marker: ```csharp // 5c. Outdoor scenery — same stencil gating. _wbDrawDispatcher!.Draw(camera, _worldState.LandblockEntries, frustum, neverCullLandblockId: playerLb, visibleCellIds: visibility.VisibleCellIds, animatedEntityIds: animatedIds, set: AcDream.App.Rendering.Wb.WbDrawDispatcher.EntitySet.OutdoorScenery); ``` - [ ] **RR2-S8: Update animated-id-set comment to reference cameraInside** Find this comment block (currently ~7157–7160): ```csharp // L-fix1 (2026-04-28): animated-entity id set. Required by both // the cameraReallyInside branch (to route them to LiveDynamic // pass) and the outdoor path (where it preserves visibility // across landblock frustum culling). ``` Replace with: ```csharp // L-fix1 (2026-04-28): animated-entity id set. Required by both // the cameraInside branch (to route them to LiveDynamic pass) // and the outdoor path (where it preserves visibility across // landblock frustum culling). ``` (Post-RR1 the comment may already say `cameraInsideCell` instead of `cameraReallyInside`. Adjust the `old_string` to match whatever's actually there.) - [ ] **RR2-S9: Update weather post-scene gate** Find this block (currently ~7252–7267): ```csharp // Bug A fix (post-#26 worktree, 2026-04-26): weather sky // meshes (Properties & 0x04, e.g. the 815m-tall rain // cylinder 0x01004C42/0x01004C44) render AFTER the scene so // the additive rain streaks overlay terrain and entities // instead of being painted over by them. This is the second // half of retail's LScape::draw split — GameSky::Draw(1) // fires after the DrawBlock loop. Same indoor gate as the // sky pass: weather is suppressed inside cells. if (!cameraInsideCell) { _skyRenderer?.RenderWeather(camera, camPos, (float)WorldTime.DayFraction, _activeDayGroup, kf, environOverrideActive); if (_particleSystem is not null && _particleRenderer is not null) _particleRenderer.Draw(_particleSystem, camera, camPos, AcDream.Core.Vfx.ParticleRenderPass.SkyPostScene); } ``` Replace the gate line only: ```csharp if (!cameraInside) { _skyRenderer?.RenderWeather(camera, camPos, (float)WorldTime.DayFraction, _activeDayGroup, kf, environOverrideActive); if (_particleSystem is not null && _particleRenderer is not null) _particleRenderer.Draw(_particleSystem, camera, camPos, AcDream.Core.Vfx.ParticleRenderPass.SkyPostScene); } ``` (Comment block stays. Only the `if (!cameraInsideCell)` → `if (!cameraInside)` line.) - [ ] **RR2-S10: Build to verify all edits compile** ```bash dotnet build -c Debug --nologo ``` Expected: green, 0 errors, 0 warnings. If the compiler reports an undefined `cameraInsideCell` anywhere, find that remaining reference and rename it to `cameraInside`. - [ ] **RR2-S11: Run full test suite** ```bash dotnet test --nologo ``` Expected: failures within the documented 14–23 flaky window only (PhysicsResolveCapture/Diagnostics static-leak from unrelated tests, pre-existing). If a test fails with `cameraInsideCell` in its name or assertion message, that's a stale reference — investigate and update. - [ ] **RR2-S12: Commit** ```bash git add src/AcDream.App/Rendering/GameWindow.cs git commit -m "$(cat <<'EOF' feat(render): Phase A8 RR2 — restructure render frame to WB-faithful order Replaces the R3.5 v1+v2 frankenstein (terrain twice + depth-clear workaround + two-flag asymmetry) with WB's RenderInsideOut order verbatim: Outdoor frame (cameraInside == false): unchanged from pre-A8. sky -> terrain -> Draw(All) -> weather Indoor frame (cameraInside == true): 1. skip initial sky 2. skip initial terrain 3. NO depth-clear (deleted) 4. MarkAndPunch (camera-cell exit portals) 5. IndoorPass (cell mesh + statics + building shells) 6. EnableOutdoorPass 7. stencil-gated sky (DepthMask off; closes R4 Issue B) 8. stencil-gated terrain re-draw 9. stencil-gated OutdoorScenery 10. DisableStencil 11. LiveDynamic 12. skip weather Unifies the two-flag asymmetry into a single strict `cameraInside` flag computed via PointInCell. Grace mechanism in CellVisibility stays alive for non-render consumers. Closes the architectural mismatch flagged in the 2026-05-26 R3.5 restructure handoff. R1 (#78 fix) + R2 (taxonomy partition) + R3 (stencil pipeline) shipped earlier; this commit replaces R3.5's patches. Design: docs/superpowers/specs/2026-05-26-phase-a8-restructure-design.md Plan: docs/superpowers/plans/2026-05-26-phase-a8-restructure.md WB reference: references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/VisibilityManager.cs:73-160 RR3 verifies the SkyRenderer-stencil-contract precondition for the stencil-gated sky step. RR4 visual-verifies. RR5 ships docs. Co-Authored-By: Claude Opus 4.7 (1M context) EOF )" ``` --- ## Task RR3: Verify SkyRenderer doesn't toggle stencil state **Goal:** Confirm the stencil-gated sky step's precondition: `_skyRenderer.RenderSky` does NOT touch `EnableCap.StencilTest`, `StencilFunc`, `StencilOp`, or `StencilMask` between EnableOutdoorPass's setup and the sky fragment writes. If it does, our gate is lost. **Files:** - Read: `src/AcDream.App/Rendering/SkyRenderer.cs` - Possibly modify: `src/AcDream.App/Rendering/GameWindow.cs` (only if SkyRenderer is dirty) - [ ] **RR3-S1: Grep SkyRenderer for stencil-state calls** ```bash grep -n "Stencil\|stencil" src/AcDream.App/Rendering/SkyRenderer.cs ``` Possible outcomes: - **No matches at all** → SkyRenderer is clean. Proceed to RR3-S2 (note-only commit). - **Matches found** → inspect each. If they are inside conditional code paths that aren't reachable from our `RenderSky` call site (e.g., dead code, debug-only), still clean. If they touch live state during a normal `RenderSky` call, dirty — proceed to RR3-S3 (wrapper required). Most likely outcome: no matches. SkyRenderer was written for outdoor rendering with no stencil concerns. Also grep for any other GL state SkyRenderer may touch that could affect our step (DepthFunc, ColorMask): ```bash grep -n "DepthFunc\|ColorMask\|DepthMask" src/AcDream.App/Rendering/SkyRenderer.cs ``` If SkyRenderer changes `DepthMask` internally and restores, our outer `DepthMask(false)` + `DepthMask(true)` brackets may be redundant but safe. If SkyRenderer permanently changes `DepthMask` without restoring, we have a different problem (also worth knowing). - [ ] **RR3-S2: If SkyRenderer is clean, commit a verification note** If RR3-S1 found no stencil-state writes, update the comment in `GameWindow.cs` at the stencil-gated sky step to record the verification. Find this comment (added in RR2-S7): ```csharp // PRE-FLIGHT (RR3): SkyRenderer.RenderSky must NOT // toggle stencil state internally. Verified in commit // . ``` Replace `` with this commit's SHA (you'll know it once you run `git commit`; first commit with the placeholder, then `git commit --amend` after seeing the SHA, OR write the comment with the line-range reference to SkyRenderer.cs instead of a SHA reference). Preferred form (line-range, more durable than a SHA): ```csharp // PRE-FLIGHT (RR3): SkyRenderer.RenderSky must NOT // toggle stencil state internally. Verified by reading // src/AcDream.App/Rendering/SkyRenderer.cs at commit // time — no Stencil*/EnableCap.StencilTest calls in // the file. ``` Commit: ```bash git add src/AcDream.App/Rendering/GameWindow.cs git commit -m "$(cat <<'EOF' chore(render): Phase A8 RR3 — verify SkyRenderer doesn't touch stencil Pre-flight precondition for the RR2 stencil-gated sky step: confirms SkyRenderer.RenderSky doesn't enable/disable stencil test, change stencil function/op/mask. Verified by grep over src/AcDream.App/Rendering/SkyRenderer.cs — no matches. Comment at the stencil-gated sky call site updated to record the verification + reference the verified source. No behavior change. Co-Authored-By: Claude Opus 4.7 (1M context) EOF )" ``` - [ ] **RR3-S3: If SkyRenderer is dirty, add a state save/restore wrapper** This step only runs if RR3-S1 found stencil writes inside `SkyRenderer.RenderSky` that would interfere. In `GameWindow.cs`, replace the stencil-gated sky block (RR2-S7's insertion) with a state-saving variant: ```csharp // 5a. Stencil-gated SKY with state save/restore wrapper. // SkyRenderer.RenderSky touches stencil state (see // RR3-S1 finding); save before, restore after. _gl!.GetInteger(GLEnum.StencilFunc, out int savedStencilFunc); _gl!.GetInteger(GLEnum.StencilRef, out int savedStencilRef); _gl!.GetInteger(GLEnum.StencilValueMask, out int savedStencilValueMask); _gl!.GetInteger(GLEnum.StencilWritemask, out int savedStencilWritemask); bool savedStencilTest = _gl!.IsEnabled(EnableCap.StencilTest); _gl!.DepthMask(false); _skyRenderer?.RenderSky(camera, camPos, (float)WorldTime.DayFraction, _activeDayGroup, kf, environOverrideActive); _gl!.DepthMask(true); // Restore stencil state to what EnableOutdoorPass left us with. if (savedStencilTest) _gl!.Enable(EnableCap.StencilTest); else _gl!.Disable(EnableCap.StencilTest); _gl!.StencilFunc((StencilFunction)savedStencilFunc, savedStencilRef, (uint)savedStencilValueMask); _gl!.StencilMask((uint)savedStencilWritemask); ``` Commit: ```bash git add src/AcDream.App/Rendering/GameWindow.cs git commit -m "$(cat <<'EOF' fix(render): Phase A8 RR3 — wrap stencil-gated sky with state save/restore SkyRenderer.RenderSky internally touches stencil state (verified in RR3-S1). The stencil-gated sky step inside the A8 indoor branch needs the EnableOutdoorPass stencil setup intact for the subsequent terrain re-draw and OutdoorScenery passes. Wrap RenderSky with glGetInteger save + restore so the outer stencil context survives. Co-Authored-By: Claude Opus 4.7 (1M context) EOF )" ``` --- ## Task RR4: Visual verification matrix **Goal:** Confirm the restructure delivers the design's promises across the four building types + both transitions + sky-through-windows. Human runs the scenarios; Claude collects logs; per-scenario PASS/FAIL recorded against the acceptance criteria. **Files:** - Create: `docs/research/2026-05-26-a8-rr4-visual-verification.md` — outcome doc - [ ] **RR4-S1: Build for verification** ```bash dotnet build src\AcDream.App\AcDream.App.csproj -c Debug --nologo ``` Expected: green. - [ ] **RR4-S2: Pre-launch — close any running client; launch fresh** ```powershell $proc = Get-Process -Name AcDream.App -ErrorAction SilentlyContinue if ($proc) { $proc.CloseMainWindow() | Out-Null if (-not $proc.WaitForExit(5000)) { $proc | Stop-Process -Force } } Start-Sleep -Seconds 3 $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" dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 | Tee-Object -FilePath "launch-a8-rr4-verify.log" ``` Background run (so the tool returns; human keeps the client window foreground). - [ ] **RR4-S3: Scenario A — Holtburg cottage interior** Human walks `+Acdream` into a Holtburg cottage near the network portal. Stand in the middle of the room. Look at each wall in turn. Look out a window. **Acceptance:** - All walls SOLID — no see-through to outdoor terrain - Outdoor terrain visible ONLY through windows / open doors - **SKY visible through windows** (the R4 Issue B closure) - Player character body visible (no head-backwards, no missing limbs) - No "transparent rectangles around buildings" regression (#100 stays closed) Record per criterion: PASS / FAIL with notes. - [ ] **RR4-S4: Scenario B — Holtburg cottage cellar** Walk to a cottage cellar (descend stairs). **Acceptance:** - Cellar walls + floor + ceiling SOLID - Cellar stairs SOLID from inside view — no grass/terrain overlay through the stair geometry - (Out-to-in stair-grass artifact is NOT A8 scope; will be filed as #103 by RR5 if observed) Record per criterion: PASS / FAIL. - [ ] **RR4-S5: Scenario C — Holtburg Inn (multi-room cell mesh)** Walk into the Holtburg inn. Move through its rooms. **Acceptance:** - All inn walls SOLID - Adjacent rooms not visible through walls (no "I can see the door of the next room") - Furniture (cell statics) visible and properly positioned - Sky visible through inn windows Record per criterion: PASS / FAIL. - [ ] **RR4-S6: Scenario D — A dungeon (portal-entry indoor world)** Pick any reachable dungeon (network portal to a known dungeon). **Acceptance:** - Corridor walls SOLID - Adjacent corridors not visible through walls - Lighting reads as indoor (sun zeroed, indoor ambient applied) - No outdoor stab/terrain leak - (Dungeons typically have no exit portals; no sky-through-window expected. If a dungeon HAS exit portals, sky should show through them.) Record per criterion: PASS / FAIL. - [ ] **RR4-S7: Transition scenarios — exit and entry** Walk through an entry/exit transition at the cottage door several times. **Exit transition (indoor → outdoor):** - Clean transition; no through-ground objects; no missing walls - (If A reproduces AND RR0 confirmed pre-existing on main, this is documented limitation; PASS with note) **Entry transition (outdoor → indoor):** - Clean transition; no floor transparent showing cellar - (If C reproduces AND RR0 confirmed pre-existing on main, documented limitation; PASS with note) Record per scenario: PASS / FAIL with notes. - [ ] **RR4-S8: Graceful close + write findings doc** ```powershell $proc = Get-Process -Name AcDream.App -ErrorAction SilentlyContinue if ($proc) { $proc.CloseMainWindow() | Out-Null if (-not $proc.WaitForExit(5000)) { $proc | Stop-Process -Force } } ``` Create `docs/research/2026-05-26-a8-rr4-visual-verification.md` capturing each scenario's PASS/FAIL outcome with observations. Template: ```markdown # A8 RR4 visual verification — render-frame restructure outcome **Date:** 2026-05-26 **HEAD:** [restructure-commit SHA from RR2] **Build:** green ## Scenario outcomes | Scenario | Acceptance | Outcome | Notes | |---|---|---|---| | A: cottage interior | walls solid + sky through windows | PASS / FAIL | | | B: cottage cellar | walls solid + stairs solid from inside | PASS / FAIL | | | C: inn (multi-room) | walls solid + sky through windows | PASS / FAIL | | | D: dungeon | walls solid + indoor lighting | PASS / FAIL | | | Exit transition | clean | PASS / FAIL / DOCUMENTED PRE-EXISTING | | | Entry transition | clean | PASS / FAIL / DOCUMENTED PRE-EXISTING | | ## Gate decision - [ ] All four building-type scenarios PASS → proceed to RR5 - [ ] Any building-type scenario FAILED → STOP, invoke /investigate - [ ] Transition scenarios FAILED but RR0 confirmed pre-existing → file as new ISSUES.md entries in RR5 - [ ] Transition scenarios FAILED and RR0 did NOT confirm pre-existing → STOP, re-brainstorm ``` Commit the findings: ```bash git add docs/research/2026-05-26-a8-rr4-visual-verification.md git commit -m "$(cat <<'EOF' docs(research): Phase A8 RR4 — visual verification outcome Cottage / cellar / inn / dungeon + exit/entry transition + sky-through- windows scenarios per the design's acceptance matrix. Gate decision recorded for RR5 ship-or-stop. Co-Authored-By: Claude Opus 4.7 (1M context) EOF )" ``` - [ ] **RR4-S9: Gate decision** Per the findings: - All building-type scenarios PASS AND transition scenarios are clean OR documented-pre-existing → proceed to RR5. - Any building-type scenario FAILED → STOP. Open `/investigate` to triage. Do NOT ship RR5. - Transition scenarios failed and NOT pre-existing → STOP. Re-brainstorm scope expansion. --- ## Task RR5: Ship docs (close #78, file follow-ups, update CLAUDE.md) **Goal:** Move #78 to closed, file new ISSUES for known limitations + any RR0-confirmed pre-existing transition issues, update CLAUDE.md's A8 paragraph from "PAUSED" → "SHIPPED." **Files:** - Modify: `docs/ISSUES.md` - Modify: `CLAUDE.md` - [ ] **RR5-S1: Read ISSUES.md to confirm next available ID** ```bash grep -n "^## #1[0-9][0-9]" docs/ISSUES.md ``` Expected: shows the highest #1xx ID currently filed. Tentative next available was #102 at plan-write time (highest filed = #101). Verify and adjust. - [ ] **RR5-S2: Move #78 to Recently closed** Find #78's current entry in `docs/ISSUES.md` (OPEN). Move it to the "Recently closed" section with format: ```markdown **#78 — Outdoor stabs/buildings visible through the rendered floor** — CLOSED 2026-05-26 by Phase A8 (R1+R2+R3+RR1+RR2 across commits ed72704 → [RR2 SHA]). Restructure ports WB's RenderInsideOut stencil pipeline with a corrected entity taxonomy (WorldEntity.IsBuildingShell). Visual-verified at cottage interior, cellar, inn, and dungeon. Sky visible through windows (Issue B closure). ``` - [ ] **RR5-S3: File #102 — Cross-cell-portal far-side visibility (Step 5 deferral)** Add this OPEN issue (use the actual next available ID confirmed in RR5-S1): ```markdown ## #102 — Far-side portal visibility through walls (WB Step 5 deferral) **Status:** OPEN (low priority; first ship of A8 deferred this). **Description:** When standing inside a multi-room building, looking at a wall between rooms, portals on the FAR side of the room (e.g. a doorway opening to outdoors on the other side of the wall) may have their silhouette stencil-marked by Phase A8. This lets outdoor terrain leak through the wall at that silhouette. The first-ship approximation in A8 RR2 stencil-marks ONLY the camera's own cell's exit portals (not BFS-extended VisibleCellIds), which AVOIDS the leak in most cases but loses cross-cell-portal visibility. **Acceptance:** Inside Holtburg Inn looking at the wall between two rooms, no visible terrain or scenery shows through. WB Step 5's 3-stencil-bit cross-building pipeline is the reference fix (see references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/VisibilityManager.cs:156-232). **Files:** - src/AcDream.App/Rendering/IndoorCellStencilPipeline.cs — currently single-bit stencil; would extend to bits 1+2. - src/AcDream.App/Rendering/GameWindow.cs — render frame would gain a per-far-portal pass. ``` - [ ] **RR5-S4: File #103 — Outdoor-to-indoor cellar terrain Z-fight (out-to-in artifact)** Add this OPEN issue: ```markdown ## #103 — Outdoor-to-indoor cellar terrain Z-fight (out-to-in artifact) **Status:** OPEN (low priority; pre-existing). **Description:** Looking from OUTSIDE a cottage cellar at the stair geometry from above, grass/terrain may overlap the stair triangles. Pre-existing; not addressed by A8 (no stencil work runs when the camera is outside). #100's 1cm terrain Z nudge is insufficient because cellar geometry sits multiple meters below terrain Z — depth-precision artifacts persist at oblique angles. **Acceptance:** From outside a cottage, looking at the cellar entrance, stair geometry reads as solid stone (no grass overlay) regardless of camera angle. **Files:** likely a deeper terrain-occlusion mechanism (per-cell terrain mask, or proper outdoor portal culling) — beyond the scope of A8. ``` - [ ] **RR5-S5: File R4 Issue A as #104 IF RR0 confirmed pre-existing on main** Read `docs/research/2026-05-26-a8-rr0-falsification-findings.md` written in RR0-S4. If outcome was "all three reproduce" (Issue A pre-existing on main), file: ```markdown ## #104 — Exit transition: objects visible through ground (pre-existing) **Status:** OPEN (medium priority; pre-existing on main, confirmed by A8 RR0 falsification). **Description:** Briefly after the camera exits a cell (transitioning indoor → outdoor), objects below terrain Z (cellar geometry, basement entities) may render visible through the ground for 1–3 frames. Falsified against `main` in [a8-rr0-falsification-findings.md](../research/2026-05-26-a8-rr0-falsification-findings.md) — reproduces on `main` without any A8 work. Likely root cause: terrain Z + grace-frame interaction with entity depth tests at certain camera angles. **Acceptance:** Exit a cottage; no objects visible through the ground at any camera angle during the transition. Steady-state outdoor view: terrain occludes below-ground entities cleanly. **Files:** - Likely terrain shader (terrain_modern.vert) or the cell-grace mechanism (`CellVisibility.FindCameraCell`). - May need a "true outside" gate that ignores grace for depth-test correctness. ``` (If RR0 did NOT confirm pre-existing, skip this step. The expected handling was already decided in RR0-S5.) - [ ] **RR5-S6: File R4 Issue C as #105 IF RR0 confirmed pre-existing on main** Same condition as RR5-S5. If RR0 confirmed Issue C pre-existing: ```markdown ## #105 — Entry transition: floor transparent showing cellar (pre-existing) **Status:** OPEN (medium priority; pre-existing on main, confirmed by A8 RR0 falsification). **Description:** Briefly during the camera entry into a cottage (outdoor → indoor transition), the cottage floor may go transparent showing the cellar geometry below, with the cellar ceiling's texture flickering at the floor pixels. Falsified against `main` in [a8-rr0-falsification-findings.md](../research/2026-05-26-a8-rr0-falsification-findings.md) — reproduces on `main` without any A8 work. Likely root cause: Z-fight between cottage floor mesh and cellar ceiling mesh at adjacent world Z values (both with +0.02 EnvCell render lift). **Acceptance:** Enter a cottage; floor reads as solid floor texture throughout the transition. No glimpse of cellar geometry through the floor. **Files:** - The +0.02m EnvCell render lift might need per-cell adjustment. - Alternative: depth-fight-resolving via polygon offset on indoor cell meshes. ``` - [ ] **RR5-S7: Update CLAUDE.md A8 paragraph** Find the current A8 paragraph in `CLAUDE.md` (begins with "**A8.P3 —" or "**Phase A8 —"; locate by grep). Find the "PAUSED" / "R3.5" / "restructure" mentions. Replace with a SHIPPED summary: ```markdown **Phase A8 — Indoor-cell visibility culling — SHIPPED 2026-05-26.** Closes issue #78. Six tasks across the restructure (after R1+R2+R3 shipped earlier in the same week and R3.5 v1+v2 paused for restructure): - RR0: falsification spike — confirmed R4 Issues A + C [pre-existing on main / A8-specific] (per `docs/research/2026-05-26-a8-rr0-falsification-findings.md`). - RR1: reverted R3.5 v1 + v2 patches (`38d5374`, `2bfeafd`) as two new revert commits. - RR2: restructured render frame to WB-faithful RenderInsideOut order. Skipped initial sky+terrain when inside; deleted depth-clear-if-inside; added stencil-gated sky inside the indoor branch (closes R4 Issue B). Unified the two-flag asymmetry into a single strict `cameraInside` flag via PointInCell. - RR3: verified `SkyRenderer.RenderSky` doesn't toggle stencil state internally — stencil-gated sky step's precondition holds. - RR4: visual-verified at Holtburg cottage interior + cellar + Inn + dungeon, plus exit/entry transitions and sky-through-windows. - RR5 (this ship-docs commit). Five deferred follow-ups remain open: - #102 — Cross-cell-portal far-side visibility (WB Step 5). - #103 — Cellar terrain Z-fight from outside (pre-existing). - #104 — Exit transition through-ground (filed only if RR0 confirmed pre-existing). - #105 — Entry transition transparent floor (filed only if RR0 confirmed pre-existing). - Grace-mechanism cleanup (Q4 third option from brainstorm). Full design: [docs/superpowers/specs/2026-05-26-phase-a8-restructure-design.md](docs/superpowers/specs/2026-05-26-phase-a8-restructure-design.md). Plan: [docs/superpowers/plans/2026-05-26-phase-a8-restructure.md](docs/superpowers/plans/2026-05-26-phase-a8-restructure.md). Restructure handoff (historical): [docs/research/2026-05-26-a8-r3.5-restructure-handoff.md](docs/research/2026-05-26-a8-r3.5-restructure-handoff.md). ``` (Customize the "Five deferred follow-ups" list based on which of #104 + #105 were actually filed — if RR0 confirmed neither pre-existing, both come off the list; if just A, drop #105; etc.) Also find the "Currently working toward" line + the A8 references in the Milestone Discipline section. Update them to reflect ship status (e.g. "M1.5 — Indoor world feels right — partially advanced; A8 shipped 2026-05-26; remaining indoor work continues at [next phase]"). - [ ] **RR5-S8: Commit ship docs** ```bash git add docs/ISSUES.md CLAUDE.md git commit -m "$(cat <<'EOF' ship(render): Phase A8 — indoor-cell visibility culling SHIPPED Closes #78 (outdoor stabs/terrain visible through indoor walls). Files #102 (cross-cell-portal Step 5 deferral), #103 (cellar Z-fight from outside, pre-existing), and [#104/#105 if RR0 confirmed Issues A/C pre-existing on main]. Visual-verified at Holtburg cottage interior + cellar, Holtburg Inn, and dungeon. Sky visible through windows. Exit/entry transitions [clean / documented pre-existing per RR0 findings]. Architecture: WB RenderInsideOut order verbatim. Entity taxonomy partition (WorldEntity.IsBuildingShell from R1) drives WbDrawDispatcher.EntitySet (R2) into IndoorPass / OutdoorScenery / LiveDynamic. Stencil-gated sky inside the indoor branch is acdream's enhancement over WB's reference. Co-Authored-By: Claude Opus 4.7 (1M context) EOF )" ``` --- ## Self-review **Spec coverage check:** - [x] Q1 (initial-terrain conditional) → RR2-S4 gates terrain on `!cameraInside`. - [x] Q2 (sky through windows) → RR2-S7 inserts stencil-gated sky step. - [x] Q3 (Issue C investigation) → RR5-S6 files as #105 if RR0 confirmed pre-existing. - [x] Q4 (gate unification) → RR2-S1 introduces single `cameraInside`; RR2-S2/S3/S6/S8/S9 propagate. - [x] Q5 (R3.5 revert) → RR1-S1/S2 revert. - [x] RR0 spike (pre-restructure falsification) → entire Task RR0 + decision gate RR0-S5. - [x] SkyRenderer precondition check → Task RR3. - [x] Visual verification matrix (cottage/cellar/inn/dungeon + transitions + sky-through-windows) → RR4 Scenarios A–D + S7 transitions. - [x] Close #78 + file new issues → RR5-S2 through RR5-S6. **Placeholder scan:** - No "TBD" or "implement later" — every step has actual code or actual commands. - Two intentional placeholder substitutions: `[RR2 SHA]` in the #78 closure entry (filled in at RR5 execution time) and `[a SHA / pre-existing / not pre-existing]` strings in the CLAUDE.md update template (filled in based on RR0 outcome). These are NOT spec failures — they're explicit "fill in at execution time based on observed state." - "Customize" appears once in RR5-S7 for the deferred-follow-ups list — accompanied by a clear conditional that the executor fills in. **Type consistency:** - `cameraInside` (single source of truth) used consistently across RR2-S1/S2/S3/S6/S8/S9; never spelled `cameraInsideCell` or `cameraReallyInside` in any post-RR1 step. - `_indoorStencilPipeline` is the field name referenced everywhere (matches R3's already-shipped code). - `EntitySet.IndoorPass` / `OutdoorScenery` / `LiveDynamic` enum values match R2's already-shipped code. - `IndoorCellStencilPipeline` method names — `UploadPortalMesh`, `MarkAndPunch`, `EnableOutdoorPass`, `DisableStencil` — match the dormant infrastructure shipped in Tasks 1–6. **Task granularity:** - RR0: 5 steps, each ~5–15 minutes (most are launch-and-observe). Visual repro takes the longest. - RR1: 4 steps, each <2 minutes. - RR2: 12 steps, each 2–5 minutes (mechanical edits with exact code shown). - RR3: 3 steps (S2 OR S3 depending on S1 outcome), each 5–10 minutes. - RR4: 9 steps, each 3–10 minutes (mostly observation). - RR5: 8 steps, each 5–10 minutes (mostly edits to two markdown files). Total estimated time: ~2.5–3 hours assuming RR0 doesn't trigger scope expansion. **Outcome contingencies:** - RR0 outcome 2 (A8-caused) → STOP at RR0-S5. Re-brainstorm. - RR3-S1 dirty → divert to RR3-S3 wrapper. - RR4 building-type FAILED → STOP at RR4-S9. Open `/investigate`. - RR4 transition FAILED + not pre-existing → STOP, re-brainstorm. All gates explicit; no dead-ends. --- **SUPERSEDED 2026-05-26 (PM) by [2026-05-26-phase-a8-wb-full-port.md](2026-05-26-phase-a8-wb-full-port.md).** This plan implemented the "WB-faithful restructure" design which RR0 evidence invalidated. The new plan implements the full WorldBuilder RenderInsideOut + RenderOutsideIn port. RR0 was completed and its findings doc is retained. This document is retained for historical reference.