Commit graph

102 commits

Author SHA1 Message Date
Erik
180b4a5010 capture(research): A6.P1 scen1 — retail.log with real hex-bits floats
v4 cdb probe captured paired field data for the Holtburg inn
doorway walk. 13,552 BP hits in ~2 sec of walking. Distribution:
  - BP1 transitional_insert: 7,686 (sub-step loop)
  - BP4 find_collisions:      5,818 (per cell per sub-step)
  - BP5 adjust_sphere_to_plane: 12 (the over-correction suspect)
  - BP6 check_walkable:        12
  - BP7 set_contact_plane:     18

Smoking-gun verification:
  BP6 threshold_h=0x3F2A0751 ≈ 0.664 = PhysicsGlobals.FloorZ
  BP5 plane normal = (0,0,1), movement = (0,-0,-0.75) — classic
       step-down probe against the ground polygon
  BP5 sphere radius = 0x3EF5C28F ≈ 0.480 m — player foot sphere

All hex-bits floats decode cleanly via Python struct.unpack('<f').
Decoder script TBD as part of the handoff.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:59:33 +02:00
Erik
2d841cb615 fix(cdb): A6.P1 — a6-probe.cdb v4 hex-bits floats
v3 with @@c++(*(float*)..) STILL produced 0.000000 across the board.
Conclusion: cdb's .printf %f is unreliable for our use case — possibly
doesn't handle the float-to-double promotion in varargs the way C
printf does, or has a deeper limitation we don't have time to debug.

Pivoting to: print all floats as 32-bit hex bits via %08X, reinterpret
in the Python analysis pipeline via struct.unpack('<f', bytes.fromhex(...))
to recover IEEE 754 single-precision values.

This bypasses cdb's float formatting entirely. Integer reads (which
work — substeps, insertType, collide flag, isWater) stay as %d.

The smoking gun: BP6's check_walkable threshold should be 0.0871556997
(cos 85°) per the decomp call site at acclient_2013_pseudo_c.txt:273202.
v4's BP6 should output threshold_h=0x3DB283D7. If it does, the
infrastructure is sound and we can proceed to all 9 scenarios.

v3 capture preserved as retail-v3-cpp-zero-floats.log audit trail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:55:48 +02:00
Erik
1b6d49ea57 fix(cdb): A6.P1 — a6-probe.cdb v3 with C++ float reads
v2 dry-run produced correct hit counts but all %f field values
printed as 0.000000 — including BP6 threshold which the decomp says
must be 0.0871556997f (cos 85°). Root cause: cdb's MASM evaluator
returns dwo(addr) as a 32-bit integer; .printf %f expects a 64-bit
double; passing the integer to %f produces formatted-zero garbage.

Fix: switch all float-reading expressions to @@c++(*(float*)addr).
The C++ evaluator dereferences memory as a float pointer, returning
a proper float that .printf %f formats correctly. Integer reads (%d)
still use MASM dwo() — that works.

For double-indirect (pointer args), the form is
  @@c++(*(float*)(*(unsigned int*)(@esp+N)+offset))
which reads the pointer at [esp+N], adds the offset, and treats the
result as a float pointer.

v2 capture preserved as retail-v2-zero-floats.log audit trail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:50:11 +02:00
Erik
d0c8c54d96 fix(cdb): A6.P1 — v1 dry-run lessons + v2 prep tooling
Dry-run of scenario 1 (retail-v1-broken-offsets.log preserved as
audit trail) surfaced three issues with the v1 cdb script:

1. STACK-ARG OFFSETS WRONG: BP actions used arbitrary registers
   (@edx, @edi) to read function args, but __thiscall puts non-this
   args on the stack ([esp+N] after the return address). All 12 BP5
   "adjust_sphere" hits printed Nx=0.0 Ny=0.0 ... — fields not read.
   Fixed by writing a type dumper (a6-types-dump.cdb + runner) that
   uses cdb's `dt` command against the loaded PDB to get authoritative
   struct offsets. v2 probe script (to be written next) will use
   double-indirect reads (dwo(poi(@esp+N)+offset)) with correct
   offsets from the dump.

2. TEE-OBJECT UTF-16 ENCODING: PowerShell's default Tee-Object writes
   UTF-16 LE with BOM, making logs unparseable by grep without
   conversion. Runner now uses Out-File -Encoding ASCII. Sacrifices
   live console echo; use `Get-Content -Tail 50 -Wait` in a separate
   shell if live monitoring is needed.

3. BP6 SYMBOL NOT FOUND: `acclient!CTransition::validate_walkable`
   doesn't exist in the PDB. Decomp at line 272811 has
   `CTransition::check_walkable` — likely the actual name. To be
   verified + fixed in v2.

The BP hit-count distribution from v1 is still meaningful diagnostic
data (14,318 transitional_insert + 16,558 find_collisions + 40
set_contact_plane + 12 adjust_sphere + 1 step_up + 1 set_collide in
a 2-second walk through the inn doorway). Preserved as a baseline
sanity-check the v2 distribution can be diffed against.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:38:31 +02:00
Erik
22e341faf6 docs(research): A6.P1 — refresh PDB verification to MATCH
User swapped in the correct Sept 2013 EoR build acclient.exe.
GUID {9e847e2f-777c-4bd9-886c-22256bb87f32}, linker UTC
2013-09-06T00:17:56 — exact match for refs/acclient.pdb.
T15 captures are unblocked.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 18:51:34 +02:00
Erik
260c60f8f5 docs(research): A6.P1 — capture directory structure + findings stub
Creates the 9 per-scenario capture directories (gitkeep stubs) and
the findings doc stub at docs/research/2026-05-21-a6-cdb-capture-findings.md.
A6.P1 fills the capture log slots (Task 15, user-driven); A6.P2
fills the analysis tables and findings section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 18:46:56 +02:00
Erik
0e21f22fc5 docs(research): A6.P1 — record retail-PDB match verification (MISMATCH)
Audit trail for the A6.P1 capture session: the retail binary at
C:\Turbine\Asheron's Call\acclient.exe is the 2015-06-12 build
(GUID {08e25c14-e2a1-46d5-b056-92b2e43a7234}), not the Sept 2013
EoR build that pairs with refs/acclient.pdb
(expected GUID {9e847e2f-777c-4bd9-886c-22256bb87f32}).

BP-driven A6 captures cannot proceed until the matching binary is
installed. User needs acclient.exe v11.4186 (linker timestamp
2013-09-06) to match our PDB.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 18:45:32 +02:00
Erik
b9c111b80d docs(O): O-T1 audit shipped + Phase O spec amended
O-T1 audit (REPORT-ONLY) maps acdream's transitive closure on WorldBuilder:
33 files / ~7.7K LOC across Chorizite.OpenGLSDLBackend (28 files) and
WorldBuilder.Shared (5 files). Verdict on O-Q1 (thread-model): SAFE —
adapters run render-thread only; no worker-thread access to WB code.

Spec amendments incorporated via brainstorm:

- O-D7: Refactor ObjectMeshManager to take DatCollection directly (not
  via adapter). T4 safety check — fall back to thin adapter if call-site
  count >20.
- O-D8: Drop LandSurfaceManager, EnvCellRenderManager, PortalRenderManager,
  TerrainRenderManager from the extract list — audit confirmed not reachable
  (we have our own ports or never used them).
