Jeroen's hands-on report: rivers continuing under the ocean. Tyre's ruling implemented: the skeleton is rung-independent, the drawn coast is rung-indexed (warp cutoff admits more octaves per rung), so reconciliation is a presentation-frame operation — a draw-time clip against the SAME per-cell morphology verdict the terrain painter used, at the rung on screen. New pure module atlas_window_water_clip.gd: cell resolution across both paths (single-window direct; tile mode selects the containing tile by each tile's OWN echoed n with nearest- wrap re-expression against that tile's canonical center — response-is- source-of-truth + wrap discipline reused, not reinvented). Strict drop (no snap); offshore mouths suppressed (return with real termini in T-1170 — retirement markers at the clip sites); basins untouched; fail-open wherever no composite data has arrived (the clip refines presentation, never gates data). The _pos split feeds the SAME wrap- resolved district to both draw position and clip test so they can never disagree about the wrap image. 49 new tests incl. antimeridian and mid-progressive-arrival fail-open; revert-verified with precise attribution (breaking water detection fails exactly the 3 water tests, fail-open/land tests stay green); smoke-suite stub crash under a real driver caught and fixed (headless skip-gating masked it). 7 suites regression-free; gdlint clean. Tickets: T-1172 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
300 lines
12 KiB
GDScript
300 lines
12 KiB
GDScript
## T-1156 wave 1: a REAL draw smoke test for AtlasWindowNatureOverlay,
|
|
## matching test_atlas_window_overlay_draw_smoke.gd's established pattern —
|
|
## `draw_circle()`/`draw_rect()`/`draw_arc()`/`draw_colored_polygon()` calls
|
|
## require a live render pass under this engine version (confirmed directly:
|
|
## a plain unit test calling `_draw()` outside one throws "Drawing is only
|
|
## allowed inside this node's `_draw()`..."). Render into a REAL SubViewport,
|
|
## force a settle wait, and assert visible non-background pixels — proving
|
|
## the river-dot/mouth-ring/basin-polygon/attractor-glyph draw calls actually
|
|
## paint, not just that the state feeding them is correct (that half is
|
|
## test_atlas_window_nature_overlay.gd's job).
|
|
##
|
|
## **REQUIRES A REAL RENDERING DRIVER — SKIPS (not fails) under
|
|
## `tests/run-godot`'s hardcoded `--headless`**, same posture/rationale as
|
|
## test_atlas_window_overlay_draw_smoke.gd's own header doc (dummy driver,
|
|
## no GPU texture output — SubViewport.get_texture().get_image() returns an
|
|
## all-zero/unusable image under it).
|
|
##
|
|
## To actually exercise this file's assertions, run it with a real driver:
|
|
## 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
|
|
|
|
const AtlasWindowNatureOverlay := preload("res://ui/implant/apps/atlas/atlas_window_nature_overlay.gd")
|
|
|
|
const COLOR_BG: Color = Color("#0d1117") # AtlasWindowViewer.COLOR_BG, mirrored (private const)
|
|
const VIEWPORT_SIZE: Vector2i = Vector2i(512, 512)
|
|
const MIN_NON_BACKGROUND_FRACTION: float = 0.0005 # river dots are sparse — a low bar is honest here
|
|
|
|
const SKIP_REASON: String = (
|
|
"no real rendering driver (dummy/headless) — run with e.g."
|
|
+ " `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` to exercise this file"
|
|
)
|
|
|
|
|
|
## Matches test_atlas_window_overlay_draw_smoke.gd's own detection exactly.
|
|
static func _dummy_renderer_active() -> bool:
|
|
return DisplayServer.get_name() == "headless"
|
|
|
|
|
|
## 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. is_tile_mode()/
|
|
## get_district_window()/get_tile_set() added for T-1172 (the water clip) —
|
|
## defaults to single-window mode with NO arrived composite (district_window
|
|
## null), the fail-open case, so these smoke tests keep drawing every marker
|
|
## exactly as before the clip existed (this file's own job is proving the
|
|
## draw calls paint pixels at all, not exercising the clip's water-detection
|
|
## branch — that's test_atlas_window_nature_overlay.gd's job).
|
|
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}
|
|
var tile_mode: bool = false
|
|
var district_window: Variant = null
|
|
var tile_set: Variant = null
|
|
|
|
func get_held_granularity_v2() -> String:
|
|
return held_granularity_v2
|
|
|
|
func get_body_radius_km() -> float:
|
|
return body_radius_km
|
|
|
|
func get_held_center() -> Vector2i:
|
|
return held_center
|
|
|
|
func get_held_n() -> int:
|
|
return held_n
|
|
|
|
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))
|
|
|
|
func is_tile_mode() -> bool:
|
|
return tile_mode
|
|
|
|
func get_district_window() -> Variant:
|
|
return district_window
|
|
|
|
func get_tile_set() -> Variant:
|
|
return tile_set
|
|
|
|
|
|
## A dense scatter of river cells spanning the whole held window's canvas
|
|
## footprint (not clustered in one corner) — a genuine "does the composite
|
|
## draw something visible across the frame" check, same intent as the
|
|
## terrain smoke test's checkerboard morphology spread.
|
|
static func _mock_layer1_dense() -> Dictionary:
|
|
var river_cells: Array = []
|
|
var river_class: PackedByteArray = PackedByteArray()
|
|
for i in range(40):
|
|
river_cells.append([i * 3, i * 3])
|
|
river_class.append(2) # trunk — visible at every rung this suite exercises
|
|
return {
|
|
"river_network": {
|
|
"river_cells": river_cells,
|
|
"river_class": river_class,
|
|
"confluences": [[60, 60]],
|
|
"mouths": [[120, 120]],
|
|
},
|
|
"drainage_basins": [
|
|
{"basin_id": 1, "boundary": [[0, 0], [0, 40], [40, 40], [40, 0]]},
|
|
],
|
|
"attractors": [
|
|
{"position": [80, 80], "strength": 0.9, "attractor_type": "Oasis", "sub_biome": ""},
|
|
],
|
|
"grid_w": 256,
|
|
"grid_h": 128,
|
|
}
|
|
|
|
|
|
## Same _BackgroundRect/_render_to_image/_non_background_fraction shared
|
|
## rendering infrastructure as test_atlas_window_overlay_draw_smoke.gd —
|
|
## duplicated rather than imported since gdUnit4 test suites are not
|
|
## typically composed via inheritance in this codebase (no precedent for a
|
|
## shared test-infra base class in client/tests/), and the block is small.
|
|
class _BackgroundRect extends Node2D:
|
|
var fill_color: Color = Color.BLACK
|
|
var fill_size: Vector2 = Vector2.ZERO
|
|
|
|
func _draw() -> void:
|
|
draw_rect(Rect2(Vector2.ZERO, fill_size), fill_color)
|
|
|
|
|
|
func _render_to_image(overlay: Node2D, zoom: float = 1.0) -> Image:
|
|
var sub_viewport := SubViewport.new()
|
|
sub_viewport.size = VIEWPORT_SIZE
|
|
sub_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
|
sub_viewport.transparent_bg = false
|
|
add_child(sub_viewport)
|
|
auto_free(sub_viewport)
|
|
|
|
var bg := _BackgroundRect.new()
|
|
bg.fill_color = COLOR_BG
|
|
bg.fill_size = Vector2(VIEWPORT_SIZE)
|
|
sub_viewport.add_child(bg)
|
|
bg.queue_redraw()
|
|
|
|
var canvas := Node2D.new()
|
|
canvas.position = Vector2(VIEWPORT_SIZE) * 0.5
|
|
canvas.scale = Vector2(zoom, zoom)
|
|
sub_viewport.add_child(canvas)
|
|
canvas.add_child(overlay)
|
|
overlay.queue_redraw()
|
|
|
|
for _i in range(6):
|
|
await get_tree().process_frame
|
|
|
|
return sub_viewport.get_texture().get_image()
|
|
|
|
|
|
static func _non_background_fraction(image: Image) -> float:
|
|
var w: int = image.get_width()
|
|
var h: int = image.get_height()
|
|
if w <= 0 or h <= 0:
|
|
return 0.0
|
|
var total: int = w * h
|
|
var differing: int = 0
|
|
var bg_rgb: Color = Color(COLOR_BG.r, COLOR_BG.g, COLOR_BG.b, 1.0)
|
|
for y in range(h):
|
|
for x in range(w):
|
|
var px: Color = image.get_pixel(x, y)
|
|
var px_rgb: Color = Color(px.r, px.g, px.b, 1.0)
|
|
if not px_rgb.is_equal_approx(bg_rgb):
|
|
differing += 1
|
|
return float(differing) / float(total)
|
|
|
|
|
|
## Region rung, every toggle on: rivers + confluence + mouth + basin fill +
|
|
## attractor glyph must all draw SOMETHING — the "does the composite actually
|
|
## paint" proof the state-only unit suite cannot provide.
|
|
func test_region_rung_draws_visible_pixels() -> void:
|
|
if _dummy_renderer_active():
|
|
print(SKIP_REASON)
|
|
return
|
|
var overlay := AtlasWindowNatureOverlay.new()
|
|
var stub := _ViewerStub.new()
|
|
overlay.viewer = stub
|
|
overlay._layer1 = _mock_layer1_dense()
|
|
overlay._requested_body_id = "SmokeBody"
|
|
|
|
# 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)
|
|
|
|
assert_float(fraction).override_failure_message(
|
|
(
|
|
"the Region-rung nature composite (rivers + confluence + mouth + basin +"
|
|
+ " attractor, every toggle on) must render VISIBLE non-background pixels —"
|
|
+ " got only %.4f%% of the frame differing from COLOR_BG"
|
|
)
|
|
% (fraction * 100.0)
|
|
).is_greater(MIN_NON_BACKGROUND_FRACTION)
|
|
|
|
|
|
## District rung: only trunk rivers (class 2, all cells in the dense fixture
|
|
## are trunk) + the mouth carve-out draw; basins/attractors/confluences are
|
|
## rung-gated off. Still must produce visible pixels — proving the "fade
|
|
## down, don't vanish" posture actually leaves SOMETHING on screen.
|
|
func test_district_rung_still_draws_visible_pixels() -> void:
|
|
if _dummy_renderer_active():
|
|
print(SKIP_REASON)
|
|
return
|
|
var overlay := AtlasWindowNatureOverlay.new()
|
|
var stub := _ViewerStub.new()
|
|
stub.held_granularity_v2 = "District"
|
|
overlay.viewer = stub
|
|
overlay._layer1 = _mock_layer1_dense()
|
|
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)
|
|
|
|
assert_float(fraction).override_failure_message(
|
|
(
|
|
"the District-rung composite (trunk rivers + mouth carve-out only) must"
|
|
+ " still render VISIBLE non-background pixels — got only %.4f%% of the"
|
|
+ " frame differing from COLOR_BG"
|
|
)
|
|
% (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)
|