fix(ui): T-1156 live rounds — zoom-compensated marker sizes; toggle-redraw regression pin

Live round 2 (the real bug): every nature-overlay marker size was a raw
screen-space constant drawn inside _canvas, whose scale IS view_zoom —
at Lendel's orbital fit zoom (0.0063) a 2.2px trunk dot rendered at
~0.014px, invisible; the same code at District's 3.75 zoom produced the
correctly-visible mouth ring, which is why one capture worked and the
headline rung didn't. Fixed via AtlasWindowGeometry.zoom_compensated_
size() (pure, floor-guarded) wired through every radius/line-width;
basin FILL points are positions and correctly stay unscaled. Suspect
tile-mode-rung-detection was ruled out live (granularity_v2=Region
confirmed in tile mode) but pinned with a named regression test anyway.
+8 pure-function tests incl. a numeric pin of the pre-fix magnitude
(<0.02px at orbital zoom); revert-verified by name. Draw-smoke suite
documented as supplementary (the shared SubViewport background harness
can pass vacuously under X11 BadMatch — the pure suite is the gate).

Live round 3 (drive-script bug, no product change): the lead's scratch
drive passed the button LABEL to set_overlay_visible() and the unknown-
id guard silently no-op'd — but the chase banked a real pin:
test_set_overlay_visible_gen_basins_flips_gate_and_redraws_nature_
overlay (draw-counting spy per the cold-start precedent; is_queued_for_
redraw does not exist in this build). Revert-verified.

Basins verified live: 7 Lendel watershed boundaries render at the
ruling's alphas. Suites: viewer 76/76, geometry-nature 42/42, nature-
overlay 22/22, zoom-ladder 50/50, no regressions across the cluster.

