# Campaign FW — the retail frame walk (implementation plan) **Status:** ACTIVE (opened 2026-08-30; spec approved by owner 2026-08-30). **Spec (approved):** [`docs/superpowers/specs/2026-08-30-campaign-w-retail-frame-walk-design.md`](../superpowers/specs/2026-08-30-campaign-w-retail-frame-walk-design.md) — note: the campaign letter is **FW** (frame walk); the spec predates the rename (the roadmap already owns "Phase W" for the historical Unified Cell Graph program). **Branch:** `claude/campaign-w-retail-frame-walk` off main `e102fb36`. **Predecessor:** Campaign PV, halted 2026-08-30 (`docs/plans/2026-08-30-pview-visibility-campaign.md`); its back half is quarantined on `claude/cathedral-rendering-debug-47a417` and nothing merges from it. **One-sentence goal:** retail owns every frame decision (rooting, portal views, cone gating, landscape walk, buildings, stage order, depth semantics, degrade, particles, camera); modern code owns only pixel-neutral GPU mechanics; the ~4.7K-line accumulated visibility layer and its patch apparatus are deleted at their stages. --- ## Binding rules (all stages, binding on subagents) 1. **The ownership line is the campaign invariant.** If a modern component makes a decision retail did not make, that is a campaign bug regardless of pixels. Every ported function cites its named retail symbol. 2. **Grep named first.** `docs/research/named-retail/acclient_2013_pseudo_c.txt` by `class::method` before any fresh decompilation; pseudocode notes in `docs/research/` before C# (the mandatory workflow). 3. **Fail loud, never silently drop.** The PV3 post-mortem rule: any admission/seeding/ordering filter that rejects work must log the rejection under a diagnostic flag or fall open — silent drops produced this week's hollow-world regressions. 4. **The transition checklist is a standing self-run gate.** Every candidate build gets, before the owner sees it: portal-in arrival frames, a Holtburg house exit, a teleport-to-Holtburg stopwatch, and a steady-state fps read (drive.ps1 + screenshots). No terrace-only verification, ever again. 5. **No long-lived dual path.** Campaign V precedent: a stage that cuts over deletes the code it replaces in the same stage. Short-lived scaffolding inside one stage is fine; a toggle that survives a stage boundary is not. 6. **Register discipline.** Deviations add their row in the same commit; ported mechanisms delete rows in the same commit (`docs/architecture/retail-divergence-register.md`). 7. **Suites green at every stage close** (hermetic filter `Lane!=InstalledDat&Lane!=Linux&Lane!=Manual&Lane!=Timing&Lane!=Live&Lane!=PreparedPackage`), plus the stage's own gates. Sonnet implements; Opus reviews stage boundaries (architectural + retail-faithfulness lenses). ## Verified seam map (recon 2026-08-30; cite these, do not re-derive) **Frame chain today:** `GameWindow.OnRender` (GameWindow.cs:1785/1809) → `GameFrameGraphSlot.Render` → `RenderFrameOrchestrator.Render` (RenderFrameOrchestrator.cs:206/226) → `VulkanWorldScenePhase` (VulkanCompositionFramePhases.cs:113, owns the backbuffer pass) → `WorldSceneRenderer.Render` (WorldSceneRenderer.cs:128) → `RetailPViewRenderer.DrawInside` (RetailPViewRenderer.cs:112), which builds `PortalVisibilityFrame` internally (line 122) and drives `RetailPViewPassExecutor` through the packed route contract (`RenderFrameCandidateRoute`: LandscapeOutdoorStatic → LandscapeBuildingShell → LookInObject → LandscapeOutsideDynamic → CellStatic → DynamicLast; `WbDrawDispatcher.PackedOracle.cs:108/171` enforces in-order consumption). **What the walk-order submitter REPLACES:** `GroupKey` material bucketing (`ClassifyBatches` WbDrawDispatcher.cs:3292, `ClassifyPackedBatches` PackedOracle.cs:610, `_groups`/`_packedGroups`), `PartitionInstanceGroups` (:2232), and the two distance sorts (`CompareOpaqueSubmissionOrder` :2865, `CompareTransparentSubmissionOrder` :2871). Note: the deferred-alpha path (`DeferTransparentGroups` :2619 → `RetailAlphaQueue`) already reconstructs draw-local order per instance — the transparent side is half-way to walk-order today and is the SSBO-layout pattern to follow. **What is REUSED unchanged:** `GlobalMeshBuffer` arena (GlobalMeshBuffer.cs:84), `WbMeshAdapter`/`ObjectMeshManager` mesh prep + self-heal (WbMeshAdapter.cs:328/435), `TextureCache` GpuTextureSlot resolution (WbDrawDispatcher.cs:3421), the ring-section SSBO writers + shared `WorldTransformFrameArena` (Rhi.cs:913/945), `MeshPipelineSet` (Rhi.cs:49), and the terminal MDI recorder `DrawIndirectRangeRhi` (Rhi.cs:798). **Caveats that shaped the stages:** three parallel classifiers exist (classic, packed, directional-shadow — WbDrawDispatcher.DirectionalShadows.cs:1021) and must agree until each is cut over; `EntityClassificationCache` and `PackedProjectionClassificationCache` assume group-bucketed submission and retire with their routes; `StageImmediateGroup` lays per-instance SSBOs by group-order cursor, so the walk submitter re-derives layout from stream order (start per-instance like deferred alpha; merge adjacent runs after correctness). **Visibility consumers to re-point at the walk output** (the complete production list — radar, audio, and picking do NOT consume visibility): - Particles: `WorldSceneRenderer.cs:263` → `ParticleVisibilityController` → `ParticleSystem.ApplyRetailView` (Core/Vfx/ParticleSystem.cs:313), fed outdoors by `TerrainModernRenderer.VisibleCellIds`. - Lights: `WorldSceneRenderer.cs:264` → `RuntimeWorldFrameEnvironmentPreparation` (WorldRenderFrameBuilder.cs:543) → `LightManager.BuildPointLightSnapshot` (Core/Lighting/LightManager.cs:284). - EnvCell prepare filter: `RetailPViewPassExecutor.cs:276` → `EnvCellRenderer.PrepareRenderBatches` (EnvCellRenderer.cs:456). - Entity routes: `RenderScenePViewFrameProduct.cs:1330-1587`. - Gated diagnostics only beyond that. **Streaming atomicity (what already holds vs what FW adds):** per-cell publication is ALREADY atomic — one dictionary swap of a complete immutable `EnvCellLandblock` (EnvCellRenderer.CommitPublication:347); outdoor terrain commits at LandblockRenderPublisher.AdvanceBeginOne:267. The real partial states are (a) landblock-stage terrain-before-interiors across yielded publication stages (LandblockPresentationPipeline.cs:711/757 — deliberate walking pop-in, hidden by the reveal hold during portal/login), and (b) committed cells drawing before every contained static mesh is resident (skip-if-missing, EnvCellRenderer.cs:720). FW keeps both as EXPLICIT, register-rowed adaptations; the walk consumes only the committed registry (`CellVisibility.TryGetCell` — production role is the registry; its BFS is already dead code). **The patch apparatus to delete (exact sites):** - `ShellDrawLiftZ` +0.02 lift, three consumers: PortalVisibilityBuilder.cs:353 (const + Build's drawLiftZ), RetailPViewPassExecutor.cs:697 (depth fans), LandblockBuildFactory.cs:523 (baked into draw cellTransform). - Punch stencils (#117 adaptation): PortalDepthMaskRenderer.Rhi.cs:59-125. - Look-in seeding heuristics: PortalVisibilityBuilder.BuildFromExterior:713-923 + callers MergeNearbyBuildingFloods (RetailPViewRenderer.cs:411), BuildInteriorRootLookIns (:471), DrawBuildingLookIns (:600-860), and the barrier math (:515-559). - The InViewCells side-channel (RetailPViewRenderer.cs:2187) once consumers read the walk output. **Camera facts:** `RetailChaseCamera.cs` — `Distance` default 2.61 m, clamps DistanceMin=2/DistanceMax=40 (:110-113); collision probe + slope align + chase already default-on retail behaviors (Core/Rendering/CameraDiagnostics.cs:28-50). Retail envelope (from the d71f5ef1 diff, which lives ONLY on the quarantined branch — this branch has no AD-116 row): `CameraSet::Farther` @0x00458890 scales the viewer offset multiplicatively and REFUSES the write once |offset.y| ≥ 10 (gates |x|<10, |y|<10, z<450, z>-1.8); the standard arc saturates near offset (0, −10, +8.33) ≈ a 13.0 m boom. `CameraSet::Raise` @0x00457980 rotates at preserved length. TS-56 records the non-retail adjustment scalars (CameraAdjustmentSpeed=40/s etc.). **Retail anchors already established:** `SmartBox::RenderNormalMode` @0x00453aa0 (frame rooting), `PView::DrawCells` @0x005A4840, `LScape::draw` @0x00506330, `LScape::grab_visible_cells` @0x00504EC0, `DrawBuilding` pre-punch flush @0x0059F2A0, `ShouldDrawParticles` @0x0050FE60, the untextured skip in `D3DPolyRender::DrawMesh` @0x0059d4a0, `ACRender::polyClipFinish` (two call sites: `PView::GetClip` + debug), `Render::viewconeCheck`. --- ## Stages ### FW0 — the walk oracle (tooling + fixtures) **STATUS: COMPLETE 2026-08-30.** Ten trace fixtures + README (`docs/research/2026-08-30-fw-walk-oracle/`, commit `71b11817`), the replay helper + 19 fixture goldens (`9f4c0f95`), and the port-ready pseudocode model + full decomp appendix (`docs/research/2026-08-30-fw-walk-pseudocode.md`, `a6885aa2`). Findings that reshaped the campaign: the frame roots at the CAMERA's cell; outdoor frames draw the #456 far building every frame and bury it by depth (no hiding mechanism exists to port); retail DOES draw depth-only invisible portal-polygon panels (`DrawPortalPolyInternal` — punch far-Z / seal own-depth) — the AD-117 stamps re-invented a real mechanism at the wrong site. **Known gap:** the first capture round did not record the camera pose; exact FW1 replay needs pose-stamped traces. A prepared template (`tools/walk-oracle/fw0-capture-pose.cdb.template`) makes the re-capture a short owner-assisted session; scheduled for when FW1's walk is ready to gate (structural conformance proceeds meanwhile on the existing traces). **Goal:** retail's actual per-frame draw walk, captured and replayable, BEFORE any port is judged. - Build the cdb capture harness (`tools/walk-oracle/`): breakpoint script logging, per frame, the sequence of cell/building draw entries with stage boundaries — hook `PView::DrawCells`, `CEnvCell` draw, `CLandBlock`/`LScape::draw`, `DrawBuilding`; dump cell ids (`this` offsets verified with one-shot `dt` first). cdb safety rules from the PV campaign are binding: never inline `-c` attach to a client that matters, every `j` branch ends in `gc`, `qd` threshold auto-detach, watch hit-rate lag. - Capture positions (owner assists — retail sessions): Sanctuary terrace center + terrace EDGE (normal camera — the #456 acceptance pose), cathedral portal-in arrival, a Holtburg doorway (the flap scene), a Holtburg street + house exit, one deep dungeon corridor. Record camera pose per capture. - Also capture the same positions in acdream (world state: cell registry contents) so W1 replays are apples-to-apples. - Pin the port function list as a research note with pseudocode stubs: `docs/research/2026-08-30-fw-walk-pseudocode.md` (grow it through FW1). - **Deliverable/gate:** trace fixtures checked into `docs/research/2026-08-30-fw-walk-oracle/`, replayable by a test helper; harness scripts committed; no production code touched. ### FW1 — `RetailFrameWalk` + `PViewSet` (pure CPU, conformant) **Goal:** the ported walk as a standalone module that reproduces the oracle traces exactly. - New `src/AcDream.App/Rendering/Walk/`: `RetailFrameWalk` (rooting per `SmartBox::RenderNormalMode`; EnvCell recursion per `PView::DrawCells`; landscape walk per `LScape::draw`/`grab_visible_cells`; building look-ins per `DrawBuilding` + `ConstructView(CBldPortal)`), `PViewSet` (`ConstructView`/`set_view`/`PView::GetClip` — the chain polygon is the only CPU-clipped geometry; one view per chain, never merged), `IWalkWorldView` (the read seam: committed cells via the registry, buildings via `BuildingRegistry`, camera pose). - Output: an ordered walk event stream (cell id, view, stage) matching the oracle trace format, plus the frame's visible-cell set. - Pseudocode first (workflow step 3), C# port line-by-line (step 4), named symbols in comments. - **Gates:** oracle-trace replay tests pass position-for-position; synthetic-world unit tests for rooting/recursion/cone edge cases; the existing replay fixture suite (Issue95/113/120/124/127/130/131/176-177/ 181, SanctuaryPortalSeam, HouseExitWalkReplay, TowerAscentReplay, CornerFloodReplay) re-expressed against the walk — behavior differences vs the old builder are adjudicated against the ORACLE, not against the old builder. No production wiring; hermetic suites green. **FW1 STATUS (2026-08-30, @`77f5342b`):** NINE of the ten pose-stamped fixtures reproduce retail frame-exactly (foundry-deep all 39 frames, doorway-still, street-outdoor, terrace-center, terrace-edge — the #456 acceptance pose — cathedral-arrival, holtburg-walkout, -transitions, -walkabout); foundry-entry is exact through F66 with the F67–F79 standing segment parked on ONE live number (building 0036's root-plane viewpoint — probe `tools/walk-oracle/fw1-f67-viewpoint-probe.cdb`, goal-sanctioned retail-session stop filed with the user). Load-bearing adjudications, all decomp-cited: the two-arm `get_degrade` threshold rule (ideal→max at the live `deg_mul≈+0.99`), deg_mul's DYNAMIC swing under capture load (doorway-still pins mul=0 — an environment pin like the viewport), znear=0.1 confirmed, and the Ghidra-arbitrated portal walker truth table (BN FPU pseudo-C mis-renders branch sense — three separate misreads this stage; Ghidra first, always). **Gate amendment:** the old-replay-fixture re-expression is retired as an FW1 gate — the ten traces are direct retail evidence and strictly supersede fixtures that encode the OLD builder's behavior; the old suite's scenario classes (doorway flap, dungeon seams, tower ascent, corner flood) are covered by the traces and re-verified live at the FW3/FW4 connected gates, where the old fixtures retire with the old builder. Production classes: `RetailFrameWalk`, `WalkPView` (the PViewSet role), `WalkBuildingPortals`, `WalkLandscape`, `WalkVisibilityMath`, `WalkScreenClip`, `WalkCopyView` under `src/AcDream.App/Rendering/Walk/`. ### FW2 — `OrderedDrawStream` + `OrderPreservingSubmitter` **Goal:** walk-order submission through the existing RHI, proven pixel-equivalent on static content. - `OrderedDrawStream`: append-only (mesh ref, transform, material state, stage, cell) commands in walk order. `OrderPreservingSubmitter`: binds `GlobalMeshBuffer` once, reuses ring-section writers + `MeshPipelineSet` + `DrawIndirectRangeRhi`; emits per-instance first (the deferred-alpha SSBO pattern), then merges ADJACENT same-state commands into MDI runs — a merge across a state or stage boundary is forbidden by construction (assert it). - Depth semantics: port retail's depth compare/write configuration for the world passes verbatim in this stage (current set uses Less — verify against retail's raster state and document the finding either way). - Diagnostic harness: a dev scene (offscreen target) drawn twice — old path vs walk path — framebuffer-compared (the Slice-7 comparison pattern, with the pixel-diff repeat floor from `feedback_pixel_diff_needs_repeat_floor`). - **Gates:** submitter unit tests (order preservation, merge legality); framebuffer equivalence on static-content scenes; hermetic suites green. **FW2 STATUS (2026-08-30, @`e65644cb`):** `OrderedDrawStream` + `WbDrawDispatcher.OrderedStream` (the submitter partial — per-instance- first emission, pure-CPU merge-run builder, fail-loud stage/pipeline/ cull boundary validation) and `WorldDepthContract` are landed with 27 RecordingGpuDevice gates; hermetic 6,714/0. Depth verified verbatim from the decomp (`zfuncVal` 0x2 = D3DCMP_LESS via `SetDepthBufferMode` @0x005a2d10; LESSEQUAL is GameSky-local). **Gate adjudication:** the offscreen pixel A/B rides FW3's cutover toggle — a walk-driven scene first exists there, `IGpuRenderTarget` has no readback verb today, and opaque content under Less is order-independent, so the RecordingGpuDevice order/merge referees are FW2's automated gate and the pixel proof joins FW3's (offline pixel gate + owner visual gate). Deferred to FW3 and recorded in the code: the building-detail overlay replay, portal-punch emission, and the `_drawCullModes`/alpha-scope sequencing constraint. ### FW3 — static world cutover + THE perf checkpoint **Goal:** terrain, EnvCell shells, and buildings draw via the walk in production; the statics gather path is deleted; perf is measured before deeper commitment. - Root the production frame at the walk: `WorldSceneRenderer` drives `RetailFrameWalk` + submitter for the static routes (LandscapeOutdoorStatic, LandscapeBuildingShell, CellStatic); dynamic routes (LookInObject, LandscapeOutsideDynamic, DynamicLast) stay on the packed path within this stage only (the route-contract split makes the seam clean). - Retire the three `ShellDrawLiftZ` sites in this stage — walk order + retail depth semantics replace the tie-break; prove it at the #130 doorway-strip scene before deleting, and delete the register row in the same commit. - Terrain/sky/weather draw at their walk turns (the stage interleave from `RetailPViewPassExecutor`'s ported knowledge moves inward). - **Perf checkpoint (the spec's stop rule):** dense Arwic uncapped, Release, exact binary: CPU/GPU p50/p99 + fps vs the current production profile (519.7 fps / 1.869 / 1.096 ms baseline). Within 20% → proceed; worse → STOP, owner decision with numbers on the table. - **Gates:** transition checklist self-run; hermetic suites; owner visual gate (statics look right indoors + outdoors, no seam strip at the doorway, no z-fighting at shells); perf numbers recorded in this plan. **FW3 SLICE PLAN (2026-08-30, from the cutover-surface survey):** - **FW3.1 — production walk world data.** Materialize the walk's world model at landblock commit time, registry-owned, through the LEGAL `IDatReaderWriter` seam (never raw `DatCollection` — `RuntimeDatAccessArchitectureTests`): (a) `WalkCell` fields onto/beside `LoadedCell` (portal side/exact from the RAW `Flags` already preserved on `CellPortalInfo`; plane from the existing `ClipPlanes` parallel list; the 0xFFFF→0xFFFFFFFF exit-sentinel widening); (b) a production `WalkBuilding` build in `LandblockBuildFactory`/`BuildingLoader` — the BIGGEST gap: today's `Building` drops ModelId/Frame/portal flags/stab lists at load; (c) the walk landscape assembly (retail z-slabs from the height table, the SideCellCount LOD pyramid, `CellBuildings[]`, viewer-centred grid) fed from landblock residency; (d) the production frame context: camera/rays/CyPlane/ObjectToClip derived from the LIVE `WorldCameraFrame` + real viewport (the capture client's 1024×720 constants are fixture pins, not production values). Conformance: the ten oracle fixtures re-run against the PRODUCTION builders (same DATs → identical walk output as the test adapter). - **FW3.2 — walk-driven static routes.** `WorldSceneRenderer` drives `RetailFrameWalk` → `OrderedDrawStream` (Terrain/BuildingShell/CellStatic/LookInStatic/PortalPunch stages) → `SubmitOrderedStream` for static content; the old builder STOPS EMITTING `LandscapeOutdoorStatic`/`LandscapeBuildingShell`/`CellStatic` ranges (the `CompletePackedProductionFrame` count assertion forbids emit-but-skip); dynamic routes (`LookInObject`, `LandscapeOutsideDynamic`, `DynamicLast`) stay packed — which requires `ClipFrameAssembler` + `ViewconeCuller` to SURVIVE this stage (their slices key the dynamic routes). Walk-path SELECTION publication (static picking today rides `publishSelection: true` in the packed classifier — an unlisted consumer; the walk submitter must feed `RetailSelectionScene` or statics go un-clickable). Portal-punch emission via `PortalDepthMaskRenderer` at walk turns; building-detail overlay replay; sky/weather move from per-slice to the walk's landscape turn; the `_drawCullModes`/alpha-scope sequencing constraint resolved (own cull scratch or strict sequencing). Route-keyed particle owners re-sourced from the walk. - **FW3.2b-2 — the production rooting (DESIGN, 2026-08-30; execute INLINE, not via subagent — the integration-slice rule).** The dual-compute split for this stage: the OLD visibility (`PortalVisibilityBuilder` + look-in frames + clip assembly + viewcone) KEEPS RUNNING to feed everything dynamic; the WALK draws everything static. No old static DRAWS remain (no double draw): 1. `RetailPViewRenderer.DrawInside` keeps steps 1–8 and 10–11 (visibility, merge/look-in seeding, clip frame, prepare — with `prepareCells` UNIONED with the walk's flood/look-in cells — viewcone, route build) but `RenderScenePViewFrameProduct` STOPS emitting `LandscapeOutdoorStatic`, `LandscapeBuildingShell`, and `CellStatic` ranges. Per the plan's route split, LOOK-IN OBJECTS (`LookInObject`) are dynamic-side and STAY PACKED this stage — the old look-in machinery keeps drawing look-in cell content and its punches; the WALK's building turns therefore draw shell content + punches for NON-look-in... NO — resolve the overlap the other way: the walk's building turns run their punch+look-in machinery ONLY for the walk's own conformance events; production look-in DRAWS (punch fans + content) stay entirely on the old path this stage, and the walk's `BuildingShell` stage content + `OnPunchGeometry`/look-in DC draws are SUPPRESSED in the driver's production wiring for look-in-owned buildings… REJECTED — that is a dual path. FINAL: the walk owns ALL of it — building shells, punches, look-in STATIC content (stage LookInStatic) — and the `LookInObject` route survives ONLY for the DYNAMICS inside look-in cells (`BuildLookInRoutes` filtered to dynamic classifications). The old `DrawBuildingLookIns` static half and `DrawLookInPortalPunch` retire with the static routes. 2. `WalkFrameDriver`'s leaf renderer maps to: sky → `RetailPViewPassExecutor` sky call; terrain slice → `_terrain.Draw(camera, frustum, clipPlanes: slice.Planes, ndcClipAabb: slice.NdcAabb)`; cell shell → `EnvCellRenderer.Render(pass, singleCellSet)` (+ transparent ordered per cell); punch fan → `PortalDepthMaskRenderer. DrawDepthFan(worldVerts, viewProjection, slicePlanes, forceFarZ: true)`; `ClearInteriorDepth` → `IWorldPassScope.ClearInteriorDepth` (keep production's slices>0 gate); `DrawExitSeals` → the existing seal-fan loop (`DrawPortalDepthWrite` seal flavor over the root flood's exit portals); alpha barrier → `RetailAlphaQueue.FlushFartherThan`. 3. Static records: cell statics via `RenderSceneQuery. CopyCellStaticsTo(cellId)`; outdoor statics via a per-landscape- cell index built once per frame from `CopyIndexTo(OutdoorStatic)`; building shells via the `IsBuildingShell` entities keyed by anchor cell. 4. Consumers re-pointed: particle owners (`RenderFrameRouteOwnerSelector.Replace(LandscapeOutdoorStatic…)` sites) re-source from the walk's populated cells; diagnostics source counts tolerate the route removal; `EmitRenderSignature`'s terrain/scenery counts re-source or annotate. 5. Sky/weather: sky moves into the walk's LS turn (once); weather stays in the old late-dynamics slice loop this stage (it is dynamic-adjacent and the plan's FW4 moves it fully). 6. Gates before the owner sees a build: hermetic + InstalledDat suites; the connected lifecycle route; the offline pixel gate (outdoor statics); dense-Arwic pre/post pair (physical display). **FW3.2b-2 STATUS (2026-08-30, @`4918677b`): THE STATIC CUTOVER IS COMMITTED.** The walk drives every production static draw (`DrawWalkDrivenStatics` + the dynamics-remainder phases); the three static routes are deleted from the product builder; particle owners re-source from the walk's per-cell-turn visited sets (retail's own gate — `ShouldDrawParticles` @0x0050FE60). Landed evidence: the walk shadow probe ran 11k+ live frames faultless with walkCells ⊂ oldCells every frame. The old static path survives ONLY behind `!walkActive` for the executor-fake test path (15 retail-ordering regression tests; unreachable by production) — **its deletion is FW4 scope**. Transitional risks recorded in code: two-pass walk cost (FW3.4 measures), interior slice-count reconciliation between the old clip assembly and the walk's exit-view survival, outdoor merged-flood punch coverage now riding the walk's building-BSP punches (owner visual gate verifies). Suites: hermetic 6,750/0; Walk 201/1; InstalledDat conformance 40/1 untouched. - **FW3.3 — ShellDrawLiftZ retirement.** THREE sites (the register row AP-32 lists only two — `LandblockBuildFactory.cs` bakes the lift into the drawn cell transform and is unlisted): delete all three, flip the #130 proof (`UnliftedGate_LeavesTheStripAtTheDrawnTopEdge` is explicitly written to fail-by-gap until the lift is gone), delete AP-32 in the same commit. **FW3.3 STATUS (2026-08-30, @`05240d2c`): RETIRED + connected-PASSED.** ShellDrawLiftZ deleted at every site (AP-32 deleted same commit); the #130 proof flipped as authored (strip test deleted, the 147-combo coverage sweep passes in the one dat space, unchanged tolerances). Three lifecycle-gate PASSES today on exact binaries; owner-confirmed live: no seams at the doorway class. PERF FLAG for FW3.4: Holtburg town 19-22 ms CPU p50 / ~1.8 MB-frame alloc on the walk path (capped diagnostic read; interiors 3.3 ms) - candidates: collapse the two-pass walk, batch per-cell shells, cache the outdoor-statics index, cut per-segment rebinds. **FW3.4 PERF PAIR (2026-08-30, same session/conditions, exact binaries):** dense Arwic uncapped, PRE (@87853359, old static path) vs POST (@3a05d659, walk-driven): CPU p50 23.6 -> 31.6 ms (+33.5%), p95 36.3 -> 44.3 ms (+21.9%), alloc p50 133 KB -> 1,920 KB/frame (14x). THE +/-20% STOP RULE TRIGGERS. Sources are the flagged known costs (two walk passes/frame, per-cell single-segment submissions with full section rebinds, per-cell record-array copies in the world data). FW3.4a fixes them (single walk pass; prepare-once/draw-ranges - the deferred-alpha architecture; pooled record segments), then the pair re-measures against the SAME baseline; the owner decision only triggers if it still exceeds 20% after the known fixes. **FW3.4a RESULT (2026-08-30, @`1da178d9`): THE STOP RULE CLEARS.** Post-refactor dense Arwic uncapped vs the SAME baseline: CPU p50 23.6 -> 22.9 ms (-3.2%), p95 36.3 -> 34.7 ms (-4.5%) - the walk path is now FASTER than the old static path. The refactor's own crash round (VK_ERROR_DEVICE_LOST) taught the binding contract: leaf draws and alpha flushes rebind set-0 between ranges, so DrawOrderedRange rebinds per call; only the ring WRITES are once-per-frame. FOLLOW-UP FILED: alloc p50 still ~1.5 MB/frame on the walk path (baseline 133 KB) - the per-frame driver/leaf/populator object graph in DrawWalkDrivenStatics; hoist to renderer fields with per-frame Reset (FW3.4 closeout or FW6 polish; CPU-neutral today, GC-hitch hygiene). - **FW3.4 — perf checkpoint + gates.** BASELINE CORRECTION: the 519.7 fps / 1.869 / 1.096 ms numbers are the Aerlinthe ordinary-production profile, NOT dense Arwic. Before the cutover lands, capture a fresh dense-Arwic pre-cutover baseline with the same harness (`tools/run-connected-r6-soak.ps1 -Uncapped -DenseTown`), and apply the ±20% stop rule to THAT pair. Transition checklist: the lifecycle gate + dense-town soak exist; a Holtburg house-exit stop and a teleport stopwatch metric must be ADDED to the lifecycle route (`drive.ps1` from the spec does not exist — the checklist runs on the existing gate scripts). ### FW4 — entities, particles, dynamics into walk turns; delete the apparatus **Goal:** everything draws at its walk turn; the patch apparatus and the old visibility layer are gone. **FW4 SLICE 1 — the interior outside-view source cutover (2026-08-30, pulled forward from the FW3 visual gate).** The owner's stairwell/grass transition report (grass briefly covering floor openings at doorway crossings, intermittent — the #119 family) probe-pinned to the FW3 dual path: the walk decided WHETHER terrain draws (`_interiorPView.OutsideView. ViewCount > 0`) while the old `PortalVisibilityBuilder` assembly decided WHERE (slice clip planes + count + scissor), and the walk's punch fans indexed the OLD slice array with WALK view indices. At boundary frames (`ACDREAM_PROBE_WALK_ROOT` captures: the slices=2 short-flood family at OUT→IN, a 1-frame outdoor blip mid-crossing) the old builder's exit views went fat/degenerate, terrain splashed over interior pixels, and the depth-clear preserves COLOR — any cell absent from the walk's flood never repainted its pixels. Retail cannot produce this: it has ONE visibility structure. The cutover: `ClipFrameAssembler.ReassembleOutsideViewFromWalk` materializes the walk's own `outside_view` (pixel points → standard NDC → the existing `ClipPlaneSet.From` machinery) into the assembly's outside-view block right after Collect, before the single `PrepareClipFrame` publication (moved below the walk block); the `Landscape` event now carries the walk's active-view count (rides the record's existing `OutsideViewCount` field — trace mapping compares kind only, ZERO oracle-fixture churn) and the driver fans exactly that many terrain slices — `activeTerrainSliceCount` is deleted end to end. Outdoor roots keep the assembler's single full-screen slice (asserted ==1; identical content by construction). Suites: hermetic 6,762/0 (4 new materializer tests pinning the y-flip + plane-sign conventions), Walk lane 209/1, InstalledDat walk conformance 40/1 — all unchanged or grown. Remaining desync surfaces deliberately left for the rest of FW4: exit SEALS + cell slices still assemble from the old per-cell views (identical dat portal polygons; only the visible SET can differ), and interior-root look-in seeding still reads the old outside view. **FW4 SLICE 2 — the walk-flood seal cutover (2026-08-30, pulled forward from the FW3 visual gate's cathedral round).** The owner's cathedral report (waterfall particles shining through from the terrace — toggling with which side of the #456 seam the CAMERA resolves to) probe-pinned via the `[walk-part]`/`[walk-alpha]` phase tags: the falls emitters ride the cell-owners route and submit POST-depth-clear on interior-rooted frames (retail's own timing — cell-scope alpha drains at the end-of-frame flush against seal-owned depth), but our seal SET still came from the old apparatus's flood, which misses exit portals at the #456 seam band (its never-drawn panel family) — unsealed aperture depth let the end-of-frame drain z-pass across the whole opening. `DrawWalkExitPortalMasks` now stamps THE WALK'S OWN ordered interior flood (`WalkFrameDriver.InteriorFloodCells`, captured at `OnInteriorFloodDrawTurn` — retail pc:432785-432786's reverse cell_draw_list), with the old assembly's per-cell slice clips where present and unclipped seals (benign: exact dat aperture polygon, z-tested) where the old apparatus had no entry. The legacy !walkActive path keeps the old seal draw. Suites: hermetic 6,762/0, Walk lane 213/1, InstalledDat walk conformance 40/1. - Entities gate per view via `Render::viewconeCheck` at their cell's walk turn; dynamics-last and alpha interleave per the walk's stages (`RetailAlphaQueue` becomes the stream's alpha stage or is absorbed — decide at implementation with the retail stage list as the arbiter); particles draw at their owner cell's turn (`ShouldDrawParticles`), unclipped. - Re-point the consumers at the walk's visible-cell output: particles (`ParticleVisibilityController`), lights (`BuildPointLightSnapshot` filter), EnvCell prepare filter. Directional-shadow caster selection consumes the same set. - DELETE in this stage (registry rows updated in the same commits): look-in seeding + callers + barrier math; punch stencils (`PortalDepthMaskRenderer` #117); the InViewCells side-channel; `PortalVisibilityBuilder`'s production role; `RetailPViewRenderer` / `RetailPViewPassExecutor` shells (their stage knowledge now lives in the walk); the packed route machinery + `PackedOracle` + both classification caches; `CellVisibility`'s dead BFS. - **Gates:** the full re-expressed replay suite; transition checklist; hermetic suites; the owner visual matrix — cathedral #456 acceptance (far building, monsters, stalks hidden at the terrace edge at NORMAL camera; no seam strip; no z-fighting; candle/falls/lake/portal-flood intact), doorway flap, dungeon wall/floor seams, portal-in, house exit, teleport timing. ### FW5 — camera completion **Goal:** the camera is retail's, end to end. - Port `CameraSet::Farther`/`CameraSet::Raise` verbatim into `RetailChaseCamera`: the multiplicative offset scaling with the write-refusal gates (|x|<10, |y|<10, z<450, z>−1.8 — NOT a simple distance clamp), the preserved-length pitch. The 40 m dev zoom goes away with it (owner-approved in the spec round). - Port retail's zoom/pitch adjustment rates if recoverable from decomp (retires TS-56); if not recoverable, TS-56 stays with a note. - **Gates:** camera unit tests against ported constants; owner side-by-side feel gate vs retail (chase, zoom saturation ≈13 m boom, collision, slope align). ### FW6 — closeout - Divergence-register reconciliation (added: landblock-stage streaming exposure rows if not already rowed, order-preserving MDI merging as intentional architecture; retired: lift, #117 stencils, look-in-era rows, TS-56 if ported). - Docs: architecture doc render section rewritten around the walk; `worldbuilder-inventory.md` updated (WB = asset layer only); `launch-options.md` rows for any probes added/removed (probes die with their investigations). - Memory: `project_render_pipeline_digest.md` rewritten current-truth-on-top around the walk; campaign memory closed out. - Roadmap + milestones updated; the quarantined PV branch gets a disposition note (kept as archive; nothing merges). - Final gates: full hermetic suites, both standard connected routes, the complete owner visual matrix, merge to main. ## Rollbacks Each stage lands as its own commit series; record `git revert` anchors here as stages close (the Modern Runtime plan's convention). FW3 and FW4 are the cutover stages — their revert anchors are mandatory entries. ## Risks (tracked, from the spec) - **Perf** — decided by FW3's checkpoint, numbers over hope. - **Streaming scope creep** — only the two register-rowed exposure adaptations may be touched; anything more is out of scope. - **Oracle fidelity** — traces need owner-assisted retail sessions (FW0); captured once, checked in. - **Classifier drift during staging** — FW3's split runs walk statics beside packed dynamics for one stage; the route contract seam is the guard, and FW4 deletes the duality. - **Camera ergonomics** — the dev zoom disappears at FW5; a separate dev flycam is deliberately deferred (the Fly camera in `CameraController` already exists for development framing).