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

9.6 KiB
Raw Blame History

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, 3c3293adocs/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.