fix(N.4) Adjustment 2: revert Task 9 renderer-level routing

Smoke test flag-on showed characters/NPCs disappearing along with
static scenery. Root cause: Task 9 routed all
InstancedMeshRenderer.EnsureUploaded calls through WB. But that
renderer is used for BOTH tiers in production — character per-part
spawn (line 2302, per-instance) AND streaming-loader spawns (lines
5137 + 5155, atlas).

The renderer is tier-blind by design. Tier-routing belongs at the
spawn-callback layer per the spec's data-flow section:

- LandblockSpawnAdapter (Task 11) calls IncrementRefCount per
  unique GfxObj — atlas-tier only.
- EntitySpawnAdapter (Task 17) routes through per-instance path
  via TextureCache.GetOrUploadWithPaletteOverride.

This commit removes the sentinel pattern + 4 sentinel-skip checks
from InstancedMeshRenderer. Kept the _wbMeshAdapter constructor
parameter (unused for now) so GameWindow's wire-up doesn't shift.
Kept all the real WB pipeline construction in WbMeshAdapter
(it's the substrate routing will use in Week 2).

Verified flag-on === flag-off post-revert.

Plan updated with Adjustment 2 explaining the discovery + correct
architectural placement for routing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-08 13:48:30 +02:00
parent c49c6edde5
commit 4f318bcbba
2 changed files with 53 additions and 38 deletions

View file

@ -837,6 +837,47 @@ writing a real bridge that shares index caches with our `DatCollection`.
**No work for this task — skip and proceed to Task 7.**
---
### Adjustment 2 (2026-05-08): Task 9 routing reverted — tier decision belongs at spawn-callback layer
**Discovered during Week 1 visual smoke test**: with flag on, characters /
NPCs disappeared along with static scenery. Root cause: Task 9 routed
**all** `InstancedMeshRenderer.EnsureUploaded` calls through
`WbMeshAdapter.IncrementRefCount` and marked their cache entries with
`WbManagedSentinel`. But `InstancedMeshRenderer` is used for both tiers
in production:
- **Atlas-tier** call sites: `_pendingCellMeshes` drain
([GameWindow.cs:5137](../../../src/AcDream.App/Rendering/GameWindow.cs:5137)),
per-MeshRef GfxObj loop on `lb.Entities`
([:5155](../../../src/AcDream.App/Rendering/GameWindow.cs:5155)).
- **Per-instance-tier** call sites: per-part loop in spawn handling
([:2302](../../../src/AcDream.App/Rendering/GameWindow.cs:2302)) — this is
character / creature rendering driven by server `CreateObject`.
The renderer is **tier-blind by design**: it doesn't know spawn source.
Putting routing logic there violates separation of concerns. The spec's
Data-Flow section already specifies the right placement — routing happens
at the **spawn-callback layer**:
- `LandblockSpawnAdapter.OnLandblockLoaded(...)` (Task 11) calls
`IncrementRefCount` per unique GfxObj — atlas-tier only.
- `EntitySpawnAdapter.OnCreate(entity)` (Task 17) routes through
per-instance path (`TextureCache.GetOrUploadWithPaletteOverride`) —
never calls `IncrementRefCount` for atlas.
**Resolution:** reverted Task 9's renderer-level routing. Removed the
sentinel logic and the 4 sentinel-skip checks in
`InstancedMeshRenderer`. **Kept** the `_wbMeshAdapter` constructor
parameter (unused for now) so `GameWindow.cs` doesn't shift when
later tasks need adapter access. Kept all the real WB pipeline
construction in `WbMeshAdapter` (verified working under flag-off).
**Week 1 endpoint shifts:** "WB infrastructure constructed; flag-on and
flag-off visually identical." Routing arrives in Week 2 (Task 11) at
the correct layer. Smoke verification is now: flag-on === flag-off.
### Task 6 (original — kept for history)
**Files:**