diff --git a/docs/research/2026-09-01-overhaul/s4-depth-alpha-packet.md b/docs/research/2026-09-01-overhaul/s4-depth-alpha-packet.md index 4ff6d506..948fa836 100644 --- a/docs/research/2026-09-01-overhaul/s4-depth-alpha-packet.md +++ b/docs/research/2026-09-01-overhaul/s4-depth-alpha-packet.md @@ -124,6 +124,80 @@ already removed from `portal_depth.vert` (verify nothing else carries them). Register: AP-34 retired; any row describing the distance sort retired; the seal/punch color-state row from S4-c1 kept or retired per its decision. +## 6. S4-c1 contract (lead draft, 2026-09-03 evening — dispatch after the S3 review closes; re-locate every owner) + +**Retail facts (verified in the decomp / the Ghidra arbitration table of +`oh1-depth-lifecycle.md`):** +- R1 far-Z punch: `DrawPortalPolyInternal` @0x0059bc90's tail writes the + punch depth from the constant with bits `0x3F7FFFEF`. +- R2 the ±12 reject: `0x59BCD6–0x59BD28` then `0x59BD40–0x59BD66` compare + each SOURCE vertex's LOCAL `x`/`y` against ±12 BEFORE `xformStart`; any hit + returns — the whole polygon is dropped (degenerate-input guard, S3 packet + §2). Then `0x59BD70–0x59BD74`: only false/true-depth SEALS increment the + counter (modulo 65,536); far punches never do (already ported, S3 §8.2 B2). + `0x59BDBC–0x59BDBF`: fewer than 3 CLIPPED vertices submit no fan (after + the possible increment). +- R3 portal-depth state: depth test ALWAYS, depth write on, no cull; color + writes ENABLED with `SRCALPHA/INVSRCALPHA` and source alpha 0 (a no-op + blend); no stencil. + +**Current acdream (at `d0c981212`):** +- `portal_depth.vert:53` `clipPos.z = clipPos.w * 0.99999988;` — the decimal + literal is 1 − 2⁻²³ = bits `0x3F7FFFFE`; retail's constant `0x3F7FFFEF` is + 0.99999898672… — FIFTEEN ULPs nearer the camera (lead's bit check, + 2026-09-03: `SingleToInt32Bits(0.99999988f) == 0x3F7FFFFE`). The depth + spec's "**wrong constant**" row is right. C0 below fixes it; T1 pins it. +- No ±12 reject anywhere on the punch/seal producers + (`WalkFrameDriver.OnPunchGeometry` @ the walk's punch event; + `RetailPViewRenderer.DrawWalkExitPortalMasks`); the clipped-count <3 gate + exists as the `vertices.Length < 3` early return in `DrawWalkPunchFan`. +- `PortalDepthMaskRenderer.Rhi.cs`: `GpuCompareOp.Always`, depth write on, + `Blend = GpuBlendMode.None`, `ColorWrite = false` — pixel-identical to R3 + (a zero-alpha blend changes no color), state-different. + +**Behavior change (small):** +- C0 the far-punch constant: `portal_depth.vert` takes retail's exact bits + (`uintBitsToFloat(0x3F7FFFEFu)`, comment citing `DrawPortalPolyInternal` + @0x0059bc90's tail), the SPIR-V is recompiled and `VulkanShaderManifestTests` + re-pinned. Visible effect: the far punch lands 15 ULPs nearer than + before — at 24-bit depth that is the difference between "at the far plane" + and "one step in front of it", which is exactly the retail relationship the + seals (true depth) and the interior repaint rely on; any capture pose whose + `PM` lines show `mode=1` punches is the regression check. +- C1 the ±12 local-input reject ported at the producer that owns the LOCAL + polygon (the walk's punch-event producer for punch fans; the exit-seal + enumeration for seals — both read the dat portal polygon in cell-local + space before the world transform), as an exact equality test on x and y + against +12/−12 on every source vertex; a hit drops the whole polygon + BEFORE any counter increment (matches R2's order: reject → transform → + clip → count). If the Ghidra table shows the bound can never be hit by an + authored portal polygon, the port still lands (it is retail's code) with + the test proving the reject fires on a synthetic ±12 vertex. +- C2 no state change for R3: add register row "portal-depth color path: + ColorWrite=false instead of retail's zero-alpha SRCALPHA/INVSRCALPHA blend + — identical output, different pipeline state" (an AD row, with the + citation), unless the reviewer prefers the exact blend attachment; the + lead's default is the row (zero-risk, honest). +- C3 the truth-table theory and the two-frame latch test (§2 above). + +**Tests:** T1 reads `portal_depth.vert`'s punch line and asserts the literal +it carries has bits `0x3F7FFFEF` (a source pin — it FAILS at `d0c981212`, +where the line reads `0.99999988` = `0x3F7FFFFE`; MUTATION: any other +literal); T2 ±12 reject: a synthetic local polygon with one vertex at +x = 12 exactly → no punch event and no seal, counter unchanged; the same +polygon at x = 11.999 → punched/sealed; T3 the truth table +(root kind × draw_landscape × outside-view count × previous count) → the +exact event subsequence; T4 two consecutive frames prove the latch crosses +frames (frame 1 seals N>0 → frame 2 clears; frame 1 seals 0 → frame 2 does +not clear); T5 multiple look-ins never touch the root latch. Mutation checks +for every new pin, texts inline in the commit body. + +**Gates:** build 0 warnings; hermetic green; InstalledDat the four known; +depth-event transcript unchanged at the four capture poses (the `PM`/`PC` +lines of the alpha-depth captures — S4-c1 changes no event unless a ±12 +polygon exists in a captured pose, in which case the transcript is the +proof); the lead's four-pose self-gate with validation on (zero errors). + ## 5. Open questions to settle before dispatch - SETTLED (2026-09-03): the walk's `SC` turn is `IWalkEventSink.OnSortCellTurn`