The user's re-gate refuted the scissor fix as THE strip (6c4b6d6 was a
real but sub-pixel under-coverage): the strip survived, screenshot at a
doorway, full width of the opening, top edge only, "very subtle".
Root cause (pinned by Issue130DoorwayStripTests.UnliftedGate_*): the
+0.02 m shell render lift. Cell shells DRAW 2 cm above the dat origin
(z-fight vs coplanar terrain); f35cb8b (the #119-residual fix,
2026-06-11) deliberately reverted the VISIBILITY graph to the physics
(unlifted) transform - but the OutsideView color gate (terrain/sky/
scissor through the doorway) and the seal/punch depth fans are
DRAW-space consumers and kept projecting the unlifted polygons. The
drawn lintel therefore sits one lift-projection above the gate's top
edge - measured 6.7 px at a 2.4 m doorway - and that band never
receives terrain/sky color while the seal also stamps 2 cm low.
A regression from f35cb8b, NOT from the W=0 clip port (987313a stays
exonerated). Vertical aperture edges are immune (the lift slides them
along themselves) - top edge only, exactly as reported; explains the
"also NOW" timing precisely.
Fix - draw space draws lifted, visibility stays physics (the f35cb8b
invariant, now symmetric):
- PortalVisibilityBuilder.Build gains drawLiftZ: the exit-portal branch
projects the OutsideView region with the lifted transform; flood
admission, side tests, and CellViews are untouched (default 0 keeps
every existing visibility test bit-identical).
- The seal/punch fans (DrawRetailPViewPortalDepthWrite) lift their
world verts to the drawn shell's space.
- One shared constant PortalVisibilityBuilder.ShellDrawLiftZ feeds the
shell registration (GameWindow:5604), the gate, and the fans.
Register: AP-32 ADDED - the +0.02 lift had NO row (a pre-register
deviation the 2026-06-12 sweep missed). The row records the split
invariant both ways: a draw-space consumer that forgets the lift
re-opens the #130 strip; a visibility consumer that picks the lifted
transform re-opens the #119-residual side-cull.
Pins: the lifted gate covers the drawn (lifted) aperture to 0.00 px
across the 147-combo sweep; the unlifted gate shows the 6.7 px strip
(sensitivity proof - if the lift is ever removed, this test says the
drawLiftZ plumbing can go too).
Suites: App 257+1skip / Core 1439+2skip / UI 420 / Net 294 green.
Awaiting the user re-gate at a doorway with the lintel on screen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The user's "doors/doorways leak through terrain and houses over a
landblock" is the #117 mark-pass bias evaluated in the wrong space.
Mechanism (confirmed analytically, Issue129PunchBiasTests): the punch's
pass-A stencil mark biased the aperture fan toward the viewer by a
CONSTANT 0.0005 NDC. NDC depth is non-linear - a constant NDC bias b
spans ~= b*d^2*(f-n)/(f*n) meters of eye depth at eye distance d. With
retail's znear 0.1 (d4b5c71) that is 0.125 m at 5 m but ~190 m at one
landblock: every hill/house in front of a distant aperture passed the
LEQUAL mark and was far-Z punched -> door-shaped leak through the
occluder. This is exactly the risk AD-18's register row recorded
("an occluder within ~bias in front of a distant aperture gets punched
through") - the symptom-scan rule found it before instrumentation.
Fix: cap the bias's EYE-SPACE span at 0.5 m -
biasNdc(d) = min(0.0005, capMeters * near / d^2)
in the mark-pass vertex shader (clipPos.w = eye depth), CPU-mirrored as
PortalDepthMaskRenderer.MarkBiasNdc for tests. Below the ~10 m
crossover the constant-NDC term is smaller and wins - bit-identical to
the T5-validated close-range behavior, so the #108 grass coverage that
justified the bias is untouched. Beyond it the punch can never reach an
occluder more than 0.5 m in front of the aperture plane.
Pins (Issue129PunchBiasTests): the old form spans >100 m of eye depth
at a landblock (the leak, kept as documentation of the refuted shape);
the capped form stays <= 0.5 m at every distance 1-400 m and matches
the validated constant bit-for-bit below 10 m.
AD-18 register row updated in the same commit (bias description + the
#129 closure + the residual risk note: door-hugging geometry beyond the
0.5 m cap at >10 m viewing range re-occludes - the cap constant is the
tuning knob if the gate shows residue).
Suites: App 256+1skip / Core 1439+2skip / UI 420 / Net 294 green.
Awaiting the user visual gate at the original spot (+ #108 cellar
re-check up close).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The register's UN-2 row recorded a contradiction: the GetMaxSpeed XML doc
claimed the bare run rate was retail-correct (~5.9 m/s catch-up, calling
the xRunAnimSpeed multiply a misread), while the implementation multiplied
by RunAnimSpeed citing ACE. Settled against the binary, not the pseudo-C:
- BN pseudo-C (acclient_2013_pseudo_c.txt:305127) renders get_max_speed as
void with a bare `this->my_run_rate;` because it DROPS x87 instructions.
- Disassembling the PDB-matched v11.4186 binary at VA 0x00527cb0: all THREE
return paths end `fld <rate>; fmul dword ptr [0x007C8918]; ret`, and the
.rdata dword at 0x007C8918 is 4.0f. Sibling get_adjusted_max_speed
(0x00527d00) carries the same trailing fmul. Verifier committed at
tools/verify_un2_fmul.py (PE parse + byte decode, rerunnable).
- Retail paths: weenie null -> 1.0 x4; InqRunRate ok -> queried x4;
InqRunRate failed -> my_run_rate x4. ACE MotionInterp.cs:665-676 matches.
Changes:
- Doc-comment rewritten: the implementation is retail-correct; the catch-up
speed 2 x get_max_speed ~= 23.5 m/s at run 200 IS retail. The 1-Hz
remote-blip symptom the old comment attributed to this multiply is
therefore UNEXPLAINED by it (if it recurs: #41 family, not this).
- Weenie-null path aligned to retail's LITERAL 1.0 default (was MyRunRate).
- Tests re-pinned to the three retail paths (the old NoWeenie test pinned
the non-retail fallback).
- Register: UN-2 row deleted per the retire rule (6 -> 5 UN rows);
shortlist renumbered.
This is the 2nd confirmed instance of the BN x87-dropout artifact class
(memory: feedback_bn_decomp_field_names) deciding a register row.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>