Tickets: T-1156

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 08:55:29 +02:00
co-authored by Claude Fable 5
parent 0d22e50e66
commit 60faf667a5
7 changed files with 314 additions and 15 deletions
@@ -218,3 +218,66 @@ func test_attractors_visible_at_rung_region_only() -> void:
assert_bool(AtlasWindowGeometry.attractors_visible_at_rung("Region")).is_true()
assert_bool(AtlasWindowGeometry.attractors_visible_at_rung("District")).is_false()
assert_bool(AtlasWindowGeometry.attractors_visible_at_rung("Quarter")).is_false()
# =============================================================================
# Coordinator live-eyeball finding (2026-07-23): zoom_compensated_size() —
# marker sizes must stay CONSTANT on screen regardless of _view_zoom
# (Araminta's ruling), but draw calls execute inside a Node2D whose .scale IS
# _view_zoom — a raw constant gets multiplied by that transform at render
# time. This function pre-divides so the transform's multiply cancels back
# out to the literal screen-space value.
# =============================================================================
## At zoom=1.0 (the canvas transform's identity scale) the compensated size
## must equal the input unchanged — no over/under-correction at the one zoom
## level where compensation is a no-op by construction.
func test_zoom_compensated_size_at_zoom_one_is_unchanged() -> void:
assert_float(AtlasWindowGeometry.zoom_compensated_size(2.2, 1.0)).is_equal_approx(2.2, 0.0001)
## The exact regression shape: at Lendel's real orbital fit zoom (~0.0063,
## live drive script), the compensated size must be much LARGER than the
## raw screen-space constant — inversely proportional to zoom — so that once
## the canvas transform re-multiplies it by view_zoom at render time, the
## EFFECTIVE on-screen size lands back at the literal ruling value, not a
## sub-pixel sliver.
func test_zoom_compensated_size_at_orbital_zoom_scales_up_inversely() -> void:
var view_zoom := 0.0063
var screen_space_size := 2.2
var compensated: float = AtlasWindowGeometry.zoom_compensated_size(screen_space_size, view_zoom)
# Round-trip: compensated * view_zoom must reconstruct the original
# screen-space size — this IS the property that makes the on-screen
# result zoom-invariant (the canvas transform performs exactly this
# multiply at render time).
assert_float(compensated * view_zoom).is_equal_approx(screen_space_size, 0.001)
assert_float(compensated).override_failure_message(
"at a tiny orbital zoom, the compensated size must be dramatically LARGER"
+ " than the raw screen-space constant — that's the whole point of the fix"
).is_greater(screen_space_size * 10.0)
## The exact BUG this fix closes, pinned as a regression: an UNCOMPENSATED
## radius (screen_space_size used directly, the pre-fix behavior) multiplied
## by Lendel's real orbital zoom produces a sub-pixel effective size — this
## is the "the ruling's px value, at orbital fit zoom, is invisible" claim
## from the coordinator's diagnosis, verified numerically rather than just
## asserted.
func test_uncompensated_radius_at_orbital_zoom_would_be_sub_pixel() -> void:
var view_zoom := 0.0063
var raw_screen_space_radius := 2.2 # RIVER_DOT_RADIUS_BY_CLASS_REGION[TRUNK]
var effective_size_if_uncompensated: float = raw_screen_space_radius * view_zoom
assert_float(effective_size_if_uncompensated).override_failure_message(
"an uncompensated radius at orbital zoom must be sub-pixel — pinning the"
+ " numeric magnitude of the bug this fix closes, not just its existence"
).is_less(0.02)
## A degenerate zero (or negative) view_zoom must not divide-by-zero/produce
## infinity/NaN — the floor guard keeps this function total.
func test_zoom_compensated_size_zero_zoom_does_not_blow_up() -> void:
var result: float = AtlasWindowGeometry.zoom_compensated_size(2.2, 0.0)
assert_bool(is_finite(result)).override_failure_message(
"a degenerate zero view_zoom must not produce inf/NaN"
).is_true()
@@ -14,14 +14,17 @@ const AtlasWindowNatureOverlay := preload("res://ui/implant/apps/atlas/atlas_win
## Minimal viewer stub — AtlasWindowNatureOverlay only reaches the viewer
## through get_held_granularity_v2()/get_body_radius_km()/get_held_center()/
## get_held_n()/get_cell_pixel_size()/is_overlay_visible(), the same
## duck-typed-viewer precedent test_atlas_window_overlay.gd's _ViewerStub
## already establishes for AtlasWindowOverlay.
## get_held_n()/get_cell_pixel_size()/get_view_zoom()/is_overlay_visible(),
## the same duck-typed-viewer precedent test_atlas_window_overlay.gd's
## _ViewerStub already establishes for AtlasWindowOverlay. get_view_zoom()
## added post-live-eyeball (coordinator finding, 2026-07-23): _draw() now
## reads it for the zoom-compensated marker-size fix.
class _ViewerStub:
var held_granularity_v2: String = "Region"
var body_radius_km: float = 6371.0
var held_center: Vector2i = Vector2i.ZERO
var held_n: int = 64
var view_zoom: float = 1.0
var overlay_visibility: Dictionary = {"gen_rivers": true, "gen_basins": false, "gen_attractors": false}
func get_held_granularity_v2() -> String:
@@ -39,6 +42,9 @@ class _ViewerStub:
func get_cell_pixel_size() -> float:
return 16.0
func get_view_zoom() -> float:
return view_zoom
func is_overlay_visible(overlay_id: String) -> bool:
return bool(overlay_visibility.get(overlay_id, false))
@@ -19,6 +19,25 @@
## godot4 --display-driver x11 --rendering-driver opengl3 \
## -s addons/gdUnit4/bin/GdUnitCmdTool.gd --ignoreHeadlessMode -c \
## -a res://tests/test_atlas_window_nature_overlay_draw_smoke.gd
##
## **Known limitation, verified directly (2026-07-23 zoom-compensation fix
## verification):** the shared _BackgroundRect/_render_to_image() harness
## (copied from test_atlas_window_overlay_draw_smoke.gd) occasionally fails
## to composite the COLOR_BG fill at all under a real X11/opengl3 run in this
## environment (sampled pixels read (0,0,0,0), not COLOR_BG — an unrelated,
## intermittent X11/SubViewport timing issue, confirmed via an XServer
## "BadMatch" warning in that same run's log). When that happens EVERY pixel
## reads as "non-background" regardless of what this overlay actually draws,
## making a low MIN_NON_BACKGROUND_FRACTION threshold pass VACUOUSLY (it
## would pass even with zoom-compensation deliberately broken — confirmed by
## direct revert-test). The terrain sibling suite is accidentally immune to
## this (its checkerboard composite covers most of the frame regardless of
## background correctness); this suite's SPARSE markers are not. **The
## reliable, environment-independent regression gate for the zoom-
## compensation fix is therefore the pure-function suite in
## test_atlas_window_geometry_nature.gd** (zoom_compensated_size()'s own
## tests) — this smoke suite is a supplementary "does it actually paint"
## check when the harness cooperates, not the primary gate.
class_name TestAtlasWindowNatureOverlayDrawSmoke
extends GdUnitTestSuite
@@ -44,11 +63,17 @@ static func _dummy_renderer_active() -> bool:
## Same duck-typed viewer contract as test_atlas_window_nature_overlay.gd's
## _ViewerStub, minus the SimBridge-signal machinery this smoke test doesn't
## need (layer1 is injected directly via _layer1, not through a response).
## view_zoom MUST be kept in sync with whatever zoom _render_to_image() is
## called with — the whole point of this smoke suite (post-live-eyeball,
## coordinator finding 2026-07-23) is proving markers stay visible at the
## REAL orbital fit zoom, not an artificially large test zoom that would
## mask the zoom-compensation bug the fix addresses.
class _ViewerStub:
var held_granularity_v2: String = "Region"
var body_radius_km: float = 6371.0
var held_center: Vector2i = Vector2i.ZERO
var held_n: int = 64
var view_zoom: float = 1.0
var overlay_visibility: Dictionary = {"gen_rivers": true, "gen_basins": true, "gen_attractors": true}
func get_held_granularity_v2() -> String:
@@ -66,6 +91,9 @@ class _ViewerStub:
func get_cell_pixel_size() -> float:
return 16.0
func get_view_zoom() -> float:
return view_zoom
func is_overlay_visible(overlay_id: String) -> bool:
return bool(overlay_visibility.get(overlay_id, false))
@@ -171,6 +199,7 @@ func test_region_rung_draws_visible_pixels() -> void:
# Zoom chosen so the held window's canvas footprint (held_n * cell_px =
# 64 * 16 = 1024 units) comfortably fills the 512px viewport.
var zoom: float = float(VIEWPORT_SIZE.x) / (float(stub.held_n) * stub.get_cell_pixel_size())
stub.view_zoom = zoom
var image: Image = await _render_to_image(overlay, zoom)
var fraction: float = _non_background_fraction(image)
@@ -200,6 +229,7 @@ func test_district_rung_still_draws_visible_pixels() -> void:
overlay._requested_body_id = "SmokeBody"
var zoom: float = float(VIEWPORT_SIZE.x) / (float(stub.held_n) * stub.get_cell_pixel_size())
stub.view_zoom = zoom
var image: Image = await _render_to_image(overlay, zoom)
var fraction: float = _non_background_fraction(image)
@@ -211,3 +241,41 @@ func test_district_rung_still_draws_visible_pixels() -> void:
)
% (fraction * 100.0)
).is_greater(MIN_NON_BACKGROUND_FRACTION)
## Coordinator live-eyeball regression (2026-07-23): the ORBITAL TILE MOSAIC
## rest state's REAL fit zoom on a Lendel-scale body (~0.0063, confirmed
## directly via a live drive script — held_n=19139 districts,
## cell_px=16, a ~1600px viewport) — NOT the comfortable ~0.5 zoom the
## sibling test above uses. Before the zoom-compensation fix, this exact
## zoom magnitude produced ZERO visible river/mouth pixels (a 2.2px trunk
## dot rasterized at ~0.014 screen px) despite RVR being on and the policy
## table correctly returning full Region visibility — the captures showed
## terrain-only with literally nothing drawn. Pins the regression at
## production scale, not a toy zoom that could accidentally still pass.
func test_orbital_scale_zoom_still_draws_visible_pixels() -> void:
if _dummy_renderer_active():
print(SKIP_REASON)
return
var overlay := AtlasWindowNatureOverlay.new()
var stub := _ViewerStub.new()
stub.held_n = 19139 # Lendel's own raw circumference, live drive script
stub.view_zoom = 0.0063 # Lendel's own live orbital fit zoom
overlay.viewer = stub
overlay._layer1 = _mock_layer1_dense()
overlay._requested_body_id = "SmokeBody"
var image: Image = await _render_to_image(overlay, stub.view_zoom)
var fraction: float = _non_background_fraction(image)
assert_float(fraction).override_failure_message(
(
"at Lendel's REAL orbital fit zoom (~0.0063), the Region-rung nature"
+ " composite must still render VISIBLE non-background pixels — got only"
+ " %.4f%% of the frame differing from COLOR_BG. This is exactly the"
+ " coordinator's live-eyeball finding: uncompensated screen-space marker"
+ " sizes get multiplied by the canvas's own zoom transform, vanishing"
+ " sub-pixel at the orbital rest state's tiny fit zoom."
)
% (fraction * 100.0)
).is_greater(MIN_NON_BACKGROUND_FRACTION)
+79
View File
@@ -16,6 +16,11 @@ const AtlasWindowRequest := preload("res://ui/implant/apps/atlas/atlas_window_re
# T-1142: district_extent()/canonicalize_district_center() — used to derive
# real (cols/rows_half) bounds for the wrap/pole-wall tests below.
const AtlasDescendGeometry := preload("res://ui/implant/apps/atlas/atlas_descend_geometry.gd")
# T-1156 wave 1 round 3: AtlasWindowNatureOverlay has no class_name (matching
# atlas_overlay_bar.gd/atlas_window_request.gd's own no-class_name precedent,
# review #8) — subclassing it (the _CountingNatureOverlay spy below) needs
# the preloaded script's PATH via `extends`, not a global class name.
const AtlasWindowNatureOverlay := preload("res://ui/implant/apps/atlas/atlas_window_nature_overlay.gd")
## Build a hand-authored DistrictWindowLayer dict (n=2, matching the shape
@@ -131,6 +136,80 @@ func test_set_overlay_visible_unknown_id_is_a_noop() -> void:
assert_bool(v.is_overlay_visible("not_a_real_overlay")).is_false()
## Counts real _draw() invocations on AtlasWindowNatureOverlay — CanvasItem
## exposes no public "is a redraw pending" query in this Godot version
## (confirmed directly: is_queued_for_redraw() does not exist on Node2D here
## — an earlier version of this test assumed it did and failed with
## "Invalid call. Nonexistent function"), so the only reliable signal that
## queue_redraw() actually had an effect is the engine calling _draw() again
## on a subsequent frame. Matches test_atlas_cold_start.gd's own
## _CountingOverlay precedent exactly (same file's own doc: "the only
## reliable signal... is the engine calling _draw() again") — subclasses the
## REAL AtlasWindowNatureOverlay so drawing still runs through genuine
## production code, this spy only adds counting.
class _CountingNatureOverlay extends AtlasWindowNatureOverlay:
var draw_count := 0
func _draw() -> void:
draw_count += 1
super._draw()
## Coordinator live-eyeball round 3 (2026-07-23): R1/R2 captures were
## byte-identical because a scratch drive script called
## set_overlay_visible("BAS", true) — the button LABEL, not the overlay id
## ("gen_basins") — which set_overlay_visible()'s own `not
## _overlay_visibility.has(overlay_id): push_warning(...); return` guard
## silently no-ops on. Real callers (atlas_overlay_bar.gd's
## _on_toggle_changed()) always pass def["id"], never the label, so product
## code was never actually broken — but this pins the EXACT gate the
## coordinator asked to verify: toggling gen_basins via the real viewer API
## must (a) flip is_overlay_visible("gen_basins") — the nature overlay's OWN
## draw gate, read live via viewer.is_overlay_visible() at _draw() time, not
## a stale copy — AND (b) actually cause the NATURE overlay (not just the
## terrain overlay/viewer) to redraw on the next frame, proven by swapping in
## a _draw()-counting spy (matching test_atlas_cold_start.gd's
## _CountingOverlay pattern) and confirming draw_count advances past a
## settled baseline after the toggle, with no other gesture.
func test_set_overlay_visible_gen_basins_flips_gate_and_redraws_nature_overlay() -> void:
var v: AtlasWindowViewer = auto_free(AtlasWindowViewer.new())
add_child(v)
assert_bool(v.is_overlay_visible("gen_basins")).override_failure_message(
"gen_basins must default to OFF (Araminta's ruling — BAS defaults off)"
).is_false()
# Swap in the counting spy (matching _CountingOverlay's own swap-after-
# construction shape) so entry's own queue_redraw() calls don't pollute
# the baseline, then let it settle before touching the toggle.
var spy := _CountingNatureOverlay.new(v)
v._nature_overlay.queue_free()
v._nature_overlay = spy
v._canvas.add_child(spy)
await get_tree().process_frame
await get_tree().process_frame
var baseline: int = spy.draw_count
assert_int(baseline).override_failure_message(
"sanity: the spy must have drawn at least once before the toggle, or"
+ " this test can't distinguish 'redrawn BY the toggle' from 'never"
+ " drawn at all'"
).is_greater(0)
v.set_overlay_visible("gen_basins", true)
await get_tree().process_frame
assert_bool(v.is_overlay_visible("gen_basins")).override_failure_message(
"the toggle must flip the draw gate is_overlay_visible() reads live"
).is_true()
assert_int(spy.draw_count).override_failure_message(
"the toggle must queue_redraw() the NATURE overlay specifically —"
+ " queue_redraw() on the viewer/terrain overlay alone leaves the"
+ " nature node's last frame cached (a Node2D child does not redraw"
+ " because its sibling did) — draw_count must have advanced past the"
+ " baseline (%d)" % baseline
).is_greater(baseline)
# =============================================================================
# T-1120 capture-API parity (the ticket's explicit note: must survive here too)
# =============================================================================
+32
View File
@@ -109,6 +109,38 @@ func test_enter_orbital_tile_mode_held_n_is_the_whole_body_extent() -> void:
assert_int(v._held_n).is_equal(raw_cols)
## Coordinator live-eyeball dossier (2026-07-23, suspect 2 — DIAGNOSED FALSE
## but pinned as a regression guard anyway per the coordinator's own
## instruction): AtlasWindowNatureOverlay's _draw() reads
## viewer.get_held_granularity_v2() to key its per-rung policy tables
## (RIVER_CLASS_VISIBLE_BY_RUNG etc.) — if that accessor returned anything
## other than the EXACT string "Region" while is_tile_mode() is true (an
## empty string, a stale District default, a different-cased tag...), the
## visibility tables would silently return their empty/default disposition
## and NOTHING would draw, indistinguishable from the live captures'
## "literally zero river dots" symptom. Live drive-script evidence
## (NATURE_DEBUG print, since removed) confirmed this was NOT the actual bug
## — get_held_granularity_v2() already correctly returns "Region" in tile
## mode — but this test makes that fact load-bearing instead of merely
## observed once, so a future refactor of _enter_tile_mode()'s
## _held_granularity_v2 assignment trips a named failure here.
func test_get_held_granularity_v2_is_exactly_region_string_in_tile_mode() -> void:
var v: AtlasWindowViewer = auto_free(AtlasWindowViewer.new())
add_child(v)
var radius_km := 6238.4 # GJ380c (Lendel) — needs tiling
v.enter_orbital({"body_id": "GJ380c", "body_radius_km": radius_km}, {})
assert_bool(v.is_tile_mode()).override_failure_message(
"this test's premise requires tile mode — Lendel must still need tiling"
).is_true()
assert_str(v.get_held_granularity_v2()).override_failure_message(
"AtlasWindowNatureOverlay's _draw() keys its ENTIRE per-rung policy off"
+ " this exact string — anything other than the literal 'Region' silently"
+ " empties every visibility table and draws nothing, indistinguishable"
+ " from the live-capture symptom (zero river dots at the orbital rest state)"
).is_equal("Region")
## **The live-round-3 regression, end to end for TILE mode:** enter_orbital()
## on GJ380c/Lendel followed by delivering ONE tile's wire-accurate response
## (clamped n=6,400, "Region" granularity_v2, the legacy sentinel in the old