Commit graph

4415 commits

Author SHA1 Message Date
Erik
28da2fcb8e docs(issues): #464 reproduced from the script — camera in front, zoomed out through the open face into the hall; stairwell draws without walls
The eye is legitimate (retail's sweep passes the same opening); the defect
is the draw of the stairwell cells seen back through the building's
exterior portals. Matrix row invariant re-worded; the one retail capture
to request is the oh-capture walk + alphadepth at exactly this eye.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:54:18 +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
060c392ecc docs(issues): #464 owner launch line — forward slashes (the previous line lost a path segment to an escape)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:41:26 +02:00
Erik
6ae511e11e docs(issues): #464 camera-cell probe rounds — the eye never leaves the cell; re-read as the exit-portal seam-band family
Four probe-on self-gate rounds (run/zoom/tilt/mid) with the camera cell,
root and eye logged every frame: sweep ok, eye in root, no fallback, in
every frame. The DAT shows 0xF4180113/0xF4180114 are one stairwell split
horizontally; the zoomed-out eye stops 0.31 m in front of 0x114's
nine-vertex EXIT portal. Owner asked for one probe-on reproduction.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:40:59 +02:00
Erik
4f091ab614 tools(selfgate): #464 middle-landing route (zoom, look-up, yaw at the owner's first pose)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:36:26 +02:00
Erik
9aced6e3c4 tools(selfgate): #464 look-up route (CameraRotateDown lowers the eye through the landing floor)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:33:43 +02:00
Erik
2018027322 tools(selfgate): #464 zoom-out route (held CameraZoomOut / CameraRotateUp / CameraMoveAway at the top stair pose)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:31:45 +02:00
Erik
36866ba663 docs(issues): #464 running reproduction (camera outside the stairwell at movement start); file #467 run-in-place at the corridor mouth
The held-forward route captured the owner's running symptom: the first frame
after the press has the chase camera above and outside the stairwell, the
next is clean. Same defect as the zoom-out. The runs also showed the
character running in place at one corridor spot for 5+ s (#467, movement,
outside the campaign).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:26:58 +02:00
Erik
590fbb66c3 tools(selfgate): #464 running-descent route (held MovementForward, ten frames at 150 ms)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:19:29 +02:00
Erik
9d52c2d3b3 docs(render): ledger — #464 stair-ladder reproduction: standing frames consistent, the running symptom is motion-bound
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:18:29 +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
20d844b06d docs: #466 owner-confirmed ours; ACViewer step dropped
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:11:17 +02:00
Erik
0bb9d1824a docs: file #466 — Ravenous Eater renders with stretched stripes and untextured patches (owner, /create 35121)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:08:54 +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
cddd3d236b docs: file #465 — post-campaign panel fill for retail's cathedral seam leak, with the regression guards and A/B acceptance
Owner decision 2026-09-03: an improvement on retail, deferred until G4
passes; retail mode off; registered when built.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 21:02:06 +02:00
Erik
455de7f24d docs(render): owner S3 double-check — all poses PASS except the zoomed-out cathedral stairwell (#464); matrix row added
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 20:40:58 +02:00
Erik
7746431133 docs(render): ledger — S3-closed validation self-gate: zero validation errors, four poses PASS provisional
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 20:20:36 +02:00
Erik
13c90f4480 docs(render): ledger — S4 row opened; S4-c1 dispatched from the S4 packet §6
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 20:18:58 +02:00
Erik
6385f44118 docs(render): ledger — S3 review fix round 1 landed, both lenses PASS; S3 CLOSED
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 20:18:03 +02:00
Erik
ea76a38035 docs(render): S3 review closeout — AD-23 retired, AD-17 says deleted not dormant, probe doc truthful, per-view EC loop guarded, conformance harness's per-cell EC limit recorded
The two lenses passed 6575cfcee and left these: AD-23 described the
ClipSlotCull the fix round deleted; AD-17's 'dormant, live for the flat
path' clause was false (the routing had no caller anywhere); the
ProbeClipRouteEnabled doc named a deleted producer; the per-view EC
print ran its loop with the flag off; the replay-side derivation still
prints one EC per flood cell while production prints one per live view,
which no fixture can tell apart today — recorded at the harness for S5.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 20:17:16 +02:00
Erik
89c4494d05 fix(render): S3 review round 1 — punch fans clipped by their own view, seal pin through the producer, dead per-cell clip machinery deleted, EC/OC transcript exact
F1 (BLOCKING, punch-fan view alignment). ClipFrameAssembler.
ReassembleOutsideViewFromWalk now keeps exactly ONE outside-view slice per
walk view, index-aligned with RetailFrameWalk.DrawBuilding's own
ActiveViewIndex (retail building_view = portal_view_num @0x0059f3bf): a
collapsed view (ClipPlaneSet.IsNothingVisible — retail polyClipFinish under
a degenerate view leaves <3 vertices, 0x59BDBC-0x59BDBF) now appends its
own ClipViewSlice.NothingVisible=true slot instead of being skipped, which
used to shift every later view's slice down by one. DrawWalkPunchFan draws
NOTHING for a NothingVisible slice and throws ArgumentOutOfRangeException
when activeViewIndex is out of range (fail-loud; never draws unclipped).
New tests: WalkOutsideViewReassemblyTests.
FirstViewCollapses_SecondSurvives_SlicesStayIndexAligned and
PunchLeaf_UsesIndexAlignedSlice_DrawsNothingForCollapsed_ThrowsOutOfRange.
MUTATION M1 (revert the append-nothing-on-skip fix, restoring the old
skip): both new tests fail with
  Assert.Equal() Failure: Values differ
  Expected: 2
  Actual:   1
MUTATION M2 (restore the old ": default" unclipped fallback in
DrawWalkPunchFan): the punch-leaf test fails with
  Assert.Equal() Failure: Values differ
  Expected: 0
  Actual:   1
(both restored; verified clean afterward).

F2 (major, exit-seal pin through the real producer + both overflow cases).
The exit-seal CPU/GPU equivalence pin moved from ClipFrameLayoutTests (which
drove ClipFrame.AppendSlot(ClipPlaneSet) via the zero-caller
ClipFrameAssembler.Assemble) to the new
tests/.../Walk/WalkFrameDriverClipSealTests.cs, which drives
WalkFrameDriver.BeginFrame + the real IWalkEventSink.OnInteriorFloodDrawTurn
hook — the SAME path RetailPViewPassExecutor.DrawExitPortalMask resolves
through via WalkFrameDriver.InteriorFloodViewClipPlanesAt. The new pin
compares WalkFrameDriver's captured planes EXACTLY (not just geometrically)
against ClipPlaneSet.From's independent CCW-normalized-perpendicular
computation, since AppendClipSlot's per-edge formula is bit-identical to
ClipPlaneSet's own. Two overflow cases added: a 9-vertex portal view exit-seals
to exactly the 4 conservative AABB planes containing every source vertex
(over-include, never under-include — AppendClipSlot's fallback for a view too
complex for the 8-plane budget); a 9-vertex OUTSIDE view (the punch-fan
sibling, WalkOutsideViewReassemblyTests.
NineVertexOutsideView_PunchSliceHasZeroPlanes_DrawsUnclipped_NotNothingVisible)
produces a zero-plane, NOT-NothingVisible slice — draws fully unclipped,
distinct from F1's "draw nothing" state.
MUTATION M1 (flip the winding selection, `ccw = area2 < 0f`):
  Assert.Equal() Failure: Values are not within 4 decimal places
  Expected: 0.9191 (rounded from 0.919144988)
  Actual:   0.8944 (rounded from 0.89442724)
MUTATION M2 (drop the normalize from the per-edge plane formula):
  Assert.Equal() Failure: Values are not within 4 decimal places
  Expected: 0.9191 (rounded from 0.919144988)
  Actual:   0.7 (rounded from 0.700000048)
MUTATION M3 (delete the >8-plane AABB overflow branch — the per-edge loop
then indexes a fixed 8-plane stackalloc with a 9-edge polygon):
  System.IndexOutOfRangeException : Index was outside the bounds of the array.
    at WalkFrameDriver.AppendClipSlot(...) line 1915
    at WalkFrameDriver.CaptureViews(...) -> CaptureCellViews -> CaptureCellViewRoute
    -> EmitFloodTurns -> IWalkEventSink.OnInteriorFloodDrawTurn
(all three restored; verified clean afterward).

F3 (minor/major). RetailPViewPassExecutor.cs's false bracket comment
(neither KEEP clip — exit seals nor punch fans — ever called Enable/
DisableClipDistances; the six DisableClipDistances() call sites all sat
around the UNCLIPPED particle/weather draws, whose bodies are no-ops on the
only backend) is rewritten to the truth; the six no-op calls and the
private DisableClipDistances() wrapper are deleted.
IWorldPassSurface.EnableClipDistances/DisableClipDistances stay on the
INTERFACE — WorldScenePassExecutor (the separate flat-world path) still
calls them.

F4a (EC transcript exactness). WalkFrameDriver.EmitFloodTurns now prints one
"EC" line per LIVE VIEW of the flood cell (retail's setup_view/DrawEnvCell
loop, PView::DrawCells @0x005a4ab1-0x005a4acc, fires once per live portal_view
slice, not once per cell) via the captured route's own SliceCount — read
directly off _lookInTurns[viewRouteIndex] rather than through
InteriorFloodViewSliceCountAt's flood-index indirection, because this same
loop also serves a building's LOOK-IN flood (WalkDrawStage.LookInStatic),
whose cells never populate InteriorFloodCells (the interior ROOT flood only)
— indexing through that accessor threw ArgumentOutOfRangeException on a real
look-in turn during verification, fixed before landing. The actual CellShell
DRAW event is unchanged (the frame stamp still dedupes it to one submission).

F4b (transcript exactness, trailing weather OC).
WalkTraceConformanceTests.Recorder now implements IWalkEventSink.
OnWeatherTurn (the interface's silent no-op default previously left the
replay side of Signature8 blind to the weather turn's own "OC" line), and
WalkTraceReplayContext.Signature8(WalkOracleFrame) no longer excludes the
trailing per-frame weather ObjectCellTurn — every ObjectCellTurn now reads
literally, on both sides. Implementing OnWeatherTurn alone left
Still_fixture_first_frame_reproduces_exactly(terrace-edge.walk) diverging
ONLY on the newly-un-excluded trailing OC (EXPECTED ...OC:f4180104|
OC:f418000b vs ACTUAL ...OC:f4180104 — a length-12 tail, nothing else
differs across a 16.6k-char signature) because
WalkTraceReplayContext.WeatherGateOpen had always defaulted to false (the
harness never needed to fire the walk's weather hook before). Per the
review round's own instruction not to weaken the pin, the harness itself is
fixed instead: WalkTraceReplayContext now implements ViewerCellId (= the
harness's own WalkFrame cameraCellId argument, matching production's
RetailPViewFrameInput.ViewerCellId invariant) and WeatherGateOpen
(retail's own SmartBox::is_player_outside gate, (cellId & 0xFFFF) < 0x100,
with no App-level render-toggle concept to AND against). MUTATION (delete
Recorder.OnWeatherTurn): Still_fixture_first_frame_reproduces_exactly
(terrace-edge.walk) fails with EXPECTED ending "...OC:f4180104|OC:f418000b"
vs ACTUAL ending "...OC:f4180104" (the trailing OC missing) — restored;
verified clean afterward.
Fixture-row status (InstalledDat lane, WalkTraceConformanceTests, 14 rows):
13 pass, 1 fails — Oh_doorway_still_first_frame_diff, the PRE-EXISTING
[Trait("Status","KnownFailure")] #458 row (a documented block-plane
precision boundary at token index 165, LC/SC content, upstream of any
EC/OC — unaffected by and unrelated to this round's OC change). Every OTHER
row, including every eight-kind (Signature8) row that now compares the
weather OC literally, passes exactly.

F5 (major, dead per-cell clip machinery). WbDrawDispatcher.SetClipRouting
(the only writer of the per-instance routing-active flag) had ZERO
production callers; EnvCellRenderer.SetClipRouting was called only with
null (WorldScenePassExecutor's BeginFrame/AbortFrame) — no path could ever
arm the per-cell clip-region table, on the walk path OR the flat path (the
S3 landing-hygiene AD-17 correction's "live for the flat path" clause is
itself corrected here: dormant in every path, deleted). Deleted:
WbDrawDispatcher's SetClipRouting/ClearClipRouting and their four backing
fields; EnvCellRenderer's SetClipRouting and its backing field (its
RenderModernMDIInternal write now unconditionally clears instanceClipSlot);
the ProbeClipRouteEnabled-gated per-frame [clip-route-disp] dispatch probe
and its three backing fields (the OTHER two ACDREAM_PROBE_CLIPROUTE
producers, [clip-route] and [clip-route-scis] in WorldRenderDiagnostics.cs,
are untouched — a different, still-live mechanism); ResolveEntitySlot,
IsIndoorCellId and the ClipSlotCull sentinel; the ACDREAM_CLIP_DEBUG probe
(RenderingDiagnostics.ClipDebugNoShellTrim) and its docs/launch-options.md
row, since the "clip shells" branch it toggled between is gone.
ResolveSlotForFrame is simplified to a parameterless
`(uint Slot, bool Culled) ResolveSlotForFrame() => (0u, false)` per the
review's own framing ("it becomes slot 0, never culled") rather than
deleted outright, since its callers (WbDrawDispatcher.cs and
WbDrawDispatcher.WalkClassify.cs) still want the same two-value shape.
tests/.../Wb/WbDrawDispatcherClipSlotTests.cs (12 tests, all exercising the
deleted routing arm via ResolveEntitySlot/the active ResolveSlotForFrame
branch) is replaced with one pin on the new parameterless behavior.
Shaders: mesh_modern.vert, mesh_atmospheric.vert, mesh_detail.vert,
particle.vert and particle_mesh.vert each lose their CellClip struct +
binding=2 ClipRegionBuf fetch, gl_ClipDistance write loop, and gl_PerVertex
redeclaration (portal_depth.vert's own, separate gl_PerVertex/gl_ClipDistance
pair — the KEEP mechanism, its planes handed through the TerrainClip UBO at
binding=2 in the UBO namespace — is untouched; verified it never read the
deleted SSBO). Recompiled via tools/compile-shaders.ps1 (glslc backend
detected; managed shaderc path ran); 24/24 pairs compiled. Re-pinned in
VulkanShaderManifestTests.RetailOracleSpirvSha256 (the only three of the
five edited shaders that carry a byte-exact retail-oracle pin):
  mesh_modern.vert.spv    = f9ed4ee7140ccd136130559dbea68545f733f6022f52b085b6df4bcb787223c6
  particle.vert.spv       = 95ce6ecf834930a92da5c5fe9aef513b38b5ba104704b98c1606af71fe17eaf3
  particle_mesh.vert.spv  = 043482b97c2ed036511692f89c75a0a6c298aba48cb519e5e3aff7fe7ba6371b
(mesh_atmospheric.vert.spv / mesh_detail.vert.spv changed too but carry no
retail-oracle pin, so no re-pin was needed for them.)
tests/.../ParticleBindlessInstanceTests.cs's
Assert.Contains("clipRegions[aClipSlot]", vertex) — a real breakage the
grep sweep caught — is deleted with a note; the surrounding aClipSlot
attribute-declaration assertion stays.
Vertex-layout residue kept THIS round, fed 0 by the CPU, unread by any
shader (S5's instance-buffer-layout revisit): instanceClipSlot[] (binding=3
SSBO) in mesh_modern.vert/mesh_atmospheric.vert/mesh_detail.vert; aClipSlot
(a per-vertex attribute) in particle.vert/particle_mesh.vert.
Grep sweep — "SetClipRouting|_clipRoutingActive|ClearClipRouting|
BeginScissor|NdcScissorRect|SetTerrainClip|BindTerrainClip|TerrainBytes|
ScissorNdcAabb|UseScissorFallback" over src/ and tests/: EMPTY (also swept
and rewrote several PRE-EXISTING prose mentions of BeginScissor/
ClearClipRouting in RetailPViewPassExecutor.cs, RetailPViewRenderer.cs,
WorldPassSurface.cs and RetailPViewPassExecutorTests.cs that predate this
commit's own work, purely to satisfy the literal sweep). "clipRegions|
instanceClipSlot|aClipSlot": every remaining match is the vertex-layout
residue named above, or a comment/assertion describing that same residue.

Deviations from a fully literal reading of F5 (recorded here since none of
them cross the mandatory automated gates, all of which pass):
- The C#-side ClipRegions SSBO publish/bind pipeline
  (RhiWorldPassSurface.PrepareClipFrame's publish, WorldFrameSections.
  ClipRegions, and ClipFrame's internal std430 byte-packing —
  RegionBytes/RegionBytesForTest/CellClipStrideBytes) is NOT deleted this
  round; it is left as documented dead residue (verified zero shader
  readers) rather than rewritten. The mandatory grep sweep targets the
  shader-source identifier `clipRegions` (lowercase), which is fully clean;
  the C# publish machinery sits behind ~8 files (ClipFrame.cs,
  WorldPassSurface.cs, WbDrawDispatcher.Rhi.cs, WorldPassScope.cs,
  GpuBindingModel.cs, EnvCellRenderer.Rhi.cs, ParticleRenderer.Rhi.cs,
  WbDrawDispatcher.OrderedStream.cs, plus the ClipFrameLayoutTests std430
  pins) and CellClipPlanesOffset/MaxPlanes are the SAME constants
  portal_depth.vert's KEEP mechanism uses for its own, unrelated UBO layout
  — a full rewrite carried materially higher regression risk than this
  round's mandatory scope justified. ClipFrame.cs and WorldPassSurface.cs
  now both name this residue explicitly in their doc comments for a future
  round to finish.
- SetClipRegionSsbo/_sharedClipRegionSsbo in WbDrawDispatcher.cs (a
  pre-existing, already fully dead GL-era write-only field/method with zero
  callers, unrelated to per-instance clip-slot routing) is left untouched —
  outside F5's named scope and outside the mandatory grep sweep.
- WalkTraceReplayContext.ViewerCellId/WeatherGateOpen (F4b, detailed above)
  is an addition beyond the literal §12 text, made to keep the InstalledDat
  lane at exactly the four established known failures without weakening
  the newly-un-excluded OC pin.

Gates: dotnet build tests/AcDream.App.Tests/AcDream.App.Tests.csproj -c
Release and dotnet build src/AcDream.App/AcDream.App.csproj -c Release both
0 warnings/0 errors; dotnet build AcDream.slnx -c Release 0 warnings/0
errors; hermetic lane 6815/6815 passed; InstalledDat lane 243 passed / 4
failed / 1 skipped (exactly the four known failures: two #383 layout tests,
TowerAscentReplayTests, Oh_doorway_still_first_frame_diff #458);
VulkanShaderDescriptorContractTests/VulkanShaderManifestTests/
RenderPackSpirvValidatorTests/SkyVertexLayoutTests 34/34 passed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 20:15:29 +02:00
Erik
6c7512de15 docs(render): ledger — E1 re-measured same-session: every stationary destination within 1.14x, chunk 3 back to CLOSED; file #463 (soak turn-sample artifact)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 19:09:03 +02:00
Erik
a614c8fd4e docs(render): ledger — S3 review both lenses FAIL; chunk 3 corrected to STOPPED-LANDED (perf gate missed in the stationary phase); fix round 1 dispatched
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 18:50:20 +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
e6f5a156b7 docs(render): ledger — hygiene chunk H landed; lens finding closed by the lead; S3 review next
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 18:26:11 +02:00
Erik
d0c9812122 docs(render): S3 hygiene lens closeout — the clip-distance doc names every writer; AppendSlot's doc drops the U.4 AABB promise
The hygiene lens's one blocking finding was a sentence the lead's own
§10.6 prescribed: 'only portal_depth.vert writes gl_ClipDistance in the
world pass'. Five mesh/particle vertex shaders still write it from the
per-cell clip-region table PrepareClipFrame publishes (dormant in the walk
path, which feeds slot 0; live for the flat path). The doc now says so.
ClipFrame.AppendSlot's doc still promised a U.4 AABB box that no longer
exists after H1. Comments only; no behavior change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 18:25:53 +02:00
Erik
99d9c6d564 chore(render): S3 landing hygiene — scissor-era dead state, stale comments, the #130 harness, a conjunction-proof weather-gate pin
Chunk H of Campaign OVERHAUL v2's S3 walk-ownership program
(docs/research/2026-09-01-overhaul/s3-walk-ownership-map.md §10.6), landing
the three post-hoc three-lens findings on S3 chunk 4 round 2. Pure dead-state
deletion, comment truth, one test deletion, one stronger pin — no admission,
order, or behavior change; no new flag or probe; no register row (AD-17's
correction is the lead's own, already on the campaign branch).

H1 — ClipPlaneSet.cs: deleted ScissorNdcAabb (no production reader — only
AppendOutsideSlice consumes ClipPlaneSet, and it reads only
IsNothingVisible/Count/PlaneArray) and renamed UseScissorFallback ->
IsPlaneOverflow with a doc stating the true consumer contract: Count==0
overflow means the region draws UNCLIPPED via the no-clip slot, never a
scissor box. Rewrote the file header's convexity-rule and Count==0-states
sections to the two states that exist (Empty / overflow) instead of three,
and simplified the private Scissor(...) AABB-computing helpers into a
parameterless Overflow() factory since nothing reads the AABB any more.
ClipPlaneSetTests.cs: renamed every UseScissorFallback reference, deleted
the AABB assertions (From_MultiplePolygons's four ScissorNdcAabb.X/Y/Z/W
checks, Empty_StaticProperty_DrawsNothing's degenerate-box check,
ScissorFallback_IsNotNothingVisible's bounds check) that pinned the deleted
consumer contract.

H2 — TerrainModernRenderer.cs: deleted Draw's clipPlanes/ndcClipAabb
parameters (grep: TerrainModernRenderer.Draw has exactly one production
caller, WorldScenePassExecutor.DrawFlatTerrain, and it never passed
either), which made CollectVisibleCells's own clipPlanes/ndcClipAabb/
viewProjection parameters and the IsAabbVisibleThroughClipRegion +
IsAabbOutsideHomogeneousPlane helper pair they fed entirely dead — deleted
along with the stale "Retail publishes landcell in_view from the clipped
landscape view" comment; CollectVisibleCells is frustum-only now, matching
DrawLandCells's own "retail never view-clips terrain" doc. Deleted the
terrainUploadCount computation at RetailPViewRenderer.cs (the
DrawInside/DrawLandscapeDynamicsPhase caller) and PrepareClipFrame's
GL-era reservation-count parameter end to end:
IWorldPassSurface.PrepareClipFrame(int), RhiWorldPassSurface's matching
body and its now-pointless "_ = terrainUploadCount" discard,
RetailPViewPassExecutor.PrepareClipFrame's pass-through, and
WorldScenePassExecutor.PrepareFlatWorldClip's hardcoded `1` argument —
PrepareClipFrame() takes nothing on every arm.
TerrainParticleCellVisibilityTests.cs: deleted the three tests that only
existed to pin the removed clip-plane/scissor mechanism
(RejectsCellsOutsideDoorwayClipPlanes, RejectsCellsOutsideDoorwayScissorAabb,
UnionsCellsFromEveryLandscapeSlice) and updated the two surviving frustum
tests to the new signature.

H3 — deleted tests/AcDream.App.Tests/Rendering/Issue130DoorwayStripTests.cs
outright. #130 was a background-color strip along a doorway's top edge from
a since-fixed under-inclusion in the CPU clip pipeline; its scissor half was
already retired at S3 chunk 4 fix round 2 (L7), and its surviving plane-gap
half exercised only PortalVisibilityBuilder.Build and
ClipFrameAssembler.Assemble, both confirmed zero-production-caller legacy
paths (grep) — the one production stage it actually touched,
ClipPlaneSet.From, is already pinned through the real producers
(BeginWalkFrame/ReassembleOutsideViewFromWalk) by the K6/L4 punch-fan
equivalence pin in ClipFrameLayoutTests, so nothing production-relevant lost
coverage.

H4 — comment truth pass:
- ClipFrameAssembler.cs: rewrote the file-header "renderer uses scissor for
  passes that need that fallback" line and the TerrainClipMode summary's
  "that path never produces Scissor" clause. Deleted the TerrainClipMode
  enum's Scissor member — grepped every reader first
  (WorldRenderDiagnostics.cs, WorldSceneDiagnosticsController.cs,
  WorldSceneRendererTests.cs all only pass the value through to a string
  Append or a mock parameter; WorldSceneRenderer.cs, the only writer, sets
  only Planes (default) or Skip, never Scissor) — kept Planes/Skip for the
  flat path and corrected Skip's stale doc ("No outside_view slice is
  visible; skip landscape indoors", a leftover from the pre-round-2 walk
  meaning) to what the flat path's own writer actually means now ("the
  PView walk ran instead of the flat-world path this frame"). Corrected
  ClipViewSlice's doc: the AABB is retained for WorldRenderDiagnostics only,
  not for a scissor consumer.
- WorldPassSurface.cs: "Four concerns... the clip-frame publication, the
  doorway scissor, gl_ClipDistance enablement, and retail's interior depth
  clear" -> three concerns (the doorway scissor was retired at L2), with a
  pointer to ClearInteriorDepth's own truthful doc. EnableClipDistances'
  "all three world vertex shaders already write 1.0" -> only
  portal_depth.vert writes gl_ClipDistance now (grep: sky.vert and
  terrain_modern.vert/terrain_atmospheric.vert no longer declare it at all
  — L3 deleted the block outright; portal_depth.vert still writes 1.0 past
  its active clip count). RhiWorldPassSurface's class doc dropped "the
  scissor is dynamic state on the borrowed encoder" (no producer left).
- RetailPViewPassExecutorTests.cs: DrawLandscapeDynamicsPhase_CallsDraw
  WeatherOnceExactlyOnce's doc corrected "unconditionally" (false since K2)
  to "conditional on WalkFrameDriver.WeatherTurnFired, see the L1 pin".
  Added the switch-table scope note (matching L8's own note on
  DrawWalkSky_RenderSkyCallSiteHasNoEnclosingBackwardBranch) to the K1 pin's
  doc (DrawLandscapeDynamicsPhase_DrawWeatherOnceCallSiteHasNoEnclosing
  BackwardBranch).
- RetailPViewRenderer.cs: the DrawWeatherOnce citation cited the callee
  address (GameSky::Draw(sky,1) @0x00506ff0) where §10.1 cites the call
  site (@0x00506396) — corrected to cite the call site with the callee
  address alongside it.

H5 — MUTATION CHECK (mandatory, run against the production gate at
RetailPViewRenderer.DrawLandscapeDynamicsPhase):
  Added DrawLandscapeDynamicsPhase_ExactlyOneBranchGuardsDrawWeatherOnce,
  which widens the L1 pin's window to start at the
  DrawUnattachedSceneParticles call (the last call before the whole gate)
  and asserts EXACTLY ONE branch total in that window — the L1 pin's own
  window (getter-call to draw-call) misses a conjoined gate's extra,
  earlier condition because that condition's own brfalse lands BEFORE the
  getter call's offset.
  - Mutation 1 (the conjoined gate this pin exists to reject): changed the
    gate to `if (clipAssembly.OutsideViewSlices.Length != 0 &&
    walkDriver.WeatherTurnFired)`, built, ran the new pin — FAILED with:
      Assert.Single() Failure: The collection contained 2 matching items
      Expected:      (predicate expression)
      Collection:    [CompiledBranch { Offset = 7, OpCode = brfalse.s, TargetOffset = 17 }, CompiledBranch { Offset = 24, OpCode = brfalse.s, TargetOffset = 42 }, CompiledBranch { Offset = 33, OpCode = brfalse.s, TargetOffset = 42 }]
      Match indices: 1, 2
    (offset 7 = the DrawUnattachedSceneParticles block's own guard, correctly
    excluded since it precedes that call's offset; offsets 24 and 33 are the
    conjoined gate's two brfalse's, both inside the widened window — exactly
    the failure this pin exists to catch). Restored the single-flag gate;
    rebuilt; the new pin and all 13 sibling tests in
    RetailPViewPassExecutorTests pass again (14/14).
  - Mutation M1 (the existing round-2 regression: restore the pre-fix gate
    `if (clipAssembly.OutsideViewSlices.Length != 0)`), built, ran the full
    suite — the L1 pin
    (DrawLandscapeDynamicsPhase_GatesDrawWeatherOnceOnWalkDriverWeatherTurnFired)
    still FAILS, as required, with:
      Assert.Equal() Failure: Values differ
      Expected: typeof(AcDream.App.Rendering.Walk.WalkFrameDriver)
      Actual:   typeof(AcDream.App.Rendering.ClipFrameAssembly)
    (the new H5 pin does NOT fail under M1 — a single-flag gate still
    produces exactly one branch in the widened window, which is correct:
    catching "wrong condition source" is L1's job, catching "an extra
    conjoined condition" is H5's). Restored the correct gate; rebuilt;
    14/14 green again.

H6 grep sweep (extends §10.5's L6 sweep per the plan):
  grep -rnE "ScissorNdcAabb|UseScissorFallback|TerrainClipMode\.Scissor|ndcClipAabb|terrainUploadCount" --include=*.cs --include=*.vert --include=*.frag src tests
  -> empty (every mention, including in this commit's own explanatory
  comments, was rephrased to avoid the literal deleted identifiers).
  The base L6 sweep (SetTerrainClip|BeginDoorwayScissor|BindTerrainClip|
  TerrainBytes|active scissor|TerrainClipMode\.Scissor|NdcScissorRect) is
  also still empty.

Gates: dotnet build tests/AcDream.App.Tests -c Release -> 0 warnings / 0
errors. Hermetic lane -> 6825/6825 passed, 0 failed. InstalledDat lane
(ACDREAM_DAT_DIR set) -> 243 passed / 4 known failures (2x #383 layout
tests, TowerAscentReplayTests's TowerAscent KnownFailure,
WalkTraceConformanceTests.Oh_doorway_still_first_frame_diff #458
KnownFailure) / 1 skipped / 248 total — one fewer test than before H3, as
expected from Issue130DoorwayStripTests's deletion.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 18:24:37 +02:00
Erik
b3ef4027a2 docs(render): ledger — post-hoc lenses all PASS on chunk 4 round 2; hygiene chunk H dispatched
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:51:01 +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
cf39dab811 docs: #459 resolved with validation proof; ledger notes the fix and the S4 draft
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:13:15 +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
e33fd24724 fix(render): #459 — enable shaderDemoteToHelperInvocation, the feature the SPIR-V 1.6 fragment modules declare
The shader compiler targets Vulkan 1.3 / SPIR-V 1.6, where glslang lowers a
fragment discard to OpDemoteToHelperInvocation; five committed modules
(sky, mesh_detail, mesh_atmospheric, both directional-shadow cutouts)
declare the capability, and vkCreateShaderModule reported
VUID-VkShaderModuleCreateInfo-pCode-08740 twice per launch under the
Khronos validation layer because the device never enabled the feature.
The feature is core 1.3 (the device gate already requires 1.3), so it is
read through the existing Vulkan13Features chain, enabled at device
creation next to dynamicRendering/synchronization2/maintenance4, and
gated as required in VulkanCapabilityRecord with its own failure text.
Found by the first validation-layer self-gate of Campaign OVERHAUL v2
(S3 chunk 4 round 2); no register row, no behavior change on a
conformant driver.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:10:00 +02:00
Erik
c64ecbde8b docs(render): ledger — G3 self-gate part C: Nanto three headings PASS provisional; 20/20 frames; four defects filed
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:08:29 +02:00
Erik
7553ff3c5e docs: file #461 (motion update after logout crashes on the retired movement controller) and #462 (intermittent interior login reveal stall)
Both found by the G3 self-gate part C at 2fbfdf18a; evidence paths and the
sequence lines are in the entries.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:06:09 +02:00
Erik
cd1e14de3c docs(render): ledger — G3 self-gate part B: the four retail capture poses PASS provisional
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 17:05:11 +02:00
Erik
2fbfdf18a8 docs: file #460 — windowless shutdown hang after an aborted automation script at the Nanto pose
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 16:41:56 +02:00
Erik
7fa83c7397 docs(render): ledger — G3 self-gate part A: 12 of 13 poses PASS provisional, Nanto incomplete; part-C route
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 16:41:30 +02:00
Erik
1ad9f4766f tools(selfgate): G3 route part B — the four retail capture poses
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 16:21:21 +02:00
Erik
5b43d8d559 docs(render): chunk 4 landed — ledger evidence, AD-17 rewritten, AP-117 narrowed
Rounds ff607a1e0 + 7df0b94c9 delete the union-AABB scissor fallback, the
sky's doorway scissor bracket and the TerrainClip UBO; AD-17 now describes
the two surviving portal-polygon clips and their overflow behavior, and
AP-117 records that the walk's ported landcell_check feeds the production
particle in-view state. The three-lens re-review is owed post-hoc (API
overload); the lead's item-by-item verification is in the ledger.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 16:20:03 +02:00
Erik
7df0b94c9f fix(render): S3 chunk 4 round 2 — draw-gate condition pinned, scissor and terrain-clip stacks deleted, one outside-view slice constructor
Round-1 three-lens FAIL at d60ca4ea0 found: the K2 fix was right in
production but nothing pinned the draw side (restoring the pre-fix gate
left every lane green); a stale "still ends an active scissor" comment
asserted a mechanism the same round had already deleted; the sky.vert
comment claimed retail clips the sky when it draws unclipped; the K6
pin ran through ClipFrameAssembler.Assemble, which has zero production
callers, so it proved nothing about the producer that actually runs.
This round closes L1-L9.

L1 (BLOCKING) — draw-side weather-gate pin. Added
RetailPViewPassExecutorTests.DrawLandscapeDynamicsPhase_GatesDrawWeatherOnceOnWalkDriverWeatherTurnFired:
reads DrawLandscapeDynamicsPhase's compiled call graph and asserts (a)
the call immediately before DrawWeatherOnce is
WalkFrameDriver.get_WeatherTurnFired and (b) exactly one
brfalse/brfalse.s branch sits between that call and the draw, jumping
forward past it. Three mutations, each shown failing:

  M1 (restore `if (clipAssembly.OutsideViewSlices.Length != 0)`):
    Assert.Equal() Failure: Values differ
    Expected: typeof(AcDream.App.Rendering.Walk.WalkFrameDriver)
    Actual:   typeof(AcDream.App.Rendering.ClipFrameAssembly)

  M2 (drop the gate, unconditional call):
    Assert.Equal() Failure: Values differ
    Expected: typeof(AcDream.App.Rendering.Walk.WalkFrameDriver)
    Actual:   typeof(AcDream.App.Rendering.RetailPViewPassExecutor)

  M3 (invert to `if (!walkDriver.WeatherTurnFired)`):
    Assert.Single() Failure: The collection did not contain any matching items
    Expected:   (predicate expression)
    Collection: [CompiledBranch { Offset = 7, OpCode = brfalse.s, TargetOffset = 17 }, CompiledBranch { Offset = 24, OpCode = brtrue.s, TargetOffset = 33 }]

Corrected WalkFrameDriverTranscriptTests.cs's doc comment (the
Collect_WeatherTurnFiredMatchesThePrintedOcLineExactly block): it pins
the print half and the flag only, and now names the real draw-side pin
instead of falsely claiming to double as one.

L2 (MAJOR) — scissor stack deleted, K4 comment corrected. Deleted
IWorldPassSurface.BeginScissor/EndScissor and their RhiWorldPassSurface
bodies, the scissor call inside ClearInteriorDepth, NdcScissorRect.cs +
NdcScissorRectTests.cs (BeginScissor had zero remaining callers, and
RhiWorldPassSurface.BeginScissor was NdcScissorRect.ToPixels' only
production caller). This left RhiWorldPassSurface's 4th constructor
parameter (IRetailPViewFramebufferSource) and RetailPViewPassExecutor.cs's
RetailPViewFramebufferSize/IRetailPViewFramebufferSource/
SilkRetailPViewFramebufferSource types entirely dead (framebuffer size
was needed only for the scissor's NDC-to-pixel conversion) — removed
them and their one call site in FrameRootComposition.cs. Rewrote
RetailPViewPassExecutor.cs's K4 comment: it no longer asserts a live
scissor mechanism; it states that VulkanGpuPassEncoder's constructor
sets the full-attachment scissor once, at pass begin
(VulkanGpuPassEncoder.cs:87), and nothing narrows it after that. KEPT
per the round-1 verdict: ScissorFallbacks, OutsidePlaneCount,
OutsideViewNdcAabb, HasOutsideView, OutdoorVisible, OutdoorSlot,
ClipViewSlice.NdcAabb (the >8-edge zero-plane slice case the punch fans
still consume) and the VulkanViewportMapping.ScissorToVulkan pass-begin
path (IGpuPassEncoder.SetScissor stays). Also deleted
ClipFrameAssembly.TerrainMode/TerrainScissorNdcAabb and their writers
in ClipFrameAssembler.cs (both Assemble and ReassembleOutsideViewFromWalk);
OutsidePlaneCount's formula reduces to `outsideHasScissorFallback ? 0 :
outsideMaxPlaneCount` without needing the deleted TerrainClipMode
comparison (a scissor-fallback slice can only exist when outdoorVisible
is already true, so the three original cases collapse identically).
Deleted the two "terrain=" / "outMode=" diagnostic reads in
WorldRenderDiagnostics.cs (:345, :409) and the now-vestigial
EmitClipRouteProbe "ubo: n=..." segment that read ClipFrame's deleted
terrain bytes.

DEVIATION from L2's literal text: kept the TerrainClipMode enum type
itself — WorldSceneRenderer.cs's flat-world safety path (explicitly
"out of this chunk's scope" per K4's own round-1 comment) still uses it
for an unrelated "did the flat terrain draw" diagnostic flag, with its
own WorldSceneDiagnosticsController/WorldRenderDiagnostics/test
consumers. Deleting the type would require rewriting files outside
every round's declared file list. Reworded its doc comment to state
this plainly.

L3 (MAJOR, completes K3) — dead TerrainClip UBO deleted from the sky
and terrain shaders. Deleted the block, both gl_ClipDistance loops, and
the gl_PerVertex redeclaration (nothing else needs it) from sky.vert,
terrain_modern.vert, terrain_atmospheric.vert. Recompiled via
tools/compile-shaders.ps1 (glslc via the Vulkan SDK, managed shaderc
fallback also runs) — 24/24 pairs compiled; only sky.vert.spv,
terrain_atmospheric.vert.spv and terrain_modern.vert.spv changed.
Re-pinned VulkanShaderManifestTests.cs's frozen retail-oracle hashes
for sky.vert.spv (7d67a9e3624d198b370d402b5c12e4ce925bf9b8e646ef5123636a86d5985ab5)
and terrain_modern.vert.spv (8a73d89ef0e51e550327b9ff8c24857e309103b1d491030cf0d4d8594b45068c)
with dated comments, matching the existing re-pin convention.

Deleted WorldFrameSectionBinding.BindTerrainClip and
WorldFrameSections.TerrainClip (+ its Reset) with its two callers
(SkyRenderer.Rhi.cs:258, TerrainModernRenderer.Rhi.cs:259). DEVIATION
from L3's literal text: kept the shared Zeroed(...) helper in
WorldPassScope.cs — it is also called by BindSceneLighting and
BindClipRegions, both of which stay; deleting it would have broken
those two live bindings. Deleted IWorldPassSurface.BindTerrainClip
(no-op interface method + RhiWorldPassSurface body) and
WorldScenePassExecutor.cs's two calls to it (:121, :235).

Deleted ClipFrame's _terrainBytes field, TerrainBytes/TerrainBytesForTest
properties, Reset's Array.Clear(_terrainBytes), and the stale
header/K3 comment paragraphs. DEVIATION from L3's literal text: kept
ClipFrame.TerrainUboBytes and ClipFrame.TerrainClipUboBinding —
PortalDepthMaskRenderer.Rhi.cs (:140, :187) is a live production
consumer of both constants for the KEPT exit-seal/punch-fan clip block,
which was never in scope for deletion (portal_depth.vert's own
TerrainClip UBO declaration is the KEEP block, untouched). Reworded
both constants' doc comments (ClipFrame.cs, VulkanPipelineLayouts.cs's
UniformTerrainClip) to say only the portal-depth clip block uses
binding 2 now, and corrected the two GpuBindingModel.cs comments that
explained why terrain-tiling/sky-params bindings are 3/4 by naming "the
terrain clip block". Updated VulkanShaderDescriptorContractTests.cs's
TerrainVertexShaderDeclaresItsClipBlockInTheUniformSet (renamed
TerrainVertexShaderDeclaresOnlySceneLightingInTheUniformSet):
terrain_modern.vert's uniform set is now {SceneLighting} only. Deleted
ClipFrameLayoutTests.NoClip_TerrainBytes_Count0_AllZeros and its K3
comment; corrected the class doc comment and LayoutConstants_MatchShaderStruct's
"terrain UBO"/binding-contract comments to describe the portal-depth
consumer instead.

REQUIRED L3 fact (declared-but-never-bound dynamic uniform binding):
VulkanFrameBindings's constructor seeds EVERY declared uniform binding
(0..UniformBindingCount-1, including binding 2) with the shared dummy
buffer's range before any renderer runs (VulkanFrameBindings.cs:128-130,
`_arena.SeedUniform(binding, dummy.Handle.Handle, dummyUniformRange)`
in a loop over every binding) — "Every binding is always bound, whether
a renderer uses it or not... unused ones point at a shared dummy range"
(VulkanFrameBindings.cs:27-31). So after this round, when the sky or
terrain pipeline draws, set 1's shared descriptor layout still declares
binding 2 (portal_depth.vert's own declaration keeps
IsDeclaredUniformBinding(2) true), and its descriptor still points at a
valid (dummy) range from that seed — vkCmdBindDescriptorSets stays
legal even though neither shader statically uses binding 2 any more.
No SPIR-V-side change was needed to keep this legal.

L4 (MAJOR) — one outside-view slice constructor. Extracted
ClipFrameAssembler.AppendOutsideSlice (frame, ViewPolygon,
outsideSlicesList, ref maxPlaneCount, ref hasScissorFallback, ref
scissorFallbacks) — the exact ClipPlaneSet.From/AppendSlot/
ClipViewSlice-construction body — and call it from both Assemble's
outside_view loop and ReassembleOutsideViewFromWalk's outside_view
loop. Rewrote ClipFrameLayoutTests's K6 pin
(ClipViewSlicePlanes_PunchFanPath_EqualsCpuViewPolygonEdgePlanes_ForASyntheticView):
builds a synthetic WalkPortalView from pixel-space points (the
WalkCopyViewTests pattern) via a trivial IWalkRayCaster, runs
BeginWalkFrame(frame, outdoorRoot: false) then
ReassembleOutsideViewFromWalk(assembly, walkView, 640, 480), and reads
assembly.OutsideViewSlices[0].Planes — the exact production pair
RetailPViewPassExecutor.cs's BeginWalkFrame call and
RetailPViewRenderer.cs's ReassembleOutsideViewFromWalk call make.
Mutation (perturbed planes[0].W inside the shared helper, right after
`planes = cps.PlaneArray;`):

  edge 0 midpoint (-0.3,0.10000001) should lie ~on its OWN GPU plane; the closest plane was only 0.5251073 away

The pin's own source contains no `Assemble(` call — grep-checked by
extracting the method body and searching it for the literal text; no
match.

L5 — shader comments corrected. sky.vert/terrain_modern.vert/
terrain_atmospheric.vert now state retail draws the sky once
(LScape::draw @0x00506330 -> GameSky::Draw(sky,0) @0x0050633c, before
draw_check_blocks) and the landscape is view-culled per cell, never
GPU-clipped (RenderDeviceD3D::DrawBlock @0x005a17c0). The "Phase W
Stage 4"/"U.3 default" clip narratives are deleted along with the
blocks they described.

L6 — grep sweep. `grep -rn "<token>" src tests docs/architecture`
returns nothing for SetTerrainClip, BeginDoorwayScissor,
BindTerrainClip, TerrainBytes, "active scissor", and NdcScissorRect —
confirmed after this commit (docs/plans and docs/research keep the
historical record, untouched). TerrainClipMode is the one deliberate
exception (see the L2 deviation note above); every one of its 9
remaining hits is a live, non-stale reference (the enum declaration,
WorldSceneRenderer's flat-path local, or their diagnostic/test
plumbing), not a stale mention of a deleted mechanism.

L7 — Issue130DoorwayStripTests. Deleted AnySliceAdmitsScissor,
worstScissorGapPx and its PIN 1 assertion, the header's scissor
sentences, and the scissorGap half of MeasureTopEdgeGap (dropped the
fbW parameter it alone needed). Rewrote the header: the scissor
mechanism is retired (the sky and landscape draw unclipped; aperture
exactness comes from the depth clear, the exit seals and the interior
repaint). The remaining plane-gap half (the canary PIN,
`worstPlaneGapPx <= 1.2f`) still pins something production reads:
AnySliceAdmitsPlanes walks slice.Planes from the SAME ProjectToClip ->
ClipToRegion -> ClipPlaneSet.From pipeline
RetailPViewPassExecutor.DrawWalkPunchFan reads through
clipAssembly.OutsideViewSlices[activeViewIndex].Planes — so the test
was kept, not deleted.

L8 — DrawWalkSky loop-shape pin. Added
DrawWalkSky_RenderSkyCallSiteHasNoEnclosingBackwardBranch (same
backward-branch-span shape as K1's DrawWeatherOnce pin), plus a note in
both pins that CompiledCallGraph.ReadBranches does not decode a
compiled switch jump table, but no C# loop construct compiles to one.
Mutation (wrapped the RenderSky call in `for (int i = 0; i < 2; i++)`):

  Assert.DoesNotContain() Failure: Filter matched in collection
  Collection: [..., CompiledBranch { Offset = 20, OpCode = brtrue.s, TargetOffset = 25 }, CompiledBranch { Offset = 23, OpCode = br.s, TargetOffset = 66 }, CompiledBranch { Offset = 72, OpCode = blt.s, TargetOffset = 13 }, CompiledBranch { Offset = 80, OpCode = brfalse.s, TargetOffset = 116 }, CompiledBranch { Offset = 88, OpCode = brfalse.s, TargetOffset = 116 }]

(the Offset=72 -> TargetOffset=13 entry is the injected loop's backward
branch spanning the call).

L9 — this message.

Gates: dotnet build 0 warnings / 0 errors. Hermetic filter
(Lane!=InstalledDat&...&Status!=KnownFailure): 6827 passed, 0 failed.
InstalledDat lane against a real DAT directory: 244 passed, 4 failed —
exactly the four known failures (LayoutImporterMediaBearingChildSweepTests
+ LayoutImporterInvisibleSweepTests, both #383; TowerAscentReplayTests,
KnownFailure; WalkTraceConformanceTests.Oh_doorway_still_first_frame_diff,
#458 KnownFailure). No register row added (every deletion here removes
an acdream-only rule; the KEEP items already had their equivalence
pins from round 1). No new flag/probe.

OWED: the lead's ACDREAM_DEVTOOLS=1 four-pose visual self-gate against
the running client is not run by this agent — CLAUDE.md and this
task's own instructions forbid launching the graphical client from
here; that visual/validation-layer pass remains the user's to run
before this round is accepted.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 16:18:27 +02:00
Erik
ff607a1e04 fix(render): S3 chunk 4 round 1 — loop-shape weather pin, one weather gate, dead terrain-clip stack deleted, sky drawn once
Campaign OVERHAUL S3 chunk 4 fix round 1 (docs/research/2026-09-01-overhaul/s3-walk-ownership-map.md
§10.4), on top of 6ba4b0b87. K1, K2, K3, K4, K6, K7, K8 (K5 was the lead's own plan-doc note, already
done).

K1 (blocking) — the Assert.Single pin over DrawLandscapeDynamicsPhase's DrawWeatherOnce call site
stayed green even wrapped in a foreach (it counts distinct call-site offsets, not loop shape). Added
a real LOOP-SHAPE pin reusing CompiledCallGraph.ReadBranches: asserts no backward branch (target
offset < its own offset) spans the DrawWeatherOnce call's IL offset — the shape every C#
for/foreach/while loop compiles to.

K2 (minor) — the Collect-time "OC" print fired on ctx.WeatherGateOpen alone while the Replay-time
draw independently re-derived clipAssembly.OutsideViewSlices.Length > 0, which could diverge on an
interior root whose landscape turn ran but whose reassembled outside-view slices ended up empty.
WalkFrameDriver now owns one WeatherTurnFired flag, set unconditionally inside OnWeatherTurn (so it
tracks "did the print's own gate hold" regardless of the transcript flag) and reset every
BeginFrame/AbortFrame; RetailPViewRenderer.DrawLandscapeDynamicsPhase gates DrawWeatherOnce on it
instead of re-deriving its own condition.

K3 (minor) — ClipFrame.SetTerrainClip (the terrain OutsideView writer) had no remaining caller after
chunk 4's original round and K4 below; deleted along with IWorldPassSurface.SetTerrainClip,
RhiWorldPassSurface.SetTerrainClip, the now-orphaned PublishTerrainClip helper, and PrepareClipFrame's
terrain-clip publish call. The terrain/sky shaders still declare the TerrainClip UBO (verified:
terrain_modern.vert, terrain_atmospheric.vert, sky.vert all read uTerrainClipCount/uTerrainClipPlanes),
so the section binding itself (WorldFrameSectionBinding.BindTerrainClip) stays — its existing
zeroed-ring fallback (for when nothing published the section) now binds that same all-zero disabled
block on every frame, identical bytes to the old permanent NoClip/Reset default.

K4 (major) — DrawWalkSky still looped the OUTDOOR case once per active landscape view under a doorway
scissor + BindTerrainClip + EnableClipDistances (the INTERIOR case already drew once unclipped, FW4
slice 6). Retail draws GameSky::Draw(sky,0) ONCE, unconditionally, before LScape::draw's block loop,
for both root kinds. Collapsed DrawWalkSky to one unconditional, unclipped draw; deleted
BeginDoorwayScissor and the RetailPViewPassExecutor.EnableClipDistances wrapper (both lost their only
caller). _surface.BeginScissor/EndScissor and IWorldPassSurface.EnableClipDistances stay:
RhiWorldPassSurface.ClearInteriorDepth still ends an active scissor, and WorldScenePassExecutor (the
separate flat-world path) still calls EnableClipDistances directly.

K6 (minor) — the punch-fan CPU/GPU equivalence pin hand-built a ClipViewSlice from ClipPlaneSet.From's
raw output, which could pass even if ClipFrameAssembler.Assemble's own packing/array-construction
diverged from that output. Rewrote it to build a real PortalVisibilityFrame and run it through
ClipFrameAssembler.Assemble, reading the planes back through assembly.OutsideViewSlices[0].Planes —
the exact outsideSlicesList.Add(new ClipViewSlice(slot, AabbOf(poly), planes)) path
ReassembleOutsideViewFromWalk (the walk's real interior-root producer) shares.

K7 (note) — restored the "a real look-in slice never reuses the reserved no-clip slot 0" assertion
the deleted VisibleClipSlotsInLookInTurn used to prove, via a new internal test-only accessor
(WalkFrameDriver.LookInSliceClipSlotAt) reading the same _lookInSlices storage
InteriorFloodViewClipPlanesAt resolves through _clipFrame.GetSlotPlanes(slice.ClipSlot).

K8 (note) — documented in DrawWeatherOnce's own comment that the weather mesh drawing before the rain
particles is this method's own call-order choice; retail's single GameSky::Draw(sky,1) imposes no
order between acdream's two substitutes.

Every new/changed pin's mutation was hand-verified this session (temporarily applied, ran the
specific test, confirmed the exact failing assertion, then reverted — see the parent task's structured
report for the four failing-assertion texts).

No register row added or removed — every change here deletes an acdream-only rule or repairs a pin;
none introduces a new deviation.

Full solution build: 0 warnings/0 errors. App hermetic (Lane!=InstalledDat/PreparedPackage/Live/
Manual/Timing/Windows/Linux/SystemFont & Purpose!=Diagnostic & Status!=KnownFailure): 6831/6831.
InstalledDat: 244 pass/1 skip/4 known — identical to 6ba4b0b87's own baseline (2x #383 layout tests,
TowerAscent, and the pre-existing #458 WalkLandscape.CheckBlocks block-visibility divergence,
unrelated to and untouched by this round).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 16:18:27 +02:00
Erik
08e864ea40 docs(render): ledger — round 2 vs a same-time tip baseline: only sky drift and actors differ
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 15:43:35 +02:00
Erik
10873c55ce docs(render): ledger — chunk 4 round 2 self-gate PASS provisional; validation finds only pre-existing #459
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 15:42:23 +02:00
Erik
e18b9d0939 docs: file #459 — five fragment shaders declare DemoteToHelperInvocation without the device feature
Found by the first validation-layer self-gate (S3 chunk 4 round 2). The
capability set is identical on the tip and the round-2 worktree, so it
predates chunk 4; the fix (enable the 1.3 feature or pin the compiler's
target to SPIR-V 1.5) gets its own commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 15:42:02 +02:00
Erik
1082c68535 docs(render): ledger — #458 resolved as an edge-plane precision boundary (AD-118)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 14:43:46 +02:00