The cathedral falls shine-through (owner report at the #456 terrace seam, toggling with the camera''s side of the seam): the probe''s new phase tags pinned the falls emitters to the cell-owners route submitting POST-depth-clear on interior roots - retail''s own timing, safe only because seals own the aperture depth by the end-of-frame alpha drain. 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), so the drain z-passed across the unsealed opening. DrawWalkExitPortalMasks now stamps the walk''s own ordered interior flood (WalkFrameDriver.InteriorFloodCells, captured at OnInteriorFloodDrawTurn - retail PView::DrawCells pc:432785-432786), keeping the old assembly''s per-cell slice clips where present and sealing unclipped where the old apparatus had no entry (benign: the exact dat aperture polygon, z-tested). The legacy path keeps the old seal draw. Also: ACDREAM_PROBE_WALK_ROOT gains [walk-part]/[walk-alpha] phase-tagged submission/drain lines (the apparatus that pinned this). Hermetic 6,762/0, Walk lane 213/1, InstalledDat walk conformance 40/1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
35 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.
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::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).