Commit graph

1165 commits

Author SHA1 Message Date
Erik
316193043d docs(overhaul): authorize narrow S4 c3a evidence fix 2026-09-04 14:37:37 +02:00
Erik
b6b0156045 fix(render): retain surfaceless particle metadata
Preserve a successfully decoded GfxObj ParticleGfxInfo when SurfaceId is zero and condition only texture acquisition. Missing/no-Gfx descriptors retain Default behavior; material, additive, routing, and untextured drawing remain unchanged.

Add a production-path GfxObj-backed synthetic no-surface pin with distinct authored/AABB centers, non-unit size, nonidentity orientation, object/particle merge order, visual center, and unassigned texture-slot assertions. Correct the synthetic-DAT evidence wording and advance only the S4-c3a ledger row.

Final F2 source audit found no defect: preparation holds reconstruction inputs only; Append reserves once; false and exception roll back the exact tail once; first-use rejection remains registered; accepted tokens stay stable; independent 3000-entry caps preserve row-2 immediate duplicates; flush/end/abort/next-preparation cleanup converges; retained capacity/bytes remain bounded; warmed production paths remain 0 B.

Gates: no-surface target 1/1; unchanged section 19 baseline 95/95; AP boundary/count 1/1; real allocations 2/2 at 0 B; shader/manifest 32/32; Release solution 0 warnings/0 errors; diff-check pass. No graphical client.

Mutation: restoring eea5793d2's SurfaceId-zero-to-Default ternary first failed CellTurn_GfxObjBillboardWithoutSurfaceRetainsAuthoredSortCenterAndUntexturedFallback at the authored-distance assertion, expected 40 actual 100.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-09-04 14:37:31 +02:00
Erik
8bd75ba312 docs(overhaul): bound final S4 c3a fix 2026-09-04 14:37:28 +02:00
Erik
01674bcc78 fix(render): repair particle CYpt preparation
Retain the GfxObj-authored SortCenter independently from the rendered AABB center and use its scaled, oriented world point for billboard/mode-2-5 CYpt. Keep the visual center unchanged.

Reserve prepared source payload only at Append, roll back the exact tail once on false or exception, cap retained preparation at 3000 CLIP plus 3000 ALPHA, preserve immediate duplicates, account the bounded scratch, and correct the static-record ordering comment. The lead-authorized plan edit records candidate 44e2bc227b's retail FAIL and this section 19 result.

Gates: Release solution build 0 warnings/0 errors; focused particle/driver/queue/order/bounds 95/95; register boundary/count 1/1; real allocations 2/2 at 0 B; shader/manifest 32/32; one-shot hermetic 16751/16751; InstalledDat 385 pass/10 documented fail/1 skip; diff-check pass. No graphical client.

Mutations: rendered pos first failed distance expected 40 actual 116; AABB center expected 40 actual 116; dropped size expected 40 actual 65; dropped orientation expected 40 actual 160; eager reservation first failed Assert.Empty with one payload; omitted false rollback first failed Assert.Single with two payloads; omitted exception rollback first failed Assert.Empty with one payload; removed caps first failed prepared count expected 6000 actual 6002.

Evidence note: the first ordinary InstalledDat filter produced 385 pass/2 expected fail/1 skip but excluded the eight required KnownFailure rows; the separate inclusive no-retry artifact produced the exact documented 10-failure set. Initial test fixture compilation/analyzer setup failures are recorded in packet section 19.5.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-09-04 14:37:23 +02:00
Erik
8e0c6fb145 docs(overhaul): bound S4 c3a retail fix round 2026-09-04 14:36:54 +02:00
Erik
a86ec73ece fix(render): restore retail per-cell alpha order
Reconstruct one combined static/dynamic object-part stream for each ordinary outdoor or interior cell, compute authored SortCenter CYpt keys, and stable-sort far to near before projecting opaque and delayed subsets. Prepare real cell-particle records at the leaf, preserve every S4-c2 router outcome, and merge object and particle delayed records by retained key before either source appends to the unchanged CLIP/ALPHA FIFO lists. Cell turns remain cell-major; equal cross-source ties are deterministically object-first.

