docs(p1): canonical pickup handoff — swept curr_cell advance is the fix
Single pickup document for the next session: state both altitudes, the 8 session commits, the confirmed finding (production membership diverges 0/11 — swept move completes but curr_cell never advances across the portal), the DO-NOT-RETRY list (3 falsified hypotheses), the apparatus inventory + run commands, the P1 fix scope (two decomp questions + the acdream code map + the RED gate), the test baseline, and a copy-paste pickup prompt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0442eadcec
commit
db94cb1c90
1 changed files with 209 additions and 0 deletions
209
docs/research/2026-06-03-p1-membership-swept-advance-handoff.md
Normal file
209
docs/research/2026-06-03-p1-membership-swept-advance-handoff.md
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
# P1 pickup handoff — doorway membership: port retail's swept `curr_cell` advance
|
||||
|
||||
> **Canonical pickup document for the next session.** Branch `claude/thirsty-goldberg-51bb9b`
|
||||
> (do NOT branch/worktree; do NOT push without asking; NEVER `git stash`/`gc`). PowerShell on
|
||||
> Windows; launch logs are UTF-16. Read this FIRST, then the linked docs as needed.
|
||||
|
||||
## State both altitudes
|
||||
|
||||
- **Milestone:** M1.5 — Indoor world feels right.
|
||||
- **Effort:** the VERBATIM spatial-pipeline port (master plan:
|
||||
[`docs/superpowers/specs/2026-06-03-verbatim-spatial-pipeline-port-master-plan.md`](../superpowers/specs/2026-06-03-verbatim-spatial-pipeline-port-master-plan.md)).
|
||||
- **Phase:** **P0 conformance apparatus = COMPLETE & gate met.** **P1 = membership, IN PROGRESS** —
|
||||
the decisive evidence is in and the RED gate is built; the remaining work is the FIX.
|
||||
- **Next concrete step:** port how retail advances `curr_cell` ACROSS the doorway portal
|
||||
**mid-sweep**, and turn the RED production-path gate GREEN. (Details in "The P1 fix" below.)
|
||||
|
||||
## TL;DR (what we learned, in one paragraph)
|
||||
|
||||
At a building doorway, acdream's cell membership LAGS retail. A live cdb capture of retail
|
||||
(`CPhysicsObj::change_cell` at the Holtburg `0031↔0170↔0171` doorway) gave a clean 22-transition
|
||||
golden. Replaying its indoor `0170↔0171` segments through acdream's **real** `ResolveWithTransition`
|
||||
yields **0/11 match**: the swept move COMPLETES (`restPos == target`) but `CellId` never leaves the
|
||||
SOURCE cell — acdream carries the body across the doorway yet never advances `curr_cell`. **Both**
|
||||
retail and acdream PICK the cell with center-only `point_in_cell`; the gap is that **retail advances
|
||||
`curr_cell` to the neighbour DURING the sweep** (the swept sphere crossing the portal / a sphere
|
||||
point that leads the foot), while acdream only re-picks at the resting end position where the
|
||||
sphere center is still in the source cell. P1 = port that swept advance.
|
||||
|
||||
## What shipped this session (commits, base `a859116`)
|
||||
|
||||
| SHA | What |
|
||||
|---|---|
|
||||
| `a90f343` | Dat-backed conformance loader (`ConformanceDats`) + characterized the cottage-doorway topology (`0031↔0170↔0171` verified real from dats; vestibule `0170` w/ exit portal, room `0171`, outdoor landcell `0031` by grid math) |
|
||||
| `ec78beb` | `find_cell_list` unambiguous goldens (interior picks + stale-seed re-pick stability) |
|
||||
| `b35e491` | Retail-trace parser (`RetailTrace`) + cdb value-capture tooling |
|
||||
| `1662da8` | Threshold-trace golden wiring + PVS scaffold + P1-entry checklist |
|
||||
| `bb4dead` | **Retail-trace golden CAPTURED** (live cdb) + divergence pinned (P0 gate met) |
|
||||
| `81ea3aa` | P1 design nuances (acdream already has `FindTransitCellsSphere`; test the production path) |
|
||||
| `46a86d2` | CORRECTION — retail pick is center-only `point_in_cell`; bare-`FindCellList` divergence might be a probe artifact |
|
||||
| `0442ead` | **Production-path conformance — divergence CONFIRMED (0/11), NOT a probe artifact** |
|
||||
|
||||
Plan + notes: [`docs/superpowers/plans/2026-06-03-p0-conformance-apparatus.md`](../superpowers/plans/2026-06-03-p0-conformance-apparatus.md),
|
||||
[`docs/research/2026-06-03-p0-conformance-apparatus-notes.md`](2026-06-03-p0-conformance-apparatus-notes.md)
|
||||
(the notes doc has the full finding + the `## ✅ RESOLVED` section + the per-transition containment table).
|
||||
|
||||
## ⛔ DO-NOT-RETRY (hypotheses falsified this session — don't waste a cycle)
|
||||
|
||||
1. **"The fix is a radius-aware pick (`SphereIntersectsCellBsp` instead of `PointInsideCellBsp` in
|
||||
the `find_cell_list` pick)."** FALSIFIED. `CObjCell::find_cell_list` pick @ pc:308810 calls
|
||||
`vtable[0x84]` = `CEnvCell::point_in_cell` (`@ 0x52c300 pc:309677`) → `CCellStruct::point_in_cell`
|
||||
(`@ 0x5338f0 pc:317657`) → **`BSPTREE::point_inside_cell_bsp`** — CENTER-ONLY. acdream's pick
|
||||
criterion already matches retail. The radius-aware `sphere_intersects_cell_bsp` (`@ 0x533900
|
||||
pc:317666`) is a SEPARATE method, used by `find_transit_cells`' set-build only.
|
||||
2. **"Retail uses portal-crossing, acdream uses point-in-cell — different PICK criteria."**
|
||||
Imprecise → effectively wrong. Both PICK with center-only `point_in_cell`. The difference is
|
||||
WHEN `curr_cell` advances (mid-sweep vs at-rest), not the pick test.
|
||||
3. **"The 0/22 bare-`FindCellList` divergence is a probe artifact."** FALSIFIED by the production-path
|
||||
test (0/11 through the real swept engine). The divergence is real in production.
|
||||
4. (Historical, already known dead — do not re-litigate) `CheckBuildingTransit` stickiness / #90
|
||||
workarounds / the R1-flap ordered-CELLARRAY are already on this branch; they are NOT the doorway
|
||||
lag. See the master-plan §1 DELETE list.
|
||||
|
||||
## The apparatus (what exists + how to use it)
|
||||
|
||||
All under `tests/AcDream.Core.Tests/Conformance/` unless noted. Conformance suite is GREEN
|
||||
(`60 pass / 1 skip / 0 fail`).
|
||||
|
||||
- **`ConformanceDats.cs`** — `ResolveDatDir()` (skip if dats absent), `LoadEnvCell(dats, cache, id)`
|
||||
→ loads a real EnvCell from the dats with its **real** ContainmentBsp + caches a `CellPhysics`
|
||||
(real collision BSP). `FixturesDir`, `HoltburgLandblock = 0xA9B40000`.
|
||||
- **`CottageDoorwayCharacterizationTests.cs`** — maps the Holtburg `0140..017F` indoor neighbourhood;
|
||||
pins the threshold building (origin `161.93,7.50,94.00`): `Vestibule0170`, `Room0171`,
|
||||
`OutdoorLandcell0031`; verified interior points (`Interior0170Local`, `Interior0171Local`).
|
||||
- **`RetailTrace.cs`** — parses `[fcl] seed=0x.. px=.. py=.. pz=.. picked=0x..` → `RetailCellPick`.
|
||||
- **Golden:** `Conformance/Fixtures/find-cell-list-threshold.log` — 22 retail `change_cell`
|
||||
transitions, decoded to decimals. The retail TRUTH.
|
||||
- **`FindCellListConformanceTests.cs`** — unambiguous interior picks (GREEN) +
|
||||
`FindCellList_DoorwayThreshold_DivergesFromRetail_PendingP1` (documents-the-bug, UNIT-level pin).
|
||||
- **`ThresholdDivergenceDiagnosticTests.cs`** — prints per-transition `point_in_cell` containment
|
||||
(the `in_seed/in_0170/in_0171` table). Always passes; invaluable for diagnosis.
|
||||
- **`ThresholdPortalCrossingReplayTests.cs`** — ★ the **production-path** gate:
|
||||
`ProductionPath_IndoorCrossings_DivergeFromRetail_PendingP1`. Replays the golden indoor segments
|
||||
through the REAL `ResolveWithTransition`. Currently `0/11`; **the fix must make it `11/11`.**
|
||||
- **`PvsConformanceTests.cs`** — render-PVS golden scaffold (skipped; filled in P4).
|
||||
- **cdb capture tooling** (`tools/cdb/`): `find-cell-list-capture.cdb` (breakpoints
|
||||
`CPhysicsObj::change_cell`, symbol-driven `@@c++`/offset reads; offsets verified live via
|
||||
`discover-types.cdb`), `decode_fcl_capture.py` (hex floats → decimals), READMEs. **PDB MATCH
|
||||
confirmed** (`refs/acclient.pdb` ↔ `C:\Turbine\Asheron's Call\acclient.exe`). The retail in-world
|
||||
client was PID 31020 this session (1164 MB = the game; the small one is the launcher).
|
||||
|
||||
**Run the gate:**
|
||||
```
|
||||
dotnet test tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj -c Debug --filter "FullyQualifiedName~Conformance"
|
||||
```
|
||||
**See the production-path detail (per-segment MATCH/DIVERGE):**
|
||||
```
|
||||
dotnet test tests/AcDream.Core.Tests/AcDream.Core.Tests.csproj -c Debug --filter "FullyQualifiedName~ProductionPath_IndoorCrossings" -l "console;verbosity=detailed"
|
||||
```
|
||||
**Capture more retail goldens** (user must launch retail + walk a doorway): run
|
||||
`tools/cdb/find-cell-list-capture.cdb` per its README; `decode_fcl_capture.py` → drop at the fixture path.
|
||||
|
||||
## The P1 fix — port retail's swept `curr_cell` advance
|
||||
|
||||
**Symptom (from `ProductionPath_IndoorCrossings`):** `restPos == target` (sweep completes) but
|
||||
`result.CellId` = source cell, every indoor segment. So `curr_cell` never advances across the portal.
|
||||
|
||||
**Two decomp questions to settle FIRST (grep-named → read → pseudocode, do not guess):**
|
||||
1. **Does retail's membership point LEAD the foot?** What is `global_sphere[0]`'s local origin
|
||||
relative to `m_position.frame.m_fOrigin` (the captured foot point)? If the sphere center is offset
|
||||
toward motion / into the room, retail's center-only `point_in_cell` lands in the neighbour while
|
||||
the foot is behind. Read how retail builds `global_sphere` (`SPHEREPATH`/`CSphere` setup) and
|
||||
compare to acdream's `sp.GlobalSphere[0].Origin`. Anchor: `SPHEREPATH` (acclient.h:32625),
|
||||
`CPhysicsObj::SetPositionInternal @ 0x515330 pc:283399`.
|
||||
2. **Does `curr_cell` advance via the swept CROSSING before/independent of the `find_cell_list`
|
||||
pick?** Read `CTransition::transitional_insert @ 0x50aa70 pc:272547` +
|
||||
`CTransition::validate_transition` + `CObjCell::find_cell_list @ 0x52b4e0 pc:308742` (set-build by
|
||||
`find_transit_cells`, then the pick). Determine whether `curr_cell` moves to a neighbour the
|
||||
swept sphere CROSSED (set-build / `find_transit_cells` @ `0x52c820 pc:309968`) even if the
|
||||
end-position center isn't yet inside it. `CPhysicsObj::change_cell @ 0x513390 pc:281192` is the
|
||||
commit-on-diff.
|
||||
|
||||
**acdream code map (architect-reported line numbers — VERIFY on pickup, the branch evolves):**
|
||||
- `PhysicsEngine.ResolveWithTransition` — `src/AcDream.Core/Physics/PhysicsEngine.cs:~621`; returns
|
||||
`sp.CurCellId` as `result.CellId` at `~894`.
|
||||
- `Transition.FindEnvCollisions` — `src/AcDream.Core/Physics/TransitionTypes.cs:~1939`; indoor branch
|
||||
`~1974`; calls `RunCheckOtherCellsAndAdvance` at `~2082` (indoor) / `~2131` (outdoor).
|
||||
- `RunCheckOtherCellsAndAdvance` — `TransitionTypes.cs:~2143`; `CellTransit.FindCellSet(...)` at
|
||||
`~2149`; `sp.SetCheckPos(sp.CheckPos, containingCellId)` at `~2160` (where `CheckCellId` gets the answer).
|
||||
- `ValidateTransition` — `TransitionTypes.cs:~3426`; **`sp.CurCellId = sp.CheckCellId` at `~3436`**
|
||||
(the commit site).
|
||||
- `CellTransit.BuildCellSetAndPickContaining` — `src/AcDream.Core/Physics/CellTransit.cs:~426`; the
|
||||
center-only `point_in_cell` pick at `~520` (this is CORRECT — do not "fix" it to radius-aware).
|
||||
- `CellTransit.FindTransitCellsSphere` — `CellTransit.cs:~74` (the partial `find_transit_cells` port:
|
||||
exit→exitOutside, loaded-neighbour→`SphereIntersectsCellBsp`, unloaded→plane-distance).
|
||||
|
||||
**Most likely fix shape (HYPOTHESIS, verify against the decomp — do NOT code before the two questions
|
||||
above are answered):** the membership answer should be the cell the swept sphere CROSSED into
|
||||
(`find_transit_cells` candidate the sweep entered), not the cell whose BSP contains the resting
|
||||
end-position center. Likely a change in how `RunCheckOtherCellsAndAdvance` / the swept advance picks
|
||||
from the candidate set, OR feeding the correct (leading/swept) sphere point. Could also be that
|
||||
acdream's `global_sphere` point differs from retail's. **The evidence-first move: instrument acdream's
|
||||
`ResolveWithTransition` to print `sp.GlobalSphere[0].Origin` + the candidate set + the pick at each
|
||||
sub-step for one failing segment, and compare to retail (capture `find_cell_list`'s `arg3->center` +
|
||||
`*arg5` via a new cdb breakpoint). Then port. Iterate against the `ProductionPath_IndoorCrossings`
|
||||
gate (sub-second loop).**
|
||||
|
||||
**Then (rest of P1, after the gate is GREEN):** the outdoor-involving segments (`0031↔0170`) need the
|
||||
landcell + building portal loaded into the test cache (the `ProductionPath` test currently skips them
|
||||
— extend it); delete `CheckBuildingTransit` (master-plan #5); unify `find_env_collisions`; demote
|
||||
`ResolveCellId` to spawn/teleport-seed. Update/rewrite the documents-the-bug tests to assert the full
|
||||
sequence (they FAIL when the fix lands — that's the signal). Master-plan §4: if a faithful port breaks
|
||||
an acdream test, the test encoded a hybrid assumption — fix the test to retail truth, don't bend the port.
|
||||
|
||||
**P1 gate (user visual):** stand in the doorway → no ping-pong, `[cell-transit]` DELTA=0 standing
|
||||
still; walk in/out → clean monotonic cell sequence.
|
||||
|
||||
## Test baseline (going into P1 fix)
|
||||
|
||||
Core: **1308 pass / 5 fail / 1 skip** — the 5 are the documented baseline (2 `BSPStepUp` +
|
||||
3 door-collision = P2's target). Conformance subset: **60 pass / 1 skip / 0 fail**. App: 177 green
|
||||
(untouched this session). The 2 NEW documents-the-bug tests
|
||||
(`FindCellList_DoorwayThreshold_DivergesFromRetail_PendingP1`,
|
||||
`ProductionPath_IndoorCrossings_DivergeFromRetail_PendingP1`) are GREEN-while-broken; they FLIP when P1 lands.
|
||||
|
||||
## Memory updated
|
||||
|
||||
`memory/project_retail_membership_criterion.md` (the finding + the swept-advance target + the
|
||||
falsified hypotheses) and the `MEMORY.md` index hook are current. Read them on pickup.
|
||||
|
||||
---
|
||||
|
||||
## PICKUP PROMPT (copy-paste for the next session)
|
||||
|
||||
```
|
||||
Continue the VERBATIM retail spatial-pipeline port. Branch claude/thirsty-goldberg-51bb9b (no
|
||||
branch/worktree; no push without asking; never git stash/gc). PowerShell on Windows; launch logs UTF-16.
|
||||
|
||||
State: M1.5. P0 conformance apparatus COMPLETE + gate met. P1 (membership) IN PROGRESS — the decisive
|
||||
evidence is in and the RED gate is built; remaining work is the FIX.
|
||||
|
||||
READ FIRST: docs/research/2026-06-03-p1-membership-swept-advance-handoff.md (canonical), then
|
||||
docs/research/2026-06-03-p0-conformance-apparatus-notes.md (the ✅ RESOLVED section + the containment
|
||||
table) and memory/project_retail_membership_criterion.md.
|
||||
|
||||
THE FINDING (confirmed in production): acdream's swept ResolveWithTransition completes the doorway move
|
||||
(restPos==target) but never advances curr_cell across the portal — 0/11 vs the retail change_cell golden.
|
||||
Both retail and acdream PICK with center-only point_in_cell (radius-aware-pick + "different pick
|
||||
criterion" + "probe artifact" hypotheses are ALL FALSIFIED — see the DO-NOT-RETRY list). The gap is that
|
||||
retail advances curr_cell to the neighbour DURING the sweep (swept crossing / a sphere point that leads
|
||||
the foot), acdream only re-picks at the resting end position.
|
||||
|
||||
THE JOB (P1 fix, evidence-first per the #98 lesson — do NOT speculate):
|
||||
1. Answer the two decomp questions in the handoff: (a) does retail's global_sphere[0] point lead the
|
||||
foot vs acdream's sp.GlobalSphere[0].Origin? (b) does curr_cell advance via find_transit_cells' swept
|
||||
crossing in transitional_insert/validate_transition before the find_cell_list pick? Anchors:
|
||||
transitional_insert @0x50aa70 pc:272547, validate_transition, find_cell_list @0x52b4e0 pc:308742,
|
||||
find_transit_cells @0x52c820 pc:309968, SetPositionInternal @0x515330 pc:283399, change_cell @0x513390.
|
||||
2. Instrument acdream's swept path (print sp.GlobalSphere[0].Origin + candidate set + pick per sub-step
|
||||
for ONE failing 0170->0171 segment) and, if needed, capture retail's find_cell_list arg3->center +
|
||||
*arg5 via a new cdb breakpoint (PDB MATCHES; tooling in tools/cdb/). Compare. THEN port verbatim.
|
||||
3. Iterate against the RED gate ThresholdPortalCrossingReplayTests.ProductionPath_IndoorCrossings_
|
||||
DivergeFromRetail_PendingP1 (sub-second loop) until 11/11. Then extend it to the outdoor 0031 segments
|
||||
(load landcell + building portal), delete CheckBuildingTransit, unify find_env_collisions, demote
|
||||
ResolveCellId to seed-only, and rewrite the documents-the-bug tests to assert the full sequence.
|
||||
4. USER VISUAL GATE: doorway, no ping-pong, clean in/out cell sequence.
|
||||
|
||||
Test baseline: Core 1308 pass / 5 fail (2 BSPStepUp + 3 door-collision = P2) / 1 skip; Conformance 60
|
||||
pass / 1 skip. Do NOT code a membership fix before the two decomp questions are answered with evidence.
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue