# Cathedral rendering review — FABLE (2026-08-30) Independent report-only review of the cathedral-terrace defect (falls particles + marker stalks over terrain; landblock `0xF418`, camera in `0xF4180104`/`0xF4180106`), baseline `37febd1f`, HEAD `bb9212c7`, branch `claude/campaign-w-retail-frame-walk`. **Evidence basis and honesty note.** Everything below marked with a citation was read directly by this reviewer (oracle trace files, decomp pseudocode docs + their byte-verification notes, commit messages/diffs, git topology, ISSUES/register/memory docs, id-allocator source). Three deeper evidence threads (fresh decomp re-reads of the alpha/particle path, a raw DAT parse of `0xF418`, and the HEAD code-flow + probe-log audit) were dispatched but had not returned when this report was due; every claim that depended on them is explicitly marked **unverified**. Per the prompt's rule, unverified is stated as unverified — nothing below is a plausible guess dressed as fact. --- ## 1. Executive verdict (≤10 lines) The six fixes failed because they accepted a false premise about WHERE this scene's content sits in retail's frame. The posed oracle traces show that at both defect poses retail's interior flood is EXACTLY ONE cell (`DC ov=1 n=1: f4180104` / `f4180106`) — every other cathedral cell, including the falls' stab-owner cells, draws as a *building look-in inside the landscape scope*, pre-depth-clear, its alpha drained against full landscape depth (`posed/terrace-center.log` F5, `posed/cathedral-arrival.log` F1-2; `PView::DrawCells` @0x005a4840 model §5). Our pipeline instead treats the whole complex as interior-flood content drawing post-clear, then tried to rescue it with seals (slice 2) and a non-retail exit-plane-straddle classifier (slices 4/5) that under-covers exactly the fully-outside falls emitters. Fix = route every object's particles to its owner cell's actual walk turn (look-in ⇒ landscape scope ⇒ pre-clear drain), delete the straddle classifier, and re-land the quarantined marker-degrade port for the stalks. --- ## 2. Retail frame reconstruction (for an interior root with exit portals) ### 2.1 The frame skeleton — verified from the FW0 model + live traces Source of truth used: `docs/research/2026-08-30-fw-walk-pseudocode.md` (§1, §2, §3, §5, §9 — its seal loop, deferred z-clear, DEPTHTEST_ALWAYS, punch-Z constants are recorded there as byte-verified against the raw pseudo-C at `@0059a49af`, `@005a48a9`, `@0059be02`, `@0059bf4b`), the extraction appendix `2026-08-30-fw-walk-pseudocode-appendix.md` (notably the DrawBuilding/DrawMeshInternal full-sequence note at appendix line 811), and the live cdb traces in `docs/research/2026-08-30-fw-walk-oracle/posed/`. Order of one interior-rooted frame (`SmartBox::RenderNormalMode` @0x00453aa0 → `PView::DrawInside` @0x005a5860 → `ConstructView` → `PView::DrawCells` @0x005a4840): 1. **Flood** (`ConstructView(CEnvCell)` @0x005a57b0): view-driven — a neighbor cell enters `cell_draw_list` only if its portal polygon survives `PView::GetClip` @0x005a4320 against the current view (the ONLY CPU polygon clip in the frame). Exit portals (`other_cell_id == 0xFFFFFFFF`) raise `outside_view`. 2. **If `outside_view.view_count > 0`** (the traces' `ov`): a. `Render::PortalList = &outside_view`; **`LScape::draw`** @0x00506330 — the whole landscape walk THROUGH the exit views: sky, terrain blocks far-to-near (view-CULLED per cell/block by `draw_check_blocks`' in_view union — **never view-clipped, never scissored**; `set_view` installs NO GPU state), buildings far-to-near, and — per building — the **look-in machinery**: `DrawBuilding` @0x0059f2a0 → BSP portal pass 1 punches apertures (`DrawPortalPolyInternal` flag=1: far-Z 0.999998987, DEPTHTEST_ALWAYS, z-write ON, alpha 0) → pass 2 recurses `ConstructView(CEnvCell)` + `DrawCells` (**`ov=0` — no landscape, no clear, no seals**) drawing look-in EnvCells + their objects into the punched aperture (appendix line 811). `DrawBuilding` itself calls **`FlushAlphaList(0f)`** before each building; `DrawBlock` @0x005a17c0 has the mid-walk pressure valve `FlushAlphaList(flush=0.75)` (appendix lines 700, 1027). b. **`FlushAlphaList(0f)`** — the pre-clear boundary drain: EVERYTHING queued during the landscape scope (terrain alpha, building alpha, look-in cell content alpha — and the particle polys of objects drawn in that scope) drains against **full landscape depth**. This is the drain that occludes the falls with terrain/water/trees. c. **Gated depth clear** (`if (forceClear || portalsDrawnCount != 0) Clear(z)`, model §5; `portalsDrawnCount` counts ONLY flag-0 seals — appendix line 811). Color is preserved; only depth clears. d. **Exit seals**: for the FLOODED cells' exit portals only, `DrawPortalPolyInternal(poly, 0)` — the portal's own projected depth, DEPTHTEST_ALWAYS, z-write ON, invisible (model §2, §5; byte-verified per model §9). 3. **Interior passes** (post-clear): `DrawEnvCell` far-to-near (BSP shells), then `DrawObjCellForDummies` (the flooded cells' objects) — depth accumulates fresh. 4. **Final drain**: `FlushAlphaList(0f)` back in `RenderNormalMode` — the flooded cells' alpha/particles drain against interior depth + the seals. ### 2.2 The four prompt questions **(a) clipped vs culled vs whole.** CPU-clipped: ONLY the portal chain's own polygon (`GetClip` @0x005a4320 — the model calls it "the only CPU polygon clip in the frame"). View-culled (coarse sphere-vs-cone, `Render::viewconeCheck` @0x0054c250, PARTIAL draws whole): objects. Cell/block-granular culled (in_view interval grids): terrain blocks/cells. Drawn whole with no per-view test: everything that passes those gates — shells, meshes, particles. No GPU clip planes/scissor exist anywhere in this frame (`set_view` = CPU globals only, model §6). **(b) order relative to clear and seals.** PRE-clear: sky, terrain, water (terrain-hosted — see §3, unverified detail), building shells, building punches, **look-in EnvCell shells + look-in cell objects + their emitters**, and all their alpha via the boundary drain. POST-clear: seals first, then ONLY the root flood's EnvCell shells + objects + their emitters, drained at the final flush. Seals draw exactly the flooded cells' exit-portal polygons at own depth, color-write effectively off (alpha 0), depth ALWAYS + write ON. **(c) alpha list.** ONE list. Flush sites established from the docs: per-building `FlushAlphaList(0f)` in `DrawBuilding` (appendix 811); the `DrawBlock` pressure valve at `flush=0.75` (~2250 meshes, appendix 1032); the `DrawCells` pre-clear boundary `FlushAlphaList(0f)` (model §5); the `RenderNormalMode` end-of-frame `FlushAlphaList(0f)` (model §1). Depth in place: landscape depth at the first three; interior + seal depth at the final one. **Unverified:** an exhaustive caller enumeration of `D3DPolyRender::FlushAlphaList` @0x0059d2e0 from the decomp itself, and the exact particle-poly insertion path (the dispatched decomp read had not returned; the MP2-era digest additionally records `CPhysicsObj::ShouldDrawParticles` @0x0050FE60 = authored degrade range + `cell->IsInView()`, from `claude-memory/project_render_pipeline_digest.md`). **(d) depth at final-drain time.** Aperture pixels: the seal's own depth (near the camera) — anything beyond the exits z-fails, so interior particles cannot repaint the vista. Vista pixels visible through the aperture ARE aperture pixels (the opening's polys); pixels covered by interior geometry hold that geometry's depth. The falls are never in this drain in retail at these poses — they drained pre-clear with the landscape. **Unverified residual:** whether any visible vista pixel can lie OUTSIDE the union of authored exit-portal polygons at the live chase camera (slice 6's observation implies yes for the WALK's clipped views; whether that reflects portal-poly authoring or our clip is open — §8 Q1). ### 2.3 The live traces at the defect poses (decisive, read directly) `posed/terrace-center.log` F5 (camera cell `f4180104` — the owner's teleloc cell): ``` DI f4180104 DC pv=009d4e38 ov=1 n=1: f4180104 ← the interior flood is ONE cell LS BLD f518002e … BLD f4180014 BLD f418000a BLD f418000c BLD f418000b (14 buildings) ``` `posed/cathedral-arrival.log` F1-2 (camera cell `f4180106`): ``` DI f4180106 DC pv=009d4e38 ov=1 n=1: f4180106 ← flood = root cell only LS BLD f3180020 … BLD f418000c DC pv=009d4398 ov=0 n=2: f4180101 f4180100 ← look-in punch during LS … BLD f418000b DC pv=009d4398 ov=0 n=1: f4180104 ← 0xF4180104 IS A LOOK-IN BLD f418000a ``` `posed/terrace-edge.log` F5 (outdoor root, camera cell `f418000b`): look-in punches `n=1: f4180106`, `n=1: f4180101`, `n=1: f4180104` interleaved with the building walk — no clear, no seals, everything drains against full depth (why the owner sees a correct scene outdoors). **Conclusion:** at the defect poses, `0xF4180104` and `0xF4180106` are in DIFFERENT buildings' interiors (`f418000b` vs the `f418000a/c` group — consistent with the "seam" being a building boundary), retail's interior flood never crosses it, and ALL non-root cathedral cells + their stabs compose in the landscape scope, pre-clear. The "toggles with which side of the seam the camera is on" symptom is the root flip between these two one-cell floods (and outdoor). --- ## 3. DAT geometry findings **Verified:** - The falls' observed particle owners `0x4F418012`–`0x4F418015` decode per `src/AcDream.Core/World/InteriorEntityIdAllocator.cs:48` (`0x40000000 | X<<20 | Y<<12 | counter`) to **interior EnvCell-stab statics of landblock F418**, counters 0x12–0x15 — NOT landblock objects (0xC0000000+ namespace) and NOT scenery (0x80000000+). The slice-5 commit message (`0d6cd5c0`) reached the same identification ("EnvCell STAB-LIST statics … ids minted by InteriorEntityIdAllocator"). - Retail cell topology at the poses (from the traces, §2.3): `0xF4180104` belongs to building `f418000b`'s look-in set; `0xF4180100/0101` to `f418000c`'s; `0xF4180106` is punched separately (arrival trace); interior floods do not cross between them at the captured camera states. - The prior campaign's offline sightline probe (recorded in `claude-memory/project_pview_visibility_campaign.md` and the PV plan) established: the exit portal of the terrace cell and the building's never-drawn panel are the SAME surface, and the "#456 seam band" IS the terrace cell's portal[4] polygon — i.e. at least one exit aperture is a thin band, corroborating slice 6's live finding that scissoring terrain to the walk's exit views starves most of the vista of depth/color. **Unverified (the DAT parse thread had not returned):** the per-cell portal tables (flags/0x4 exits/other_cell ids) for `0x0104/0x0105/0x0106/0x010D/ 0x010F`; WHICH EnvCell's stab list carries counters 0x12–0x15 (the counter is allocated in ascending cell order in `LandblockBuildFactory` `src/AcDream.App/Streaming/LandblockBuildFactory.cs:494-503`, so the DAT stab tables resolve it mechanically); the exit-portal polygon vertex extents vs the visible opening; whether the lake water is terrain-hosted; the cathedral shell GfxObj roster (`0x01001FB2/B0/B3` — asserted by the owner's prior analysis and consistent with the PV panel model (`0x01001FB0/B2/B3/B7` panels, PV plan §"established model" item 3), but not independently re-read here). --- ## 4. Divergence table (ranked by causal weight for THIS defect) | # | Divergence | Ours | Retail | Evidence | |---|---|---|---|---| | D1 | **Particle emission site for cell statics/dynamics** | flood-membership + `SphereStraddlesExitPlane` classifier decides pre- vs post-clear emission (slices 4/5) | the owner object's actual walk turn decides: drawn during LS (shadow-cell overlap or look-in) ⇒ landscape scope ⇒ pre-clear drain; drawn in the root flood ⇒ final drain | traces §2.3; model §5; appendix 811; commit msgs `f3a03efc`/`0d6cd5c0` | | D2 | **Interior "flood" membership for the cell-owners route** | the production cell set treats the connected cathedral complex as interior content (slice-2/3 messages: "the cell-owners route", "the OLD apparatus flood"); walk conformance proves the WALK floods n=1, but consumers were still being cut over one at a time | flood = what survives GetClip from the root; at these poses exactly ONE cell; everything else is landscape-scope | traces §2.3; commit msgs `c40aecfc`/`5f7ccdea`; plan FW3.2b-2 "prepareCells UNIONED" | | D3 | **Dynamics-last** (register row AD-19, `docs/architecture/retail-divergence-register.md:147`): ALL dynamics in one z-buffered final pass | per-landcell painter-ordered draws inside the landscape pass; interior per cell turn | register row (self-declared); `DrawBlock` 0x005a17c0 / DrawSortCell pc:430124 | | D4 | **No degrade/LOD admission on this branch** — the marker stalks (Setup `0x0200085A` → GfxObj `0x010001EC`, ladder `0x1100002E` = {self at MaxDist 0, id 0 to ∞}) are DRAWN | retail selects `gfxobj[deg_level]` via `get_degrade` @0x0051E4B0 and **never draws** this model at any distance (gates in `DrawBuilding` @0x0059F2A0 and `CPhysicsPart::Draw` @0x0050D7A0) | `fce250ec` exists ONLY on `claude/cathedral-rendering-debug-47a417` (`git branch -a --contains`; `git merge-base --is-ancestor fce250ec HEAD` = false; `git grep IsNeverDrawnByDegrade -- src` = empty at HEAD) | | D5 | **Seal/vista coverage geometry**: post-clear alpha can z-pass wherever the visible vista is not covered by a stamped seal; slice 6 proved the walk's exit views at this seam are "thin BANDS far narrower than the real opening" | retail is not exposed to this because the leaking content class isn't post-clear in the first place (D1/D2) | commit msg `bb9212c7`; PV sightline probe (campaign memory) | | D6 | (regression candidate) straddle-classified emitters now emit pre-clear on interior roots — an interior emitter drained at the landscape flush is subsequently over-painted by the post-clear interior repaint | retail: root-cell emitters drain at the final flush, after interior geometry | mechanism prediction from `f3a03efc`/`0d6cd5c0` + model §5; matches the owner's new "particles WITHIN the cathedral are wrong" report — **unverified until probed** | The pre-existing #451 fix (owner-accepted 2026-08-27, `docs/ISSUES.md:249-289`) had already implemented the D1-correct contract for exterior particles ("submits attached and ownerless exterior particles inside `LScape::draw` for every PView root"). The FW2/FW3 window (`git diff --stat e102fb36..37febd1f -- src/AcDream.App/Rendering` = ~7,081 insertions: the whole `Walk/` tree, `WalkFrameDriver`, the static cutover) is the regression window that displaced it. --- ## 5. Per-commit verdicts **`37febd1f` (slice 1 — interior outside-view slices from the walk): KEEP.** Correct single-source-of-truth move (retail has ONE visibility structure); fixed a real dual-path desync (the #119-family grass flash) with a real mechanism (old-apparatus fat/degenerate exit views + walk-indexed punch fans). Not causal for the cathedral defect either way. Its per-view terrain slice FAN was still non-retail — superseded by slice 6, which it should be read together with. **`c40aecfc` (slice 2 — exit seals stamp the walk's flood): KEEP the code, REJECT the diagnosis (wrong-mechanism).** Stamping the walk's own flood's exit portals is exactly retail (model §5 seal loop, pc:432785-6, and the walk flood is conformance-proven against the traces). But the commit's premise — falls emitters submitting POST-clear is "retail's own timing" — is refuted by the traces: retail composes those cells pre-clear as look-ins. Seals could never fix an over-draw whose correct rendering is "drawn pre-clear with landscape depth"; at best they would z-reject the falls and make them wrongly INVISIBLE through the aperture. The plan's slice-2 paragraph (`docs/plans/2026-08-30-campaign-fw-frame-walk.md` FW4 slice 2) carries the same false premise and should be corrected. **`5f7ccdea` (slice 3 — outside-stage predicate reads the walk flood): KEEP.** Feeding predicates from the walk's VisitedCells (root flood + look-in floods — "all of whose objects retail draws inside LScape::draw, pre-clear") is the correct retail-shaped direction and removed one more old-apparatus consumer. Insufficient alone: it gates the DYNAMIC split, and the falls turned out to be cell statics (slice 5's own finding). **`f3a03efc` (slice 4 — straddler dynamics' particles pre-clear, once): WRONG-MECHANISM — revert once D1 lands.** Retail has no exit-plane-straddle classifier for emission timing; the cited rule ("retail submits an emitter's polys at its object's FIRST draw — the landscape stage for anything overlapping outdoor shadow cells") is right, but the implementation substitutes a plane-straddle test for draw-site membership. It under-covers emitters wholly OUTSIDE the exit plane (they never "straddle" ⇒ stay post-clear ⇒ still leak) and over-covers interior straddlers into the pre-clear drain where the interior repaint erases them (divergence D6 — the likely source of the new in-cathedral particle wrongness). Drawn-once bookkeeping (each owner emits exactly once) is worth preserving in whatever replaces it. **`0d6cd5c0` (slice 5 — straddling cell-statics' particles pre-clear): WRONG-MECHANISM — revert once D1 lands.** Its identification work is the best of the six (falls = EnvCell stab statics; the shadow-cell rule correctly cited at `DrawBlock` pc:430056-430064), but it ports the rule as the same geometric straddle test instead of the actual membership question ("is this object drawn during the landscape scope this frame?" — for the falls cells at these poses: yes, as building look-ins, regardless of any plane test). Same under/over-coverage failure modes as slice 4. **`bb9212c7` (slice 6 — interior roots draw landscape unclipped): KEEP.** Matches retail exactly: landscape content is view-CULLED, never view-CLIPPED (model §3: the views feed only `draw_check_blocks`' in_view union; `set_view` installs no GPU state; no scissor exists). Its probe finding — falls submitted pre-clear with depth LESS still passed because the scissored terrain had left the vista without depth — is the load-bearing discovery of the round and independently confirms the thin-band aperture geometry. It cannot, by itself, fix emitters that still submit post-clear on other frames/poses, and it does not address D6. --- ## 6. Why the symptom survived all six fixes 1. **A wrong premise was locked in at slice 2 and never re-examined against the traces the campaign itself captured.** "The falls submit post-clear — retail's own timing" is contradicted by `posed/terrace-center.log` / `posed/cathedral-arrival.log`: retail's interior flood at these poses is ONE cell and the falls' owner cells are landscape-scope look-ins. Every subsequent fix (seals, predicates, straddle emission) tried to make a post-clear world safe instead of putting the content in the pre-clear world where retail has it. 2. **The corrective classifier is not retail's rule.** The straddle test (slices 4/5) approximates "overlaps outdoor shadow cells" with "sphere crosses the exit plane" — a strictly narrower predicate that misses fully-outside emitters (the falls hang OVER the lake) and wrongly captures interior straddlers. 3. **Mixed visibility sources during the staged cutover.** Slices 2 and 3 each discovered another consumer still reading the OLD apparatus's flood (seal set, outside-stage predicate). The FW3.2b-2 design explicitly runs old visibility for dynamics beside the walk for statics (`docs/plans/2026-08-30-campaign-fw-frame-walk.md`); every such seam is a place where the walk's correct n=1 flood is not what production consumes. AD-19 (dynamics-last) keeps the weenie stalks post-clear regardless. 4. **Two of the leaking content classes cannot be fixed by ANY ordering/seal work:** the marker stalks should never be drawn at all (D4 — the degrade admission port is quarantined off-branch), and pre-slice-6 the vista had no depth to occlude against (D5) — so even correct pre-clear emission "passed" its z-test into stale color. 5. **Each fix was validated against the previous fix's failure, not against a falsifiable retail prediction.** The probes pinned real facts (phase=pre/post, straddler classification) but the acceptance question was "did the leak stop" rather than "does the frame now match §2.1's shape at this pose" — so five plausible partial mechanisms shipped in one day without any landing the frame-shape divergence (D1/D2). --- ## 7. Recommended fix plan (mechanism-first) **Step 0 — probes before code (falsifiable predictions):** - **P1:** With `ACDREAM_PROBE_WALK_ROOT` at the terrace pose on HEAD, the falls owners `0x4F418012-15` will log submission OUTSIDE the landscape scope (post-clear route or final drain) on defect frames, while the walk's own event stream visits their owner cells at BUILDING LOOK-IN turns (not in the interior flood, which stays n=1). If instead they already log landscape-scope submission + pre-clear drain on defect frames, D1 is falsified — investigate the drain's depth state (attachment, compare op) instead. - **P2:** The DAT stab tables will place stabs #0x12-0x15 in cell(s) OTHER than the frame's root cell at the defect poses (look-in-reached cells). If they are stabs of the root cell itself, the look-in theory is falsified. - **P3:** Forcing the falls emitters to submit at their owner cell's look-in turn (landscape scope, drained at the pre-clear boundary flush) removes the over-draw at EVERY camera on interior roots, while the falls stay visible through the opening and terrain-occluded exactly as on outdoor roots. - **P4:** Reverting slices 4/5's straddle emission (in favor of the walk-turn rule) makes the new "particles within the cathedral are wrong" report disappear (root-cell emitters return to the final drain). - **P5 (optional, owner-assisted):** a cdb capture at the terrace with a breakpoint on the particle-poly alpha-list insertion will show falls polys entering the list BEFORE `DrawCells`' depth clear on interior-rooted retail frames. **Step 1 — the emission-site port (fixes the falls).** An object's particles submit when and where the object itself draws in the walk: look-in cell content and outdoor shadow-cell content submit during the landscape turn and drain at the pre-clear boundary flush; root-flood cell content submits at its cell turn and drains at the final flush. Retail pins: appendix 811 (look-in `DrawCells` inside the landscape scope), `DrawBlock` pc:430056-430064 (shadow-cell object draw), model §5 (the two drain sites). Delete `SphereStraddlesExitPlane`-based emission (slices 4/5) in the same commit; keep the emit-once ledger. **Step 2 — finish the flood-consumer cutover (fixes the class).** Every remaining consumer of the old apparatus's cell set (cell-statics particle owners, dynamics routes, prepare unions) reads the walk's per-turn visited sets. AD-19's interior-root half retires when dynamics draw at their cell's walk turn; if that is deferred, dynamics must at minimum gate on the walk's visited set so a non-visited cell's weenies cannot draw at all. **Step 3 — re-land the marker-degrade admission (fixes the stalks being visible at all).** `fce250ec`'s mechanism (never-drawn degrade ladders: `get_degrade` @0x0051E4B0; `gfxobj[deg_level] != 0` gates) is a retail port stranded on the quarantined branch. Re-land it cleanly on this branch (fresh commit, not a cross-merge from quarantine), covering static AND dynamic classifiers. If stalk-like shapes remain afterwards, identify by guid before theorizing (they'd be weenies with a different model — campaign-memory rule). **Step 4 — verification gates.** The ten oracle fixtures stay green (the walk itself is already conformant); add a fixture-level assertion that the DRIVER's submission stream places look-in-cell content in the landscape scope (the current conformance compares walk events, not submission scope — that gap is how D1 shipped); then the owner matrix: terrace both cells, seam crossing, outdoor falls, interior candles, doorway flap, Holtburg exit. --- ## 8. Open questions - **Q1:** Why are the walk's exit views at this seam thin bands — is the full visible opening authored as multiple portals (0/1/2/4) of which only portal 4 survives GetClip at these camera states, or is our clip/winding at fault, or does the chase camera sit outside the cell volume? (Slice 6 measured the symptom; the cause is unestablished. The PV probe's "panel ∪ solid covers every sightline" was measured at ≤6 m camera rises only.) - **Q2:** Which EnvCell(s) own falls stabs #0x12-0x15, and do the falls additionally exist as dynamics (slice 3 probed entities "f4243/f4285" as [walk-dyn] — the relationship between those ids and the stab owners is unestablished). **DAT parse owed.** - **Q3:** The exact HEAD drain/depth state of `ParticleRenderer` under Vulkan (depth attachment, compare op, write mask) at each drain site — required to close P1's alternative branch. **Code audit owed.** - **Q4:** Whether `ShouldDrawParticles` (@0x0050FE60) is evaluated per-frame or per-view in our port, and against which cell set at HEAD. - **Q5:** The gated clear's `portalsDrawnCount` semantics across frames (seals increment it AFTER the clear check — does the first interior frame after an outdoor frame skip the clear in retail?), and whether our `slices>0` production gate is equivalent. - **Q6:** Whether the seal fans at HEAD still apply the old assembly's per-cell slice clips ("where present", slice 2) and whether that can shrink a seal below its authored polygon. - **Q7:** The uncharacterized in-cathedral particle wrongness (owner report #3) — D6 is a prediction, not a diagnosis; one probe frame with `[walk-part]`/`[walk-alpha]` at a candle would settle it. --- *Reviewer: Fable. All decomp addresses cite the named 2013 build (`docs/research/named-retail/`); trace lines cite files under `docs/research/2026-08-30-fw-walk-oracle/posed/`; commit claims cite the SHAs in §5; everything not directly read is marked unverified above.*