docs: A6.P3 #98 resolution + A6.P4 design + #99/#100 filed
Knowledge-preservation pass after the issue #98 cellar-up fix shipped (`b3ce505`). Closes the saga's documentation loop and plans the next phase. Changes: - docs/research/2026-05-23-a6-p3-issue98-comparison-harness-findings.md Appended "Resolution 2026-05-24" section: v3 hypothesis falsified, actual mechanism (head-bump cottage GfxObj floor poly from below) confirmed,b3ce505fix shipped, known door regression flagged. Memory artifacts cross-referenced. - docs/ISSUES.md #98 moved to DONE with full resolution writeup + decomp anchors. #99 filed: door regression at building thresholds (caused by b3ce505's indoor-primary gate). Closes via A6.P4. #100 filed: transparent rectangular patches around houses (terrain rendering). Bisect found commit35b37dfintroduced the hiddenTerrainCells mechanism that collapses 24m outdoor cells when buildings sit in them; cottage building only fills part of its cell so the rest of the 24m cell shows the sky-bleeding gap. Three fix-path options documented. - docs/superpowers/specs/2026-05-24-phase-a6-p4-retail-shadow-architecture.md Full A6.P4 design doc. Three-slice plan: (1) query-side portal expansion to close #99 while preserving #98 fix, (2) port retail's BuildShadowCellSet at registration time so per-cell semantics match `CObjCell::find_cell_list`, (3) removeb3ce505stopgap entirely. Decomp anchors, file-by-file plan, risk inventory, open questions. Memory entries written separately (out-of-tree at ~/.claude/projects/.../memory/): - feedback_retail_per_cell_shadow_list.md The architectural lesson: retail uses per-cell shadow_object_list with portal-aware registration; our landblock-wide spatial registry diverges at indoor/outdoor seams. - feedback_apparatus_for_physics_bugs.md The apparatus-first pattern that cracked the saga: live capture + fixture dump + replay harness. Template for future physics bugs. Quote rule: "when a physics bug is resisting and you catch yourself about to ship 'fix attempt N+1 with no new evidence,' STOP. Build the apparatus first." - MEMORY.md index updated with both new entries. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b3ce505ca8
commit
b55ae831bd
3 changed files with 487 additions and 1 deletions
|
|
@ -534,3 +534,116 @@ LiveCompare_FirstCap_HarnessMissesCottageFloorBecauseCottageGfxObjNotRegistered
|
|||
test is now in documents-the-bug form (PASSES while bug exists; FAILS
|
||||
when fix lands) — flip it when the cottage GfxObj is registered.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Resolution 2026-05-24
|
||||
|
||||
### What was wrong with the evening-v3 hypothesis
|
||||
|
||||
The v3 "stale ramp contact plane" hypothesis (top of this doc) was
|
||||
**FALSIFIED** by chronological walk of `a6-issue98-resolve-capture-2.jsonl`:
|
||||
|
||||
- Player position at the first cap event (tick 55101, line 55102 of the
|
||||
JSONL): world `(141.605, 7.304, 92.656)`
|
||||
- `bodyBefore.walkableVertices`: the ramp polygon at world
|
||||
X∈[140.5, 142.1], Y∈[5.80, 8.70], Z∈[90.99, 93.99]
|
||||
- Player XY is **inside** the ramp polygon's footprint
|
||||
- `bodyBefore.contactPlane.normal` = (0, 0.7189884, 0.69502217) — the
|
||||
ramp's plane
|
||||
|
||||
The v3 doc claimed "ramp at world X∈[129.7, 131.3], 10m away from
|
||||
player." That geometry was computed from a wrong source (not the actual
|
||||
ramp polygon). The live capture's `walkableVertices` are the ground
|
||||
truth and show the player IS on the ramp at the cap event. The contact
|
||||
plane is the ramp's plane because the player is on the ramp — correct,
|
||||
not stale.
|
||||
|
||||
Tick 55020 (line 55021) shows the contact plane refreshing in real time
|
||||
as the player crossed onto the ramp: `bodyBefore` had the previous
|
||||
polygon's plane, `bodyAfter` had the ramp's plane. The walkable-refresh
|
||||
chain works. No drift mechanism exists in the way v3 described.
|
||||
|
||||
### What the actual mechanism was
|
||||
|
||||
The evening-v2 finding was correct: head-sphere bumps the cottage
|
||||
GfxObj's downward-facing floor poly (poly 0 in the GfxObj fixture, a
|
||||
triangle covering world X∈[136.3, 142.5], Y∈[3.5, 19.5], Z=94) from
|
||||
below. Player at (141.605, 7.304) is inside that triangle. Head sphere
|
||||
top at Z=foot+1.68=94.336 penetrates the cottage floor at Z=94 by
|
||||
0.336m → cn=(0,0,-1) push-back → stuck.
|
||||
|
||||
Why retail doesn't have this cap: decomp grep of
|
||||
`CObjCell::find_obj_collisions` (line 308916) shows retail iterates
|
||||
`this->shadow_object_list` — a **per-cell list**. `CObjCell::find_cell_list`
|
||||
(line 308742) branches indoor/outdoor at registration time: indoor adds
|
||||
only the indoor cell + portal-visible neighbors; outdoor adds all
|
||||
overlapping outdoor cells via `add_all_outside_cells`. So a landblock-
|
||||
baked static like the cottage gets added to outdoor cells'
|
||||
shadow_object_list only — never to indoor EnvCells like the cellar.
|
||||
`CEnvCell::find_collisions` therefore never tests the sphere against
|
||||
the cottage when sphere is inside the cellar.
|
||||
|
||||
`sides_type` (the polygon flag the v2 finding option (b) speculated
|
||||
about) does NOT affect retail's BSP collision code — it only appears in
|
||||
rendering/mesh-batch code. The collision-path divergence is purely
|
||||
architectural: per-cell list vs spatial-radius registry.
|
||||
|
||||
### What shipped (commit b3ce505)
|
||||
|
||||
Smallest behavioral patch matching retail's effect at the query level:
|
||||
|
||||
- `ShadowObjectRegistry.GetNearbyObjects` gained an optional
|
||||
`primaryCellId` parameter. When indoor (≥ 0x0100), the outdoor radial
|
||||
sweep is skipped — only indoor-scoped shadows from `indoorCellIds` are
|
||||
returned.
|
||||
- `Transition.FindObjCollisions` passes `sp.CheckCellId`.
|
||||
- Harness `LiveCompare_FirstCap_HarnessReproducesCottageFloorCapNormal`
|
||||
flipped to `LiveCompare_FirstCap_FixClosesCottageFloorCap` — asserts
|
||||
the downward-facing cottage-floor cap does NOT fire after the fix.
|
||||
- Residual-X-motion test deleted — it documented post-cap edge-slide,
|
||||
irrelevant once the cap is gone.
|
||||
|
||||
Verified: 11/11 cellar harness tests pass. 55 directly-affected physics
|
||||
tests pass. Pre-existing static-state leakage failures (8–19 across
|
||||
serial runs) unchanged. Full `dotnet build` clean.
|
||||
|
||||
Visual verification: user confirmed "Finally I can go up!" in the
|
||||
Holtburg cottage cellar.
|
||||
|
||||
### Known regression caused by b3ce505 + next phase
|
||||
|
||||
Doorway edge case (flagged in the commit message): doors are server-
|
||||
spawned entities with their own cylinder collision, registered via
|
||||
`UpdatePosition` to whichever cell their position resolves to. Doors at
|
||||
building thresholds typically resolve to outdoor cells. With the
|
||||
indoor-primary radial-sweep gate, a sphere inside an indoor doorway-
|
||||
adjacent cell doesn't see the outdoor door → can walk through.
|
||||
|
||||
User reported this: "I can also run through doors."
|
||||
|
||||
This regression is the direct consequence of NOT doing retail's full
|
||||
portal-aware shadow propagation at registration time. Retail's
|
||||
`find_cell_list` indoor branch recurses through `VisibleCellIds` and
|
||||
adds the object to all portal-visible cells. Our `Register` doesn't do
|
||||
this; the b3ce505 stopgap covers cottage-cellar but not doorways.
|
||||
|
||||
**Next phase: A6.P4 — port retail's per-cell shadow_object_list
|
||||
architecture in full.** Design spec at
|
||||
`docs/superpowers/specs/2026-05-24-phase-a6-p4-retail-shadow-architecture.md`
|
||||
(this session). Approach: refactor `ShadowObjectRegistry.Register` to
|
||||
compute the cell set via the retail-faithful indoor/outdoor branch +
|
||||
portal-visible recursion (using `CellPhysics.VisibleCellIds`). Eliminate
|
||||
the cellScope=0 spatial approximation. `GetNearbyObjects` becomes pure
|
||||
per-cell list iteration. Removes the b3ce505 stopgap. Closes the door
|
||||
regression as a side effect.
|
||||
|
||||
Also-likely-closed by A6.P4: #97 (phantom collisions on 2nd floor),
|
||||
indoor sling-out (Finding 3 family), other indoor/outdoor seam bugs.
|
||||
|
||||
### Memory updates (this resolution)
|
||||
|
||||
- `feedback_retail_per_cell_shadow_list.md` — the architectural lesson
|
||||
- `feedback_apparatus_for_physics_bugs.md` — the apparatus pattern that
|
||||
finally cracked this saga (template for future physics bugs)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue