diff --git a/docs/research/2026-05-21-a6-p1-partial-ship-handoff.md b/docs/research/2026-05-21-a6-p1-partial-ship-handoff.md new file mode 100644 index 0000000..623e096 --- /dev/null +++ b/docs/research/2026-05-21-a6-p1-partial-ship-handoff.md @@ -0,0 +1,344 @@ +# A6.P1 partial-ship handoff — 2026-05-21 + +**Status:** Infrastructure complete + scenario 1 (Holtburg inn doorway) +captured end-to-end (retail + acdream paired). Scenarios 2–9 deferred to +next session. + +**Pasteable session-start prompt at the bottom of this doc.** + +## TL;DR + +A6.P1 ships in two milestones: +1. **Infrastructure milestone (DONE today):** `[push-back]` acdream probe (3 + helpers + 3 sites + DebugVM mirror + CLAUDE.md docs), cdb probe script + (v4 with PDB-verified offsets + hex-bits float output), PowerShell + runner with ASCII encoding, README, capture-dir scaffolding, + PDB-match verification, type dumper, hex→float decoder. +2. **Capture milestone (PARTIAL):** 1 of 9 scenarios captured. Scenarios + 2–9 user-driven, deferred at user direction to avoid fatigue. + +**Scenario 1 already surfaces two strong M1.5 findings** (before any +formal A6.P2 analysis): + +| Metric | Retail | acdream | Notes | +|---|---:|---:|---| +| dispatcher entries (find_collisions / BSPQuery.FindCollisions) | 5,818 | 295 | acdream calls dispatcher **20× less often** | +| ContactPlane writes (set_contact_plane fn / per-field writes) | 18 calls | **73,304** field-writes | acdream **rewrites CP every frame/sub-step** vs retail's per-event | + +The CP-write blowup directly confirms the spec's hypothesis +([2026-05-21-phase-a6-indoor-physics-fidelity-design.md §1.2](../superpowers/specs/2026-05-21-phase-a6-indoor-physics-fidelity-design.md)) +that `FindEnvCollisions` indoor branch resynthesizes CP per frame +instead of retaining via Mechanisms A/B/C. Same family as the +`TryFindIndoorWalkablePlane` workaround. + +## State both altitudes (next session) + +> **Currently working toward: M1.5 — "Indoor world feels right."** +> +> **Current phase: A6 — Indoor physics fidelity (cdb-driven).** +> +> **Next concrete step: Capture scenarios 2–9 (paired retail + acdream +> traces). Then run A6.P2 analysis on all 9 captures.** + +## What shipped today (16 commits) + +### Infrastructure (Tasks 1–14 from the A6.P1 plan) + +| Commit | What | +|---|---| +| `ace9e62`, `ad6c89d` | T1: `ProbePushBackEnabled` toggle + roundtrip test | +| `3a173b9` | T2: `LogPushBackAdjust` helper | +| `eb8a318` | T3: instrument `BSPQuery.AdjustSphereToPlane` | +| `2d1f27d` | T4: `LogPushBackDispatch` helper | +| `35631d1` | T5: instrument `BSPQuery.FindCollisions` | +| `66ee757` | T6: `LogPushBackCellTransit` helper | +| `642734d` | T7: instrument `Transition.CheckOtherCells` | +| `dd95c10` | T8: DebugVM `ProbePushBack` mirror | +| `e1f7efe` | T9: CLAUDE.md `ACDREAM_PROBE_PUSH_BACK` env var docs | +| `7bb799b` | T10: `tools/cdb/a6-probe.cdb` v1 (broken offsets) | +| `1c640eb` | T11: `tools/cdb/a6-probe-runner.ps1` (later patched to ASCII) | +| `df315a9` | T12: `tools/cdb/README-a6-probe.md` | +| `0e21f22`, `22e341f` | T13: PDB-match verification (audit trail) | +| `260c60f` | T14: capture-dir scaffolding + findings doc stub | + +### cdb script iteration (T15 dry-runs) + +| Commit | What | +|---|---| +| `d0c8c54` | v1→v2 prep: type dumper (`a6-types-dump.cdb` + runner) + ASCII runner | +| `7b9b26f` | v2 cdb script: PDB-verified offsets + BP6 fix to `check_walkable` | +| `1b6d49e` | v3 cdb script: `@@c++(*(float*)addr)` for floats (still produced zeros) | +| `2d841cb` | v4 cdb script: hex-bits float output via `%08X` (WORKS) | + +### Scen1 capture + decode tooling + +| Commit | What | +|---|---| +| `180b4a5` | scen1 retail.log captured (v4 cdb, 13,552 hits, real hex bits) | +| `8ca718a` | scen1 acdream.log paired (84,130 lines, full probe distribution) | +| `194ed3e` | `decode_retail_hex.py` — Python hex→float decoder + scen1 decoded log | + +## Why cdb v1→v4 iteration was necessary + +The cdb side hit three landmines we didn't anticipate when writing the +A6.P1 plan: + +1. **v1: Stack-arg offsets wrong.** Plan's probe actions used arbitrary + registers (`@edx`, `@edi`) to read function args. `__thiscall` puts + non-this args on the stack (`[esp+N]`), not in arbitrary registers. + All 12 BP5 hits printed `Nx=0 Ny=0 ...` — confirming the read + addresses were wrong. **Fix:** type dumper + double-indirect via + `dwo(poi(@esp+N)+offset)`. + +2. **v2: BP6 symbol wrong + PowerShell UTF-16 encoding.** v1's + `validate_walkable` doesn't exist in the PDB (the actual function is + `CTransition::check_walkable`). PowerShell's `Tee-Object` writes + UTF-16 LE by default, making logs ungreppable. **Fixes:** BP6 symbol + corrected, runner switched to `Out-File -Encoding ASCII`. v2 had + correct integer reads (substeps=3, insertType=0) but all `%f` floats + still printed as 0.000000. + +3. **v3: `%f` doesn't work with `dwo()`.** Switching to + `@@c++(*(float*)addr)` to force C++ interpretation also produced + 0.000000 across all float fields. cdb's `.printf %f` appears to not + reliably handle our float values (possibly varargs promotion, possibly + a deeper limitation). **Workaround (v4):** print all floats as 32-bit + hex bits via `%08X`; Python decoder reinterprets via + `struct.unpack('= 50000)` → `100000`). + +6. **BP6 fires with FloorZ (0.6642) not cos85 (0.0872).** v4 confirmed + this — `check_walkable` is called with `PhysicsGlobals.FloorZ` for + ground verdicts. The cos85 value (0.0872) is passed in a different + code path (post-set_collide wall-slide) which didn't fire during + scen1 (no wall hits). Will appear when scenarios 2–9 hit walls. + +## Pickup prompt for fresh session + +Open a new Claude Code session at this worktree's branch +(`claude/strange-albattani-3fc83c`, HEAD at the latest A6.P1 commit). +Then paste: + +--- + +``` +Pick up A6.P1 capture work — scenarios 2 through 9. The infrastructure +shipped today (probe + cdb v4 + decoder all working). Scenario 1 captured +end-to-end with paired retail + acdream traces; preliminary findings +already strong (CP-write blowup confirms the M1.5 hypothesis). + +Read FIRST: + docs/research/2026-05-21-a6-p1-partial-ship-handoff.md +Then state both altitudes: + Currently working toward: M1.5 — Indoor world feels right + Current phase: A6.P1 — capture scenarios 2-9 + Next concrete step: scenario 2 (Holtburg inn stairs) + +Workflow per scenario (validated by scen1): + 1. Verify retail binary matches PDB: + py tools/pdb-extract/check_exe_pdb.py "C:/Turbine/Asheron's Call/acclient.exe" + Expect MATCH (GUID {9e847e2f-...}). + 2. User launches retail, walks character to scenario start, stops. + 3. .\tools\cdb\a6-probe-runner.ps1 -ScenarioTag "scenN_..." + Wait for "a6-probe v4 armed:" in the log file. + 4. User performs the scripted walk. + 5. Wait for cdb auto-detach (50K hits) OR kill cdb (acclient dies too; + relaunch needed). Hit rate ~6.5K/sec under motion. + 6. User launches acdream with all 5 probe env vars + output to + docs/research/2026-05-21-a6-captures/scenN_.../acdream.log + 7. User walks acdream through the SAME scripted walk. + 8. Close acdream gracefully. + 9. py tools/cdb/decode_retail_hex.py docs/research/.../retail.log + 10. Commit retail.log + retail.decoded.log + acdream.log for that scenario. + +Scenario list per the README at tools/cdb/README-a6-probe.md. + +DO NOT modify the cdb script. v4 works (verified by BP6 threshold +decoding to FloorZ 0.6642 exactly). The hex-bits + Python decoder +pattern is the stable approach. + +CLAUDE.md rules apply: + - Three failed visual verifications = handoff (we hit this on the + cdb script v1→v2→v3 cycle; v4 broke the streak). + - No workarounds without approval (v4 hex output isn't a workaround, + it's the chosen design after cdb %f proved unreliable). + - Visual verification at the Holtburg Sewer is the M1.5 physics + acceptance test (deferred to A6.P4 after fixes land). + +After all 9 captures: proceed to A6.P2 analysis per the design spec +docs/superpowers/specs/2026-05-21-phase-a6-indoor-physics-fidelity-design.md +§4. Note: Finding 2 (CP-write blowup) is already evidence-confirmed +from scen1; A6.P2 just needs to quantify + extend across scenarios. +``` + +--- + +## References + +- Design spec: [`docs/superpowers/specs/2026-05-21-phase-a6-indoor-physics-fidelity-design.md`](../superpowers/specs/2026-05-21-phase-a6-indoor-physics-fidelity-design.md) +- Implementation plan: [`docs/superpowers/plans/2026-05-21-phase-a6-p1-cdb-probe-spike.md`](../superpowers/plans/2026-05-21-phase-a6-p1-cdb-probe-spike.md) +- cdb script: [`tools/cdb/a6-probe.cdb`](../../tools/cdb/a6-probe.cdb) (v4) +- cdb runner: [`tools/cdb/a6-probe-runner.ps1`](../../tools/cdb/a6-probe-runner.ps1) +- Type dumper: [`tools/cdb/a6-types-dump.cdb`](../../tools/cdb/a6-types-dump.cdb) + [`a6-types-dump.txt`](../../tools/cdb/a6-types-dump.txt) (PDB-extracted offsets) +- Hex decoder: [`tools/cdb/decode_retail_hex.py`](../../tools/cdb/decode_retail_hex.py) +- Scen1 retail: [`docs/research/2026-05-21-a6-captures/scen1_inn_doorway/retail.log`](2026-05-21-a6-captures/scen1_inn_doorway/retail.log) + [`retail.decoded.log`](2026-05-21-a6-captures/scen1_inn_doorway/retail.decoded.log) +- Scen1 acdream: [`docs/research/2026-05-21-a6-captures/scen1_inn_doorway/acdream.log`](2026-05-21-a6-captures/scen1_inn_doorway/acdream.log) +- Findings doc stub (to be filled by A6.P2): [`docs/research/2026-05-21-a6-cdb-capture-findings.md`](2026-05-21-a6-cdb-capture-findings.md)