File AP-241 and AP-242 for the remaining separate opaque/row-5 channels and unrepresented equal-key common ordinal. File AP-243 for the paired-binary correction: retail shares the cell CYpt/heading beyond 50 m while this bounded port always uses the more exact authored per-part center. Pin 162 active AP rows and correct world-alpha and AlphaFlushCounts prose.

Lead-approved scope clarification: RetailPViewPassExecutor.WalkLeaf.cs and RetailPViewPassExecutor.cs are the minimum existing production leaf adapter and thin particle-prepare forwarder omitted by the literal Walk/Wb file list. They contain no router, queue, mask, state, depth, or flush behavior; relocating them would create an artificial seam.

Gates: Release solution build 0W/0E; shader/manifest 32/32; focused production 210/210; real allocation 3/3 at 0 B; one-shot hermetic 16743/0/0 across 14 assemblies; InstalledDat 385 pass/10 documented fail/1 skip with all six AlphaFlushSites passing; git diff --check PASS. Initial no-restore solution build failed NETSDK1004 for 42 missing scratch assets; one solution restore preceded the official build.

Mutation proof, each restored before final gates:

1. Reverse comparator: authored-center order expected [202,101], actual [101,202].

2. Move ties left: multipart/subset order expected [11,12,21,22], actual [22,21,12,11].

3. Restore static/dynamic blocks: expected [2,3,1], actual [3,1,2].

4. Use entity origin: authored-center order expected [202,101], actual [101,202].

5. Restore particle tail: expected [Wb,Particle,Wb,Particle], actual [Wb,Wb,Particle,Particle].

6. Scope-global sort: first cell model X expected 5, actual 50.

7. Restore dead camera parameter: SubmitWalkAlphaInstance parameter count expected 2, actual 3.

8. Restore stale global-queue prose: exact Assert.DoesNotContain failure on distance-sorts one shared queue.

9. Remove AP-241 identity: Assert.Single found no matching row.

10. Allocate in real merge: expected 0 B, actual 3072 B.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-09-04 14:36:48 +02:00
Erik
06b986622b docs(overhaul): stop S4 c3a after final review 2026-09-04 14:22:50 +02:00
Erik
5c9da6fc25 docs(overhaul): define S4 c3 upstream order repair 2026-09-04 12:42:01 +02:00
Erik
d8c88adeb0 docs(overhaul): close S4 chunk 2 landing 2026-09-04 12:32:06 +02:00
Erik
89f1e2676f feat(render): S4 chunk 2 — retail's two-list alpha FIFO cutover
Replaces the single scope-global distance-sorted RetailAlphaQueue with
retail's own two independent FIFO lists (CLIP/ALPHA, capacity 3000 each,
D3DPolyRender::AddMeshToAlphaList's exact append-only/capacity-drop
behavior — Ghidra-verified 2026-09-04), routed by a new
RetailAlphaMeshRouter porting DrawMesh's five-row immediate/delayed
branch table and ConstructMesh's subset-mask formula as pure functions,
and drained at retail's four normal-world FlushAlphaList sites
(DrawBuilding/DrawBlock/PView::DrawCells/RenderNormalMode) under the
exact Ghidra-verified no-op predicate (both counts strictly below
threshold*3000). A new WalkFrameEventKind.SortCellExit /
IWalkEventSink.OnSortCellExit / IWalkFrameLeafRenderer.FlushSortCellExit
fires once per admitted land-block cell for DrawBlock's 0.75f valve,
pinned by a dedicated far/near ordering test in RetailFrameWalkTests.cs.

WbDrawDispatcher's two submit sites and ParticleRenderer's one route
through the router; since none of the three ever draws during the Sky
leaf, installs a detail surface, or sets MultiPassAlpha, rows 1/2/4/5
are provably unreachable there and the call sites assert loudly rather
than building unexercisable immediate-draw plumbing. FlushFartherThan,
RetailAlphaOrdering.ComputeViewerDistance, and every viewerDistance
argument on the submit path are deleted.

