docs(N.4) Task 21: mark Week 3 complete + Adjustments 4-5

Week 3 ships: AnimatedEntityState (Tasks 16+18+19, commit ce72c57),
EntitySpawnAdapter routing server-spawned content through the existing
TextureCache.GetOrUploadWithPaletteOverride path (Task 17, commit
c02c307). 947 tests pass.

Adjustment 4: WorldEntity lacks HiddenPartsMask + AnimPartChanges
fields. Adapter scaffolding ships; AnimatedEntityState gets default
values (empty mask + empty override map). Plumbing deferred to Task 22
brainstorm — either add fields to WorldEntity or thread through a
separate parameter to EntitySpawnAdapter.OnCreate.

Adjustment 5: Task 20 (per-instance decode conformance) is structural.
Both old and new paths call the same TextureCache function — bytes
identical by construction. EntitySpawnAdapterTests already cover the
routing. No separate conformance test file needed.

Next: Task 22 (Week 4) — WbDrawDispatcher full draw loop. First task
that actually draws through WB and unlocks Adjustment 3's mitigation
(dual-pipeline cost resolves when legacy renderer can short-circuit
its upload for atlas-tier content).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-08 14:48:20 +02:00
parent c02c307bee
commit 312d3b3ee0

View file

@ -66,9 +66,9 @@ This plan is the **execution source of truth** for N.4. It is updated as tasks l
Status: **Living document — work in progress, started 2026-05-08.**
**Progress (2026-05-08):** Weeks 1 + 2 ✅ COMPLETE. WB pipeline running flag-on (constructed + ref-counted + per-frame Tick draining its queues). Three architectural adjustments documented: 1 (DefaultDatReaderWriter discovery, no bridge needed), 2 (renderer is tier-blind; routing belongs in spawn callbacks), 3 (FPS regression root-caused as dual-pipeline cost; Task 22's dispatcher will allow the legacy-renderer short-circuit). Build green, 912 tests pass, 8 pre-existing failures only.
**Progress (2026-05-08):** Weeks 1 + 2 + 3 ✅ COMPLETE. WB pipeline running flag-on (constructed + ref-counted + per-frame Tick draining its queues). Per-instance tier wired (`EntitySpawnAdapter` routes server-spawned entities through existing `TextureCache.GetOrUploadWithPaletteOverride` path; per-entity `AnimatedEntityState` accumulates AnimPartChange + HiddenParts data, ready for the dispatcher). Five architectural adjustments documented: 1 (DefaultDatReaderWriter discovery), 2 (renderer is tier-blind), 3 (FPS regression = dual-pipeline cost; resolves at Task 22), 4 (WorldEntity missing HiddenPartsMask + AnimPartChanges fields, plumbing deferred), 5 (Task 20 is structural — same function called both paths). Build green, 947 tests pass, 8 pre-existing failures only.
**Next: Task 16** (Week 3) — `AnimatedEntityState` type + per-instance customization path.
**Next: Task 22** (Week 4) — `WbDrawDispatcher` full draw loop. The first task that actually draws through WB and unlocks the dual-pipeline-cost mitigation from Adjustment 3.
| Task | Status | Commit |
|---|---|---|
@ -87,9 +87,18 @@ Status: **Living document — work in progress, started 2026-05-08.**
| 13 — Memory budget verification | ✅ deferred to Task 22 (Adj. 3) | — |
| 14 — Pending-spawn integration test | ✅ | `f4f0101` |
| Tick — drain WB pipeline queues | ✅ added per Adj. 3 | `bf53cb4` |
| 15 — Week 2 wrap-up | ✅ | (this commit) |
| 1621 — Week 3: per-instance + animation | pending | — |
| 2228 — Week 4: draw dispatcher + ship | pending | — |
| 15 — Week 2 wrap-up | ✅ | `36f7a60` |
| 16+18+19 — AnimatedEntityState + AnimPartChange + HiddenParts | ✅ | `ce72c57` |
| 17 — EntitySpawnAdapter | ✅ + Adj. 4 | `c02c307` |
| 20 — Per-instance decode conformance | ✅ structural (Adj. 5) | (no test file) |
| 21 — Week 3 wrap-up | ✅ | (this commit) |
| 22 — WbDrawDispatcher full draw loop | pending | — |
| 23 — Surface metadata side-table population | pending | — |
| 24 — Sky-pass preservation check | pending | — |
| 25 — Component micro-tests round-out | pending | — |
| 26 — Visual verification + flag default-on | pending | — |
| 27 — Delete legacy code paths | pending | — |
| 28 — Update memory + ISSUES + finalize plan | pending | — |
---
@ -935,6 +944,54 @@ without violating Adjustment 2's tier-blind-renderer principle.
infrastructure for Task 22 anyway. We just paid for it without
seeing FPS recovery yet.
---
### Adjustment 4 (2026-05-08): WorldEntity lacks HiddenParts + AnimPartChange fields — deferred plumbing
**Discovered during Task 17 implementation.** `EntitySpawnAdapter.OnCreate`
needed to populate `AnimatedEntityState` with the entity's `HiddenParts`
mask + `AnimPartChange` override map. But: `WorldEntity` (the per-frame
render-side struct) does not currently expose either field. Both pieces
of customization data live on the network-layer spawn record and are
consumed before the `WorldEntity` is built.
**Resolution.** Task 17 ships the adapter scaffolding with a TODO comment
acknowledging the gap. The created `AnimatedEntityState` always has an
empty override map + zero hidden mask. Per-instance customizations like
"hide this character's head" won't take effect with flag-on until the
plumbing lands.
**Why this is safe to defer.** No production path consumes
`AnimatedEntityState`'s override / hidden data yet — Task 22's
`WbDrawDispatcher` is the first consumer. By the time Task 22 lands, we
either:
1. Add `HiddenPartsMask` + `AnimPartChanges` fields to `WorldEntity` and
populate them at spawn time. Small change to the network → render
pipeline.
2. Inject them into `EntitySpawnAdapter.OnCreate` via a separate
parameter that the spawn handler provides directly (sidesteps the
`WorldEntity` change).
Option 1 is cleaner long-term; Option 2 is faster for landing Task 22
without touching WorldEntity. Decision deferred to Task 22 brainstorm.
### Adjustment 5 (2026-05-08): Task 20 (per-instance decode conformance) is structural, not byte-comparison
**Original plan.** Task 20 was supposed to compare RGBA8 output of
"old path" (`TextureCache.GetOrUploadWithPaletteOverride` direct) vs
"new path" (`EntitySpawnAdapter``ITextureCachePerInstance`
`TextureCache.GetOrUploadWithPaletteOverride`) to prove byte-identity.
**Reality.** Both paths call the **same function**. The new path adds a
seam interface (`ITextureCachePerInstance`) for testability but does
not modify the decode logic — the bytes are identical by construction.
A test asserting byte-equality would be tautological.
**Resolution.** Existing `EntitySpawnAdapterTests` cover the routing
behavior (does the adapter call the cache with the right args?). The
decode-byte conformance is structural: same function = same output.
Mark Task 20 ✅ structurally; no separate test file.
### Task 6 (original — kept for history)
**Files:**