fix(client): T-1153/T-1152 round 4 — mosaic canvas-local frame, offset recompute on rung crossing, tile texture RID lifetime; real-driver draw smoke

Three live-found rendering bugs, all invisible to green unit suites:
- _draw_tile_mosaic placed tiles from absolute district (0,0); canvas-
  local (0,0) is held_center - held_n/2 everywhere else, and tile-mode
  held_n is the whole-body extent — the entire mosaic drew tens of
  thousands of px off-canvas. New pure district_to_canvas_local() +
  viewer accessors route every tile through the shared frame.
- _maybe_reselect_rung updated held_n across crossings without
  recomputing _view_offset — the single-window composite landed off-
  canvas the moment any crossing happened (why District/Quarter were
  black too). New pure recompute_offset_for_held_n_change().
- _build_tile_texture created an unstored ImageTexture per _draw,
  racing the RenderingServer's deferred upload — CPU pixels correct,
  screen white. Per-tile-index texture cache, same reference-identity
  discipline as the single-window _cached_texture.

Structural close of the twice-bitten 'nothing asserts pixels' gap:
test_atlas_window_overlay_draw_smoke.gd renders overlay output into a
SubViewport and asserts visible pixels for both modes — runs under a
real driver (invocation documented in DEVOPS.md, visual_capture
precedent; migration to the T-1157 harness noted on that ticket), skips
loud-but-green under the gate's headless run (verified green-with-skips
AND genuinely red with detection forced off). +7 geometry/crossing
tests, all revert-verified. Targeted suites 270 green; gdlint clean.
This commit is contained in:
2026-07-22 14:41:00 +02:00
parent 9ffda88e57
commit 493a7345d3
7 changed files with 732 additions and 92 deletions
+26
View File
@@ -352,6 +352,32 @@ Key components:
- **CauseChain** (production ECS component) — Tracks causal attribution for testable observation sequences (D-030).
- **Deterministic replay** — Server simulation is deterministic given the same seed + input sequence. Replay logs enable regression testing (#201, critical).
### Real-rendering test exception: `test_atlas_window_overlay_draw_smoke.gd`
`tests/run-godot` hardcodes `--headless`, whose dummy driver produces no usable GPU
texture output (`SubViewport.get_texture().get_image()` returns unusable data). One
file needs real pixels — `client/tests/test_atlas_window_overlay_draw_smoke.gd` (T-1153
live round 4) renders `AtlasWindowOverlay` into a `SubViewport` and asserts real terrain
pixels were composited, closing a "did anything draw at all" gap that bit twice
(a tile-mosaic coordinate bug and an unstored-texture GPU-lifetime bug, both invisible
to cache-state-only assertions). It self-detects the dummy driver
(`DisplayServer.get_name() == "headless"`) and **skips** under the standard suite —
`tests/run-godot --filter test_atlas_window_overlay_draw_smoke` reports green-with-skips,
never a false failure that would bounce the push gate. To exercise its real assertions:
```bash
godot4 --display-driver x11 --rendering-driver opengl3 \
-s addons/gdUnit4/bin/GdUnitCmdTool.gd --ignoreHeadlessMode -c \
-a res://tests/test_atlas_window_overlay_draw_smoke.gd
```
Same underlying constraint as `tests/visual_capture.gd` (`tests/run-visual`), which is
the project's other real-driver exception — currently broken on this branch by the
retired `AtlasViewer` API (T-1157, capture-harness redesign). This file's scenarios are
slated to migrate into that redesigned harness once T-1157 lands, folding it into
`tests/visual.json` for consistency; until then it stays a standalone gdUnit file with
its own skip guard.
## Planning store (pql)
Tickets and decisions live in **pql**, not in the old SQLite wrapper scripts. Decisions