From feef7aa1c58088a384eb824b47705a79a9b9e230 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Sat, 25 Jul 2026 22:36:03 +0200 Subject: [PATCH] =?UTF-8?q?fix(client):=20PR=20#212=20review=20fixes=20?= =?UTF-8?q?=E2=80=94=20true=20on-screen=20footprint=5Fpx,=20self-describin?= =?UTF-8?q?g=20shot=20coverage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tyre finding 2: _log_atlas_view_transform's footprint_px now logs the real on-screen pixel footprint (StepCanvasTransport.canvas_footprint_px * canvas_scale — the same public pure function the terrain layer uses), with the old cell-count field kept as canvas_cells. Live-verified the divergence the fix exposes: Global logs footprint_px=(1528, 760) vs canvas_cells=191x95 — the T-1192 fit-multiplier class the log exists to root-cause, previously invisible under the mislabel. Tyre finding 3: atlas_shots.json's one_shot_per_body note replaced by rung_coverage stating the true distribution — 13 goldens across 7 bodies (per-rung coverage map, GJ380c's 3 shots as the invariance-proof body, curated-subset rationale per T-1121). Corrects the prior commit message's '12 new goldens' miscount: the true count everywhere is 13, verified against shots array, visual.json entries, and PNGs on disk. Co-Authored-By: Claude Fable 5 --- client/tests/visual_capture.gd | 36 +++++++++++++++++++++++++++++++--- tests/atlas_shots.json | 2 +- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/client/tests/visual_capture.gd b/client/tests/visual_capture.gd index 706856796..9a190b3eb 100644 --- a/client/tests/visual_capture.gd +++ b/client/tests/visual_capture.gd @@ -294,6 +294,27 @@ func _settle_atlas_viewer_if_pending(tree_root: Node) -> void: ## mismatch is root-causable (PR #204's own precedent: this exact log shape ## identified an edge-scroll drift bug by its PAN_SPEED_PX_S*frame_time ## fingerprint) instead of a bare "pixels don't match". +## +## PR #212 review (Tyre finding 1): `footprint_px` previously sourced +## canvas_width/canvas_height off get_current_canvas_summary() — those are the +## held canvas's CELL dimensions (gridunits), not its on-screen PIXEL +## footprint, which is exactly the wrong quantity for a log whose whole job is +## catching a fit-scale-multiplier bug (the T-1192 Global integer-fit ratio, +## PR #204's own drift class). The real on-screen footprint is +## StepCanvasTerrainLayer's own `_footprint_px` — private to that node, so +## rather than reach into it (this cluster's own "no private-field reach" +## discipline — get_current_canvas_summary()'s doc makes the same call for +## `_canvas_ref`), this recomputes the identical value from the SAME public, +## pure function the terrain layer itself calls to produce it +## (StepCanvasTransport.canvas_footprint_px(rung, extent) — +## step_canvas_terrain_layer.gd's own rebuild_from_canvas(): +## `_footprint_px = StepCanvasTransport.canvas_footprint_px(rung, new_size)`), +## then multiplies by the SAME canvas_scale already logged here (the T-1192 +## Global integer-fit multiplier, 1.0 elsewhere) — matching +## _centered_view_offset()'s own `raw_footprint * scale` pattern for the +## identical "true on-screen size" quantity. canvas_cells is kept alongside +## it (relabeled from the old footprint_px name) since the cell count is +## still useful log context, just correctly named now. func _log_atlas_view_transform(tree_root: Node, scenario_name: String) -> void: var viewer: Variant = _get_atlas_regional_viewer(tree_root) if viewer == null: @@ -302,18 +323,27 @@ func _log_atlas_view_transform(tree_root: Node, scenario_name: String) -> void: var canvas_node: Node2D = viewer.get_node_or_null("StepCanvas") var canvas_pos: Vector2 = canvas_node.position if canvas_node else Vector2.ZERO var canvas_scale: Vector2 = canvas_node.scale if canvas_node else Vector2.ONE + var rung: String = str(summary.get("rung", "")) + var held_extent_raw: Variant = summary.get("held_extent", [0, 0]) + var extent_cells := Vector2i(int(held_extent_raw[0]), int(held_extent_raw[1])) + var StepCanvasTransport := load( + "res://ui/implant/apps/atlas/step_canvas/step_canvas_transport.gd" + ) + var raw_footprint_px: Vector2 = StepCanvasTransport.canvas_footprint_px(rung, extent_cells) + var on_screen_footprint_px: Vector2 = raw_footprint_px * canvas_scale print( ( "visual_capture: view-transform[%s] rung=%s world_center=%s held_extent=%s " - + "canvas_position=%s canvas_scale=%s footprint_px=%dx%d" + + "canvas_position=%s canvas_scale=%s footprint_px=%s canvas_cells=%dx%d" ) % [ scenario_name, - str(summary.get("rung", "")), + rung, str(summary.get("world_center", [])), - str(summary.get("held_extent", [])), + str(held_extent_raw), str(canvas_pos), str(canvas_scale), + str(on_screen_footprint_px), int(summary.get("canvas_width", 0)), int(summary.get("canvas_height", 0)), ] diff --git a/tests/atlas_shots.json b/tests/atlas_shots.json index d89544667..41a064fd2 100644 --- a/tests/atlas_shots.json +++ b/tests/atlas_shots.json @@ -69,7 +69,7 @@ "veg": ["gen_dw_veg"] }, "matrix_rules": { - "one_shot_per_body": "each body gets ONE golden shot at a rung chosen to exercise a different depth of the ladder across the set (Global-heavy for the orbital opener, deeper rungs for a few bodies) — the full 6-rung x 7-body cross product (42 shots) is deliberately NOT curated here, matching T-1121's 'curated subset, not the full matrix' precedent; the full cross product remains reachable ad hoc via AtlasAgentInterface jump_to intents, not as a golden." + "rung_coverage": "13 goldens across the 7 bodies above (NOT one-shot-per-body): most bodies (GJ144e, GJ338Bd, GJ820Bc, GJ251c) get 2 shots — the Global opener plus one deeper rung — so every fixed rung below Global is exercised at least once across the set (Region: GJ380c/GJ251c; District: GJ380c/GJ820Bc; Quarter: GJ144e; Block: GJ338Bd; Chunk: GJ445c-m1). GJ380c gets 3 (Global/Region/District) since it is also the PR #212 cache-invariance-proof body (Hoshe's cold-vs-warm check on both the NEAREST/Global and LINEAR/District terrain-layer draw branches). GJ244Ad and GJ445c-m1 get 1 each (Global and Chunk respectively) — the curated pick, not an exhaustive per-body sweep. The full 6-rung x 7-body cross product (42 shots) is deliberately NOT curated here, matching T-1121's 'curated subset, not the full matrix' precedent; the full cross product remains reachable ad hoc via AtlasAgentInterface jump_to intents, not as a golden." }, "shots": [ { "body_id": "GJ380c", "rung": "Global", "overlays": ["gen_dw_temp"], "filename": "atlas_GJ380c_Global.png" },