Scope note (packet s4-depth-alpha-packet.md §10): C4 (routing EnvCell's
transparent shell batches through the shared queue) was not attempted —
EnvCell draws one per-cell MultiDrawIndexedIndirect call with no
per-subset deferred-replay abstraction, and building one without visual
verification (no graphical client in this worktree) was judged out of
this bounded chunk's scope. AP-34 is therefore retired and replaced by
two narrower rows rather than deleted outright: AP-236 (the carried-
forward EnvCell-immediate residual) and AP-237 (a newly identified gap:
TranslucencyKind.AlphaBlend can arise from either retail's Alpha/
Translucent bits, mask 0x02/ALPHA, or the Translucent+ClipMap "cloud"
override, mask 0x08/CLIP — GroupKey doesn't retain the raw bit to tell
them apart, so the router always picks ALPHA; only known example is
cloud GfxObj 0x01004C35). Both are compositing-order-only divergences,
never blend/visual ones.

Mutation checks (each applied, confirmed failing, then reverted):
- FIFO drain order reversed -> 5 RetailAlphaQueueTests fail (order).
- FlushAlphaList `<` -> `<=` -> boundary/scratch tests fail (2250 case
  reads drained=0 instead of 2250).
- Capacity check loosened (3000 -> 6000) -> overflow-drop test fails
  (TryAppend returns true, PendingCount reads 3001).
- IsFirstForList forced true -> flag test fails once inspected on the
  pre-flush two-entry snapshot (the post-flush single-survivor version
  of this test was vacuous and rewritten).
- Router row 3 condition inverted -> both the hand-traced Theory (6
  cases) and the 160-cell independent-truth-table brute force fail (20
  mismatches).
