acdream/docs/research/2026-05-08-phase-n3-handoff.md
Erik 6010827b21 docs: roadmap N.0 shipped + realistic N.2-N.9 estimates + N.3 handoff
Roadmap updates after Phase N.1 ship:
- Marks N.0 (submodule + project refs setup) as ✓ SHIPPED with the
  c8782c9 commit reference
- Updates N.2-N.9 effort estimates with realistic post-N.1 numbers
  (originals were 1-2 days / 1 week / 2 weeks; realistic numbers
  factor in conformance-test discovery, ACME-vs-Chorizite delta
  hunts, and the visual-verification-then-revert cycle that ate
  most of N.1's calendar time)
- Adds a "Lessons from N.1" subsection so future N phases benefit
  from the rotation-bug-conformance-test pattern, the ACME divergence
  insight, and the "whackamole = stop" rule
- Updates total calendar estimate to 3-4 months / 10-12 engineering
  weeks for N.2-N.9 (was 2-3 months / 6-8 weeks)

New handoff doc at docs/research/2026-05-08-phase-n3-handoff.md
captures everything a fresh agent picking up N.3 (texture decoding)
needs: phase context, what to read first, suggested task decomposition,
watchouts (especially the ACME-divergence and conformance-test
lessons), and where to start.

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

6.4 KiB

Phase N.3 handoff — texture decoding via WorldBuilder

Use this whole document as the prompt when handing off to a fresh agent. Everything they need to pick up cold is below.


Background you'll need

You're working in acdream, a from-scratch C# .NET 10 reimplementation of Asheron's Call's retail client. The project's house rule (in CLAUDE.md) is the code is modern, the behavior is retail.

acdream just shipped Phase N.1 (commits 26cf2b8 through ad8b931), the first sub-phase of a strategic migration to fork WorldBuilder (github.com/Chorizite/WorldBuilder, MIT) and depend on its tested rendering + dat-handling code instead of porting algorithms from retail decomp ourselves.

Read first:

  • docs/architecture/worldbuilder-inventory.md — the full taxonomy of what WB has and what we keep porting ourselves
  • docs/superpowers/specs/2026-05-08-phase-n-worldbuilder-migration-design.md — the parent design doc for Phase N
  • CLAUDE.md — especially the "Reference repos" section (now points at WB as the rendering BASE) and the workflow rules

Phase N.1 commit history (just shipped): read git log --oneline c8782c9..ad8b931 to see how N.0 + N.1 were structured. The pattern repeats for N.3.

What N.3 is

Replace acdream's texture decoding pipeline with WorldBuilder's Chorizite.OpenGLSDLBackend.Lib.TextureHelpers. WB handles INDEX16, P8, BGRA, DXT, and alpha-channel decoding. Our existing implementations of these are scattered across src/AcDream.App/Rendering/TextureCache.cs and possibly src/AcDream.Core/Meshing/ — find them with grep -rln "INDEX16\|P8 decode\|DXT\|BGRA" src/.

Acceptance criteria

  • Build green (dotnet build)
  • All existing tests green (the 8 pre-existing DispatcherToMovementIntegrationTests failures don't count — they exist on main)
  • New conformance tests added per format that's substituted (one xUnit Theory per: INDEX16, P8, BGRA, DXT). Each compares a fixed input byte array decoded by our path vs WB's path; assertions on output pixel array.
  • Visual verification at Holtburg (or wherever) shows no texture regressions: terrain texturing, mesh texturing, particle textures all look the same.
  • ISSUES.md updated with any known cosmetic deltas (the N.1 pattern — if WB and retail disagree on something subtle, file it, don't try to fix it inline).

Tasks (suggested decomposition)

Follow the N.1 plan structure (docs/superpowers/plans/2026-05-08-phase-n1-scenery-via-wb-helpers.md) as the template. Concretely:

  1. Audit our texture decode paths. Grep, list every file/method that decodes a texture. Map each to the WB equivalent in references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/TextureHelpers.cs (read it end to end first).
  2. Per-format conformance test. TDD style: write the test, run it to fail, then plumb the substitution. Conformance test fixture inputs should include real-dat byte sequences (read a known-good texture from a dat, encode the bytes as a hex blob in the test).
  3. Substitution. Replace each decode site with the WB call. Keep our GL upload pathways — those are NOT WB's responsibility.
  4. Visual verification. Launch the client at Holtburg, walk around, look at a tree (mesh texture), the ground (atlas texture), particles (the recent C.1 rain/clouds/aurora work), and a building (composite texture). Compare against retail or against a screenshot before the change.
  5. Delete legacy decoders once visual verification passes.
  6. Update roadmap + ISSUES as the final commit.

Watchouts (lessons from N.1)

  • ACME has a downstream fork with extra filters (references/WorldBuilder-ACME-Edition/). WB's TextureHelpers may have ACME-specific patches not yet in upstream. Compare both before assuming WB's version is canonical. We forked upstream WB; ACME is reference-only.
  • Conformance tests are non-negotiable. Phase N.1's rotation bug was caught by the conformance test. Don't skip them. If a test fails, it's a real divergence — investigate before "fixing" the test.
  • Whackamole stops the migration. If 3+ visual regressions appear on default-on, stop, file as ISSUES, ship. The migration goal is "use WB's tested code"; pixel-perfect equivalence with our broken hand-ports is not the goal.
  • Setup.SortingSphereSetup.CylSphere. The N.1 attempt at obj_within_block over-suppressed because we used the wrong radius source (sorting sphere too large). For texture decoding this likely doesn't matter, but the general lesson is: read WB's full source carefully before adapting; don't assume parallel methods do parallel things.
  • Per-vertex road check — STOP signal. If you find yourself reading ACME for "what's missing" and considering a per-vertex filter, STOP. N.1 tried this (commit e279c46), regressed visually, reverted in 677a726. ACME's filter set works as a coherent unit; pick-and-choose fails. If the N.3 work uncovers a similar ACME-only filter, file it in ISSUES and move on, don't port it inline.

Where to start

  1. git pull on main to get the latest (Phase N.1 just merged).
  2. Create a new worktree for the work: git worktree add .claude/worktrees/<your-name> -b claude/<your-name>.
  3. Read the three "read first" docs above.
  4. Run dotnet build && dotnet test to confirm clean baseline.
  5. Read references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/TextureHelpers.cs end to end. Take notes on the public API surface.
  6. Run the audit task (#1 in Tasks above). Output should be a markdown table of "our function / file:line / WB equivalent / format covered."
  7. Use superpowers:writing-plans to convert the audit into a concrete per-format plan. Then use superpowers:subagent-driven-development to execute it with fresh subagents per format.

Useful greps

  • grep -rln "INDEX16\|IndexedSurface\|P8\|DXT\|BGRA\|TextureFormat" src/ — find decode paths
  • grep -rln "TextureCache" src/ — find our cache layer
  • grep -n "public static.*Decode\|public static.*Convert" references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/TextureHelpers.cs — WB's public API

Open question to resolve early

Does Chorizite.OpenGLSDLBackend.Lib.TextureHelpers cover ALL the formats we use, or does it have gaps? Audit our texture types against WB's API in step 1. If WB is missing a format we need, the migration for that format gets deferred (file in ISSUES; keep our decoder for it; note in the roadmap).