The FW3 visual gate's stairwell/grass transition flash (grass briefly covering floor openings at doorway crossings - the #119 family) was the FW3 dual path leaking: the walk decided WHETHER terrain draws while the old PortalVisibilityBuilder assembly decided WHERE (slice planes, count, scissor), and punch fans indexed the old slice array with walk view indices. The new ACDREAM_PROBE_WALK_ROOT apparatus pinned the boundary frames: fat/degenerate old-apparatus exit views splash terrain over interior pixels, the interior depth-clear preserves color, and cells absent from the walk's flood never repaint. Retail has ONE visibility structure and cannot produce this. ClipFrameAssembler.ReassembleOutsideViewFromWalk now materializes the walk's own outside_view (pixel screen points -> standard NDC -> the existing ClipPlaneSet machinery) into the assembly's outside-view block after Collect, ahead of the single PrepareClipFrame publication (moved below the walk block). The Landscape event carries the walk's active view count on 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. Hermetic 6,762/0 (4 new materializer tests pin the y-flip and plane-sign conventions), Walk lane 209/1, InstalledDat walk conformance 40/1. Seals/cell slices/look-in seeding stay on the old per-cell views for the rest of FW4 (identical dat polygons; only the visible set can differ). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
33 KiB
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
— 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)
- 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.
- Grep named first.
docs/research/named-retail/acclient_2013_pseudo_c.txtbyclass::methodbefore any fresh decompilation; pseudocode notes indocs/research/before C# (the mandatory workflow). - 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.
- 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.
- 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.
- Register discipline. Deviations add their row in the same commit;
ported mechanisms delete rows in the same commit
(
docs/architecture/retail-divergence-register.md). - 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 byTerrainModernRenderer.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 — hookPView::DrawCells,CEnvCelldraw,CLandBlock/LScape::draw,DrawBuilding; dump cell ids (thisoffsets verified with one-shotdtfirst). cdb safety rules from the PV campaign are binding: never inline-cattach to a client that matters, everyjbranch ends ingc,qdthreshold 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 perSmartBox::RenderNormalMode; EnvCell recursion perPView::DrawCells; landscape walk perLScape::draw/grab_visible_cells; building look-ins perDrawBuilding+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 viaBuildingRegistry, 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: bindsGlobalMeshBufferonce, reuses ring-section writers +MeshPipelineSetDrawIndirectRangeRhi; 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:
WorldSceneRendererdrivesRetailFrameWalk+ 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
ShellDrawLiftZsites 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
IDatReaderWriterseam (never rawDatCollection—RuntimeDatAccessArchitectureTests): (a)WalkCellfields onto/besideLoadedCell(portal side/exact from the RAWFlagsalready preserved onCellPortalInfo; plane from the existingClipPlanesparallel list; the 0xFFFF→0xFFFFFFFF exit-sentinel widening); (b) a productionWalkBuildingbuild inLandblockBuildFactory/BuildingLoader— the BIGGEST gap: today'sBuildingdrops 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 LIVEWorldCameraFrame+ 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.
WorldSceneRendererdrivesRetailFrameWalk→OrderedDrawStream(Terrain/BuildingShell/CellStatic/LookInStatic/PortalPunch stages) →SubmitOrderedStreamfor static content; the old builder STOPS EMITTINGLandscapeOutdoorStatic/LandscapeBuildingShell/CellStaticranges (theCompletePackedProductionFramecount assertion forbids emit-but-skip); dynamic routes (LookInObject,LandscapeOutsideDynamic,DynamicLast) stay packed — which requiresClipFrameAssembler+ViewconeCullerto SURVIVE this stage (their slices key the dynamic routes). Walk-path SELECTION publication (static picking today ridespublishSelection: truein the packed classifier — an unlisted consumer; the walk submitter must feedRetailSelectionSceneor statics go un-clickable). Portal-punch emission viaPortalDepthMaskRendererat 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):RetailPViewRenderer.DrawInsidekeeps steps 1–8 and 10–11 (visibility, merge/look-in seeding, clip frame, prepare — withprepareCellsUNIONED with the walk's flood/look-in cells — viewcone, route build) butRenderScenePViewFrameProductSTOPS emittingLandscapeOutdoorStatic,LandscapeBuildingShell, andCellStaticranges. 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'sBuildingShellstage 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 theLookInObjectroute survives ONLY for the DYNAMICS inside look-in cells (BuildLookInRoutesfiltered to dynamic classifications). The oldDrawBuildingLookInsstatic half andDrawLookInPortalPunchretire with the static routes.WalkFrameDriver's leaf renderer maps to: sky →RetailPViewPassExecutorsky 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 (DrawPortalDepthWriteseal flavor over the root flood's exit portals); alpha barrier →RetailAlphaQueue.FlushFartherThan.- Static records: cell statics via
RenderSceneQuery. CopyCellStaticsTo(cellId); outdoor statics via a per-landscape- cell index built once per frame fromCopyIndexTo(OutdoorStatic); building shells via theIsBuildingShellentities keyed by anchor cell. - 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. - 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).
- 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.csbakes the lift into the drawn cell transform and is unlisted): delete all three, flip the #130 proof (UnliftedGate_LeavesTheStripAtTheDrawnTopEdgeis 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.ps1from 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.
- Entities gate per view via
Render::viewconeCheckat their cell's walk turn; dynamics-last and alpha interleave per the walk's stages (RetailAlphaQueuebecomes 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 (BuildPointLightSnapshotfilter), 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/RetailPViewPassExecutorshells (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::Raiseverbatim intoRetailChaseCamera: 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.mdupdated (WB = asset layer only);launch-options.mdrows for any probes added/removed (probes die with their investigations). - Memory:
project_render_pipeline_digest.mdrewritten 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
CameraControlleralready exists for development framing).