- SortCellExit emitted before OnLandscapeCellTurn instead of after ->
  RetailFrameWalkTests ordering pin fails ("SCX must immediately follow
  its own cell's SC").
- Prepare-per-list instead of prepare-once-combined -> the CLIP/ALPHA
  boundary batching test throws (index out of range).

Gates: Release build 0 warnings/0 errors. Hermetic lane (Lane!=Installed
Dat&...&Status!=KnownFailure) 6855/6855 passed. InstalledDat lane 249
passed / 10 failed — exactly the 4 pre-existing failures (#383 x2
LayoutImporter, TowerAscent KnownFailure, #458 Oh_doorway_still
KnownFailure) plus 6 NEW KnownFailure Facts
(AlphaFlushTranscript_*_MatchesRetailFrame2, one per capture) extending
this gate from PM/PC to AM/FL: the flush SITE+THRESHOLD sequence matches
the capture exactly for all six poses (including zero SortCellExit
drains in every capture, confirming the 0.75 valve is inert at these
scene complexities in both retail and this replay); the drained-COUNT-
per-list dimension diverges because this hermetic harness (matching the
existing PM/PC gate's own EmptyAlphaDepthWorldData design) carries no
live GfxObj/particle content, so every observed count reads (0,0)
against retail's real per-frame volume — both sequences quoted in full
per pose in the packet's new §10. Shader classes (VulkanShaderDescriptor
ContractTests/VulkanShaderManifestTests/RenderPackSpirvValidatorTests)
32/32 passed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 11:52:40 +02:00
Erik
3f69f1126b docs(overhaul): start S4-c2 completion attempt 2
Record attempt 1's shader-source-hash contract conflict and permit only the deterministic manifest/paired vertex-SPIR-V closure needed by the required comment correction.
2026-09-04 11:34:33 +02:00
Erik
249dabb41b docs(overhaul): authorize five S4-c2 completion attempts
Start attempt 1/5 as an evidence-and-comment-only repair of a094bf2b7. Preserve behavior, assertions, shader/SPIR-V, register, package, sequential review, and no-landing-before-dual-PASS constraints.
2026-09-04 11:31:29 +02:00
Erik
e8d89ba29a docs(overhaul): stop owner S4-c2 repair after retail review
Record a094bf2b7 as behaviorally retail-clean but unlanded because the binding evidence/prose contract failed. Preserve the sequential-review stop: the production lens did not run, no graphical gate ran, and G3/G4 remain unpassed.
2026-09-04 10:53:37 +02:00
Erik
4e863f7486 docs(overhaul): authorize bounded S4-c2 repair
Record the owner override after the required stop and bind the one-attempt repair to exact EnvCell pass membership, retail CLIP state, bounded source scratch, and production-path discriminators. Keep G3/G4 unpassed and the implementation unlanded pending dual review.
2026-09-04 09:42:59 +02:00
Erik
dc971ea2be docs(overhaul): stop S4-c2 after final review 2026-09-04 09:22:06 +02:00
Erik
ac74fbd84e docs(overhaul): contract S4-c2 final fix round 2026-09-04 08:06:14 +02:00
Erik
90d4ef4ac9 docs(overhaul): hand-off intro — no subagent running at hand-over
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 07:33:46 +02:00
Erik
cb71a92d51 docs(overhaul): hand-off at S4-c2 fix round 1 DONE (cc8e5677a in s4-c2-impl) — what is left on chunk 2, the review and landing procedure; ledger S4 row updated
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 07:33:34 +02:00
Erik
2a35f0a4c3 docs(overhaul): hand-off rewritten clean at S4-c2 fix round 1 (review verdicts, #464 fixed, #468 filed, landing procedure, fixer-state check)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 06:39:23 +02:00
Erik
2001103ca6 docs+gate: #468 filed — the Holtburg doorway pose seats the player in the interior cell at a floorless point and it falls through the world; route-g3b pose 15 moved to the outdoor standing point
The 'empty plane under fog' frame the S4-c1 capture-pose self-gates produced
at frame 15 is the terrain seen from below by a falling player, not a draw
change: the camera probe holds playerCell=0xA9B4013F at (134.07,17.36) while
z drops 96 -> -20 m after materialization. The S3-state run had seated the
same request outdoors in 0xA9B40029 and stood. Placement is not the campaign's
domain; the gate pose is moved so the G3 frame is deterministic and the
original pose is kept in the issue as the reproduction. #462 recurrence on
the pre-S4 control build noted.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 06:37:09 +02:00
Erik
3e76f71d5b docs(overhaul): S4-c2 production/gate lens FAIL recorded; fix round 1 addendum §11.1 (A1–A8)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 06:21:06 +02:00
Erik
3813f0bbf2 docs(overhaul): S4-c2 review round 1 — retail lens FAIL recorded; fix round 1 contract (packet §11, M1–M8)
The two-list/router/flush core of 048d5b12f is exact at the bytes; the
failures are at the call sites (a data-driven row 5 turned into a throw;
detail-surface input hardcoded false while the drain applies detail),
the register (the structurally empty CLIP list is undeclared; AP-237's
example is wrong; AP-34 not retired by convention), the first-for-list
quantifier, the all-KnownFailure gate, and the skipped C4 that turns out
to be bounded.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 06:14:53 +02:00
Erik
36fddf17ca docs(overhaul): S4 hand-off — landed state, the in-flight S4-c2 implementer, the #464 RenderDoc plan, the Holtburg doorway A/B, owner-owed items
Written for a fresh session on another account: read order, exact tips and
worktrees, what S1-S4-c1 landed with their proof, how to find the state of
the chunk 2 implementer dispatched this morning, the #464 attribution plan
(RenderDoc pixel history on the scripted artifact frame - the lead's own
job once ACE is up), the Holtburg doorway frame read, tooling gotchas, and a
paste-prompt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 05:00:35 +02:00
Erik
49d2447a95 docs(render): S4-c1 fix round 1 verdicts (2 PASS / 1 FAIL) and the round-2 contract (packet §9): seed the portal counter from the capture, both sequences compared, the discriminating ±12 case, the sixth pose
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 22:49:33 +02:00
Erik
3a6aa7eef4 research(render): retail portal-polygon vertex capture at the #464 pose + the pm-verts cdb template
Sixteen DrawPortalPolyInternal attempts per frame, vertex-identical to
acdream's sixteen collect-time punches; twelve lie entirely on the local
y=12 plane and are rejected by the ±12 guard in both clients, so the hall
building's doorways are never punched in either.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 22:42:01 +02:00
Erik
4f12cd06b5 research(render): retail capture cathedral-stair-arch — the #464 artifact pose (walk 5 frames + alphadepth 5 frames)
Root 0xF4180114 with seven outside views; retail admits the same seven
hall building-portal groups in the same order as acdream, yet shows the
solid far face above the arch. The fifth transcript pose for S4.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 22:26:29 +02:00
Erik
4173cbd6e0 docs(research): move the #464 tilted-frame walk record out of the ignored logs dir
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 22:19:33 +02:00
Erik
c3b989305a docs(research): #464 camera investigation report; reclassified as an interior-root draw defect (S4); archway route
Read-only decomp + real-DAT replay: eleven sweep/root differences, each
unreachable at the pose or more constrained than retail; the replay seats
the pivot in 0xF4180114, stops the boom on its east pier at y=16.448, and
the walk from that root floods 114/113/112 with seven exit views. The
owner's probe launch line now also sets ACDREAM_PROBE_FACILITY_STAIRS.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:50:40 +02:00
Erik
d5fbcc6d5b docs(render): S4-c2 contract (packet §8) — two FIFO alpha lists, the DrawMesh router, four flush sites, AM/FL transcript gate
Drafted from the five alphadepth captures (10,556 AM lines, every clip=0;
FL by return address 13,705 / 309 / 18 / 23) and the OH1 alpha-list
contract. Dispatch waits for S4-c1 to land.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:46:01 +02:00
Erik
7148b8060b docs(render): ledger — S4-c1 round 0 failed three lenses (the ±12 quantifier); fix round 1 dispatched; §7 notes the vacuous register-test gate
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:18:09 +02:00
Erik
e9bb627b81 docs(render): S4 packet §7 — S4-c1 fix round 1 (retail's ±12 quantifier, seal count order, the automated PM/PC depth-event gate)
The round-0 retail and production lenses both found the guard's
quantifier inverted (the lead's paraphrase); the production lens's DAT
scan found 2,163 exit polygons lying entirely on a ±12 plane, which makes
the guard the likely mechanism behind retail's never-sealed seam family.
The PM/PC transcript comparison becomes the chunk's own gate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:13:55 +02:00
Erik
ad6b0599cc docs(render): S4 packet — the ±12 reject's quantifier corrected to retail's (ALL vertices on ONE bounding plane); #464 stair-ladder route
The S4-c1 retail lens caught the lead's paraphrase inverting retail's
predicate (any vertex on any plane vs every vertex on the same plane);
the contract and T2 now state the decomp's four per-plane predicates.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:07:38 +02:00
Erik
174f30f176 docs(render): §12 — S3 review fix round 1 (punch-fan view alignment, seal pin through the producer, dead clip routing, EC/OC transcript exactness) and the chunk-3 perf evidence correction
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 18:48:46 +02:00
Erik
5bc4b36879 docs(render): S4 packet — S4-c1 contract draft; the far-punch constant is NOT retail's (0x3F7FFFFE vs 0x3F7FFFEF)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 18:28:00 +02:00
Erik
6989868c37 docs(render): §10.6 — post-hoc lens verdicts (three PASS) and the landing-hygiene chunk; AD-17 particle clause corrected
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:50:42 +02:00
Erik
6435655d73 docs: S4 packet — particles take the retail DrawMesh branch table; #459 names the unconsumed-attribute candidates
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:14:57 +02:00
Erik
17315f0e7d docs(render): S4 packet — settle the valve hook and the alpha capture format questions
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:14:02 +02:00
Erik
ac1b7afeb7 docs(render): S4 packet draft — what S3 already delivered, the alpha-list cutover, open questions
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:12:37 +02:00
Erik
37e42aafc4 docs(render): resolve #458 — the a9c9 doorway admission is a 0.5 % edge-plane precision boundary (AD-118)
Two live cdb captures on the paired 2013 client at the Holtburg doorway:
the blockset template (every Render::block_check call of one frame — 2,601
resident blocks x 2 exit views) proves retail tests a9c9 at ring slot
25,46 and returns PARTIALLY then OUTSIDE; the blockcheck template dumps
its four corner interval vectors (0 0 0 0 300.4|310.2 and 0 0 0 1001 ...,
slab 75..330). acdream's replay at the same P pose reproduces the sentinel
pattern, the four edge planes and both verdicts, drawing a9c9 once, with
clip heights 298.8/308.5 m — a 0.5 % plane difference (about 0.35 px of
projected door-vertex position). At the fixture pose that margin is what
flips the south-west corner from inside to outside on the fourth edge
plane, so retail's four-corner unanimity test says OUTSIDE where ours
says PartiallyInside. Not fixable bit-exactly short of D3D's x87
transform; the KnownFailure row stays with its comment rewritten, the
register carries AD-118, and the first filtered capture's silent miss
(cdb sign-extends poi() inside .if; use dwo()) is noted in the template.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 14:43:14 +02:00
Erik
65675e77a8 docs(render): S3 chunk 4 fix round 2 contract (§10.5) — the last allowed round
Round 1 (d60ca4ea0) failed all three lenses: the draw-side weather gate is
unpinned, the scissor stack survived K4 on a false comment, the sky shader
still claims retail clips the sky, the K6 pin runs through an assembler
overload production never calls, and K3 left a dead UBO fed per draw.
L1-L9 delete the stacks outright and pin the draw gate's condition.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 14:29:33 +02:00
Erik
386b1327b5 docs(render): S3 chunk 4 fix round 1 — loop-shape weather pin, one weather gate, dead terrain-clip stack, sky drawn once
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 13:33:45 +02:00
Erik
9b55d78a28 docs(render): S3 chunk 1 fix round 2 — one weather OC per frame (pinned), literal EC/OC comparison, cost/wording items
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 11:52:36 +02:00
Erik
6e3de1bc6b docs(render): chunk 1 fix round 1 — SC at DrawSortCell entry, the weather OC, EC evidence, eight-kind conformance
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 11:03:18 +02:00
Erik
4215222304 docs(render): S3 chunk 1 fix round 1 — vacuous flag-off pin, LC/SC work outside the flag, flag-on round trip
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 11:00:01 +02:00
Erik
0b770afc11 docs(render): chunk 4 inventory re-checked after chunk 3
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 10:18:09 +02:00
Erik
38b5adc523 docs(render): S3 chunk 3 fix round 2 — the soak shows ~500 terrain submissions/frame; opaque stream marks stop splitting terrain batches
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 10:16:34 +02:00
Erik
e10765aaa0 fix(render): S3 chunk 3 re-review follow-ups
- the LandCell event doc states the deferred cross-block batch rule (the
  same-landblock lookahead text was stale);
- the AlphaSubmitMark arm's comment gives the true reason it is not a
  flush point (it only enqueues into the CPU alpha list; the drain leaves
  flush first);
- the pending terrain batch is cleared with the other transient frame
  lists in AbortFrame/BeginFrame;
- CompleteWalkTerrainFrame runs in a finally so a throwing Replay cannot
  leak its accumulated ticks into the next frame's sample;
- CopyRenderableEmittersInCell keeps its own doc comment;
- the outdoor-root LandCell pin now observes one real cell turn after its
  terrain;
- the oh1 landscape contract's stale "whole pre-stage" prose is resolved.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 10:00:28 +02:00
Erik
651badc2b9 fix(render): S3 chunk 3 round 1 - slot key, deferred cross-block terrain batches, per-frame terrain diagnostic
Fixes the three-lens review blockers against 671eb3ad4 (S3 section 9.6 F1-F6).

F1 - slot key (blocking, retail). TerrainModernRenderer.DrawLandCells
normalizes every incoming landblockId to (id & 0xFFFF0000u) | 0xFFFFu
before the _idToSlot lookup: the walk hands 0xXXYY0000
(WalkLandBlock.LandblockId) but AddLandblock stores under the DAT id
0xXXYYFFFF (LandblockRenderPublisher.LandblockId) - every walk lookup
was missing and the walk path drew NO terrain. Unit-tested end-to-end
through a real RecordingGpuDevice-backed TerrainModernRenderer
(TerrainWalkSlotKeyNormalizationTests): AddLandblock(0xA9B4FFFF, ...)
is found by a 0xA9B40000 lookup, an unknown landblock is a silent
per-entry no-op, and a batch mixing a known and unknown entry submits
only the known one.

F2 - deferred cross-block batching (blocking, driver). Retail's
DrawSortCell always follows DrawLandCell (LC/SC strictly alternate,
never two LC in a row - S3 section 9 R1), so chunk 3's "merge
consecutive same-landblock LandCell events" rule never actually
merged anything; the driver review flagged batching as inert.
WalkFrameDriver.Replay now keeps ONE pending terrain batch across
landblocks ((landblockId, side, cellIndex) entries, cleared at
Replay's own start); a LandCell event only appends; every OTHER event
kind that will itself submit GPU work (StreamMark, Sky, CellShell,
PunchFan, AlphaBarrier, LandscapeFlush, ClearInteriorDepth,
ExitSeals) flushes the pending batch first; a StaticParticles/
CellParticles turn asks the new ParticleSystem.
HasRenderableEmittersInCell (an allocation-free sibling of
CopyRenderableEmittersInCell) and, when the cell has no renderable
emitter, submits nothing and does NOT flush either - the whole point
of the deferred rule. The end of Replay flushes the remainder. This
is order-preserving by construction: a flush always lands at the
exact point the unbatched draw would have, so GPU submission order -
and therefore pixels - is identical to the unbatched baseline; only
the number of small terrain draw calls shrinks.
TerrainModernRenderer.DrawLandCellRuns becomes DrawLandCells(
viewProjection, IReadOnlyList<(uint LandblockId, int SideCellCount,
int CellIndex)>) - one MultiDrawIndexedIndirect over every entry's
runs, unknown slots skipped per-entry. IWalkFrameLeafRenderer.
DrawLandCellBatch drops its separate landblockId parameter to match
(a batch can span several landblocks now) and gains
HasRenderableEmittersInCell.

Batch-count demonstration: driven through a real WalkFrameDriver
Replay (OnLandCellTurn_MergesAcrossLandblocksOverAnEmptyParticleTurn_
RealSubmissionsSplit), 4 LandCell turns across 3 distinct landblocks,
separated only by an empty particle turn, a real StreamMark, and a
building's alpha barrier, submit as exactly 3 DrawLandCellBatch calls
(2+1+1) instead of 4 - the empty particle turn's non-flush merges two
otherwise-separate cross-landblock entries. At production scale the
same mechanism is expected to cut the terrace-edge frame's ~578
individual DrawLandCell events (S3 section 9's captured transcript
count) to "tens" of submitted batches, per the contract's own
expectation: most terrain cells have no particle owner nearby, so the
strict LC/[empty-SC]/LC/[empty-SC]/... run collapses into one batch
per region bounded by real content (a building, a StreamMark-worthy
cell, or a genuine emitter) rather than per cell.

F3 - per-frame terrain diagnostic (blocking, build/test). The walk
leaf no longer brackets each batch with TerrainDrawDiagnosticsController
.Begin()/Complete() (a per-batch Stopwatch Restart/Stop pair that was
pushing one timing SAMPLE per batch, not per frame).
RetailPViewPassExecutor.DrawWalkLandCellBatch instead times its own
call with a raw Stopwatch.GetTimestamp() delta (no allocation) and
hands the ticks to the controller's new AccumulateWalkBatch;
RetailPViewRenderer.DrawWalkDrivenStatics calls the new
CompleteWalkTerrainFrame() exactly once, immediately after
driver.Replay finishes - "the end of the walk replay", where the
deleted whole-stage terrain leaf's own Begin()/Complete() bracket
used to close - which pushes ONE elapsed-time sample (even a
zero-batch frame pushes a zero sample: one sample per frame, not per
landscape turn) and publishes on the existing 5-second cadence.
TerrainRenderDiagnosticFacts gains a Draws field alongside
VisibleSlots (both were the same field before); TerrainModernRenderer
tracks its own per-frame WalkVisibleSlotCount/WalkDrawCount (a
HashSet<int>/int cleared in BeginFrame, populated by DrawLandCells),
and the diagnostics source reports those whenever the walk drew at
least one batch this frame, falling back to the non-walk Draw()
path's VisibleSlots otherwise (the two paths never both run in the
same frame). The [TERRAIN-DIAG] line's meaning (cpu_us per frame) is
unchanged, so the S3 section 9.5 before/after compare stays valid.

F4 - driver pins for the LandCell position (major). Three RunFrame-
level pins replace the deleted TERRAIN:0 pins: an outdoor-root
sequence (SKY, then one LANDCELL, driving RetailFrameWalk.
DrawLandscape directly with a one-view/zero-vertex WalkPortalView so
WalkLandscape.CheckBlocks' admission stays the same deterministic
"CY-only" test RetailFrameWalkTests already relies on, while still
satisfying WalkFrameDriver's real >=1-active-view fail-loud guard);
an interior-root test with one real exit view and one populated
block (SKY, LANDCELL, LFLUSH, SEALS, SHELL...) built on the existing
RunFrame_InteriorFloodWithExitView_... fixture; and the T4 batching
pin re-expressed for the F2 rule (OnLandCellTurn_
MergesAcrossLandblocksOverAnEmptyParticleTurn_RealSubmissionsSplit,
described above). The fake leaf's DrawLandCellBatch now logs
LANDCELL:<lb>:<side>:<idx>[,...] per batch and gains
HasRenderableEmittersInCell backed by an opt-out CellsWithoutEmitters
set (default true - has-emitters - so every pre-existing pin in the
file keeps its old unconditional-submission behavior unchanged).

F5 - no code change: the walk's in-view gate is unchanged; no
whole-block terrain re-added.

F6 - minor/notes: DrawLandCells' own comment now states the walk's
CheckBlocks/landcell_check admission is the sole terrain culling
authority (retail has no separate terrain frustum test); the
HandleLandscapeTurn comment's inverted claim is corrected (a FARTHER
building's punch survived because NEARER terrain was drawn BEFORE
it, not after - the interleave now draws it after, matching retail);
the "flat/directional-shadow paths" claim is corrected to the one
actual caller, WorldScenePassExecutor.DrawFlatTerrain (a directional-
shadow receiver selects its pipeline inside the SAME DrawRhi call,
not through a second caller); the cathedral order-trace token gains
the LOD side/index (":LC<lb>/<side>:<idx>"); T2's vacuous "no
TERRAIN event" assertion in RetailFrameWalkTests is replaced by a
comment pointing at the F4 driver-level pins; and the stale
"Confirmed OH5 defect" row in oh1-construction-landscape-contract.md
is retired with "FIXED by S3 chunk 3 (commit 671eb3ad4 + fix round
1)".

App hermetic lane: 6,795/6,795 (up from 671eb3ad4's 6,786 baseline -
net +9 tests: 3 F1 slot-key tests, 2 F4a/b driver RunFrame pins, 3
TerrainDrawDiagnosticsController walk-frame tests, plus the T4->F4c
rewrite and the RetailPViewPassExecutorTests split are net neutral).
InstalledDat lane: 241 passed, the same 3 accepted failures (2
pre-existing #383 layout fixture-drift tests, 1 TowerAscent
Status=KnownFailure) - unchanged from baseline. Core Vfx tests:
109/109 (108 baseline + 1 new HasRenderableEmittersInCell lifecycle
pin mirroring CopyRenderableEmittersInCell's own add/move/remove
test).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 09:57:34 +02:00
Erik
eb80c80eb6 docs(render): S3 chunk 3 fix round 1 — slot key, cross-block deferred batching, per-frame diagnostic, LandCell pins
Three-lens review of 671eb3ad: the terrain slot map is keyed by the DAT id
(0xXXYYFFFF) while the walk passes 0xXXYY0000 (no terrain drawn); the
adjacent-same-landblock batching can never merge because retail's own
DrawSortCell interposes a particle turn after every land cell; the timing
diagnostic moved inside the per-batch loop. Round 1 of two.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 08:58:43 +02:00
Erik
bbe41d5993 docs(render): S3 chunk 1 contract — transcript kinds, fixtures, print-only emitter
Runs after chunk 3 (LC/SC need per-cell terrain). One print-only flag,
the FW0 parser extended for the OH kinds, the five captures as fixtures
in the existing still-frame conformance harness, and an offline signature
diff as the transcript gate. No validator, no canonical format.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 07:49:56 +02:00