- O-D9: Promote 3 internal types in Chorizite to public on extraction
  (EmbeddedResourceReader, TextureFormatExtensions, BufferUsageExtensions).
- O-D10: Strip [MemoryPackable] from TerrainEntry (we don't serialize).
- O-D11: Namespace AcDream.Core.Rendering.Wb.* for extracted code.
- O-D12: Drop ResolveId + [indoor-upload] NULL_RESULT diagnostic block.

Task breakdown: T6 (EnvCell/portal) eliminated; T5 (stateless helpers)
shrinks to 0.5d; T4 (mesh + refactor) grows to 2.5d. Net effort estimate
holds at ~7.75d.

All originally-open spec questions are now closed (Q1/Q2/Q3/Q4) or
deferred to T3 with an explicit verify step (Q5: SixLabors.ImageSharp
reachability).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:35:38 +02:00
Erik
e702dec7a3 docs(O-T1): session handoff prompt for Phase O Task 1 (WB usage audit)
Self-contained prompt for a fresh Claude Code session. The next session
reads it once, has all the context it needs, produces the WB-usage
closure audit at docs/research/2026-05-21-phase-o-t1-wb-audit.md,
and stops before any extraction. Investigation-only (the /investigate
skill applies). User reviews the audit before T2 begins.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:01:06 +02:00
Erik
f02bd1fb4d docs(handoff): M1.5 kickoff — pickup prompt + workaround inventory
Comprehensive session-end handoff for picking up M1.5 in a fresh
session. Includes:
  - Today's 11 shipped commits (table with retail oracle anchors)
  - Visual verification status at Holtburg inn + cottages
  - Open issues tagged M1.5 scope (#80, #81, #83, #88, #90, #93, #94)
  - Workaround inventory with A6.P4 removal criteria:
    - #90 sphere-overlap stickiness (PhysicsEngine.ResolveCellId:285)
    - TryFindIndoorWalkablePlane synthesis (TransitionTypes.cs:1294)
  - A6.P1 cdb probe spike methodology + 9 capture scenarios
  - Pasteable session-start prompt
  - Anti-patterns from today's session (especially: don't ship
    workarounds without flagging them upfront — #90 was a slip)
  - Code anchors + retail decomp anchors for A6 brainstorming

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 11:12:46 +02:00
Erik
6d18d879a2 docs(milestones): promote indoor work to M1.5 — primary focus
Continued indoor testing through 2026-05-20 surfaced a deep family
of physics + lighting bugs that span buildings AND dungeons. Today's
session shipped 5 surgical fixes (A4 + #89 + #90 + #91 + #92) that
close the user-visible "walls walk through at Holtburg inn" symptom,
but #90 specifically is a CLAUDE.md-rules workaround (sphere-overlap
stickiness on top of point-only cell containment) added without prior
approval. The underlying issue (BSP push-back distance probably
diverges from retail) hasn't been measured. Plus the umbrella #83
(indoor multi-Z walking) has been open since 2026-05-19 with multiple
aborted fix attempts; plus indoor lighting (#80 + #81 + new #93 +
#94) has been deferred as "M7 polish" but is actually part of the
same indoor-experience problem.

Promoting to a milestone of its own forces the work to be central,
retail-anchored, and complete — not another whack-a-mole patch.

Milestone M1.5 — "Indoor world feels right":
  Demo: enter Holtburg Sewer through the in-town portal, navigate
  through 5-7 rooms with stairs + a multi-Z chamber, exit back to
  town. Walls block. Stairs work. Items block. Lighting reads
  correctly. Cell transitions smooth.

  Phases:
    A6 — Indoor physics fidelity (cdb-driven)
    A7 — Indoor lighting fidelity (RenderDoc + retail-decomp driven)

  Issues in scope: #80, #81, #83, #88, #90 (workaround removal),
  #93 (new lighting umbrella), #94 (held-item spotlight),
  + TryFindIndoorWalkablePlane synthesis removal.

M2 ("Kill a drudge") deferred until M1.5 lands.

This commit updates:
  - docs/plans/2026-05-12-milestones.md (M1.5 block inserted, M2 moved
    to deferred status)
  - docs/plans/2026-04-11-roadmap.md (A6 + A7 sub-pieces detailed)
  - CLAUDE.md (Currently working toward updated to M1.5, M2 paragraph
    marked deferred, M1.5 baseline shipped paragraph added)
  - docs/ISSUES.md (#80, #81, #83, #88, #90 tagged M1.5 scope;
    new #93 indoor lighting umbrella + #94 held-item spotlight filed)
  - docs/research/2026-05-21-open-items-pickup-prompt.md (landscape
    table reorganized around M1.5 phases)

A6 + A7 specs to be drafted in the next session(s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:32:24 +02:00
Erik
1534990102 docs(roadmap): A4 shipped + #90 cell-tracking ping-pong filed
Phase A4 (multi-cell BSP iteration) ships in three commits (e6369e2,
493c5e5, 691493e — with revert 3add110 + reapply during visual
verification that proved A4 is not the cause of the issue surfaced).
1139 + 8 baseline maintained. 10 new unit tests pass. Wires retail's
CTransition::check_other_cells (acclient_2013_pseudo_c.txt:272717-272798)
into Transition.FindEnvCollisions.

Visual verification at the Holtburg inn vestibule surfaced a separate,
pre-existing M2 blocker (filed as #90): CellId ping-pongs between
outdoor 0xA9B40022 and indoor 0xA9B40164 on every wall push-back
because the push-back exits the indoor CellBSP volume, causing the
resolver to flip back to outdoor and bypass walls on outdoor ticks.
Indoor BSP results (Collided/Adjusted/Slid all firing) prove walls ARE
detected when the player is indoor; the aggregate "walls walk through"
appearance comes from CellId classification instability, not from
collision detection.

Bug reproduces fully with A4 reverted (launch-revert2.log captured 18
cell-id flips between 0xA9B40022 ↔ 0xA9B40164, 11 inside=True
building-transit events, 61 indoor-bsp queries firing the full
result distribution). A4 is correct and tested but dormant in
practice until #90 is fixed.

Updates:
  - docs/research/2026-05-20-phase-a4-shipped-cell-pingpong-finding.md (new)
  - docs/plans/2026-04-11-roadmap.md (A4 shipped row added)
  - CLAUDE.md (Indoor walking Phase A4 paragraph + next-step pointer
    to #90 with retail oracle anchor at acclient_2013_pseudo_c.txt:308742-308783)
  - docs/ISSUES.md (#90 filed, HIGH severity, M2-blocker)
  - docs/research/2026-05-21-open-items-pickup-prompt.md (landscape
    table updated — A4 closed, #90 promoted to top blocker)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 20:10:29 +02:00
Erik
fd9daddb37 docs(handoff): strategic pickup prompt for all 6 open items
After the 2026-05-21 session merged A1/A1.5/A1.6/A1.7 to main, six
discrete items remain. This doc maps them as a landscape rather than
single-phase:

- Collision (M2 critical path): A4 multi-cell BSP iteration → verify
  stairs → A2 PHSP inversion → A3 synthesis removal
- Rendering (M7 polish): indoor lighting + spotlight-projection bugs

The recommended order is A4 first (biggest user payoff, unblocks A3),
then stairs verification, A2 + A3 paired, lighting in a separate
session. A3 must NOT ship before A4 — that's the Bug A regression
from 2026-05-20.

Includes a pasteable session-start prompt that the user can box into
a fresh Claude Code session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 15:10:23 +02:00
Erik
f80b53763f docs(handoff): update pickup prompt to point at main + fresh worktree
After merging the 2026-05-21 session into main (56d2b5e), update the
pickup prompt so the next session starts from main and creates its
own worktree for the A4 work — not the now-merged lucid-goldberg
branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 15:05:07 +02:00
Erik
56d2b5e4a1 docs(physics): handoff for 2026-05-21 collision-fix session
Captures everything that shipped in the session — A1, A1.5, A1.6,
A1.7 plus the walk-miss probe spike — and what's still open:

- A4 (multi-cell BSP iteration) — the next big architectural fix,
  closes the "walls walk-through-able in vestibule cells" gap
- A2 (PHSP inversion) — small fix, but only meaningful paired with A3
- A3 (synthesis removal) — needs A4 in place first to avoid
  reverting back to Bug A's free-fall regression
- Lighting bugs (indoor lighting + spotlight projection) — M7 polish,
  separate session

Includes per-fix commit SHAs, code anchors, retail decomp anchors,
probe + launch reference, anti-patterns, and a fresh-session pickup
prompt for boxing into Claude Code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 14:42:47 +02:00
Erik
bb1e919ef2 docs(physics): spec + plan + findings for ISSUES #83 walk-miss probe spike
Three docs from the indoor walk-miss probe spike landed in commits
27c7284..a2e7a87:

- Spec: design of the [walk-miss] + [floor-polys] diagnostic emissions
  with the H1/H2/H3 disambiguation matrix.
- Plan: 3-task TDD implementation plan (flag, aggregator, emissions).
- Findings: live-capture analysis showing H3 (walkable_hits_sphere /
  adjust_sphere_to_plane synthesis rejection) is the dominant defect.
  817 of 876 ground-contact misses (93%) cluster at dz~0.48 m, while
  the 7 HITs all sit at dz~0.46 m — a 2 cm boundary between working
  and broken that points at the sphere-overlap math, not the probe
  distance. H1 (multi-cell iteration missing) is real but only 3%
  of misses, secondary. H2 (probe distance) ruled out.

Next step: line-by-line decomp comparison of FindWalkableInternal /
walkable_hits_sphere / adjust_sphere_to_plane against retail at
acclient_2013_pseudo_c.txt:322032 / :323006 / :326793, then design
the fix in a follow-up session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:00:11 +02:00
Erik
d258334573 docs(handoff): pickup prompt for indoor walking doorway investigation
Companion to the Bug A wrong-scope handoff (35c266a). Provides the
boxed copy-paste prompt for a fresh session + quick reference for the
user and the helper:
- Branch state + KEEP/REMOVE recommendation
- Anti-patterns to avoid (don't repeat Bug A, validate risks with
  probe data, stop at three failed verifications)
- Code anchors for Mechanisms A/B/C in our code
- Retail decomp anchors for the doorway investigation
- Probe + diagnostic env var menu
- 5-scenario visual verification list
- Launch command with UTF-8 conversion step

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 09:55:47 +02:00
Erik
35c266a800 docs(handoff): indoor walking Bug A wrong-scope handoff
Bug B (indoor BSP world-origin fix) shipped today at de8ffde.
Bug A (delete per-frame walkable-plane synthesis) attempted and
reverted at 0a7ce8f. Real bug is deeper than scoped:

Indoor cell floor polys don't cover the player's full XY range when
crossing thresholds (doorways). Step-down probes miss past the floor
edge, Mechanism C (post-OK step-down) can't catch the player,
ContactPlane invalidates, gravity pulls them through the void.

We have all three retail CP retention mechanisms (A, B, C). The
defect is geometry, not retention. Either dat-decoder missing some
floor polys, or cell-transition timing too late, or some retail
mechanism we haven't traced.

Handoff includes:
- State of every commit on this branch + KEEP/REMOVE recommendation
- Bug B evidence and recommendation to ship to main
- Bug A failure analysis with probe data
- Mechanisms A/B/C location in our code vs retail decomp anchors
- 5 prioritized investigation targets for fresh session
- Anti-patterns to avoid (don't repeat Bug A approach)
- Lessons learned (probe-first discipline, risk-as-falsification,
  3-fails-in-a-session stop signal, Matrix4x4.Decompose idiom,
  binary-timestamp paranoia)

Recommendation: merge Bug B alone, leave the rest for fresh session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 09:38:13 +02:00
Erik
7034be9294 docs(handoff): ContactPlane retention investigation pickup prompt
Self-contained fresh-session prompt that points at the BSP-port
shipped-handoff, summarizes the foundation work to keep vs delete,
notes the retail decomp anchors for CTransition::transitional_insert /
last_known_contact_plane, and includes the session-lesson reminder:
probe-first, design-second.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 07:06:11 +02:00
Erik
c6b3fd6ebf docs: indoor walkable-plane BSP port partial-ship handoff
Foundation work (6 commits ff548b9..f845b22) landed but visual
verification 2026-05-19 FAILED to fix the user-reported indoor bugs.
Documenting the deeper diagnosis + the next phase target without
reverting the foundation work.

What landed (kept):
- BSPQuery.FindWalkableInternal gained ref ushort hitPolyId (Task 1).
- New public BSPQuery.FindWalkableSphere wrapper over the existing
  retail-faithful walkable finder (Task 2).
- Transition.TryFindIndoorWalkablePlane refactored through it,
  PointInPolygonXY deleted (Task 3).
- [indoor-walkable] runtime-toggleable probe (Task 4).
- 5 new tests + 9 updated existing tests, all green; build clean.

What didn't fix: cellar descent FAIL, 2nd-floor walking FAIL
(intermittent falling-stuck), single-floor cottage REGRESSION (was
stable, now intermittent falling-stuck), phantom collisions PERSIST.

Probe evidence: 1443 MISS / 2 HIT over 1445 calls. Smoking gun:
foot-sphere-tangent-to-floor case fails PolygonHitsSpherePrecise's
|dist| > radius - epsilon check by ~0.0002. The BSP walker is
correct; the caller (TryFindIndoorWalkablePlane) is misusing it.

Root cause (deeper than originally diagnosed): TryFindIndoorWalkablePlane
exists only as a Phase 2 commit eb0f772 stop-gap. Retail doesn't
synthesize a ContactPlane per frame — retail RETAINS the previous
frame's plane when the BSP says no collision. Retail's find_walkable
only runs inside step_sphere_down (a sweep), never as a standing-still
query.

Next phase target: port retail's ContactPlane retention so the
resolver retains state across frames. Likely eliminates the per-frame
TryFindIndoorWalkablePlane call entirely. Foundation work (BSP walker
+ probe + tests) remains useful regardless.

ISSUES #83 remains OPEN with the deeper diagnosis.
Roadmap header updated to reflect partial-ship status.
Handoff at docs/research/2026-05-19-indoor-walkable-plane-bsp-port-shipped-handoff.md.

Spec: docs/superpowers/specs/2026-05-19-indoor-walkable-plane-bsp-port-design.md
Plan: docs/superpowers/plans/2026-05-19-indoor-walkable-plane-bsp-port.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 07:03:14 +02:00
Erik
d942ff73c0 docs(handoff): retarget pickup prompt — indoor/collision/physics/dungeons only
User explicitly redirected the next-phase track: no M2 (kill-a-drudge), stay
on indoor walking issues, collision, physics, and dungeons. Update the
pickup prompt to reflect this:

- Drop M2 from the candidate list entirely.
- Add #83 (walking up stairs) as the recommended next phase — pure
  indoor/physics, unblocks both multi-floor cottages AND dungeons.
- Add a "dungeon stress test" candidate (Path B) — verify Phase 2's
  portal traversal works on multi-cell indoor spaces.
- Move indoor lighting from "recommended" to Path E with a note that it
  depends on stairs (#83) landing first to be testable.
- Update the helper section with concrete file pointers per path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 19:52:17 +02:00
Erik
a5d6bb3536 docs(handoff): indoor walking Phase 2 pickup prompt for fresh session
After merging Phase 1 + Phase 2 to main at 1af49b7, file a pickup prompt
that orients a fresh Claude Code session: what shipped, what's open, the
four ranked candidate next phases (indoor lighting / M2 / #88 vibration /
triage), and key file pointers for whichever path is chosen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 19:35:47 +02:00
Erik
1af49b710e Merge branch 'claude/competent-robinson-dec1f4' — Indoor walking Phase 1 + Phase 2
Cluster A (Indoor walking Phase 1 — BSP cluster):
- WorldPicker cell-BSP occlusion → #86 closed
- CellId promotion via AABB containment (partial Phase D fix)
- Diagnostic infrastructure: [indoor-bsp], [cell-cache] probes

Indoor walking Phase 2 (Portal-based cell tracking):
- CellBSP + Portals wired into CellPhysics
- CellTransit static class: FindTransitCellsSphere + AddAllOutsideCells + FindCellList
- ResolveCellId rename + sphereRadius plumbing
- BuildingPhysics + CheckBuildingTransit (outdoor→indoor entry)
- Foot-sphere center fix (made portal tracking actually work in production)
- Indoor walkable-plane synthesis (closes the falling-stuck bug)

Closes ISSUES.md #84, #85, #86, #87.
Files new issues #88 (indoor object vibration) + #89 (port SphereIntersectsCellBsp).

Spec: docs/superpowers/specs/2026-05-19-indoor-portal-cell-tracking-design.md
Handoff: docs/research/2026-05-19-indoor-walking-phase2-shipped-handoff.md
2026-05-19 19:34:13 +02:00
Erik
a9c74d153a docs(phase): Indoor walking Phase 2 — Portal-based cell tracking shipped
Closes ISSUES.md #87 + #85 + the remaining wall-pass-through portion of
#84 (fully closes #84). Portal-graph cell traversal replaces Phase D's
AABB containment. Walking through doors promotes/demotes CellId correctly
via portal traversal; walls block from inside indoor cells; indoor walkable
plane is synthesized from the cell's floor poly so the resolver tracks
walkability correctly during indoor movement.

Files two new issues: #88 (indoor static objects vibrate — pre-existing,
spotted during Phase 2 testing) and #89 (BSPQuery.SphereIntersectsCellBsp
— follow-up to make CheckBuildingTransit retail-faithful; currently uses
radius-less PointInsideCellBsp as a documented approximation).

ISSUES.md: #87, #85, #84 moved to DONE. #88 + #89 filed.
Roadmap: Indoor walking Phase 2 added to shipped table.
CLAUDE.md: recent-phase paragraph updated to reflect Phase 2 shipped.
New handoff: docs/research/2026-05-19-indoor-walking-phase2-shipped-handoff.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 19:31:22 +02:00
Erik
f0900ebe12 docs(phase): Cluster A — partial ship + handoff
Cluster A's investigation pinned #86 (picker) as structural and closed
it (Phase B). #84 and #85 both pinned on missing indoor cell tracking;
Phase D promoted CellId via AABB containment which un-stuck the
spawn-in-building case (closes #84 partially) but proved too tight for
threshold/doorway cells to keep CellId indoor during normal walking.
The proper fix is retail's portal-based cell traversal; filed as a
new ISSUES.md issue (see body) for the follow-up phase. Phase E
diagnostic infrastructure ([cell-cache] + extended [indoor-bsp]) stays
in place as scaffolding for that work.

ISSUES.md: #86 → Recently closed. #84 status updated to PARTIAL with
resolution paragraph. #85 status update note added. New issue #87 filed
for portal-based indoor cell tracking.

Roadmap: Cluster A added to Recently shipped with partial-ship note.
Forward entry added for the portal-traversal follow-up under Phase G.

CLAUDE.md: current-phase paragraph updated to reflect Cluster A partial
ship. Next phase deferred to Claude's choice in a future session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 16:12:24 +02:00
Erik
eeb45e16e3 docs: file #87 — retire WB fork band-aid via geom-only API
Phase 2's one-line WB patch (Setup-prefix guard at ObjectMeshManager.cs:1230)
fixed the symptom but is structurally a band-aid. CLAUDE.md's
no-workarounds rule says we should retire it.

The proper fix is switching our EnvCell rendering from the
general-purpose PrepareMeshDataAsync entry point (which iterates
static-object parts + emitters we don't need + triggers the buggy
TryGet<Setup> call) to WB's narrower PrepareEnvCellGeomMeshDataAsync
API at ObjectMeshManager.cs:386. That function only builds cell
room mesh — which is the only thing we use WB for at the cell
level. Static objects are already hydrated separately, particle
scripts already run via our own EntityScriptActivator.

#87 is the issue tracking that refactor. When it lands the WB fork
returns to pristine state (no acdream-specific commits on the
acdream branch for this file).

Handoff doc updated to flag the patch as a known band-aid pending #87.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 14:31:14 +02:00
Erik
b04ad448fa docs(handoff): indoor follow-up brief + fresh-session kickoff prompt
After Phase 1+2 (indoor cell rendering — missing floors fixed),
9 follow-up issues (#78-#86 in docs/ISSUES.md) need their own
phases. This handoff doc gives the next session everything it needs
to start cold: probe infrastructure status, issue cluster groupings,
suggested phase order, and the verification approach that worked
for Phase 1+2.

Companion prompt file is a self-contained kickoff that can be pasted
into a fresh Claude Code session to start work on the cluster.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 13:36:18 +02:00
Erik
73288657fd docs(research): Phase 2 verification — floor renders, fix landed
User visually confirmed floors render in Holtburg Inn after the WB
TryGet<Setup> guard. Probe re-capture: 0 [wb-error] lines (was 385),
0 NULL_RESULT (was 55), Holtburg 123/123 cells complete (was 97/123).

Documents the nine pre-existing indoor bugs the user observed during
verification (see-through floor, indoor collision, stairs, walls,
clicking, indoor lighting artifacts, stabs-don't-react-to-atmospheric-
lighting, slope terrain lighting). All pre-existing; filed for follow-up
phases via docs/ISSUES.md.

Phase 2 complete.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 13:12:53 +02:00
Erik
b838eccb38 feat(wb): ConsoleErrorLogger + cause report — H1 swallowed-exception confirmed
Phase 2 diagnostic chain identified the EXACT cause of 26/123 Holtburg
cells silently failing in WB's PrepareEnvCellMeshData:
ArgumentOutOfRangeException thrown from Setup.Unpack inside
DatReaderWriter when WB calls TryGet<Setup>(stab.Id, ...) on a stab id
whose prefix is GfxObj (0x01xxxxxx), not Setup (0x02xxxxxx).
DatReaderWriter finds the file in Portal's tree (GfxObjs and Setups
share tree-lookups), attempts to parse GfxObj bytes as Setup format,
throws OOR. Exception bubbles to PrepareMeshData's outer try/catch
which silently swallows + returns null. Entire cell fails to upload.

This commit lands the diagnostic infrastructure that surfaced the bug:

- WbMeshAdapter: replaced NullLogger<ObjectMeshManager> with a small
  Console-backed ConsoleErrorLogger<T> private class. Filters to
  LogLevel.Error+. WB's existing _logger.LogError(ex, ...) at the
  swallow site now writes [wb-error] lines with type + message + top 5
  stack frames. Bridges WB's intentional log point to acdream's console.
- WbMeshAdapter: extended [indoor-upload] NULL_RESULT probe with
  reader-divergence diagnostic (ourCellDb.TryGet, wbResolveId.Count,
  wbSelectedType, wbDbIsPortal, wbDbTryGet<EnvCell>, hadRenderData).
  Made it possible to rule out cache-hits and reader-divergence as
  causes before identifying the real one.
- Cause report at docs/research/2026-05-19-indoor-cell-rendering-cause.md
  documents the full chain: 55 ArgumentOutOfRangeException stack traces
  captured in one launch, all from PrepareEnvCellMeshData line 1223.

The fix itself (1-line guard at WB's TryGet<Setup> call site) is applied
to references/WorldBuilder/.../ObjectMeshManager.cs — which is a git
submodule. Will be committed separately to the WB submodule after
visual verification.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 13:00:18 +02:00
Erik
25f009140a docs(research): Phase 1 indoor probe capture — H1 confirmed
Captured at Holtburg landblock 0xA9B4 with ACDREAM_PROBE_INDOOR_ALL=1.

Result: 123 EnvCells in Holtburg get [indoor-upload] requested but
ONLY 97 get a matching [indoor-upload] completed. 26 cells silently
fail in WB's PrepareEnvCellMeshData / PrepareMeshData. The first
interior cell 0xA9B40100 — likely the inn entry or another major
building anchor — is among the failures, exactly matching the
user's "floor missing" symptom.

Other hypotheses ruled out:
- H2 (empty batches): completed cells have cellGeomVerts=14-86.
- H3 (cull bug): walk probe confirms cells pass all visibility filters.
- H4 (double-spawn): partCount values match expected SetupParts.
- H5 (transform double-apply): xform probe shows composedT==meshRefT;
  no double-apply.
- H6 (MeshRefs structure): lookup probe shows isSetup=True and
  partsHit≈partCount for uploaded cells.

Phase 2 plan: wrap PrepareMeshDataAsync with our own catch-and-log
in WbMeshAdapter so the swallowed exception (most likely cause of
the 26 silent failures, per WB ObjectMeshManager.cs:589) becomes
visible. Once we know the actual failure reason, target the fix.

Also flags IsEnvCellId false-positives on GfxObj IDs whose lower 24
bits ≥ 0x0100 — tightening recommended in Phase 2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 12:03:25 +02:00
Erik
a54cd7bef6 fix(lighting): match retail indoor ambient (0.20 neutral, not 0.10/0.09/0.08 warm)
Indoor cells rendered "almost black" because the hardcoded ambient at
GameWindow.cs:8342-8345 was an early-2026 guess (0.10, 0.09, 0.08 — half
retail brightness, warm-tinted) rather than the retail value. The named
retail decomp (acclient.pdb, Sept 2013 EoR build) shows
CellManager::ChangePosition @ 0x004559B0 calls
SmartBox::SetWorldAmbientLight(0.2f, 0xFFFFFFFF) whenever the player's
CObjCell::seen_outside flag is 0 — a flat 0.20 white floor, not a
dungeon-tone warm color.

Investigation also confirmed:
- EnvCell.dat does NOT carry inline lights — CEnvCell::UnPack reads
  numVisibleCells where Binary Ninja's heuristic decomp inferred
  "num_lights". Retail's CObjCell.light_list is populated at runtime via
  add_light() calls from neighbouring cell light registrations + per-cell
  static-object Setup.Lights, NOT from the dat byte stream.
- Setup.Lights from indoor static objects (entity.SourceGfxObjOrSetupId
  prefix 0x02xxxxxx) DO flow through LightInfoLoader.Load (line 5765)
  and reach LightManager via LightingHookSink. The wire is intact; the
  per-frame Tick + UBO upload chain (line 6865-6867) is intact.
- Retail's particle system does NOT emit lights from particles themselves.
  The light comes from the owning Setup's LightInfo records.

Pre-existing failures in DispatcherToMovementIntegrationTests, BSPStepUpTests,
and MotionInterpreterTests are on the branch already and unrelated to this
change (verified by stashing + retesting).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 10:14:25 +02:00
Erik
677266d477 docs(research): handoff for issue #77 — close-range auto-walk + pickup overshoot
Self-contained handoff doc for a follow-up focused session that fixes #77.
Captures: the two bugs (NPC at walking range never auto-walks; pickup at
walking range overshoots and snaps back), the trace evidence from Step 2's
verification run (cmd=0x0005 speed=-1.84 from ACE), four ranked
root-cause hypotheses (H1 missing BeginServerAutoWalk fire / H2
walk-run-threshold misclassification / H3 negative ForwardSpeed
sign-interpretation / H4 arrival predicate firing too early), the
reproduction recipe with ACDREAM_PROBE_AUTOWALK=1, acceptance criteria,
and the "don't workaround, fix root cause" guardrail.

The auto-walk diagnostic infrastructure already exists from Phase B.6
work — the next session just turns it on and reads the trace.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 08:38:31 +02:00
Erik
2950cd5740 docs: rewrite handoff — M2 redirected from "kill a drudge" to indoor walkability
User chose fundamentals-first after M1 landed: indoor walking is
untested (M1 only verified outdoor + doorway), indoor lighting is
broken, camera clips into walls indoors. Better to fix indoor
foundations before stacking combat on top.

Three sub-phases proposed for the new M2:
  1. Camera correctness (~1 day)
  2. Indoor collision audit (~1 week)
  3. Indoor lighting basics (~1-2 weeks)

Combat ("Kill a drudge") slides to M3.

Next session opens with superpowers:brainstorming to scope the
demo scenario + agree on sub-phase boundaries + update the
milestones doc + CLAUDE.md to formalize the reorder.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 21:01:30 +02:00
Erik
5d79dd3b88 docs: session handoff 2026-05-16
Captures M1 landing, Phase B.6 architectural details, new rules
(no-workarounds, no-demo-videos, graceful-shutdown), M2 next steps,
and test baselines for fresh-session pickup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 17:53:11 +02:00
Erik
520badd566 docs(B.6+B.7): ship handoff — 36 commits, faithfulness audit, workaround retirement plan
Covers the 2026-05-15 session in full: B.6 local-player auto-walk on
inbound MoveToObject (issue #63 working), B.7 Vivid Target Indicator
MVP, WorldPicker tightening (#59 closed).

Includes:
- 36-commit table cf22f9c..e49c704
- Wire-format facts (MovementType 6/7/8, WalkRunThreshold, heartbeat cadence)
- Auto-walk state machine current shape + GameWindow wiring
- Picker + target-indicator current shapes
- Honest faithfulness audit (user-requested) — workarounds are our bugs not ACE's
- Closed issues (#59, #62, #67) + open follow-ups (#65, #66, #68, #69)
- Reproducibility commands + diagnostic env vars
- Files touched
- Workaround retirement plan (single fix retires four workarounds: per-tick outbound)
- Next-session entry points (sign indicator size, #66 MovementType=8, etc.)

Single biggest lesson surfaced in session: when a workaround starts feeling
load-bearing, find the heartbeat-cadence root cause first. The 10 Hz
AutonomousPosition bump (301281d) closed #67 and tightened firing distance
for every other interaction in one commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:29:53 +02:00
Erik
d132fcccfb docs(B.5): ship handoff + roadmap/CLAUDE update + file #63 #64
Phase B.5 (ground-item pickup, close-range path) shipped and
visual-verified 2026-05-14 at Holtburg. M1 demo target 4/4 ("pick up
an item") met.

New ship-handoff doc captures the 5-commit history including the
post-visual-test PickupEvent (0xF74A) wire-handler fix that closes
the local-despawn gap.

Roadmap and CLAUDE.md updated to reflect the ship + the new follow-up
issues:

  - #63 (MEDIUM) — server-initiated MoveToObject auto-walk not
    honored; blocks double-click pickup + out-of-range F. Filed as
    candidate Phase B.6. holtburger has the reference implementation.
  - #64 (LOW) — local-player pickup animation does not render
    (retail observers see it correctly). Likely a self-echo filter
    dropping UpdateMotion(Pickup) on the local player.

Carry-overs from B.4c (#61 link-cycle flash, #62 PARTSDIAG null-guard)
unchanged.
2026-05-14 16:23:20 +02:00
Erik
86440ff04a docs(B.5): fresh-session handoff for BuildPickUp + ground-item interaction
Captures post-B.4c state, click-NPC investigation findings (chain
already wired via Tell/CommunicationTransientString/etc; verify
opportunistically during B.5 visual test), and B.5 scope decisions
made in chat before the user requested a session handoff:

- Trigger: F-key (SelectionPickUp action, already bound)
- Target: requires _selectedGuid (no pick-under-cursor fallback)
- Wire opcode 0x0019 (GameAction.PutItemInContainer)
- Payload: itemGuid + containerGuid + placement (12 bytes)
- Container = _playerServerGuid
- Three changes in two existing files (~50 LOC total)

Plus carry-overs from B.4c (#61 cycle-boundary flap, #62 PARTSDIAG
null-guard), the B.4b ID-translation gotcha pattern to watch for,
and the standard ACE session-race tip.

Branch `claude/phase-b5-pickup` (renamed from
`claude/investigate-npc-click`) is the workspace; the fresh session
should start there.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 14:35:52 +02:00
Erik
8bb81db659 docs(B.4c): correct handoff fabrications surfaced by final review
Opus final review of B.4c flagged that Task 4's handoff doc invented
implementation details that don't exist in the code:

1. IsDoorSpawn claimed to check "spawn.WeenieObj.WeenieType == 8 OR
   IsDoorName(spawn.Name)" — the actual code is just IsDoorName(spawn.Name)
   delegating to "name == "Door"". No WeenieType lookup exists.

2. A "_doorSequencers" per-door dict was referenced in three places — that
   dict doesn't exist. The actual code reuses the existing
   _animatedEntities[entity.Id] dict (same one that holds creatures + the
   player), with Animation = null! per the existing pattern at line 7885.

3. The UM dispatch path was described as a new B.4c-added branch with
   pseudocode — that's wrong. B.4c does NOT add a new dispatch path;
   OnLiveMotionUpdated's existing TryGetValue against _animatedEntities
   handles doors automatically once Task 1's spawn-time branch registers
   them. The only UM-dispatch B.4c contribution is the [door-cycle]
   diagnostic line, gated on IsDoorName.

Corrects sections "At world load (spawn time)", "When the door opens",
"Per-frame mesh rebuild", and "Door types covered" to reflect the actual
shipped code. cmd→motion mapping (cmd=0x000C → open, cmd=0x000B → close)
left as-is — it was correct.

No code change. Verified by re-reading GameWindow.cs IsDoorSpawn /
IsDoorName helpers, the Task 1 spawn-time branch body, and the
TickAnimations sequencer dispatch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 08:03:45 +02:00
Erik
ebdbf821dc docs(B.4c): ship handoff + close #58 + file #61 #62 + roadmap/CLAUDE update
Phase B.4c shipped end-to-end 2026-05-13. Holtburg inn doorway
double-click verified: door visually swings open, player walks
through, door visually swings closed.

4 implementation commits:
- B.4c Task 1: door spawn-time AnimationSequencer with state-seeded cycle
- B.4c Task 2: [door-cycle] diagnostic in OnLiveMotionUpdated
- B.4c Task 2 review: IsDoorName shared predicate + durable comment + UM locals
- B.4c stance fix: NonCombat = 0x3D (not 0x01); read spawn.MotionState

Closes #58. Files:
- #61 (AnimationSequencer link->cycle frame-0 flash; visible as brief
  flap at end of door swing; low-severity polish)
- #62 (PARTSDIAG null-guard for sequencer-driven entities; latent
  not currently reachable for doors)

Memory file project_interaction_pipeline.md updated outside the repo.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 07:50:36 +02:00
Erik
48ce52c6ed docs(B.4b): final-review polish — file #59 #60 follow-ups + handoff correction
Final whole-branch code review (Opus) surfaced two Important post-merge
follow-ups + a one-word inaccuracy in the handoff doc:

- #59: tighten WorldPicker per-entity Setup.Radius (M1-deferred; the
  ServerGuid==0 invariant is load-bearing and worth documenting before
  L.2d's CBuildingObj port lands).
- #60: port retail's obstruction_ethereal downstream path so combat-HUD
  contact reporting works for ethereal creatures (M2-combat).
- handoff: corrected "Added a _entitiesByServerGuid reverse-lookup" to
  "Used the pre-existing _entitiesByServerGuid" — the dict has existed
  since Phase 6.6/6.7; slice 1c used it, didn't add it.

Review verdict: branch ready to merge to main.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 19:43:38 +02:00
Erik
2c9bdb512b docs(B.4b): ship handoff + close #57 + file #58 + roadmap/CLAUDE update
Phase B.4b shipped end-to-end 2026-05-13. Holtburg inn doorway
double-click verified: pick -> BuildUse -> ACE SetState reply ->
ID-translated registry update -> CollisionExemption exempts ->
player walks through. M1 demo target "open the inn door" met.

9 commits on this branch:
- Tasks 1-4 per plan (BuildRay, Pick, rename, handler wiring)
- 4 bonus visual-test discoveries:
  * InputDispatcher double-click detection (was dead code)
  * DoubleClick activation gate fix in OnInputAction
  * L.2g slice 1b: CollisionExemption widened to ETHEREAL alone
  * L.2g slice 1c: ServerGuid -> entity.Id translation (silent blocker)

Closes #57. Files #58 for door swing animation (UpdateMotion routing
for non-creature entities, M1 deferred polish). Updates roadmap and
CLAUDE.md Phase L.2 paragraph. Memory file project_interaction_pipeline.md
updated outside the repo.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 19:33:27 +02:00
Erik
aba6c9ac7f docs(phys L.2g): slice 1 shipped handoff + B.4 gap discovery + plan-of-record
L.2g slice 1 is CODE-COMPLETE: parser + registry mutator + WorldSession
dispatcher + GameWindow subscriber (4 commits: 2459f28, d538915,
536a608, 108e386). Build clean, 6 new tests pass, baseline-stable
across the full suite. Per-commit + final integration code reviews
all approved.

Visual verification deferred: while running the Holtburg-doorway test,
Phase B.4's outbound Use handler turned out to be unwired. The wire
builders (InteractRequests.BuildUse), classes (SelectionState,
WorldPicker), input-action enums, and keybindings all exist — but
GameWindow.OnInputAction has no case for SelectDblLeft, so the click
silently does nothing. The inbound L.2g chain we just landed can't
fire until something sends an outbound Use.

This commit captures the handoff + reframes next-session work:

  * docs/research/2026-05-12-l2g-slice1-shipped-handoff.md (NEW)
    Full evidence: 4 shipped commits, end-to-end code flow, B.4
    discovery explanation, 4 minor + 1 Important review notes
    (the Important one is a test-coverage gap that the B.4b visual
    test will settle automatically), reproducibility recipe,
    next-session pick.

  * CLAUDE.md
    "Currently in Phase L.2" paragraph: L.2g slice 1 code shipped;
    visual test deferred to B.4b. Next-phase-candidates list:
    L.2g slice 1 (now done) replaced with the B.4b candidate
    pointing at the slice scope.

  * docs/plans/2026-04-29-movement-collision-conformance.md
    L.2g section gains a "Current shipped slice (2026-05-12):" table
    listing the 4 commits.

  * docs/plans/2026-05-12-milestones.md
    M1 phase-list updated: L.2g slice 1 (code) shipped; B.4 renamed
    "B.4 / B.4b" with the gap-discovery note + B.4b shape.

  * docs/ISSUES.md
    New issue #57 (HIGH) for the B.4 interaction-handler gap.
    Promoted to Phase B.4b; will close as
    DONE (promoted to Phase B.4b) when B.4b's design spec lands.

  * Memory file project_interaction_pipeline.md (in personal
    memory dir, not in this commit) updated to reflect reality.

Next session: Phase B.4b (~30-50 LOC, 1-2 subagent dispatches,
~30 min). Subscribe SelectDblLeft -> WorldPicker.Pick ->
InteractRequests.BuildUse -> _liveSession.SendGameMessage. Same
Holtburg-doorway visual test verifies both L.2g slice 1 and B.4b
in one pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 23:17:05 +02:00
Erik
34b7f1faa1 docs(phys L.2d): slice 1 + 1.5 shipped handoff + 3rd plan-of-record reframe
L.2d as scoped is essentially closed at the Holtburg site. The slice-1.5
trace settled the question: the "I can't walk through doorways" symptom
is a closed Door entity (Setup 0x020019FF named "Door") at the building
threshold, not a building-BSP-collision issue. Building BSP is healthy.

The two prior framings turned out wrong:
- L.2a handoff (2026-05-12): "per-cell walkability missing" — based on
  hit attribution pointing at the building, missed the Door cylinder
  also colliding per tick.
- L.2d slice 1 spec (2026-05-13 morning): "BSP shape fidelity, three
  hypotheses X/Y/Z" — ruled out by the trace once the probe labeling
  bug was fixed in slice 1.5.

Handoff doc captures full evidence, side findings (building double-
registration latent bug, missing PhysicsState in entity-source log),
and a candidates list for the next-session ordering discussion.

Plan-of-record L.2d sub-direction paragraph updated to match: "watch-
and-wait" mode, no more slices until a new shape-fidelity bug is
observed at a different site. Door-state handling becomes its own
sub-phase, scope deferred to project-ordering discussion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 19:46:45 +02:00
Erik
eb401e8cac docs(phys L.2a): handoff + next-session prompt + CLAUDE.md / plan-of-record updates
Documents the L.2a-slice-1/2/3 ship for the next session and updates
the project's source-of-truth docs to reflect current state.

New files:
- docs/research/2026-05-12-l2a-shipped-l2d-handoff.md — full cold-start
  handoff: what shipped, three findings (L.2e cell-id format gap, L.2c
  wall-slide working, L.2d sub-direction = CBuildingObj port), branch
  state, diagnostic surface inventory, files changed, open concerns,
  cold-start checklist, reproduction recipe.
- docs/research/2026-05-12-l2d-next-session-prompt.md — terse copy-paste
  prompt for the next Claude Code session.

Modified:
- docs/plans/2026-04-29-movement-collision-conformance.md — added "Current
  sub-direction" note under L.2d capturing the evidence-driven call:
  building-mesh fidelity issue, not door-state-toggle.
- CLAUDE.md — updated "Currently between phases" → "Currently in Phase
  L.2"; added L.2a shipped paragraph; added ACDREAM_PROBE_RESOLVE /
  ACDREAM_PROBE_CELL to Diagnostic env vars; prepended L.2d brainstorm
  to next-phase candidates list.

No code changes in this commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 18:15:16 +02:00
Erik
175ad14f8b Merge branch 'claude/friendly-varahamihira-7b8664' — Tier 1 entity-classification cache (closes #53)
Post-A.5 polish Priority 3. EntityClassificationCache keyed by
(entityId, landblockHint) tuple. Entity dispatcher cpu_us median ~1.2 ms,
p95 ~1.5 ms — ~66% reduction vs pre-Tier-1 baseline. Closes the
post-A.5 polish phase entirely (#52, #54, #53 all closed).

See docs/ISSUES.md #53 closure + memory/project_tier1_cache.md for the
24-commit chain, 4 bug-fix iterations, and the per-tuple-vs-per-entity
recurring trap pattern documented for future cache work.
2026-05-11 00:11:42 +02:00
Erik
c7021d8645 docs(phase-m): sharpen Phase M into design spec + opcode coverage matrix
Captures Phase M (Network Stack Conformance) as a fully-formed phase
ready to be picked up later. Three deliverables:

1. Design spec at docs/superpowers/specs/2026-05-10-phase-m-network-stack-design.md
   (~700 lines, 8 sections):
   - Bar C completeness target ("wireable on demand"): every wire opcode
     a 2013 EoR retail client receives or sends gets a parser/builder +
     golden-vector test + typed event in the new layered stack.
   - Three-layer architecture: INetTransport / IReliableSession /
     IGameProtocol, with WorldSession as a thin behavior consumer.
     Concrete C# interface signatures, sub-component decomposition.
   - Worktree-branch big-bang migration on claude/phase-m-network-stack;
     weekly rebase cadence; single --no-ff merge ships the phase.
   - Per-sub-phase entry/exit gates, conformance test plan (golden vectors
     + live capture replay + live ACE smoke), 10-row risk register, scope-
     cut order if calendar compresses.
   - Cost: 256 hours / ~6.4 weeks single-developer; 4-6 weeks calendar
     with subagent parallelization on M.1 + M.6.

2. Opcode coverage matrix at docs/research/2026-05-10-phase-m-opcode-matrix.md
   (~284 rows across 5 sections):
   - Section 1: 22 transport flags (14 implemented).
   - Section 2: 12 optional-header fields (10 partial).
   - Section 3: 51 top-level GameMessages (21 implemented).
   - Section 4: 103 GameEvent sub-opcodes inside 0xF7B0 (27 parsed,
     26 wired).
   - Section 5: 96 GameAction sub-opcodes inside 0xF7B1 (24 built,
     8 with live callers).
   - Roll-up: ~34% complete by raw opcode count. Biggest single
     unblocking step is wiring the 16 dead builders in section 5
     (Phase B.4 surface — Use / UseWithTarget / Allegiance / Inventory
     / Social / Cast / Appraise).
   - Sources cited per row: holtburger (629695a), ACE, named retail
     decomp, acdream current state.
   - Produced by 4 parallel research agents (one per class). Spot-check
     pass owed before M.1 closes.

3. Roadmap update: Phase M section trimmed to summary + status + pointer
   to the spec; the previously-tracked M.0 Tier 1 quick-wins are folded
   into M.3 / M.4 / M.6 per the spec; M.1 retained as the matrix
   construction sub-lane with status note.

Why this shape: the user goal is a complete, layered, testable network
stack that can be wired in as gameplay phases need it — independent of
whether each opcode is yet hooked to game state. The matrix is the
source of truth for "done"; the spec is the architecture the matrix
implements against; the roadmap is the index that points at both.

Decisions captured during the design discussion (in case they need
revisiting):
- Bar C ("wireable on demand") chosen over Bar A (holtburger parity)
  or Bar B (named-retail completeness).
- Three layers (INetTransport / IReliableSession / IGameProtocol)
  chosen over holtburger's two-layer split.
- Big-bang on a feature branch (worktree) chosen over strangler
  pattern; preserves live-ACE testing on main throughout the phase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 19:22:49 +02:00
Erik
b8b9845f50 docs(post-A.5): capture holtburger network-stack study + Phase M.0 quick-wins
Holtburger reference fast-forwarded from 88b19bd to 629695a (+237 commits).
Four parallel research agents produced a parity-first-pass between
holtburger's network stack and acdream's src/AcDream.Core.Net/.

Why captured now: study surfaced six small, high-confidence "Tier 1" fixes
that can ship before the bigger M.1-M.8 layer extraction. Most likely fix
for the longstanding "remote retail observer sees us not perfect" bug
(MoveToState wire-format mismatches). Two transport gaps (no EchoResponse
reply, eager port-switch) match recent holtburger fixes (403bc98, 99974cc).
One latent bug worth a 5-min check (ISAAC search-mode for out-of-order
ENCRYPTED_CHECKSUM packets).

Captured as Phase M.0 in the roadmap so the work survives the session and
can be picked up later. Existing M.1-M.8 lift unchanged; M.1 marked as
partially started since the research note is the parity-map deliverable
in draft form.

Files:
- docs/research/2026-05-10-holtburger-network-stack-study.md (new) — full
  study with ranked port candidates, recent commits worth knowing, and
  acdream-vs-holtburger file map.
- docs/plans/2026-04-11-roadmap.md — Phase M Plan-of-record updated with
  2026-05-10 pointer; M.0 sub-lane added before M.1; M.1 status note.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 17:52:26 +02:00
Erik
4abb838729 docs(post-A.5 #53): Tier 1 retry — mutation audit + cache design spec
The audit at docs/research/2026-05-10-tier1-mutation-audit.md enumerates
every entity.MeshRefs write site (5 STATIC at hydration, 1 DYNAMIC at
GameWindow.cs:7580 inside TickAnimations) and verifies that all 7
Position/Rotation write sites only touch entities in _animatedEntities.
Establishes the load-bearing invariant: an entity's renderer state is
stable from spawn to despawn iff entity.Id is NOT in _animatedEntities.

The spec at docs/superpowers/specs/2026-05-10-issue-53-tier1-cache-design.md
locks in the design from brainstorming on 2026-05-10:
- Static-only cache + DEBUG cross-check (option c) — catches future
  regressions of the prior bug class without paying perf cost in Release
- Separate EntityClassificationCache class injected into WbDrawDispatcher
- Cache the rest pose, not the full model matrix (Position/Rotation read
  live each frame so Release stays correct even if the invariant breaks)
- Pre-flatten Setup multi-parts at populate time (the bulk of the win)
- 15 new tests covering all invalidation paths + DEBUG cross-check +
  Setup pre-flatten + lifecycle pin

Closes the audit + design steps of the post-A.5 polish Priority 3 work.
Implementation plan owned by superpowers:writing-plans next.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 16:50:26 +02:00
Erik
15376c7a73 docs(post-A.5): cold-start handoff for the Tier 1 retry session (#53)
After the post-A.5 lifestone (#52) + JobKind plumbing (#54) work shipped,
only Priority 3 (Tier 1 entity-classification cache retry, ISSUE #53)
remains. This handoff captures the audit insights gathered during the
#52 investigation that the original post-A.5 handoff didn't have:

- MeshRef is a `readonly record struct` — its fields can NOT be mutated
  in place. The actual per-frame mutation for animated entities is the
  entire MeshRefs LIST replacement at GameWindow.cs:7474-7553. This
  reframes the cache design.
- _animatedEntities dict at GameWindow.cs:160 is the source of truth
  for which entities go through the per-frame rebuild path.
- Static entity = entity.Id NOT in _animatedEntities. Its MeshRefs is
  the same instance from spawn until rare events (ObjDesc / palette
  swap / part hide / scale apply).
- Recommended cache approach: static-only with explicit invalidation
  hooks on the network/spawn-time write sites enumerated in the doc.

Doc covers: where main is, what shipped this session, why the first
Tier 1 attempt failed, the pre-started audit, cache design options,
acceptance criteria, files to read, workflow for the next session, and
things-to-NOT-do.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 16:14:24 +02:00
Erik
c111312e13 docs(post-A.5): cold-start handoff for the next session
Captures the three deferred items from A.5 ship:
- ISSUE #52: lifestone visual missing (1-3 hours, fast win)
- ISSUE #54: JobKind plumbing through BuildLandblockForStreaming
  (~30 min - 1 hour, worker-thread efficiency cleanup)
- ISSUE #53: Tier 1 entity-classification cache retry (~5-7 days,
  biggest perf win remaining; needs animation-mutation audit before
  designing to avoid the freeze-pose bug from the first attempt)

Doc covers: A.5 final state + 3 high-value gotchas, files to read,
per-priority detail with effort estimates and acceptance criteria,
what NOT to do, the first-30-minute workflow, and the full A.5
commit chain for reference.

Phase is sized ~1 week if all three priorities land. The audit
step on Tier 1 is the highest-leverage investment.

Tier 2 + Tier 3 (static/dynamic split + GPU compute culling) are
explicitly out-of-scope for this phase — separate multi-week phases
per docs/plans/2026-05-10-perf-tiers-2-3-roadmap.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 10:16:10 +02:00