acdream/docs/research/2026-06-12-doorway-artifacts-129-130-handoff.md

156 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Doorway artifacts #130 + #129 (+ #113 re-check, UN-2 desk work) — handoff (2026-06-12)
**Branch state:** `claude/thirsty-goldberg-51bb9b` == `main` == pushed to BOTH
remotes (github + git.snakedesert.se) at `c007f5a`. Suites green:
App 246 + 1 skip / Core 1438 + 2 skips / UI 420 / Net 294.
CLAUDE.md is the NEW CONDENSED structure — orient via its `## Current state`
section (status ≤5 lines + pointers; do not re-add banners).
## 0. What this session closed (do NOT re-litigate)
| Closed | Root cause | Commits |
|---|---|---|
| **#119/#128** tower broken stairs + "water barrel" (user-gated) | (1) interior entity ids discarded the landblock X byte + Tier-1 cache hinted by PLAYER landblock → cross-entity batch serving; (2) anchor-±5m culling bounds didn't contain the mesh (gaze-dependent vanish); (3) the knife-edge in-plane portal clip | `3cf6bcc` probe, `2163308` cache/ids, `987313a` W=0 clip port + rescue DELETED, `1ca412d`+`6a9b529` vertex-derived bounds |
| **#112** hill-cottage transparent interior (user-gated) | the cottage's entry cell 0x104 is a 0.22 m threshold band; running tick-skips it, and the outdoor-seed pick had NO growing-array walk → the miss was ABSORBING (stuck outdoor-classified inside). Retail walks ONE growing array for every seed; ported verbatim | `be03146` (pins: `Issue112MembershipTests`) |
| **The divergence register** | 108 audited rows of every known acdream-vs-retail deviation; rules in CLAUDE.md (same-commit rows; scan-on-symptom) | `ebf61f9`, `3c3293a` — [docs/architecture/retail-divergence-register.md](../architecture/retail-divergence-register.md) |
Durable lesson shipped to memory: [[feedback_culling_bounds_from_drawn_data]]
(culling volumes derive from the DATA that gets drawn, never a constant).
## 1. THE QUEUE (in order)
### #130 — background-color strip along the TOP outer edge of a doorway, looking out from inside (FIRST: suspected fresh regression)
- **User report ("also NOW")** — plausibly a regression from `987313a` (the
W=0 clip port / EyeInsidePortalOpening rescue deletion). Fresh debt
outranks the queue.
- **Symptom:** standing inside looking out, a thin strip of clear/world
color runs along the outer TOP edge of the doorway opening.
- **Leads (ISSUES.md #130):** if the OutsideView's top edge sits ~1 px BELOW
the aperture's drawn shell edge, terrain isn't drawn in that strip while
the seal/punch cleared it → background. Suspects inside the port:
`MergeSubPixelVertices` shaving a top vertex; the exact-w boundary vs the
old 1e-4 epsilon shifting the projected edge; the deleted rescue no longer
substituting a full view for an eye-pressed doorway. Alternate: a 1-px
seal-vs-shell mismatch (#118-era machinery).
- **Plan:** (1) capture at a doorway showing the strip —
`ACDREAM_PROBE_VIEWER=1` + a screenshot + the `[snap]`/[viewer] eye+cell;
(2) replay the frame headlessly (CornerFloodReplayTests machinery:
`LoadCell`/`LoadBuilding` + `PortalVisibilityBuilder.Build`) and diff the
OutsideView top edge NDC against the aperture polygon's projected top
edge; (3) cross-check by locally reverting `987313a` at the same doorway.
- **⚠️ Discipline:** if it traces to the port, fix the EDGE MATH — the
rescue does NOT come back (CLAUDE.md no-workarounds; the rescue was the
documented compensation we just retired).
### #129 — doors/doorways leak through terrain + houses from ~a landblock away
- **Lead (top suspect, ISSUES.md #129):** #117's stencil depth-gate punch
(`478c549`, PortalDepthMaskRenderer) marks aperture pixels at biased true
depth with a CONSTANT 0.0005 NDC bias. Screen depth is non-linear: at
~200 m that constant spans METERS of view depth → hills/houses in front
of the aperture get marked + far-Z punched → door-shaped leak through the
occluder. (A register row of the documented-approximation kind, in
effect.)
- **Fix shape:** re-derive the bias in EYE-SPACE (scale by w / convert a
fixed eye-space epsilon to per-pixel NDC), keeping #108's coverage (the
bias exists so the punch covers the aperture's own pixels at close range).
- **Falsification first:** capture at the spot (screenshot + [viewer] eye)
→ confirm the leak patch matches a distant building's aperture polygon;
then a headless test on the bias math at 5 m vs 200 m depths.
### #113 re-check (rides the first launch — costs one glance)
- The hill-cottage phantom staircase (appearing at distance, half-embedded
in the wall). **Plausibly already dead**: the `2163308` cache fix killed
cross-entity batch serving (the phantom may have been a town twin wearing
the tower's staircase batches — distance-dependent via the old
player-landblock cache hints).
- If STILL present: the proper fix is the TS-20 register row — drawing-BSP
orphan polys (hall 0x010014C3 dict polys {0,1} referenced by NO
DrawingBSP node; retail draws by BSP traversal, we iterate the dict).
Spec + the histogram-on-a-door-GfxObj first step:
`docs/research/2026-06-11-building-render-holistic-port-handoff.md` (the
naive filter `e46d3d9` broke doors Holtburg-wide → un-applied `124c6cb`;
do not re-apply naively).
### UN-2 — GetMaxSpeed contradictory justifications (DESK WORK — no user/launch needed)
- `src/AcDream.Core/Physics/MotionInterpreter.cs` ~:972: the method doc's
upper paragraph says multiplying by RunAnimSpeed was "a misread of the
decomp — retail's catch-up IS that slow on purpose" (~5.9 m/s at run
200); the implementation comment below it APPLIES ×RunAnimSpeed (4.0)
citing "ACE MotionInterp.cs:670-678 verified against retail"
(≈11.76 m/s). Both cannot be true — possible 4× remote catch-up error
(the #41 remote-blip family).
- Resolve via the oracle: grep `get_max_speed`/`InterpolationManager::adjust_offset`
in the named decomp; cdb-trace a live retail remote if the decomp is
ambiguous. Then fix the doc OR the code, and move the register row
UN-2 → its resolved kind (or delete it if ported exactly).
### After these: #124 (far-building back walls through openings — interior-root
look-in floods missing, lead in ISSUES.md), #108-residual (cellar grass band,
eye-below-grade window), #127 (distant-building admission churn), #116
(slide-response family, oracle-first). Closing this list ≈ the M1.5 → M2
boundary (M2 = kill a drudge: combat).
## 2. Apparatus inventory (use, don't rebuild)
| Tool | How | For |
|---|---|---|
| `[viewer]`/`[viewer-diff]` probe | `ACDREAM_PROBE_VIEWER=1` | root/flood/outPolys/pCell + mm eye per change |
| `[cell-transit]` probe | `ACDREAM_PROBE_CELL=1` | player cell changes (membership side) |
| `[dump-entity]` probe | `ACDREAM_DUMP_ENTITY=0xID,0xID` | one-shot entity MeshRefs/cache/bounds dump (HYDRATE/DRAW/WALK-REJECT) |
| `[WB-DIAG]` counters | `ACDREAM_WB_DIAG=1` | entSeen/entDrawn/meshMissing + [mesh-miss] self-heal |
| CornerFloodReplayTests | App.Tests | dat-backed headless flood replay (LoadCell/LoadBuilding fixtures) — the #130 replay base |
| Issue112MembershipTests | Core.Tests | membership pick replay incl. RegisterBuildings helper |
| The divergence register | docs/architecture/ | scan on ANY unexplained symptom BEFORE instrumenting |
| Launch protocol | CLAUDE.md "Running the client" | build green FIRST; background launch + Tee to log; graceful close; ACE session rules |
## 3. Process reminders
- The user's reports are AXIOMS; visual gates are the acceptance tests.
- Launch, hand over, do NOT foreground/screenshot while they play; read
logs when told (live tail-reads of the Tee'd log are fine and effective —
the #112 capture was decided live this way).
- Register discipline: new deviation → row in the same commit; retired →
delete the row. Phase checklist now enforces it.
- Suites green per commit: App 246+1skip / Core 1438+2skip / UI 420 / Net 294.
## 4. Paste-ready pickup prompt
```
Pick up acdream as a SENIOR 3D ENGINE DEVELOPER on the doorway render
artifacts. Branch claude/thirsty-goldberg-51bb9b == main (everything
pushed). Read FIRST: CLAUDE.md "Current state" (the condensed structure),
then docs/research/2026-06-12-doorway-artifacts-129-130-handoff.md (THE
handoff — queue, leads, apparatus), then the render digest
(claude-memory/project_render_pipeline_digest.md, DO-NOT-RETRY table
applies).
WORK ORDER:
1. #130 — background strip at the doorway TOP edge looking out from
inside. Suspected REGRESSION from the W=0 clip port (987313a). Capture
at a doorway (ACDREAM_PROBE_VIEWER=1 + screenshot + eye/cell), then
headless replay (CornerFloodReplay machinery) diffing the OutsideView
top edge vs the aperture polygon's projected edge. If it's the port,
fix the EDGE MATH — the EyeInsidePortalOpening rescue does NOT come
back.
2. #129 — doors/doorways leak through terrain/houses at ~a landblock.
Top suspect: #117's stencil punch bias is a constant 0.0005 NDC
(478c549) — meters of real depth at 200 m. Falsify with a capture,
then re-derive the bias in eye-space; keep #108's aperture coverage.
3. #113 re-check rides the first launch: one glance at the hill-cottage
phantom stairs — plausibly dead via 2163308 (cache cross-serving). If
alive, the TS-20 register row + the holistic-port handoff own the fix.
DESK-WORK ALTERNATIVE (no user needed): UN-2 register row — resolve the
GetMaxSpeed ×4 contradiction (MotionInterpreter.cs ~:972) against the
named decomp / live cdb; possible 4x remote catch-up error.
The user's reports are AXIOMS. Visual gates are the acceptance tests.
Build + test green per commit (App 246+1skip / Core 1438+2skip / UI 420 /
Net 294). Launch protocol per CLAUDE.md: build green first, background
launch with Tee to a log, hand over, read logs when told. Register
discipline applies: any new deviation gets its register row in the same
commit.
```