fix(ui): T-1172 round 2 — tile wrap resolution mirrored to the painter's own direction
Live round: the first clip removed only 133 pixels. Root cause (dossier- traced): resolve_morphology_zone wrapped the QUERY toward a tile's raw canonical center — the inverse of the painter's draw_col = nearest_wrap_image(tile_center, held_center) — so seam tiles tested containment against the wrong wrap-image and read real-but-wrong- location land cells. Fix mirrors the painter exactly: wrap the tile's own center toward held_center, test the (already held-wrapped) query against that. Index math itself was confirmed correct end-to-end and is now factored into shared AtlasWindowGeometry.cell_index_for_local_ offset() (full painter unification not applicable — the painter only iterates forward, never reverse-looks-up; documented). Post-fix: 1082 traced positions cross-checked against actual painted pixels, 0 real mismatches; regenerated captures show every dot/mouth on land. The one pre-existing test encoding the buggy direction as correct was replaced by positive+negative wrap-semantics tests (the negative one is the reliable revert discriminator) plus a wire-accurate seam-tile fixture with an honestly-documented proof limit (a single-tile fixture cannot distinguish the wrap directions; the multi-tile scan tests can). Also: two harness traps found and fixed in the lead's drive scratch — canvas_items stretch factor (root.size now matches the 1920x1080 base viewport) and mid-arrival snapshots (explicit is_fully_arrived wait; the round-1 faint result was partly a 4-of-6-tiles capture). 46/46 + 50/50 + five sibling suites regression-free; gdlint clean. Tickets: T-1172 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -281,3 +281,46 @@ func test_zoom_compensated_size_zero_zoom_does_not_blow_up() -> void:
|
||||
assert_bool(is_finite(result)).override_failure_message(
|
||||
"a degenerate zero view_zoom must not produce inf/NaN"
|
||||
).is_true()
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# T-1172 round 2: cell_index_for_local_offset() — the shared painter/clip
|
||||
# index formula (see its own doc for the "why shared, not duplicated" case).
|
||||
# =============================================================================
|
||||
|
||||
|
||||
func test_cell_index_for_local_offset_top_left_is_zero_zero() -> void:
|
||||
var cell: Vector2i = AtlasWindowGeometry.cell_index_for_local_offset(0.0, 0.0, 6400, 64)
|
||||
assert_that(cell).is_equal(Vector2i(0, 0))
|
||||
|
||||
|
||||
## The exact live-repro numbers from T-1172 round 2's trace: a query whose
|
||||
## district-space local offset is (2594.09, 5593.15) inside a 6400-wide,
|
||||
## 64-cell-side window must resolve to (col=25, row=55) — pinned directly
|
||||
## against the LIVE captured values that closed the investigation (both the
|
||||
## painter's _build_tile_texture() and the clip independently produced this
|
||||
## exact pair for the same query in the live trace).
|
||||
func test_cell_index_for_local_offset_matches_the_live_trace_repro() -> void:
|
||||
var cell: Vector2i = AtlasWindowGeometry.cell_index_for_local_offset(
|
||||
2594.0849609375, 5593.15258789062, 6400, 64
|
||||
)
|
||||
assert_that(cell).override_failure_message(
|
||||
"must match the live-captured painter/clip agreement point from the"
|
||||
+ " T-1172 round 2 investigation — (col=25, row=55)"
|
||||
).is_equal(Vector2i(25, 55))
|
||||
|
||||
|
||||
func test_cell_index_for_local_offset_bottom_right_boundary_clamps_inside() -> void:
|
||||
# local offset == n (the exclusive upper boundary) must clamp to the LAST
|
||||
# cell, not overflow to a nonexistent grid_side'th cell.
|
||||
var cell: Vector2i = AtlasWindowGeometry.cell_index_for_local_offset(6400.0, 6400.0, 6400, 64)
|
||||
assert_that(cell).is_equal(Vector2i(63, 63))
|
||||
|
||||
|
||||
func test_cell_index_for_local_offset_zero_n_or_grid_side_returns_sentinel() -> void:
|
||||
assert_that(AtlasWindowGeometry.cell_index_for_local_offset(10.0, 10.0, 0, 64)).is_equal(
|
||||
Vector2i(-1, -1)
|
||||
)
|
||||
assert_that(AtlasWindowGeometry.cell_index_for_local_offset(10.0, 10.0, 6400, 0)).is_equal(
|
||||
Vector2i(-1, -1)
|
||||
)
|
||||
|
||||
@@ -209,28 +209,160 @@ func test_resolve_tile_mode_empty_tile_list_is_no_data() -> void:
|
||||
assert_int(zone).is_equal(AtlasWindowWaterClip.MORPHOLOGY_ZONE_NO_DATA)
|
||||
|
||||
|
||||
## Wrap case: a tile whose CANONICAL center is near the antimeridian, queried
|
||||
## with a district position expressed in a DIFFERENT (unwrapped) longitude —
|
||||
## resolve_morphology_zone() must re-express the query against the tile's
|
||||
## own wrap-image before testing containment, the same discipline
|
||||
## AtlasWindowOverlay._draw_tile_mosaic() already uses for drawing.
|
||||
func test_resolve_tile_mode_wraps_the_query_to_the_tiles_own_image() -> void:
|
||||
## Live round 2 fix (coordinator's trace, T-1172): a tile whose CANONICAL
|
||||
## center is far from `held_center` (the seam-tile case — exactly Lendel's
|
||||
## own live repro, tile canonical center 12739 drawn at draw_col=-6400) must
|
||||
## have its CENTER wrapped toward `held_center_x` — mirroring
|
||||
## AtlasWindowOverlay._draw_tile_mosaic()'s own `draw_col =
|
||||
## nearest_wrap_image(center.x, held_center.x, cols)` EXACTLY — before
|
||||
## testing containment. The query `district` is assumed ALREADY expressed in
|
||||
## the held-center-wrapped frame (AtlasWindowNatureOverlay._district()'s own
|
||||
## contract) and is NOT separately re-wrapped.
|
||||
##
|
||||
## Original (pre-fix) test asserted the INVERSE — wrapping the query toward
|
||||
## the tile's raw canonical center — which was the actual bug: it happened
|
||||
## to land inside the tile's CANONICAL (unwrapped) span by coincidental mod
|
||||
## arithmetic, silently testing the WRONG real-world location whenever a
|
||||
## tile needed wrapping to appear on screen at all. Live capture evidence:
|
||||
## a river dot at district.x=-9569 sitting on the painter's WEST wrap-image
|
||||
## of a seam tile (canonical center 12739, draw_col=-6400) read a real but
|
||||
## wrong-location land cell under the old code, and only stopped doing so
|
||||
## once resolve_morphology_zone() wrapped the TILE's center instead.
|
||||
func test_resolve_tile_mode_wraps_the_tiles_own_center_toward_held_center() -> void:
|
||||
var cols := 100
|
||||
var morph := PackedByteArray()
|
||||
morph.resize(16)
|
||||
for i in range(16):
|
||||
morph[i] = MORPHOLOGY_OPEN_OCEAN
|
||||
# Tile's canonical center is column 2 (near the origin side of the wrap).
|
||||
var tile := {"center": Vector2i(2, 0), "window": _mock_district_window(Vector2i(2, 0), 4, morph)}
|
||||
# Query at column -98 — NOT canonical (canonicalizes to 2 under mod 100),
|
||||
# but expressed as the "west of origin" wrap-image the real district
|
||||
# position lives at (matching Lendel's own antimeridian repro shape from
|
||||
# the T-1156 nearest_wrap_image() tests).
|
||||
# Tile's canonical center is column 98 (far east) — but its nearest
|
||||
# wrap-image to held_center=0 is column -2 (98 - 100), matching the
|
||||
# Lendel seam tile's own shape (canonical 12739 -> draw_col -6400).
|
||||
var tile := {"center": Vector2i(98, 0), "window": _mock_district_window(Vector2i(98, 0), 4, morph)}
|
||||
# Query at column -2.5 — inside the tile's WRAP-IMAGE span [-4, 0), the
|
||||
# real on-screen location, held_center-relative (the caller's own
|
||||
# _district() contract) — NOT inside the canonical span [96, 100).
|
||||
var zone: int = AtlasWindowWaterClip.resolve_morphology_zone(
|
||||
Vector2(-98.0, 0.0), true, null, [tile], cols
|
||||
Vector2(-2.5, 0.0), true, null, [tile], cols, 0
|
||||
)
|
||||
assert_int(zone).override_failure_message(
|
||||
"a query expressed in a different (non-canonical) wrap-image of the same"
|
||||
+ " real position must still resolve against the tile whose canonical"
|
||||
+ " center it's periodic-equivalent to"
|
||||
"the tile's CENTER must be wrapped toward held_center_x (mirroring the"
|
||||
+ " painter's draw_col computation) so a query already expressed in the"
|
||||
+ " held-center frame resolves against the tile's REAL on-screen wrap-image"
|
||||
).is_equal(MORPHOLOGY_OPEN_OCEAN)
|
||||
|
||||
|
||||
## The INVERSE position — a query at the tile's CANONICAL (unwrapped) span —
|
||||
## must NOT resolve against this tile once wrapping is applied, since that
|
||||
## span is no longer where the tile actually draws relative to held_center.
|
||||
## Pins that the fix doesn't just "also succeed at the old span" by accident.
|
||||
func test_resolve_tile_mode_does_not_match_the_tiles_stale_canonical_span() -> void:
|
||||
var cols := 100
|
||||
var morph := PackedByteArray()
|
||||
morph.resize(16)
|
||||
for i in range(16):
|
||||
morph[i] = MORPHOLOGY_OPEN_OCEAN
|
||||
var tile := {"center": Vector2i(98, 0), "window": _mock_district_window(Vector2i(98, 0), 4, morph)}
|
||||
# Query at column 97 — inside the tile's CANONICAL span [96,100) — but
|
||||
# that is NOT where this tile is drawn relative to held_center=0 (it's
|
||||
# drawn at the wrap-image [-4,0) instead), so this must NOT resolve.
|
||||
var zone: int = AtlasWindowWaterClip.resolve_morphology_zone(
|
||||
Vector2(97.0, 0.0), true, null, [tile], cols, 0
|
||||
)
|
||||
assert_int(zone).override_failure_message(
|
||||
"a query at the tile's stale CANONICAL span must not resolve against it"
|
||||
+ " once the tile is wrapped toward held_center — that span is not where"
|
||||
+ " the tile actually draws on screen"
|
||||
).is_equal(AtlasWindowWaterClip.MORPHOLOGY_ZONE_NO_DATA)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# T-1172 round 2 (coordinator's "wire-accurate fixture" hardening ask —
|
||||
# cold-start batch discipline): a fixture derived from an ACTUAL live tile
|
||||
# response captured during the round-2 investigation, at the REAL wire scale
|
||||
# (n=6400, grid_side=64, Region granularity) — not a hand-shrunk 4x4 mock.
|
||||
# The round-2 bug (wrapping the query toward the tile instead of the tile
|
||||
# toward held_center) passed EVERY test against the small mocks above,
|
||||
## because those mocks never modeled a tile whose canonical center is FAR
|
||||
# from held_center — the exact condition the bug needed to manifest. This
|
||||
# fixture reproduces that condition at production scale, so a future
|
||||
# regression of the same SHAPE (stub-and-code silently agreeing on a wrong
|
||||
# convention) can't hide behind "the small tests still pass."
|
||||
# =============================================================================
|
||||
|
||||
|
||||
## Lendel's own seam tile from the live drive capture that closed T-1172
|
||||
## round 2 (client/tmp_drive_clip.gd, SR_LIVE=1 against the worktree release
|
||||
## server): canonical center (12739, -3200), TILE_N=6400 districts,
|
||||
## Region granularity (grid_side = round(6400/100) = 64). `cols=19139`
|
||||
## matches Lendel's real district_extent() circumference. The morphology
|
||||
## array is NOT the real 4096-byte payload (too large to hand-author) — only
|
||||
## the ONE cell index the live trace actually resolved for the
|
||||
## district=-9569.414 repro query (idx=1024, col=0/row=16 — the exact
|
||||
## INDEX_TRACE line from the live investigation) is given a real value;
|
||||
## every other cell is left at 0 (OpenOcean), which is irrelevant here since
|
||||
## this fixture exists to pin the WRAP resolution reaching the CORRECT
|
||||
## tile/cell pair, not to re-verify the index math itself (already covered
|
||||
## above and in test_atlas_window_geometry_nature.gd).
|
||||
static func _lendel_seam_tile_fixture() -> Dictionary:
|
||||
var morph := PackedByteArray()
|
||||
morph.resize(4096)
|
||||
morph[1024] = MORPHOLOGY_LAND # col=0, row=16 — the live-traced cell
|
||||
return {
|
||||
"center": Vector2i(12739, -3200),
|
||||
"window": {
|
||||
"center": [12739, -3200],
|
||||
"n": 6400,
|
||||
"granularity_v2": "Region",
|
||||
"morphology": morph,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## The exact district position from the live capture that ORIGINALLY exposed
|
||||
## the round-2 bug (district.x=-9569.414 — a dot visibly sitting on the
|
||||
## painter's WEST wrap-image of the seam tile). held_center_x=0 (the
|
||||
## viewer's canonical orbital-frame origin, cols=19139 (Lendel's real
|
||||
## circumference in districts). Must resolve to the SAME land zone the live
|
||||
## painter trace independently confirmed for this exact query.
|
||||
##
|
||||
## Honest note (found DURING revert-verification, worth recording): for a
|
||||
## SINGLE tile in isolation, the old (query-wrapped-toward-tile) and new
|
||||
## (tile-wrapped-toward-held_center) formulas are mathematically GUARANTEED
|
||||
## to agree whenever local_x lands in-range for both — both reduce to
|
||||
## `query - tile_center (mod cols)`, and a valid `local_x` is unique in
|
||||
## `[0, n)`. This single-tile fixture therefore does NOT independently
|
||||
## distinguish old from new (confirmed: it still passes with the pre-fix
|
||||
## code) — it locks in the real wire-scale numbers as a realistic regression
|
||||
## fixture (shared index formula, tile shape, wrap arithmetic all exercised
|
||||
## together), not as the old-vs-new discriminator. The tests that DO reliably
|
||||
## catch the round-2 regression are
|
||||
## test_resolve_tile_mode_wraps_the_tiles_own_center_toward_held_center and
|
||||
## test_resolve_tile_mode_does_not_match_the_tiles_stale_canonical_span above
|
||||
## (confirmed: the latter fails by name against the reverted code) — the
|
||||
## real-world bug's actual mechanism was the MULTI-TILE SCAN ORDER matching
|
||||
## the WRONG tile's data before reaching the right one, not a single-tile
|
||||
## formula divergence; a true multi-tile live reproduction would need the
|
||||
## full 6-tile fixture, impractical to hand-author at full 4096-cell scale.
|
||||
func test_wire_accurate_lendel_seam_tile_resolves_correctly() -> void:
|
||||
var tile: Dictionary = _lendel_seam_tile_fixture()
|
||||
var zone: int = AtlasWindowWaterClip.resolve_morphology_zone(
|
||||
Vector2(-9569.414, -4784.793), true, null, [tile], 19139, 0
|
||||
)
|
||||
assert_int(zone).override_failure_message(
|
||||
"the live T-1172 round 2 repro position must resolve against the seam"
|
||||
+ " tile's WRAPPED (on-screen) image and read the real traced land zone"
|
||||
+ " — a regression here reproduces the ORIGINAL over-ocean-dots bug"
|
||||
).is_equal(MORPHOLOGY_LAND)
|
||||
|
||||
|
||||
## The SAME fixture, queried at a position that legitimately falls OUTSIDE
|
||||
## even the wrapped tile's span (nowhere near either wrap-image) — must fail
|
||||
## open (NO_DATA), not silently match by coincidental mod arithmetic (the
|
||||
## general shape of the original bug, pinned generically here in case a
|
||||
## future change reintroduces a different mod-arithmetic coincidence).
|
||||
func test_wire_accurate_lendel_seam_tile_out_of_range_query_is_no_data() -> void:
|
||||
var tile: Dictionary = _lendel_seam_tile_fixture()
|
||||
var zone: int = AtlasWindowWaterClip.resolve_morphology_zone(
|
||||
Vector2(500.0, 500.0), true, null, [tile], 19139, 0
|
||||
)
|
||||
assert_int(zone).is_equal(AtlasWindowWaterClip.MORPHOLOGY_ZONE_NO_DATA)
|
||||
|
||||
Reference in New Issue
Block a user