94 KiB
S3 — Walk: exact PView views, leaf admission, and interleave — ownership map and chunk plan
Status: DRAFT packet written 2026-09-03 at the S2 closeout, BEFORE the owner's §7 capture session. Every retail claim below is decomp-verified (named pseudo-C + Ghidra bridge, cited by address); the capture session adds the per-frame TRANSCRIPT the automated gate needs and may amend §3 (marked "capture-owned"). Nothing in this packet is implemented yet.
Plan: docs/plans/2026-09-01-campaign-overhaul-world-solidity.md §9 S3.
Binding inputs: oh1-retail-world-contract.md §4–§5 (view/frame order),
oh1-built-mesh-view-contract.md (caller order, stamps, direct answers,
binding constraints), 2026-08-30-fw-flood-pseudocode-appendix.md, the FW
plan's verified seam map (docs/plans/2026-08-30-campaign-fw-frame-walk.md
§"Verified seam map"), and S2's ownership truth
(s2-membership-ownership-map.md §9: the registry is the only membership
source; the walk reads GetRetailPartEntriesInCell).
1. What S3 changes (behavior)
WalkPView owns retail's exact per-frame state — the portal-view lists, the
view/update counts, the todo order, the draw list, and the stamps — and each
content category follows its retail leaf rule. Terrain is emitted as ordered
landcell events interleaved with buildings and object lists in retail
far-to-near order. DrawBuilding is one semantic sequence. The "all terrain
first" simplification and every generic GPU clip rule that retail does not
have are deleted. S3 ships no evidence infrastructure beyond the one
print-only transcript emitter its own gate consumes (rule §5).
2. Retail truth (decomp-verified; addresses are the Sept 2013 build)
| Retail function | Address | What it decides | Verified in |
|---|---|---|---|
PView::InitCell / InsCellTodoList |
(walk root; see flood appendix) | seeds the flood from the viewer cell, orders the todo list | flood appendix |
PView::ClipPortals / AddViewToPortals / ConstructView |
PView::GetClip → polyClipFinish @0x006B6D00 |
builds CHILD VIEWS by polygon-clipping PORTAL polygons — the only polygon clip in the walk | built-mesh contract §"What polygon-clips?" |
Render::copy_view |
0x0054dfc0 |
copies the view polygon, derives edge planes (0x48 semantic fields, prune, cap 31) | built-mesh contract ledger |
Render::set_view |
0x0054d0e0 |
installs the view in render globals; NO scissor, NO general mesh clip | idem |
Render::obj_view_set |
0x0054b9b0 |
transforms the active planes/sphere through FrameCurrent, publishes local_object_center/radius |
idem (side effects unrepresented — Medium row) |
Render::viewconeCheck |
0x0054c250 |
the ordinary sphere admission: strict-outside / inclusive-partial | WalkVisibilityMath pins |
CPhysicsPart::Draw |
0x0050d7a0 |
outer part-stamp skip (+0xdc vs device +0xb0); force bypasses; local player bypasses the inner stamp |
idem |
RenderDeviceD3D::DrawMeshInternal |
0x0059f360 |
first admitted view stamps the non-player part and submits the WHOLE eligible mesh once; later views return | idem |
RenderDeviceD3D::DrawEnvCell |
0x0059f170 |
no sphere admission; cell stamp (+0x130) gate; whole shell once per stamp |
idem |
RenderDeviceD3D::DrawBuilding |
0x0059f2a0 |
detail state → FlushAlphaList(0) → CPhysicsPart::Draw(part,1) portal-only BSP pass → flag → Draw(part,0) ordinary shell |
idem |
PView::DrawCells |
0x005a4840 |
outside-view branch (sunlight, LScape::draw, alpha flush, device-stamp advance @0x005a4886, counter consume/clear, exit seals) then reverse shells (CEnvCell::setup_view @0x0052c430 per live view + DrawEnvCell) then reverse object lists (DrawObjCellForDummies) |
retail-world contract §5.2 |
LScape::draw_check_blocks / landcell_check / grab_visible_cells / draw / calc_draw_order |
(landscape walk) | admitted land cells in retail FAR-TO-NEAR order; per admitted cell DrawLandCell THEN DrawSortCell (building pass / look-in / shell / object turn) |
retail-world contract §5.2; capture-owned: the exact calc_draw_order sequence at the four poses |
DrawObjCellForDummies |
(object-list path) | installs the cell's top portal_view_type as PortalList, walks the cell's shadow part list (CShadowPart::insertion_sort by CYpt) and draws each part through the view loop |
built-mesh contract §"object-list path" |
Facts already PROVED and binding (do not re-derive, do not weaken):
- the built cell shell is stamped and submitted whole once after Boolean admission;
- portal polygons, not built meshes, are polygon-clipped;
DrawCellsdraws all shells then all object lists, both in reverse draw-list order, views ascending;- device, cell-shell and part stamps persist with the local-player bypass;
- the "first view clips the shell" hypothesis is RETIRED.
3. Current acdream owners (functions, not line numbers — re-locate at chunk time)
| Retail mechanism | Current owner | Assessment (from the built-mesh comparison at eaea8776, re-checked against c94a1a40 file list) |
S3 action |
|---|---|---|---|
| view polygon / planes | WalkViews |
strong match | keep; pin |
| viewcone sense | WalkVisibilityMath |
exact | keep |
| flood + todo order | WalkFrameDriver (flood turns, VisitedCells, OnLandscape) |
order proven for shells/objects; _skyDrawnThisFrame is a PROXY for retail's outside_view.view_count != 0 |
chunk 2 replaces the proxy with the real outside-view count |
| whole-mesh admission at slot 0 | WbDrawDispatcher.WalkClassify (ResolveWalkLightSet, part stamps, RetailWholeMeshSlot) |
correct | keep; chunk 4 deletes the still-translated clip slots per category |
| part stamp identity | (RenderProjectionId, PartIndex) |
retail identity is the CPhysicsPart*; S2 made per-cell membership registry-borrowed, so one logical part now reaches the classifier from EVERY cell it is in with the SAME projection id — the identity audit the contract asked for is now structurally answered; pin it |
chunk 2 pin |
| cell shell once per stamp + mid-frame re-arm | WalkFrameDriver shell loop, RetailPViewPassExecutor.WalkLeaf |
correct | keep; re-arm gate moves to the real outside-view count |
| building sequence | WalkFrameDriver building turn, RetailFrameWalk |
matches alpha barrier → portal pass → shell | keep; pin as ONE sequence |
| terrain emission | RetailPViewPassExecutor landscape stage (whole-stage terrain event before building/object turns) |
DIVERGES: retail is DrawLandCell then DrawSortCell PER admitted land cell, far-to-near |
chunk 3 |
| landscape leaf's use of the installed outside-view list | TerrainModernRenderer visible cells + WalkFrameDriver.VisitedLandscapeCellIds |
top-level ownership proven; per-leaf pixel use is an S3 audit item | chunk 3 audit (bounded: one pose) |
| generic GPU clip rules for categories retail never clips | Vulkan clip slots on look-in / straddling / building categories (RetailPViewPassExecutor, UseIndoorMembershipOnlyRouting) |
retail clips only portal polygons | chunk 4 delete, with a CPU/GPU equivalence pin for any category that must keep a translated clip |
obj_view_set side effects |
not represented (world-space sphere vs captured planes) | mathematically aligned for affine transforms | out of S3 unless the capture shows a consumer |
missing SelectionSphere fallback |
"any view → whole mesh" | not a retail branch | keep as a corruption fallback, outside parity claims (register row if it survives S5) |
4. Chunks (bounded; one Sonnet agent each; stop on a third round)
Chunk 1 — transcript emitter + parser + fixture import (needs §7 captures).
One print-only flag (documented in docs/launch-options.md in the same
commit) emits the OH line kinds the capture templates produce
(tools/walk-oracle/oh/*.template: walk / parts / alpha-depth) from the
production walk; the existing FW0-style test-side parser is extended for the
new kinds; the four captured pose logs are imported as fixtures. Gate: the
emitter's lines parse with the same parser as the retail logs; NO validator,
NO canonical JSONL (rule §5, feedback-evidence-infrastructure-sink).
BLOCKED until the owner runs the capture session.
Chunk 2 — exact PView state. WalkPView (new, App/Rendering/Walk) owns:
the live view list per cell (retail portal_view_type lists), the
outside-view count, the view/update counts, the todo order, the draw list and
the two stamps. _skyDrawnThisFrame and every other proxy for
outside_view.view_count != 0 is replaced by the real count. Per-category
leaf contract pinned: whole-once (built shell), Boolean sphere (ordinary
part), actual polygon clip (portal polygons only), repeated submission (local
player). Part identity pin: the same logical part reached from two cells
classifies once per stamp. Can start before the capture (decomp oracle);
the capture confirms.
Chunk 3 — interleave. Terrain becomes ordered landcell events: for each
admitted land cell in retail far-to-near order, DrawLandCell (that cell's
terrain range) then DrawSortCell (building pass 1 / look-in work / building
shell / land-cell object turn). Per-landcell terrain ranges come from the
existing terrain mesh layout (index ranges per landcell — verify
TerrainModernRenderer exposes them; if not, the chunk adds the range table
at bake/upload time, not a per-frame rebuild). The whole-stage terrain event
is deleted in chunk 4, not here (two-step so the pixel gate can bisect).
Gate: terrain pixels/mesh counts unchanged when no interleave is present;
dense-outdoor p50/p99 recorded before/after.
Chunk 4 — deletions. The whole-stage terrain event; the generic clip rules on categories retail never clips (Vulkan clip slots removed from those categories); any residual "first view clips the shell" code path. Gate: no duplicate draw of a stamped part across a pan/zoom replay; membership/draw count changes only at a retail view boundary.
5. Review (one Opus retail lens + one shader/perf lens at the S3 boundary)
- retail lens on every stamp/view loop branch and on the call order against the capture transcript and the decomp;
- shader review of clip-space sign, y inversion, W plane, plane count and scissor for the categories that KEEP a translated clip;
- performance review: the command-count increase from interleaving is
measured (dense outdoor p50/p99), not hidden by reordering.
Lead verifies every finding against the source before an edit (S2 precedent:
19 findings, 4 blocking, all real; see
s2-membership-ownership-map.md§9).
6. Automated gate (S3 has no standalone owner gate; folds into G3)
- transcript equality with the §7 captures at the captured depth for all four poses plus the FW0 still fixtures;
- tests distinguish whole-shell-once, Boolean part admission and actual polygon clipping;
- pan/zoom replay changes membership/draw count only at a retail view boundary;
- no duplicate draw of a stamped part;
- terrain pixels/mesh counts unchanged when no interleave is present;
- self-gate route (
tools/overhaul-selfgate/) at the three owner poses + the four capture poses, pixel-diffed against the G2 candidate runlogs/selfgate-20260903-010022-s2-review-fixes-3— the per-region diff, not the eye, is the verdict (feedback-deleted-fallback-carried-population).
6b. Capture session progress (2026-09-03)
- Recon PASSED against the live 2013 client (
logs/oh-capture/oh-recon.log): every template offset and breakpoint address matches; globals sane. - Pose
cathedral-leak(extra, owner-chosen): standing on the cathedral stairs where the outside structure leaks into the interior — RETAIL SHOWS THE ARTIFACT (2013 and EoR clients both). Transcript:logs/oh-capture/cathedral-leak.walk.log(5 frames: DIf4180108, DC withov=4, EC/OC stamps, 531LC/SCland-cell draws per frame in far-to-near order over landblocksf3–fe×00–18),cathedral-leak.parts.log(3 frames, 5,933 PD / 965 DM),cathedral-leak.alphadepth.log(5 frames, 1,407 AM / 2,856 FL / 28 PM / 16 PC). Owner's retail screenshot (2026-09-03, 2013 client, SAVED atlogs/oh-capture/cathedral-leak.retail.png, lead-verified): standing on the floating stairs inf4180108, a large slab of the EXTERIOR wall (arched exterior stone texture) cuts diagonally through the stair chamber from the upper left, drawn over the interior landings and ramps that remain visible around it — the same leak acdream shows at the same spot. This pose is S3/S4's primary oracle: the target is to reproduce retail's frame at it, leak included. - Pose
cathedral-arrival(owner "ready" 2026-09-03 06:58): transcriptlogs/oh-capture/cathedral-arrival.walk.log(5 frames, 5,604 lines: main PView009d4f48DIf4180108, DCov=3n=2f4180108 f4180107; a SECOND PView009d4530withov=0draws cellsf4180113/f4180112/f4180114each frame with no DI of its own — RESOLVED (§8 R1): it isRenderDeviceD3D::outdoor_pview's look-inDrawCells, driven byPView::DrawPortalfrom the building pass; 454LC+ 619SCper frame, 40 EC / 40 OC total),cathedral-arrival.parts.log(3 frames, 7,822 PD / 1,240 DM),cathedral-arrival.alphadepth.log(5 frames, 1,735 AM / 3,570 FL / 35 PM / 19 PC). NOTE: the kit README expectedDI f4180106(FW0's arrival still); the live client reportedf4180108, the stair-chamber cell — the owner's actual standing cell, recorded as-is. - Chunk-3 oracle read off the two cathedral transcripts (frame 2 of each,
viewer in
f4180108): after the rootDI/DCand ONELS, retail emitsLC <cell>thenSC <cell>for every admitted land cell in STRICT alternation (LSLSLS…, never twoLCin a row) —DrawLandCellthenDrawSortCellper cell, exactly the per-cell interleave chunk 3 ports. Block order is far-to-near from the far corner: rowsy=00…0deach walkedx=fe→f6, then from the Chebyshev-10 ring inward the column and row interleave diagonally (fe0e fd0e fe0f fc0e fe10 fb0e fe11 …), ending at… f417 f318 f418; the exact rule isLScape::calc_draw_order's and the transcript pins it. Far blocks draw ONE cell (xx000001, side count 1); near the viewerSCfires for all 64 cells of the block whileLCfires only for the in-view ones (f418: 16 LC / 64 SC;f417: 56 / 64;f318: 3 / 64) —DrawSortCellruns underalwaysDrawObjectsfor every cell of an in-view block,DrawLandCellonly for in-view cells (RenderDeviceD3D::DrawBlock@0x005a19d9 — chunk 3 re-reads the exact gate). Per frame: leak pose 531 LC / 757 SC / 16 BLD; arrival pose 533 LC / 698 SC / 14 BLD. - Pose
holtburg-doorway-still(owner "ready" 2026-09-03 ~07:35): transcriptlogs/oh-capture/holtburg-doorway-still.walk.log(5 frames, 5,986 lines: DIa9b4013f; frame 2: rootDC pv=009d4f48 ov=2 n=3: a9b4013f a9b40150 a9b4014c, 5 look-in DC turns (ov=0, cellsa9b40103/a9b40100— the same cell punched by consecutive look-ins, as FW0 noted), 469 LC / 677 SC / 13 BLD; 45 EC / 45 OC over 5 frames),holtburg-doorway-still.parts.log(3 frames, 3,304 PD / 510 DM),holtburg-doorway-still.alphadepth.log(5 frames, 430 AM / 3,414 FL / 35 PM / 29 PC). No memory errors. - Pose
terrace-edge(owner "ready" 2026-09-03 ~07:45, "I think this is the correct edge"): OUTDOOR root, viewer cellf418000b. Transcriptlogs/oh-capture/terrace-edge.walk.log(5 frames, 5,590 lines; frame 2: 1 LS, 578 LC / 780 SC, 14 BLD, 2 look-in DC turns into the cathedral cellsf4180100/0101/0104; buildingF518002Eis drawn FIRST on every complete frame (1–4; frame 5 is the detach marker), and the 14-building set and ORDER are identical to FW0'sterrace-edge.logframe 2 — the #456 vista oracle holds and the owner stood at the same edge),terrace-edge.parts.log(3 frames, 11,767 PD / 5,173 DM — the densest pose),terrace-edge.alphadepth.log(5 frames, 6,880 AM / 3,515 FL / 10 PM / 10 PC). No memory errors. - Pose
foundry-deep(owner "ready" 2026-09-03 ~07:50): DIa9b40176, rootDC ov=1 n=2: a9b40176 a9b40177— the surviving stairwell chain FW0 recorded; frame 2: 62 LC / 161 SC / 12 BLD (the landscape and 12 town buildings drawn from the basement and buried by depth, exactly FW0's reading).logs/oh-capture/foundry-deep.walk.log(5 frames, 1,269 lines; 10 EC / 10 OC),foundry-deep.parts.log(3 frames, 2,524 PD / 189 DM),foundry-deep.alphadepth.log(5 frames, 104 AM / 700 FL / 4 PM / 4 PC). No memory errors. - CAPTURE SESSION COMPLETE 2026-09-03: the four kit poses
(
holtburg-doorway-still,terrace-edge,cathedral-arrival,foundry-deep) plus the extracathedral-leakpose each have walk (5 frames, with LC/SC), parts (3 frames) and alpha-depth (5 frames) transcripts underlogs/oh-capture/(untracked; the §6b lines above are the durable record). Chunk 1 (transcript emitter + parser + fixture import) is UNBLOCKED.
7. Open questions for the capture session (ask for exactly these two)
LScape::calc_draw_ordersequence at each of the four poses (far-to-near land cell order) — chunk 3's oracle. Captured by the walk template'sLC/SClines (added 2026-09-03:RenderDeviceD3D::DrawLandCell0x0059f120 /DrawSortCell0x0059f140, one line per call with the cell'sm_DID).- Per-frame
outside_view.view_countand the device-stamp advance count at each pose — chunk 2's oracle for the re-arm gate.
8. Chunk 2 contract — exact PView state (lead, 2026-09-03, written during the capture session)
Every claim below was re-read this session in the named pseudo-C and, where
BN's FPU rendering was ambiguous, in Ghidra (port 8081, patchmem.gpr, the
paired 2013 build). Addresses are the Sept 2013 build.
8.1 Retail facts (verified)
- R1 — two PViews.
RenderDeviceD3D::Init@0x0059efb0 constructsindoor_pview = PView(…, 1)andoutdoor_pview = PView(…, 0); the ctor argument isdraw_landscape(@0x005a52c1).RenderDeviceD3D::DrawInside@0x0059f0d0 tail-callsPView::DrawInside(indoor_pview, cell);RenderDeviceD3D::DrawPortal@0x0059f0e0 pinsbuilding_view = -1aroundPView::DrawPortal(outdoor_pview, …). The captures' secondpvwithov=0(009d50e0at cathedral-leak,009d4530at cathedral-arrival, cellsf4180112/13/14, fourDrawCellsper frame, noDI) is outdoor_pview's look-in flood through the cathedral's exterior portals. acdream'sRetailFrameWalk._outdoorPView { DrawLandscape = false }andWalkBuildingPortals.DrawPortalalready model this. PIN ONLY. - R2 — flood reset.
PView::ConstructView(CEnvCell)@0x005a57b0 setsoutside_view.view_count = 0,master_timestamp++,cell_todo_num = 0,cell_draw_num = 0beforeInitCell.WalkPView.ConstructViewmatches. PIN ONLY. - R3 — the
outside_view.view_count > 0branch encloses the whole landscape turn.PView::DrawCells@0x005a4840: from 0x005a4852 to 0x005a49eb, ALL ofuseSunlightSet(1),PortalList = this,LScape::draw,FlushAlphaList(0f)@0x005a4872,m_nFrameStamp += 1@0x005a4886, the gated Z clear @0x005a4893–0x005a48a9, and the exit-seal loop @0x005a48c0–0x005a49eb (per draw-list cell far-to-near, per live viewCEnvCell::setup_view@0x005a4983, thenDrawPortalPolyInternal(portal_poly, 0)@0x005a49b7 for every portal whoseother_cell_id == 0xffffffff) sit INSIDEif (outside_view.view_count > 0). OnlyuseSunlightSet(0),restore_all_lighting, the reverse shell loop @0x005a4a00 and the reverse object-list loop @0x005a4ade are unconditional. DIVERGENCE TODAY:WalkFrameDriver.OnInteriorFloodDrawTurnemitsClearInteriorDepthandExitSealsunconditionally and gates the stamp advance on the_skyDrawnThisFrameproxy; its comment and the driver's type doc claim "both unconditional for an interior root's own flood" — that claim is wrong against the decomp, and theWalkFrameDriverTestspin that reads "ov==0 … CLEAR/SEALS still fire unconditionally" pins the wrong behavior. (The plan's S5 cleanup inventory already lists "unconditional clear code"; chunk 2 retires it now.) - R4 — the Z clear is gated by a persistent seal counter. The clear is
if (forceClear != 0 || portalsDrawnCount != 0) Clear(Z), withD3DPolyRender::portalsDrawnCount(uint16 @0x008719b4) read-then-zeroed at that point (@0x005a489c–0x005a489e).forceClear(@0x008ed824) is a.dataint with no write anywhere in the pseudo-C (its only references are the two reads and its definition) → the clear fires iffportalsDrawnCount != 0. The counter increments ONLY inDrawPortalPolyInternal@0x0059bc90 at 0x0059bd74, and only when its second argument is FALSE, after a degenerate-polygon guard (Ghidra: skip when every vertex hasx == +12, or everyx == −12, or everyy == +12, or everyy == −12— an equality sentinel, NOT a ±12 clip box as BN's FPU rendering suggests) and BEFOREpolyClipFinish— it counts calls, not surviving fans. False-argument callers: the exit seals (@0x005a49b7, literal 0); pass-3ConstructView(CBldPortal)punches (@0x005a5a7b,arg5 == 1→ false for pass 3);PView::DrawPortal'sarg4 == 3failure branch (@0x005a5b7c). ButDrawMeshInternalruns buildings through passes 1 and 2 only (@0x0059f3cc / @0x0059f3d9), and pass 1's punch passes TRUE (maxZ1, no increment) — so in the building path the counter is fed by EXIT SEALS ALONE. Consequence, a retail quirk to port as-is: the firstov>0interior frame after a period without seals draws NO Z clear; every laterov>0frame clears because the previous frame's seals armed the counter. Outdoor frames and look-inDrawCells(ov=0) neither arm nor consume it. - R5 — punch/seal depth state.
SetDepthBufferMode(DEPTHTEST_ALWAYS, (maxZ >> 2) & 1)withmaxZ1 = 7(argument true: building pass 1) andmaxZ2 = 6(argument false: seals, pass 3); both write depth. S4's terrain-punch question is untouched by chunk 2. - R6 — part identity. Retail stamps the
CPhysicsPart(+0xdc against the device's +0xb0). After S2, one logical part reaches the classifier from every cell it is in with the SAME projection id, so(RenderProjectionId, PartIndex)is the identity. PIN ONLY.
8.2 Production behavior change
- B1 — the real count gates the whole turn.
RetailFrameWalk.DrawInsidepasses_interiorPView.OutsideView.ViewCounttoIWalkEventSink.OnInteriorFloodDrawTurn(cells, outsideViewCount). The driver then executes retail's branch exactly:outsideViewCount > 0→ the landscape flush leaf (retailFlushAlphaList(0f)@0x005a4872 plus the pre-clear dynamics hook thatRetailPViewRenderer.ClearWalkInteriorDepthbundles today), the stamp advance (AdvanceWalkPartPassStamp+ the shell and particle-turn re-arms), thenClearInteriorDepthONLY IFPortalsDrawnCount != 0(read-then-zero, R4), thenExitSeals;outsideViewCount == 0→ none of them._skyDrawnThisFrameis deleted; its "second landscape turn" fail-loud guard is kept on a frame-scoped count field, its "landscape ran" use is replaced by the count the sink receives. - B2 — the counter. The driver owns
PortalsDrawnCount(retailD3DPolyRender::portalsDrawnCount), retained ACROSS frames (the driver is retained byRetailPViewRenderer; never cleared byBeginFrame/AbortFrame/EndFrame), incremented at the exit-seal turn by the number of seal polygons actually submitted: for each flood cell (far-to-near) × each live view slice × each portal withOtherCellId == 0xFFFFand ≥3 vertices — the same enumerationRetailPViewPassExecutor.DrawPortalDepthWriteperforms. Implement it as a return value from the seal leaf (DrawExitSealsreturns the submitted count) so the count and the draws come from ONE enumeration; the driver adds it. Never incremented by punch fans. Not touched by look-inDrawCells. - B3 — leaf split.
RetailPViewRenderer.ClearWalkInteriorDepthsplits intoFlushWalkLandscape(pre-clear dynamics +FlushLandscapeAlpha) andClearWalkInteriorDepth(the Z clear only);IWalkFrameLeafRenderergains the flush leaf andDrawExitSealsreturnsint;WalkFrameEventKindgainsLandscapeFlush. The fake leaf inWalkFrameDriverTestslogs it as"LFLUSH". - B4 — no new owner class. The packet's "
WalkPView(new)" is the EXISTINGWalkPView; chunk 2 adds no class. The per-category leaf contract (whole-once built shell; Boolean sphere for ordinary parts; polygon clip for portal polygons only; repeated submission for the local player) is pinned by tests — the implementer first LISTS which of these four pins already exist (WalkFrameDriverTests,WbDrawDispatcherWalkClassify tests,WalkVisibilityMathpins) and adds ONLY the missing ones, naming the retail address in each test's comment.
8.3 Tests (flip, add, keep)
- T1 (flip): the
ov==0pin expects NOLFLUSH/CLEAR/SEALSand no stamp advance before the flood — the opposite of today's expectation. - T2 (add):
ov>0first frame →LFLUSH, NOCLEAR,SEALS, flood; the next frame of the same driver →LFLUSH,CLEAR,SEALS, flood (armed by frame 1's seals); a driver whose flood cells have no exit portal never clears. - T3 (add): a look-in
DrawCells(ov=0,LookInStaticstage) neither arms nor consumes the counter. - T4 (add if absent): R1 (two pviews, the outdoor one never raises an outside view) and R2 (the reset) pins.
- T5 (update): the existing direct
OnInteriorFloodDrawTurncallers (WalkFrameDriverTests≈ lines 349, 602–610, 642, 693–703) pass the count they model; the two "look-in shell repaints after the clear" tests modelov>0: one asserts the first-frame no-clear quirk explicitly, the other pre-arms the counter (a prior seal turn) and asserts the clear — both behaviors stay pinned. - Keep: every other driver/walk pin unchanged;
LaunchOptionsDocumentationTestsis unaffected (no flag added or removed).
8.4 Out of scope for chunk 2
Terrain interleave (chunk 3); clip-slot deletions and the
ProbeCathedral* discriminators (chunk 4 / the S5 inventory); S4's punch
z-func; the pre-clear dynamics hook's retail home (LScape::draw's per-cell
object turn — chunk 3 places it).
8.5 Lead verification and gate
Every R-fact re-read at its address before the commit; the App hermetic
lane plus the InstalledDat lane green; the three-pose self-gate plus the two
captured cathedral poses pixel-diffed against
logs/selfgate-20260903-062615-s2-chunk6 — the expected delta is zero at
steady state (the only retail-different frame is the first ov>0 frame after
a no-seal period, which no still captures); the walk transcript at
cathedral-arrival must still show the root DC ov=3 and four look-in
DC ov=0 turns per frame.
9. Chunk 3 contract — the landscape interleave (lead, 2026-09-03)
Written during the capture session from the two cathedral transcripts and the decomp; every fact below is verified at the cited address or against the captured sequence itself. Chunk 3 implements AFTER chunk 2 lands (it edits the same driver).
9.1 Retail facts (verified)
- R1 — the per-cell interleave.
RenderDeviceD3D::DrawBlock@0x005a17c0 runs two loops over the block'sdraw_array(far-to-near): loop 1 (@0x005a1876)IsInView && num_shadow_objects→UpdateObjCell+CShadowPart::insertion_sort; loop 2 (@0x005a197d)if (IsInView) DrawLandCell(cell)@0x005a19c0, thenif (alwaysDrawObjects != 0 || IsInView) DrawSortCell(cell)@0x005a19e6 followed byFlushAlphaList(flush)only whenflush > 1. Retail defaults:alwaysDrawObjects = 1(@0x00820ed4),flush = 0.75f(@0x00820ed0) — soDrawSortCellruns for EVERY cell of an in-view block,DrawLandCellonly for in-view cells, and the per-cell alpha flush is inert. Transcript (frame 2 of both captures): oneLS, thenLC/SCin strict alternation, never twoLCin a row; 531 LC / 757 SC (leak), 533 LC / 698 SC (arrival);SC= 64 per near block,LC= only the in-view cells. - R2 — the order port is oracle-exact.
LandWalkOrder.GetBlockOrder(LScape::get_block_order@0x00504c50, walked backwards) andFillCellOrderFarToNear+ClosestCell(CLandBlock::calc_sq_draw_order@0x0052f4a0;CLandBlock::calc_draw_order@0x00530300 is a tail call to it) reproduce the capturedLCANDSCsequences for all 260 (arrival) / 256 (leak) blocks with ZERO mismatches, given two facts the check needed: (i) the captured blocks span Chebyshev ring 24, so the grid radius is ≥ 24 —WalkLandscapeAssembler.MidRadius = 25is consistent; (ii) LOD cell ids are numberedx*8 + y + 1in LOD coordinates (a side-2 block's cells are1, 2, 9, 10), i.e. retail'slcell[x*side+y].m_DID. LOD by ring from the captures: ring 0–1 → side 8, ring 2 → 4, ring 3–4 → 2, ring ≥ 5 → 1 — exactlyWalkLandscapeAssembler.SideCellCountForRing. The FW-eraIWalkEventSink.OnLandscapeCellTurn(landblockId, side, cellIndex)already expands a coarse cell into its covered 8×8 owner buckets. - R3 — one land cell's terrain is arithmetic on the existing mesh.
DrawLandCell@0x0059f120 draws one land cell at the block's LOD. acdream's terrain mesh is 8×8 cells per landblock, cell-major (LandblockMesh.Build:cyouter,cxinner,indices[i] = i, 6 indices per cell), uploaded per slot withFirstIndex = slot * 384(TerrainModernRenderer.IndicesPerLandblock == 384). acdream cell(cx, cy)is the contiguous run[(cy*8 + cx)*6, +6)inside the slot; a retail LOD cell (siden, LOD coords(X, Y)) coverscx ∈ [X*8/n, (X+1)*8/n),cy ∈ [Y*8/n, (Y+1)*8/n)→8/nruns of(8/n)*6contiguous indices (side 8: one run of 6; side 4: two runs of 12; side 2: four runs of 24; side 1: one run of 384). No range table is baked; no per-frame rebuild. - R4 — why the interleave is a behavior change (the S4 hypothesis). The
far-Z punch (
DrawPortalPolyInternal,DEPTHTEST_ALWAYS+ write) runs at the BUILDING's cell turn (DrawSortCell→DrawBuilding). In retail every NEARER land cell's terrain is drawn AFTER that punch and overwrites the punched depth, so a doorway behind a hill cannot show its interior through the hill. acdream draws ALL terrain first (TerrainSlice(0)at the landscape turn) and every building afterwards, so a doorway behind a hill punches through it — the doorway-sized house fragments through the Holtburg hill in the owner's G2 screenshot. Chunk 3 is expected to remove that artifact by ORDER alone; the Holtburg self-gate pose is the verdict. If it does, S4's "exact z-func" question closes with no z-func change (ledger + S4 row note). This supersedes the packet's §4 "two-step bisect" wording: the whole-stage terrain event is replaced in THIS chunk (drawing terrain twice would already hide the punch and make the gate meaningless), and chunk 4 loses that deletion. - R5 — the sky draws TWICE, and the second pass is the WEATHER.
LScape::draw@0x00506330 callsGameSky::Draw(sky, 0)@0x0050633c BEFOREdraw_check_blocks, walks the blocks (DrawBlock@0x00506374), then callsGameSky::Draw(sky, 1)@0x00506396 AFTER every block.GameSky::Draw@0x00506ff0'sarg2 == 1is the weather pass, gated onSmartBox::is_player_outside@0x00451e80 (already Ghidra-arbitrated and modeled byRetailPViewPassExecutor.DrawLandscapeSliceLate'sRenderWeathercall — see that method's comment). Chunk 3 keeps the sky at the landscape turn's start and places the weather pass AFTER the last land cell of the turn (retail order); the implementer confirms where the late landscape slice runs relative to the new per-cell events and moves the weather call only if it currently runs before them.
9.2 Production behavior change
- B1 — per-cell land-cell events.
RetailFrameWalk.DrawLandscapeemits, perDrawArraycell in retail order:sink.OnLandCellTurn(landblockId, side, cellIndex)whenCellInView[cellIndex] != Outside(R1'sDrawLandCellgate), THEN the existingDrawBuilding+OnLandscapeCellTurn(theDrawSortCellhalf, gated byAlwaysDrawObjects || in viewas today). The driver records aLandCellframe event (slot landblock id, LOD side, LOD cell index, plus the retail LOD cell idx*8+y+1for the chunk-1 transcript) at that point in the stream, and DELETES the whole-stageTerrainSlice(0)emission and theDrawTerrainSliceleaf. The leafDrawLandCellsubmits the R3 index runs through a newTerrainModernRenderer.DrawCellRuns(landblockId, side, cellIndex)(or a batched form, B2) with the same pipeline/state the whole-block draw uses, UNCLIPPED for interior roots exactly as the FW4-slice-6 comment demands (retail never view-clips terrain; the exit seals and the interior repaint own aperture exactness). - B2 — order-preserving batching. Consecutive
LandCellevents of the SAME slot with no intervening non-terrain event merge into ONE indirect draw whose command list is the concatenated runs in event order; any intervening event (building alpha barrier, punch, shell, statics mark) splits the batch. Pixel-identical by construction; this is the only concession to the ~530–700 land cells per frame. - B3 —
TerrainModernRenderer.Draw(...)keeps serving non-walk callers (directional-shadow receivers etc.); the walk path stops calling it. The_walkTerrainInViewLandcellsplumbing that only fed the walk draw is deleted if nothing else reads it (grep; if a shadow pass reads it, leave it and say so). - B4 — no new class beyond the leaf/renderer entry points, no flag, no
probe. The existing
OnLandscapeCellTurnLOD expansion is unchanged.
9.3 Tests
- T1 (order pin, R2):
LandWalkOrder+WalkLandscape.CalcDrawOrder+SideCellCountForRingreproduce frame 2'sLCandSCsequences of BOTH captures. Fixture = the parsed cell-id sequences (reuse the existing test-side readertests/AcDream.App.Tests/Rendering/Walk/WalkOracleTrace.csfor theLC/SCline kinds; no new evidence infrastructure). Viewer: blockf4/18, sq cell(1, 1)(from thePline: x 36.6, y 24.0). - T2 (interleave, R1/B1): a two-block synthetic landscape with one building
and one out-of-view cell: events are
SKY, LC(far)…, [LC, BLD…, statics]…with each cell'sLCbefore its own building/statics, cells far-to-near; the out-of-view cell gets NOLCbut keeps its sort turn underAlwaysDrawObjects; noTerrainSliceevent exists any more. - T3 (runs, R3): for side ∈ {1, 2, 4, 8} and every LOD cell, the runs cover
exactly the covered 8×8 cells' index ranges, disjoint, total
(8/n)²·6. - T4 (batching, B2): two consecutive same-slot
LCmerge into one draw; an intervening building barrier splits; order inside the batch is the event order. - T5: existing
WalkFrameDriverTests/ renderer pins onTERRAIN:0updated to the per-cell events; every other pin unchanged.
9.4 Out of scope
Clip-slot deletions (chunk 4); any depth-compare change to the punch (S4 — but the Holtburg verdict is recorded and S4 re-scopes if the punch leak is gone); the pre-clear dynamics hook's home (chunk 4).
9.5 Lead verification and gate
R-facts re-read at their addresses; the App hermetic + InstalledDat lanes green; the three-pose self-gate plus the Holtburg terrain-leak pose (the owner's G2 screenshot spot) plus the two cathedral poses, pixel-diffed against the chunk-2 run: the ONLY expected delta is the punch region at Holtburg (fragments gone); dense-outdoor p50/p99 recorded before/after with the existing frame-time diagnostics (no new counters).
9.6 Chunk 3 fix round 1 (lead, 2026-09-03, after the three-lens review of 671eb3ad)
Verdicts: build/test FAIL (blocking: the per-batch timing diagnostic), retail
FAIL (blocking: the terrain slot key), driver FAIL (blocking: batching is
inert). Lead-verified against the source; every item below is real. Fix in the
same worktree on top of 671eb3ad; this is round 1 of the two the plan allows.
- F1 — slot key (blocking).
TerrainModernRenderer._idToSlotis keyed by the DAT landblock id0xXXYYFFFF(LandblockRenderPublisher.LandblockId => Build.Landblock.LandblockId; the old walk filter compareddata.LandblockId & 0xFFFF0000), while the walk hands0xXXYY0000(WalkLandBlock.LandblockId = bx<<24 | by<<16).DrawLandCellRunstherefore misses every lookup and the walk path draws NO terrain. Normalize at the terrain entry: look up(landblockId & 0xFFFF0000u) | 0xFFFFu; add a unit test thatAddLandblock(0xA9B4FFFF, …)is found by a0xA9B40000lookup and that an unknown block is a no-op. - F2 — batching across landblocks, deferred across no-op turns (blocking).
Retail's
DrawSortCellfollows everyDrawLandCell, soHandleLandscapeCellTurnalways appends aStaticParticlesevent (and, for cells with content, aStreamMark) between twoLandCellevents — the "adjacent, same landblock" rule never merges. The terrain index buffer is ONE buffer withFirstIndex = slot*384 + start, and the deleted whole-stage draw already issued oneMultiDrawIndexedIndirectspanning every visible slot, so a batch may span LANDBLOCKS. New rule, still order-preserving by construction: Replay keeps a PENDING terrain batch (list of(landblockId, side, cellIndex), cleared at frame start); aLandCellevent appends to it; before any leaf call that WILL submit GPU work the pending batch is flushed (DrawLandCellsonce); a particle turn whose cell has no renderable emitter submits nothing and does NOT flush — addParticleSystem.HasRenderableEmittersInCell(pass, cellId)(a lookup in the existing per-pass cell→handles index, no allocation) and ask it in Replay'sStaticParticles/CellParticlesarms BEFORE flushing; every other event kind (StreamMark,AlphaBarrier,LandscapeFlush,ClearInteriorDepth,ExitSeals,PunchFan,CellShell,Sky) flushes first, and the end of Replay flushes the remainder. The GPU submission order is then IDENTICAL to the unbatched order (a skipped particle turn submits nothing either way).TerrainModernRenderer.DrawLandCellRunsbecomesDrawLandCells(viewProjection, IReadOnlyList<(uint LandblockId, int SideCellCount, int CellIndex)>): resolve each entry's slot (F1), skip unknown slots, build the run commands in list order, ONE indirect draw. Expected at terrace-edge frame 2: tens of submissions, not 578; report the count from a driver test and in perfNote. - F3 — the terrain diagnostic (blocking). One sample per FRAME, not per
batch: the leaf accumulates each batch's elapsed
Stopwatch.GetTimestamp()delta (no allocation) and the executor/renderer pushes ONE sample at the end of the walk replay (where the old whole-stageComplete()semantics lived);TerrainRenderDiagnosticFacts.VisibleSlots= distinct slots submitted this frame (a per-frame bit set/scratch cleared atBeginFrame),draws= batches submitted. The[TERRAIN-DIAG]line keeps its meaning (cpu_us per frame) so §9.5's before/after compare is valid. - F4 — driver pins for the LandCell position (major). The deleted
TERRAIN:0pins are REPLACED, not dropped: the fake leaf logsLANDCELL:<lb>:<side>:<idx>[,…]per batch; add (a) an outdoor-rootRunFrametest with a synthetic in-view block whose sequence isSKY, LANDCELL…with the block's cell turns after their terrain, (b) an interior-root test with one exit view and one block:SKY, LANDCELL…, LFLUSH, SEALS, SHELL…, (c) the batching pin from T4 re-expressed for the new rule: two land cells of DIFFERENT landblocks with only an empty particle turn between them merge into oneLANDCELLbatch; aStreamMark(a cell with statics) or a building barrier between them splits; the fake leaf's particle turn reports "has emitters" from a test-set so both arms are covered. - F5 — interior-root terrain extent (major, answered, no code change).
Retail's
DrawLandCellfires only for in-view cells (DrawBlock@0x005a197d; capture:f41816 LC of 64) — the per-cell admission IS retail; the FW4 under-paint came from the GPU clip of terrain to the portal polygon, which no longer exists. Keep the in-view gate; the cathedral self-gate poses are the check (recorded in the ledger either way). - F6 — minor/notes. Frustum cull: the walk's
CheckBlocksadmission is the authority (retail has no separate terrain frustum test beyondlandcell_check); document that inDrawLandCells' comment. The cathedral order-trace token prints:LC<lb>/<side>:<idx>. Fix the inverted comment inHandleLandscapeTurn(a FARTHER building's punch survives because NEARER terrain was drawn before it; the interleave draws that terrain after). Fix the "directional-shadow receivers" claim (the only non-walk caller is the flat-terrain path). Replace T2's vacuousTERRAINassertion with the driver-level pins of F4. Retire the stale "Confirmed OH5 defect" row inoh1-construction-landscape-contract.md(line ≈310) with a one-line "FIXED by S3 chunk 3 (<sha>)". - Gates unchanged (§9.5); the implementer additionally reports, from the F4(c)-style driver test over a synthetic terrace-like frame, the batch count for the terrace-edge cell sequence if it can be driven cheaply, else the reasoning.
9.7 Chunk 3 fix round 2 (lead, 2026-09-03 — the perf gate of §9.5 FAILED at e10765aa; round 2 of the two the plan allows)
Measured. Connected R6 soak logs/connected-r6-soak-20260903-100400 at
e10765aa versus the S2-final baseline …-010403 (same runner, both
Uncapped=false, both graceful with zero failures): CPU p50 = 31.2 ms at EVERY
outdoor destination (baseline 2.0–15.5 ms), FPS 32 flat (baseline 51–452),
GPU p50 2–4× (Holtburg 1.8→4.6 ms, Caul return 2.9→12.2, Aerlinthe 1.4→3.0,
Rynthid 0.7→2.2, Sawato 0.2→0.8). The cost is flat because the admitted land
cell count (~500–600) is the same at every outdoor stop; nearly every cell
carries scenery statics, so a StreamMark follows almost every LandCell and
splits the pending batch → ~500 terrain submissions per frame, each running
TerrainModernRenderer.DrawRhi's full bind sequence (pipeline, push
constants, vertex/index buffers, tiling table, scene-lighting and terrain-clip
sections, the shadow uniform) plus one ring allocation and one MDI.
- F10 — an opaque ordered-stream flush is NOT a terrain flush point. The
ordered stream holds ONLY
IsOpaquebatches (WalkStaticStreamPopulatorroutes translucent batches to the alpha list;WbDrawDispatcher.DrawOrderedRangedraws them with theOpaque/OpaqueAlphaToCoveragepipeline, depth test AND write on, no blending). Opaque terrain and opaque statics are therefore depth-resolved in either order — pixel-identical except exact z-ties — so aStreamMarkno longer flushes the pending terrain batch. The flush points that REMAIN are exactly the events whose GPU order against terrain is observable:PunchFan(depth ALWAYS + write — the ordering chunk 3 exists for),AlphaBarrierandLandscapeFlush(translucent drains),ClearInteriorDepth,ExitSeals,Sky,CellShell, a particle turn whose cell has a renderable emitter, and the end of Replay. Consequence: batches split only at buildings and punches (terrace-edge: 14 buildings → tens of batches per frame), and the punch ordering is preserved because every punch flushes the terrain drawn before it and the terrain after it starts a new batch. The implementer CITES the ordered stream's pipeline state (file:line of the pipeline selection and the depth/blend state) in the Replay comment; if any ordered-stream stage blends or disables depth write, that stage's mark stays a flush point and the contract is amended, not bent. - F11 — no per-batch bind latch. With tens of batches per frame the full bind sequence per batch is acceptable; do not add state tracking.
- F12 — tests. F4(c) updated: a
StreamMarkbetween two land cells no longer splits (one batch); aPunchFan, anAlphaBarrier, and a has-emitter particle turn each split. New punch-order pin:LandCell(far), building turn with aPunchFan,LandCell(near)→ the leaf log readsLANDCELL(far),PUNCH,LANDCELL(near)— the far terrain is flushed BEFORE the punch and the near terrain drawn AFTER it. Every other pin unchanged. - Gate. Re-run the SAME soak at the fix commit: CPU p50 per destination ≤ 1.3× the baseline and GPU p50 ≤ 1.3× the baseline (Sawato's sub-ms values compare by absolute ≤ +0.5 ms); the four-pose self-gate: the Holtburg fragments still gone, Facility/cathedral/house structurally unchanged. Both recorded in the ledger. If this round does not meet the gate, chunk 3 STOPS and is written up (plan rule §5).
10. Chunk 4 contract — deletions (lead draft, 2026-09-03; re-locate every owner at chunk time, after chunks 2 and 3 land)
10.1 What retail clips, and what it does not (verified)
- Retail polygon-clips exactly three things on the CPU with
ACRender::polyClipFinish: portal polygons when building child views (PView::GetClip@0x005a4320 →polyClipFinish), the punch fans (DrawPortalPolyInternal@0x0059bc90 clips the fan against the installed view —building_view@0x0059f3bf during the building pass), and the exit seals (the same function underCEnvCell::setup_viewper live view, @0x005a4983–0x005a49b7). Ordinary meshes, cell shells, terrain, particles and the weather are NEVER view-clipped:DrawMeshInternal@0x0059f360 submits the whole mesh after the sphere test,DrawEnvCell@0x0059f170 draws the whole shell,LScape::drawdraws whole blocks, andGameSky::Draw(sky, 1)@0x00506396 runs ONCE after the blocks with only theis_player_outsidegate (§9 R5).
10.2 acdream inventory (at edb32783; names, not lines — RE-CHECKED at 38b5adc5 after chunk 3:
DrawTerrainSlice and _walkTerrainInViewLandcells are already gone; DrawLandscapeSliceLate,
SetTerrainClip, BeginDoorwayScissor, BindTerrainClip, SetCellShellClipRouting,
VisibleClipSlotsInLookInTurn, UseIndoorMembershipOnlyRouting, ClearClipRouting, the
sky-post-scene clipSlot: and the six remaining ProbeCathedral* members/rows still exist)
KEEP (translated clips with a retail CPU counterpart — each gets a CPU/GPU equivalence pin if it lacks one):
- exit seals:
RetailPViewRenderer.DrawWalkExitPortalMasks→DrawExitPortalMask(cell, InteriorFloodViewClipPlanesAt(...))per (flood cell, live view) — retail'ssetup_view+polyClipFinishper view; - punch fans:
DrawPunchFan(worldPolygon, activeViewIndex)clipped by the pinned view's slice planes — retail'sbuilding_viewclip; - the walk's
CaptureViews/AppendClipSlotslot table ONLY as far as the two consumers above need it.
DELETE (no retail counterpart):
- the whole-stage terrain event and
DrawTerrainSliceleaf — already replaced by chunk 3 (§9 R4); chunk 4 verifies nothing re-grew; - the per-outside-view-slice weather/late landscape loop
(
RetailPViewRenderer"GameSky's weather pass still runs through each active landscape view":SetTerrainClip+ClearClipRouting+DrawLandscapeSliceLateper slice withBeginDoorwayScissor+BindTerrainClip) — retail draws the weather ONCE, unclipped; one weather draw after the last land cell (chunk 3 places it; chunk 4 deletes the loop, the scissor, and the terrain-clip binding if no consumer remains); - the sky-post-scene particle submission's per-slice
clipSlot: slice.Slot— retail inserts emitters into one unclipped alpha list; RetailPViewPassExecutor.SetCellShellClipRouting(no caller in src or tests) and everySetClipRouting/ClearClipRouting/UseIndoorMembershipOnlyRoutingcall that becomes a no-op once no shell or entity clip routing exists — the "first view clips the shell" residue;WbDrawDispatcher.WalkClassify.ResolvePartClipSlots's slot LIST return shape: it already answers "whole mesh" (RetailWholeMeshSlot) whenever any view admits the sphere; reduce it to the Boolean retail asks (SphereVisibleInLookInTurn) and deleteVisibleClipSlotsInLookInTurnif the seals/punches do not use it (they read planes, not slots — verify);- the
ProbeCathedralSkip*discriminators (ProbeCathedralSkipFloatingStairSeals,…StairBuildingPunch,…FloatingStairCellShells,…SouthLookInCellShells,…LookInShellCellId,…SouthBuildingShell,ProbeCathedralShellOrderEnabled) with theirdocs/launch-options.mdrows andRenderingDiagnosticsmembers — the investigation they served is closed by the retail axiom (the cathedral leak is retail behavior); the S5 inventory already lists them, chunk 4 takes them because it touches every one of their call sites anyway.
10.3 Gate
- no duplicate draw of a stamped part across a pan/zoom replay (the existing replay pins); membership/draw counts change only at a retail view boundary;
- the three-pose self-gate + Holtburg + the two cathedral poses pixel-diffed against the chunk-3 run: expected delta ZERO except where a deleted per-slice scissor previously under-painted the weather at an exit-view edge (record the region if it appears; it is the deletion's intended effect, not a regression);
LaunchOptionsDocumentationTestsgreen with the seven probe rows and their read sites removed together (the test enforces both directions);- the register: no row is added (every deletion removes an acdream-only rule); any KEEP item still lacking a CPU/GPU equivalence pin gets one.
10.4 Chunk 4 fix round 1 (lead, 2026-09-03, after the three-lens review of 6ba4b0b87; round 1 of the two the plan allows)
Retail lens PASS. Build and renderer lenses FAIL on one blocking item plus real leftovers. Every item lead-verified.
- K1 — a once-per-frame weather pin that can fail (blocking). The
replacement pin (
Assert.SingleoverDrawWeatherOncecall sites) passes with aforeachwrapped around the single call — the exact round-1 regression. IL-offset ORDER pins have now failed three times to be discriminating; use a LOOP-SHAPE pin instead: with the existingCompiledCallGraph/CompiledBranchreader, assert that NO backward branch inRetailPViewRenderer.DrawLandscapeDynamicsPhase(a branch whose target offset is lower than its own offset) spans theDrawWeatherOncecall's offset. MUTATION: wrap the call inforeach (var slice in clipAssembly.OutsideViewSlices)→ the pin fails (quote it); restore. - K2 — one weather gate for the print and the draw (minor). The Collect-
time
OCprint fires onctx.WeatherGateOpen; the Replay draw adds a second condition (clipAssembly.OutsideViewSlices.Length > 0). Derive BOTH from one predicate on the frame context (the walk's own "a landscape turn ran with the weather gate open") so the transcript can never report a weather turn the frame did not draw; pin: gate closed → neither; gate open → both. - K3 — delete the dead terrain-clip producer stack (minor). No producer
writes the terrain clip any more: delete
IWorldPassSurface.SetTerrainClip,RhiWorldPassSurface.SetTerrainClip,ClipFrame.SetTerrainClipand their unit test,PrepareClipFrame's terrain-clip publish half, and the TerrainClip UBO section binding if no shader reads it (verify: if the terrain/sky shaders declare the section, keep the section bound as an all-zero disabled block and say so). - K4 — the sky is drawn ONCE, unclipped, like the terrain and the weather
(major, same rule).
DrawWalkSkystill draws the sky dome per active view underBeginDoorwayScissor+BindTerrainClip+EnableClipDistances. Retail draws the sky once (GameSky::Draw(sky, 0)@0x0050633c) before the blocks; aperture exactness for an interior root comes from the depth clear, the exit seals and the interior repaint (§9 R4 / FW4 slice 6's own argument). Draw it once at the Sky leaf, no scissor, no clip; thenBeginDoorwayScissor,BindTerrainClip,EnableClipDistances/DisableClipDistanceslose their last consumer — delete them with K3 (theEnableClipDistances/DisableClipDistancespair around the exit-seal and punch draws is DIFFERENT: those are the kept translated clips — keep those calls). Gate: the four-pose self-gate + the cathedral-arrival pose show no sky through interior walls (the seals/repaint cover it). - K5 — plan inventory (note). The plan's S5 cleanup inventory still lists
the six
ACDREAM_PROBE_CATHEDRAL_*flags — the lead updates the plan. - K6 — the punch-fan equivalence pin runs through production (minor).
Build the slice with
ClipFrameAssembler.Assemble(the realoutsideSlicesList.Add(new ClipViewSlice(slot, AabbOf(poly), planes))path) and read it back throughclipAssembly.OutsideViewSlices[i].Planes, not a hand-builtClipViewSlice. - K7 — restore the look-in slot assertion (note). Put back the deleted
Assert.NotEqual(0u, clipSlot)on a look-in slice (the exit-seal KEEP reads_clipFrame.GetSlotPlanes(slice.ClipSlot)). - K8 — the rain emitters now submit after the weather mesh (note). Retail
imposes no order between acdream's two substitutes; state that in
DrawWeatherOnce's comment so the order change is on record. - Gates: §10.3 unchanged; InstalledDat exactly the four known failures.
10.5 Chunk 4 fix round 2 — the LAST the plan allows (written 2026-09-03 after the round-1 three-lens FAIL at d60ca4ea0)
Round-1 verdicts (all three lenses FAIL, s3-chunk4-impl @ d60ca4ea0).
Shared BLOCKING finding: K2's fix is right in production
(RetailFrameWalk.cs:253 → WalkFrameDriver.OnWeatherTurn sets
WeatherTurnFired at the print site → RetailPViewRenderer.cs:665
if (walkDriver.WeatherTurnFired) passes.DrawWeatherOnce(ctx);) but NOTHING
pins the draw side: the only test naming the flag
(WalkFrameDriverTranscriptTests.cs:765) builds a WalkFrameDriver alone, and
the two IL pins (RetailPViewPassExecutorTests.cs:171, :205) never inspect
the branch CONDITION — restoring the pre-fix gate
clipAssembly.OutsideViewSlices.Length != 0 leaves every lane green. The
transcript test's doc (:725-733) falsely claims it "doubles as the draw-side
pin". MAJOR: (a) K4 deleted BeginDoorwayScissor but kept
IWorldPassSurface.BeginScissor/EndScissor, NdcScissorRect and the
EndScissor() inside ClearInteriorDepth on the comment "still ends an active
scissor" (RetailPViewPassExecutor.cs:450-459) — no producer of a scissor
exists any more (BeginScissor has ZERO callers), so the comment asserts a
mechanism that does not exist, the exact C4-closeout failure class. (b)
sky.vert:88-102 still states retail clips the sky to the exit-portal region
and cites the deleted ClipFrame.SetTerrainClip; the decomp
(acclient_2013_pseudo_c.txt:267912-267918, GameSky::Draw(sky,0) @0x0050633c
before draw_check_blocks) and K4's own doc say the opposite. (c) The K6 pin
runs through ClipFrameAssembler.Assemble, which has ZERO production callers
(ClipFrameAssembler.cs:4-5; production uses BeginWalkFrame @
RetailPViewPassExecutor.cs:156 and ReassembleOutsideViewFromWalk @
RetailPViewRenderer.cs:285); the slice construction is DUPLICATED at
ClipFrameAssembler.cs:394 and :533, so the pin proves nothing about the
producer that runs. MINOR: K3 turned one per-frame publish into one 144-byte
zeroed ring allocation + clear per terrain flush and per sky draw
(WorldPassScope.cs:190-216 fallback, called from
TerrainModernRenderer.Rhi.cs:259 and SkyRenderer.Rhi.cs:258); the retained
ClipFrame._terrainBytes/TerrainBytes/TerrainBytesForTest triple is dead state
kept only so NoClip_TerrainBytes_Count0_AllZeros compiles (unfailable by any
production edit); ClipFrame.cs:140 names the deleted SetTerrainClip;
Issue130DoorwayStripTests (:20, :36-39, :297-310) pins a scissor
mechanism production no longer has; the commit message deferred the mutation
texts to an ephemeral report and said "four" for five; DrawWalkSky has no
loop-shape pin although K1 added one for the identical class; the round-1
review prompt's "two #383 + TowerAscent" InstalledDat expectation was stale
(the fourth known failure is #458, pinned by §10.4 itself).
Rule. This is fix round 2. A third round STOPS chunk 4 and writes it up in §13 (plan §5); nothing here may be forced. Every item below is a deletion, a comment correction, or a pin — no new admission/order/flag/probe.
L1 (BLOCKING) — the draw-side weather-gate pin. Add to
RetailPViewPassExecutorTests a pin
DrawLandscapeDynamicsPhase_GatesDrawWeatherOnceOnWalkDriverWeatherTurnFired
that reads the private method's calls (CompiledCallGraph.Read) and branches
(ReadBranches) and asserts, with c = the index of the DrawWeatherOnce
call: (a) calls[c-1].Target is WalkFrameDriver.get_WeatherTurnFired — the
condition is the LAST call before the draw; (b) exactly one branch b with
calls[c-1].Offset < b.Offset < calls[c].Offset, b.OpCode in
{brfalse, brfalse.s}, and b.TargetOffset > calls[c].Offset — a forward
skip over the draw on a false flag. Keep round 1's loop-shape pin. THREE
mutation checks, each shown failing with its assertion text recorded: M1
restore if (clipAssembly.OutsideViewSlices.Length != 0); M2 delete the if
(unconditional draw); M3 invert to if (!walkDriver.WeatherTurnFired). Then
correct WalkFrameDriverTranscriptTests.cs:725-733: that test pins the
PRINT half and the flag; the draw half is the new pin (name it).
L2 (MAJOR) — delete the scissor stack outright and tell the truth in the K4
comment. Delete IWorldPassSurface.BeginScissor/EndScissor and their
RhiWorldPassSurface bodies (WorldPassSurface.cs:82-87, :157-171), the
EndScissor() call inside ClearInteriorDepth (:183) together with the
paragraph justifying it — the pass encoder sets the full-attachment scissor
at pass begin (VulkanGpuPassEncoder.cs:87) and after this round nothing
narrows it (cite both facts in the replacement comment), NdcScissorRect.cs
and NdcScissorRectTests.cs, and the NdcScissorRect.ToPixels mention in
VulkanViewportMapping.cs:41 / VulkanViewportMappingTests.cs:21.
IGpuPassEncoder.SetScissor STAYS (pass begin). Delete the assembly's
terrain-mode remnants whose only readers are diagnostic text:
TerrainClipMode, ClipFrameAssembly.TerrainMode, TerrainScissorNdcAabb,
their writers at ClipFrameAssembler.cs:282/293/400-419/539-550, and the two
readers WorldRenderDiagnostics.cs:345 (terrain=) and :409 (outMode=).
KEEP ScissorFallbacks, OutsidePlaneCount, OutsideViewNdcAabb,
HasOutsideView, OutdoorVisible, OutdoorSlot and ClipViewSlice.NdcAabb:
the >8-edge zero-plane slice case (ClipFrameAssembler.cs:524-533,
ClipPlaneSet.cs:23-39) is live for the punch fans
(RetailPViewPassExecutor.WalkLeaf.cs:103-118), and EmitVis reads the
counters. Rewrite RetailPViewPassExecutor.cs:450-459 to what is true after
this round.
L3 (MAJOR, completes K3) — delete the dead TerrainClip UBO from the sky and
terrain shaders and everything that fed it. No writer can ever exist again,
so the block is dead in sky.vert:103-106 (+ loops :169-180),
terrain_modern.vert:56-59 (+ :185-190) and terrain_atmospheric.vert:58-61
(+ :204-209). Delete the block, both gl_ClipDistance loops, and the
gl_PerVertex redeclaration where nothing else needs it; recompile with
tools/compile-shaders.ps1 (read its header) and commit the .spv files and
the manifest it updates (VulkanShaderManifestTests pins source SHA-256 to the
compiled module; RenderPackSpirvValidatorTests validates the modules).
Delete WorldFrameSectionBinding.BindTerrainClip and Zeroed
(WorldPassScope.cs:185-216) with the two callers (SkyRenderer.Rhi.cs:258,
TerrainModernRenderer.Rhi.cs:259) and WorldFrameSections.TerrainClip (+ its
reset WorldPassScope.cs:53); delete the no-op IWorldPassSurface.BindTerrainClip
(WorldPassSurface.cs:47-64, :143-145) and WorldScenePassExecutor.cs:121/235's
calls to it; delete ClipFrame.TerrainUboBytes, _terrainBytes, TerrainBytes,
TerrainBytesForTest, Reset's Array.Clear(_terrainBytes) (ClipFrame.cs:69,
:85-86, :140-141, :312, :321) and the stale header/K3 paragraphs
(:16, :31-35, :233-243); delete NoClip_TerrainBytes_Count0_AllZeros and
the :183-187 comment in ClipFrameLayoutTests. KEEP
ClipFrame.TerrainClipUboBinding = 2 and VulkanPipelineLayouts.UniformTerrainClip
= 2: portal_depth.vert:32-34 (the exit-seal/punch clip block, a KEEP clip)
still binds there (PortalDepthMaskRenderer.Rhi.cs:184) — fix both consts'
docs (ClipFrame.cs:70-77, VulkanPipelineLayouts.cs:377-384) to say only
the portal-depth clip block uses binding 2 now. Update
VulkanShaderDescriptorContractTests.cs:136-156 (terrain_modern's uniform set
becomes {SceneLighting}); its purpose (set-0/set-1 dialect regression) stays.
REQUIRED in the commit body, with file:line: what VulkanGpuPassEncoder /
the set-1 dynamic-offset path does for a declared-but-never-bound dynamic
uniform binding on a draw whose shader does not statically use it (read the
encoder's BindUniformBuffer and the set-1 bind; a descriptor not statically
used by the pipeline may be unwritten — cite the code path that makes the
terrain and sky draws legal). The lead re-runs the self-gate with
ACDREAM_DEVTOOLS=1 (Vulkan validation layers) and reads the log for
validation errors; a validation error fails this round.
L4 (MAJOR) — one outside-view slice constructor, and the K6 pin through the
producer that runs. Extract ONE internal static helper in
ClipFrameAssembler that turns a ViewPolygon into the appended slot + the
ClipViewSlice (the code at :379-394 and :509-533 — including the
zero-plane fallback branch and the max-plane/fallback bookkeeping) and call it
from BOTH Assemble and ReassembleOutsideViewFromWalk. Rewrite the K6 pin to
build a synthetic WalkPortalView holding one pixel-space polygon (the way
WalkCopyViewTests builds views), run BeginWalkFrame(frame, outdoorRoot: false, null) then ReassembleOutsideViewFromWalk(assembly, view, w, h), and
read assembly.OutsideViewSlices[0].Planes. Mutations: perturb planes[0].W
INSIDE the shared helper → fails (record the text); the pin's source contains
no Assemble( (grep-checked in the commit body). Fix the K6 doc comment.
L5 — shader comments state retail truth. After L3, whatever comment remains
in sky.vert / the terrain shaders about clipping says: retail draws the sky
ONCE (LScape::draw 0x00506330 → GameSky::Draw(sky,0) @0x0050633c, before
draw_check_blocks, no view installed, no clip) and the landscape is
view-CULLED per cell, never GPU-clipped (RenderDeviceD3D::DrawBlock
0x005a17c0). Delete the "Phase W Stage 4" narrative (sky.vert:88-102,
:169-176) and the "U.3 default" clip paragraphs in both terrain shaders.
L6 — stale comments. Everything L2/L3 does not already delete that names
SetTerrainClip, BeginDoorwayScissor, BindTerrainClip, TerrainBytes or
"an active scissor": a grep over src, tests and docs/architecture for
SetTerrainClip, BeginDoorwayScissor, BindTerrainClip, TerrainBytes,
active scissor, TerrainClipMode, NdcScissorRect (cs, vert, frag, md)
must return nothing after this round except the plan/research record under
docs/plans and docs/research (history stays).
L7 — Issue130DoorwayStripTests. Delete the scissor half
(AnySliceAdmitsScissor, worstScissorGapPx, its assertion, the header's
scissor sentences at :20, :36-39, :297-310). Rewrite the header: the #130
scissor mechanism was retired at S3 chunk 4 (the sky and the landscape draw
unclipped; an interior root's aperture exactness comes from the depth clear,
the exit seals and the interior repaint — WalkFrameDriver's interior turn);
what remains pins the outside-view polygon pipeline (ProjectToClip →
ClipToRegion → ClipPlaneSet.From) that the punch fans still consume
(DrawWalkPunchFan reads OutsideViewSlices[i].Planes). If the remaining half
pins nothing production reads, delete the test and say so in the commit body.
L8 — DrawWalkSky loop-shape pin. The K1 pin's shape applied to
RetailPViewPassExecutor.DrawWalkSky's SkyRenderer.RenderSky call site: no
backward branch spans it. Mutation: wrap the call in a two-iteration for
loop → fails (record the text). Note in the K1 and L8 pins' comments that
CompiledCallGraph.ReadBranches ignores switch jump tables (no C# loop
compiles to one) — the reviewers' scope note.
L9 — the commit message. Inline EVERY mutation check's failing assertion
text verbatim (M1–M3, L4, L8), as 6ba4b0b87 did; state the L3 encoder fact
with file:line; state the L6 grep result; last line Co-Authored-By.
Gates (unchanged from §10.3/§10.4 plus): build 0 warnings / 0 errors;
focused filter incl. FullyQualifiedName~Gpu; hermetic lane fully green;
InstalledDat exactly the four known failures (2x #383, TowerAscent, #458
doorway); VulkanShaderDescriptorContractTests, VulkanShaderManifestTests,
RenderPackSpirvValidatorTests, SkyVertexLayoutTests green; no register
row (every deletion removes an acdream-only rule); no new flag/probe; the
lead's ACDREAM_DEVTOOLS=1 four-pose self-gate shows no validation error and
no visual delta against logs/selfgate-20260903-104516-s3-chunk3-r2 beyond
actors/daylight.
10.6 Post-hoc three-lens verdict on round 2 and the landing-hygiene chunk (lead, 2026-09-03 evening)
Verdicts (all three PASS, s3-chunk4-impl @ 2e3ae95ff, run after the API
overload lifted; the lead had already landed the round on its own
verification — §13 S3 row). The findings are documentation and dead-state
hygiene, none touches admission, order or a pin's discriminating power:
- (major, two lenses) AD-17 still described the deleted scissor fallback in
the chunk's own worktree — already rewritten on the campaign branch at
5b43d8d55; the rewrite's "particles never GPU-clipped" clause is corrected in this hygiene commit (the mesh/particle shaders KEEP the per-cellclipRegions[aClipSlot]input; the walk feeds every ordinary part and every particle the whole-mesh slot 0 = no clip, so the machinery is dormant in the walk path, live only for the non-walk flat path). - (major)
Issue130DoorwayStripTests' rewritten header claims the surviving plane-gap half pins "ProjectToClip → ClipToRegion → ClipPlaneSet.From that the punch fans consume"; onlyClipPlaneSet.Fromhas a production caller — the test drivesPortalVisibilityBuilder+Assemble, both zero-caller legacy paths. - (major)
ClipPlaneSet.csheader (:23-39) and member docs (:80-92) still promise a consumer that "draws the ScissorNdcAabb box";UseScissorFallback/ScissorNdcAabbhave no production reader (AppendOutsideSlicereads onlyIsNothingVisible/Count/PlaneArray). - (minor) stale sentences:
ClipFrameAssembler.cs:14-15,:37-38(TerrainClipMode.Scissor, a value nothing produces),:45-46;WorldPassSurface.cs:22-26("Four concerns" incl. "the doorway scissor"),:54-58(shaders "write 1.0 into every slot" — they no longer writegl_ClipDistance),:76-77;TerrainModernRenderer.cs:244-245deadclipPlanes/ndcClipAabbparameters ofDrawand theIsAabbVisibleThroughClipRegionscissor branch + comment:521-524(no producer left);RetailPViewRenderer.cs:418-419computes aterrainUploadCountthe onlyPrepareClipFramediscards, with a GL-era doc atWorldPassSurface.cs:34-41;RetailPViewPassExecutorTests.cs:159-161says "unconditionally" (false since K2); the K1 pin's doc lacks the switch-table scope note L8 put on its own;RetailPViewRenderer.cs:647cites the callee address@0x00506ff0where §10.1 cites the call site@0x00506396. - (minor, pin limit) the L1 condition pin accepts a CONJOINED gate
if (clipAssembly.OutsideViewSlices.Length != 0 && walkDriver.WeatherTurnFired)(the extrabrfalselands before the getter's offset); the print/draw divergence it would reintroduce is exactly K2's.
Hygiene chunk H (one Sonnet agent in s3-hygiene at the campaign tip; one
lens; no third round — a FAIL here is written up, not fixed again):
- H1
ClipPlaneSet: deleteScissorNdcAabb; renameUseScissorFallback→IsPlaneOverflowwith the doc "Count == 0 because the region needs more thanMaxPlaneshalf-planes (or is multi-polygon); the consumer draws UNCLIPPED (AppendOutsideSliceemits an empty plane array; the punch fan covers the whole fan) — over-include, never a scissor"; rewrite the file header (:23-39) to the three states that exist (Empty / overflow / planes); updateClipPlaneSetTeststo the new name and delete its AABB assertions (they pinned the deleted consumer contract). - H2
TerrainModernRenderer: deleteDraw'sclipPlanes/ndcClipAabbparameters, the scissor branch ofIsAabbVisibleThroughClipRegion(keep the clip-plane test only if a caller still passes planes — grep; if none, delete the whole helper and its comment:521-524soCollectVisibleCellsis frustum-only), and theterrainUploadCountcomputation atRetailPViewRenderer.cs:418-419+PrepareClipFrame's parameter and its GL-era doc (IWorldPassSurface.PrepareClipFrame()takes nothing). - H3
Issue130DoorwayStripTests: DELETE the test (its remaining half drives two zero-caller legacy paths; the one production stage it touches,ClipPlaneSet.From, is pinned by the K6 punch-fan pin through the real producers) and say so in the commit body with #130's history in one sentence. - H4 comments:
ClipFrameAssembler.cs:14-15/:45-46(no scissor consumer), deleteTerrainClipMode.Scissor(nothing produces it; keepPlanes/Skipfor the flat path — grep the enum's readers first);WorldPassSurface.cs:22-26→ three concerns,:54-58→ onlyportal_depth.vertwritesgl_ClipDistancein the world pass now,:76-77drop the scissor sentence;RetailPViewPassExecutorTests.cs:159-161→ "conditional onWalkFrameDriver.WeatherTurnFired, see the L1 pin"; add the switch-table note to the K1 pin's doc;RetailPViewRenderer.cs:647→ the call-site address@0x00506396(callee@0x00506ff0). - H5 strengthen the L1 pin against the conjoined gate: between the
DrawUnattachedSceneParticlescall (the last call before the gate) and theDrawWeatherOncecall there is exactly ONE conditional branch in total, and it is the forwardbrfalseafterget_WeatherTurnFired— MUTATION: the conjoined gate adds a secondbrfalse→ fails; record the text. - H6 commit body: every mutation text (H5), the H2 grep results, the
H3 sentence;
Co-Authored-Bylast.
Gates: build 0 warnings; hermetic lane fully green; InstalledDat exactly the
four known (2× #383, TowerAscent, #458); the L6 grep from §10.5 extended
with ScissorNdcAabb|UseScissorFallback|TerrainClipMode.Scissor| ndcClipAabb|terrainUploadCount returns nothing under src/tests; no
register row (AD-17's correction is the lead's, in the same landing).
12. S3 review fix round 1 (lead, 2026-09-03 evening — after the two-lens slice review of 51d532320..e6f5a156b, both FAIL)
Verdicts. Retail lens FAIL: one BLOCKING (F1), one major (F2), one minor (F3), three notes (F4a/F4b, and the weather-gate/print cell mismatch, logged below as an open question). Shader/perf lens FAIL: one BLOCKING on the ledger's chunk-3 perf evidence (E1, the LEAD's item), two majors (F5, F3), two minors (perf reductions available — S5 candidates, logged), one note (the two KEEP clips' >8-edge overflow branches lack equivalence pins — folded into F2).
F1 (BLOCKING) — punch fans clipped by the wrong view. RetailFrameWalk. DrawBuilding pins ActiveViewIndex = v over the walk's views (retail
building_view = portal_view_num @0x0059f3bf); the leaf indexes
clipAssembly.OutsideViewSlices[activeViewIndex] — but
ReassembleOutsideViewFromWalk skips a view whose polygon collapses
(AppendOutsideSlice returns false on IsNothingVisible), so the slice array
can be SHORTER than the view list: every later fan takes view v+1's planes
and the last takes default = UNCLIPPED. Fix: the reassembly keeps ONE slice
per walk view, index-aligned (a collapsed view yields a slice flagged
nothing-visible: ClipViewSlice.NothingVisible, slot 0, empty planes, empty
AABB); DrawWalkPunchFan draws NOTHING for a nothing-visible slice (retail:
polyClipFinish under a degenerate view leaves <3 vertices → no fan,
0x59BDBC–0x59BDBF) and FAILS LOUD (exception, fail-loud rule) when
activeViewIndex >= OutsideViewSlices.Length instead of drawing unclipped.
OutsidePlaneCount/ScissorFallbacks bookkeeping unchanged. Tests: a
synthetic two-view WalkPortalView whose FIRST polygon collapses (area under
MinPolygonArea) → OutsideViewSlices.Length == 2, [0].NothingVisible,
[1].Planes equal the second polygon's edge planes (through
BeginWalkFrame + ReassembleOutsideViewFromWalk); the punch leaf with
activeViewIndex = 1 uses [1] (recording surface: the fan submitted with
those planes); with activeViewIndex = 0 submits nothing; with index 2
throws. MUTATION: revert the skip (append nothing) → the index test fails;
restore the : default fallback → the throw test fails.
F2 (major) — the exit-seal equivalence pin through the producer that
runs, and both overflow branches. Production seal planes come from
WalkFrameDriver.AppendClipSlot (pixel→NDC, winding selection, normalize,
the >8-vertex NDC-AABB branch) read back by InteriorFloodViewClipPlanesAt
→ ClipFrame.GetSlotPlanes; the current pin drives
ClipFrame.AppendSlot(ClipPlaneSet), which has zero production callers.
Rewrite it to drive CaptureViews/AppendClipSlot on a synthetic
WalkPortalView (the K6 pin's construction) and read back through
InteriorFloodViewClipPlanesAt; add the two overflow cases: a 9-vertex
view → the seal slot carries exactly the 4 AABB planes that contain every
vertex (over-include); a 9-vertex outside view → the punch slice has zero
planes and the fan draws unclipped. Mutations: flip ccw, drop the
normalize, delete the AABB branch — each must fail (record all three).
F3 (minor/major, both lenses) — the false bracket comment at
RetailPViewPassExecutor.cs:453-457: neither KEEP clip brackets anything
with Enable/DisableClipDistances (the six DisableClipDistances() calls sit
around the unclipped particle draws; the surface's bodies are no-ops on
Vulkan). Rewrite to the truth; then DELETE the six no-op
DisableClipDistances() calls and the private wrapper (a method that does
nothing on the only backend is a false mechanism too), keeping the
IWorldPassSurface members only if WorldScenePassExecutor still needs
them (it calls them — leave the interface, delete this file's use).
F4 (notes, transcript exactness) — (a) EmitFloodTurns prints one EC
per flood cell; retail's DrawEnvCell breakpoint fires once per (cell ×
live view) (PView::DrawCells @0x005a4ab1–0x005a4acc, the setup_view /
DrawEnvCell loop). Print EC once per live view of the cell
(InteriorFloodViewSliceCountAt), draw unchanged (the stamp dedupes).
(b) WalkTraceConformanceTests.Recorder lacks OnWeatherTurn, so the
eight-kind signature drops the weather OC on both sides; implement it and
stop dropping the trailing OC on the oracle side — the signature then pins
the trailing weather turn. Every fixture row must still pass (the captures
carry the OC literally).
F5 (major) — the dead per-cell clip machinery. WbDrawDispatcher. SetClipRouting(...) (the only writer of _clipRoutingActive) has ZERO
callers; EnvCellRenderer.SetClipRouting is called only with null. So no
path can arm the per-cell clip-region table — §10.6's "live for the flat
path" was wrong, and five pipelines (mesh_modern, mesh_atmospheric,
mesh_detail, particle, particle_mesh) still fetch clipRegions[slot]
and write eight always-passing gl_ClipDistances per vertex. Delete: the
routing state and methods (SetClipRouting both overloads,
ClearClipRouting remnants, _clipRoutingActive, ResolveSlotForFrame's
routing arm — it becomes "slot 0, never culled"), the ProbeClipRouteEnabled && _clipRoutingActive branch, the five shaders' clipRegions fetch +
gl_ClipDistance loops + gl_PerVertex redeclarations (recompile; re-pin
the manifest), and the ClipRegions SSBO publication/binding IF no other
shader reads it (portal_depth.vert takes its planes per draw through the
UBO at binding 2 — verify; if ClipRegions has no reader, delete
PrepareClipFrame's publish, WorldFrameSections.ClipRegions,
BindClipRegions, and ClipFrame's region packing, keeping only
AppendSlot/GetSlotPlanes as the CPU plane store the seals read). Keep
the vertex layouts' aClipSlot/instanceClipSlot inputs THIS round (the
instance-buffer layout is S5's), fed 0; note the residue in the commit body.
AD-17 is corrected by the lead in the landing ("dormant in every path;
deleted").
E1 (LEAD, BLOCKING on evidence) — the chunk-3 perf gate. The ledger's
"every destination within the §9.7 gate" quoted only the turn phase of the
two report files; the stationary phase has Aerlinthe 4.00→5.80 ms GPU p50
(1.45×, +1.8 ms; p95 4.20→6.00) — outside the gate — and two destinations
(Sawato revisit/plateau) were omitted. The lead re-reads both files, records
the COMPLETE table, and re-measures the current tip against the S2-final
binary in the same session (run-connected-r6-soak.ps1 -SkipBuild, both
worktrees, back-to-back); chunk 3's status becomes STOPPED-LANDED with an
open perf item if the regression holds (the plan's own rule), and the
order-preserving reductions the shader lens listed (skip the terrain flush
when the alpha queue is empty; coalesce contiguous per-cell runs into fewer
indirect commands) become the S5 perf chunk's contract.
Open question logged (not this round): the weather gate reads the
PLAYER cell (is_player_outside) while the OC line prints the VIEWER cell
(retail's after_sky_cell = the P cell). A camera inside a cell with the
player outdoors would print an EnvCell id; no capture exercises it. Settle
with one retail capture at such a pose before S5's transcript closeout.
Gates: build 0 warnings; hermetic fully green; InstalledDat exactly the
four known; every fixture row of WalkTraceConformanceTests unchanged
except the OC now compared; the shader tests (descriptor contract, manifest,
SPIR-V validator, sky layout) green; the L6+H6 grep sweeps plus
SetClipRouting|_clipRoutingActive|clipRegions|instanceClipSlot (the last
two allowed only in the vertex-layout residue named in the body); no new
flag/probe; the lead's four-pose validation self-gate afterwards.
11. Chunk 1 contract — transcript kinds, fixtures, and the print-only emitter (lead, 2026-09-03; runs AFTER chunk 3, because LC/SC only exist once terrain is per cell)
11.1 What exists (verified in the tree at 542b049b)
- The FW0 test-side parser
tests/AcDream.App.Tests/Rendering/Walk/WalkOracleTrace.csparsesF,P,LS,BLD,DI,DCand drops the truncated detach frame;WalkTraceReplay.csrebuilds the camera from thePpose (retail projection globals, +Y forward) and drivesRetailFrameWalkover DAT-adapter world data;WalkTraceConformanceTests(InstalledDat lane) already proves the FW0 still fixtures' first frames position-for-position andWalkOracleTraceTestspins per-fixture facts.Load(name)is rooted atdocs/research/2026-08-30-fw-walk-oracle/. - The five OH captures are committed under
docs/research/2026-09-01-overhaul/oh-capture/(README there): per pose a walk log (addsLC/SC/EC/OCto the FW0 kinds), a parts log (PD,DM), and an alpha-depth log (AM,FL,PM,PC); line formats are intools/walk-oracle/oh/*.cdb.template. SameF/Pframing; same detach rule.
11.2 Production behavior change (the one allowed piece of evidence infrastructure)
- B1 — one print-only flag,
ACDREAM_DUMP_WALK_TRANSCRIPT=1, read once intoRuntimeOptions(rule 4) and owned byRenderingDiagnostics(rule 5), with itsdocs/launch-options.mdrow in the same commit (LaunchOptionsDocumentationTestsenforces both directions). When set, the production walk prints, to the existing diagnostics sink, exactly the OH line kinds at the points retail's breakpoints sit:F n+P …at the frame root (SmartBox::RenderNormalMode@0x00453aa0 — the camera cell, origin and quaternion in retail's storage order),LSat the landscape turn,LC <cell>/SC <cell>per land cell (chunk 3's events, with the LOD idx*8+y+1),BLD <cell>at the building turn,DI <cell>at DrawInside,DC pv=<0|1> ov=<n> n=<k>: <cells…>at every DrawCells (pv 0 = interior pview, 1 = outdoor pview — a stable stand-in for retail's pointer, which the parser already ignores),EC <cell>per shell draw,OC <cell>per object-list turn. NOTHING else changes: no admission, depth state, or draw order may depend on the flag (the print sits AFTER each decision, never inside it). - B2 — parser extension.
WalkOracleTracelearnsLC,SC,EC,OCas event kinds and gainsLoad(root, name)(or a fixture-set enum) so the OH captures load from their own directory; the parts and alpha-depth kinds get their own small readers (PD/DM→ gfx id, force, bound, cell;AM/FL/PM/PCper the template's documented fields) — read-only records, no validator, no canonical JSONL, no new tool (feedback-evidence-infrastructure-sink). - B3 — fixtures + pins. The five walk captures join
WalkOracleTraceTests.AllFixtures(parse + complete-frame pin) and the four kit poses joinWalkTraceConformanceTests' still-fixture theory at the DI/DC/BLD/LS level (first complete frame, position-for-position, the SAME harness as FW0 — the cathedral-arrival capture's root isf4180108, not FW0'sf4180106, so it is a NEW pose row, not a replacement). TheLC/SCsequences of both cathedral poses become the chunk-3 order pin's fixture (§9 T1) if chunk 3 landed with a hand-extracted one. The parts and alpha-depth logs are imported and parsed (B2) but pinned only where a later chunk/S4 names a consumer — no speculative assertions. - B4 — the automated transcript gate (§6). A Release run with the flag at
the four kit poses (session-config login +
/telelocfrom the self-gate kit) produces acdream transcripts; the test-side comparison is the existing signature diff (WalkTraceReplayContext.Signature) extended to the new kinds, run offline over the two files — a FACT-level report per pose (first divergent event and position), consumed by the S3 review and G3. It is a test-side script, not a client subsystem.
11.3 Tests
- T1: the flag off → zero output and zero allocation on the walk path
(the existing
WalkFrameDriverallocation pins stay green). - T2: the flag on, one synthetic interior frame → the printed lines parse
with the extended
WalkOracleTraceinto the same events the driver recorded (emitter/parser round trip). - T3:
AllFixtures+ the still-fixture theory rows for the four OH kit poses (InstalledDat lane); the two cathedralLC/SCorder pins. - T4:
LaunchOptionsDocumentationTestsgreen with the one new row.
11.5 Chunk 1 fix round 1 (lead, 2026-09-03, after the three-lens review of 079483bb6)
Verdicts: build/test FAIL and production-path FAIL on the SAME blocking
finding; retail lens pending at draft time (amended below if it adds
items). Every item lead-verified against the source. Fix in the same
worktree on top of 079483bb6; round 1 of the two the plan allows.
- G1 — the flag-off integration test is vacuous (blocking).
Collect_TranscriptFlagOff_ProducesNoConsoleOutputdrives ONE frame and asserts throughWalkOracleTrace.Parse, which structurally discards the last (open) frame — so a one-frame transcript parses to nothing whether or not anything printed. Fix: drive TWO frames and assert (a) the parser sees ZERO frames and (b) no captured line starts with any of the ten kinds (F,P,LS,LC,SC,BLD,DI,DC,EC,OC) — robust to other test classes' console noise, which never begins with those tokens. MUTATION CHECK (mandatory for every pin in this round): show, in the commit message, that the pin FAILS when the flag gate is forced true (temporarily) — a pin that cannot fail is not a pin. - G2 — LC/SC compute before the flag (major).
LodCellId(...)runs on every land-cell turn (~1,300 divisions/modulos/checked conversions per outdoor frame) beforePrintLandCell/PrintSortCelltest the flag. Guard the call sites:if (RenderingDiagnostics.DumpWalkTranscriptEnabled) WalkTranscriptDump.PrintLandCell(WalkTranscriptDump.LodCellId(...)), and audit every other print site for argument work outside the guard (the DC site builds nothing until insidePrintDrawCells— fine; the frame-root site is already guarded). - G3 — the flag-on round trip never prints LC/SC/BLD (major). Extend T2:
one outdoor-root frame over a synthetic landscape with one in-view block
and one building (the
WalkFrameDriverTestslandscape fixtures already exist) → the captured lines parse to a frame whose events containLS, ≥1LC, ≥1SC, and theBLD, in that order, matching the driver's recorded turns; plus one interior-root frame coveringDI/DC/EC/OC. Both with the mutation check. - G4 — parts/alpha-depth smoke pins (minor). Assert
AM > 0andPM > 0(andPD > 0,DM > 0for the parts logs) for every committed capture — §6b lists the counts; a regex that silently matches nothing must fail. - G5 — launch-options wording (minor). The side-effects column says exactly: flag off = one bool read per print site, nothing else; flag on = one console line per walk turn (≈600–800 lines per outdoor frame) — a print-only diagnostic for offline diffing, never for ordinary runs.
- G6 — comment hygiene (note). Remove the self-correction noise in the conformance test comment ("DI f4180108... no, a9b4013f"); keep the two bespoke Facts (doorway-still, foundry-deep) — they need the full DAT-built world the theory body already uses, so either shape is acceptable; say why in a one-line comment.
- G7 —
SCsits atDrawSortCellENTRY, beforeDrawBuilding(blocking, transcript lens). Retail'sbp 0059f140fires atRenderDeviceD3D::DrawSortCellentry andDrawBuilding@0x0059f2a0 is called from INSIDE it, so retail printsLC→SC→BLD(terrace-edge.walk.log:2331-2333; a not-in-view cell printsSCthenBLDwith noLC,:1042-1044). acdream printsSCfromOnLandscapeCellTurn, whichRetailFrameWalkcalls AFTERDrawBuilding. Fix:RetailFrameWalk.DrawLandscapecalls a newIWalkEventSink.OnSortCellTurn(landblockId, side, cellIndex)at theDrawSortCellentry point (after the LC turn, beforeDrawBuilding, under the sameAlwaysDrawObjects || in viewgate); the driver printsSCthere and nowhere else; the object-list turn after the building is unchanged. MUTATION: with the print moved back afterDrawBuilding, the terrace-edge conformance row (G10) must fail on the first building. - G8 — the trailing
OC <viewer land cell>of every outdoor frame (major). It is retail's WEATHER pass:GameSky::Draw@0x00506ff0 witharg2 == 1runsif (LScape::weather_enabled != 0) DrawObjCellForDummies(this->after_sky_cell)@0x005070da — the rain emitters live in the after-sky cell, whose DID is the viewer's land cell (terrace-edge.walk.log:1416OC f418000b= thePcell, once per complete frame; 12 EC vs 16 OC in that capture are exactly these four). It is NOT a walk turn and NOT the creature-modeDrawObjCellForDummies(creature_cell)@0x00452be1. acdream's equivalent isRenderWeather(RetailPViewPassExecutor.DrawLandscapeSliceLate, gated on the player being outside): printOC <viewer land cell>at that call when the weather pass actually runs, print-only, with the addresses in the comment; rewritePrintObjectCellTurn's doc, which currently denies the line exists. - G9 — the EC evidence comment is false (minor). "EC and OC counts are
always equal" — terrace-edge has 12 EC / 16 OC (G8). The conclusion (EC is
per flood visit; the stamp dedupe lives inside
DrawEnvCell, past the breakpoint) is right; the proof isholtburg-doorway-still.walk.log:1126, 1131, 1134, 1137—EC a9b40100four times in one frame across four look-inDCturns. Fix both comment sites. - G10 — the conformance signature must see the new kinds (minor → required).
WalkTraceReplayContext.Signaturedrops LC/SC/EC/OC, so no test compares their placement against retail — which is how G7 shipped green. Extend the test-sideRecorderwithOnLandCellTurn/OnSortCellTurnand includeLC/SCin BOTH signatures; deriveEC/OCfor eachDCfrom its cell list (retail's two reverse loops: every shell far-to-near, then every object list far-to-near — the driver's own order) on both sides; exclude the trailing weatherOCfrom the comparison (assert separately that an outdoor retail frame ends withOC <P cell>). The four kit-pose rows must then reproduce at the eight-kind level, or the FIRST divergence is reported in deviations with its position (a real finding, not a skip). - Gates unchanged (§11.3); the InstalledDat lane must still show only the three known failures; the new still-fixture rows must still reproduce.
11.6 Chunk 1 fix round 2 (lead, 2026-09-03 — the LAST round the plan allows; after the three-lens re-review of 36be6b598)
Round 1 closed G1–G7 and G10's LC/SC half with documented mutation checks,
and delivered the milestone (three of four kit poses reproduce exactly at
the eight-kind level; the fourth is #458, a walk finding, not chunk 1's).
The re-review FAILED on the weather OC and on what the EC/OC comparison
actually compares. Every item below is lead-verified.
- H1 — one weather
OCper frame, at the one weather draw (blocking). The print sits insideDrawLandscapeSliceLate, which the renderer calls ONCE PER OUTSIDE-VIEW SLICE (RetailPViewRenderer's "GameSky's weather pass still runs through each active landscape view" loop), so an interior root with the player outdoors prints 2–4OClines where retail prints one. Retail draws the weather ONCE:GameSky::Draw(sky, 1)@0x00506ff0 →if (LScape::weather_enabled) DrawObjCellForDummies(after_sky_cell)@0x005070da, afterLScape::draw's blocks (@0x00506396). Fix: move the weather draw (_sky.RenderWeather(...)) AND theOCprint out of the per-slice method into ONE call after the slice loop (a newRetailPViewPassExecutor.DrawWeatherOnce(frame), gated exactly as today onRenderSky && RenderWeather && playerOutside), unclipped, no scissor — chunk 4 later deletes the slice loop's remaining scissor/clip apparatus. TheOCid: retail sets the after-sky cell's DID from the position the sky is updated with each frame (after_sky_cell->SetDID(arg2->objcell_id)@0x00506dde), and every capture'sOCequals the frame'sPcell — so print the SAME cell id the frame-rootPline prints (the camera/viewer cell), not the player's cell; say so in the comment. PIN: a test that drives the executor's weather path with the flag on for (a) an outdoor root and (b) an interior root with two exit-view slices, asserting EXACTLY ONEOC <viewer cell>line per frame and none when the player is inside. MUTATION: delete the print → the pin fails (quote it). - H2 — G9's second comment site (blocking as reported).
WalkFrameDriver's EC print comment still claims "EC and OC counts are always exactly equal"; replace with the real proof (holtburg-doorway-still.walk.log:1126,1131, 1134,1137—EC a9b40100four times in one frame across four look-inDCturns; terrace-edge has 12 EC / 16 OC because of the weatherOC). - H3 — compare retail's LITERAL EC/OC (minor → required). The oracle
side of
Signature8drops the capturedEC/OCevents and derives them from theDClists, so both sides derive and the EC/OC half can never fail. Fix: the ORACLE side keeps its capturedEC/OCevents verbatim (excluding only the trailing weatherOC— the last event of an outdoor frame when its id equals thePcell); the REPLAY side derives EC/OC from the driver's real two reverse loops (the existing derivation), with the same non-look-in deferral on both sides (close thependingRootCellsasymmetry the note found). The four kit rows must still reproduce (three exactly; #458's row staysKnownFailureat its documented position — if the literal EC/OC comparison moves that first divergence EARLIER, record the new position in #458's row comment). MUTATION: reverse the replay derivation (OC before EC) → the cathedral-arrival row fails on an EC/OC token (quote it). - H4 — the SC hook's flag-off cost (minor).
OnSortCellTurnrunsRequireOpenFrameand two range validations before reading the flag. Read the flag FIRST and return; the remaining flag-off cost is one interface call per land cell (state that in the hook's doc and in H5). - H5 — launch-options wording (minor). Flag on: measured ≈1,200–1,400
lines per outdoor frame (terrace-edge 1,384; cathedral-arrival 1,269;
doorway 1,187) — write the measured range, not "600–800". Flag off: one
bool read per print site plus one interface call per land cell for the
SChook, nothing else. - H6 — #458 citation (note). The
KnownFailurerow's comment citesdocs/ISSUES.md #458and the divergence position; the InstalledDat lane's known-failure set is now FOUR (two #383 layouts, TowerAscent, #458) — the build lens compares against that set. - Gates: §11.3 unchanged; hermetic fully green; InstalledDat exactly the four known failures. If this round does not close every item, chunk 1 STOPS and is written up (plan rule §5) with the emitter kept as-is and the open items carried to the S3 review round.
11.4 Out of scope
Any validator, canonical format, or dashboard; any behavior change; any second flag. If the gate report shows a divergence, that is a finding for the S3 review round, fixed in the owning chunk's follow-up — not in chunk 1.