feat(client): invert the Atlas rung relation — rung sets extent, not spacing
A rung used to fix the gridunit SPACING, with the canvas extent falling out of spacing x cell count. That is why the top of the ladder was unusable: at REGION_M spacing a viewport-sized canvas spanned ~251,658 km — six times around a rocky body — so the Region rung capped to the body and redrew the Global picture pixel-for-pixel. "Global and region look the same" was not a rendering bug; it was this relation, stated in metres. Inverted: a rung fixes the EXTENT and the spacing falls out of the canvas size. The shorter viewport axis spans exactly one cell of the rung's level, so a widescreen window shows more ground on the long axis rather than less on the short one. Every rung now shows the ground its name promises — Region 262x466 km, District 4.1x7.3 km — and the canvas cell count is viewport-driven and identical at every rung, so derive cost no longer varies with depth and resize is free. Consequences that fell out of the inversion rather than being chosen: - Region leaves the orbital derive set. It was envelope-only because at 251,658 km nothing finer made sense; at 262 km it is a genuine provincial map and takes the full courses-aware derive. Region having no rivers at all was much of why the top of the ladder read flat. It also joins the deep display ratio for the same reason. - The S2 station-spacing floor is deleted, not retuned. It guarded an O(1/spacing) blowup that the inversion makes structurally impossible (the canvas cell count is now constant across rungs, so stations-per-course is bounded however deep you scroll). Kept, it would do active harm in the opposite direction: a 2,048 m pitch across a 3.6 km District canvas places two stations and draws every river as a straight line. Station placement gets its own generator pass. - cap_extent_to_body is superseded and now a documented no-op. A canvas can no longer over-request a body by construction. The residual question — whether a rung's cell exceeds the whole body — is liveness, not capping, and is_rung_live_on_body() answers it by omitting the rung. Empirically it never fires on inhabited content: all six rungs are live on all 271 populated bodies with a radius. - snap_to_gridunit no longer truncates its multiplier to int. Post-inversion the deep rungs run sub-metre (Chunk ~0.12 m at a 1080 px short axis), where int(spacing) floors to zero and would collapse every request centre onto the origin. Both sides derive spacing from the same three inputs (rung, echoed cell extent, body radius) rather than one telling the other, so there is nothing to keep in sync beyond the constant table itself. Body radius already reaches the viewer via enter(); no wire change. Pair session with Jeroen, 2026-07-26. D-243/D-255 amendments to be backfiled. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -510,26 +510,43 @@ func test_global_canvas_arrival_populates_the_body_extent_cap_source() -> void:
|
||||
assert_that(v._global_body_extent).is_equal(GJ1C_GLOBAL_EXTENT)
|
||||
|
||||
|
||||
## The T-1183 eyeball regression itself: once the Global echo has landed,
|
||||
## scrolling to Region and firing its request must produce a CAPPED extent
|
||||
## — never the raw viewport-fit 384x216 that overran the body on both axes.
|
||||
func test_region_request_extent_is_capped_to_the_landed_global_extent() -> void:
|
||||
## The T-1183 eyeball regression, restated for the post-inversion ladder
|
||||
## (D-255 amendment, pair session 2026-07-26). It used to be fixed by CAPPING
|
||||
## Region's extent to the body's region grid; the inversion removes the defect
|
||||
## at its source instead. Region's cell count is now plain viewport-fit, and
|
||||
## what bounds it to the body is its GROUND extent: the shorter viewport axis
|
||||
## spans exactly one region, so the canvas cannot wrap the body however large
|
||||
## the window is. Asserting the ground extent is the honest version of what
|
||||
## the old cap was reaching for.
|
||||
func test_region_request_covers_exactly_one_region_on_the_short_axis() -> void:
|
||||
var v: StepCanvasViewer = _make_viewer()
|
||||
add_child(v)
|
||||
v.size = Vector2(1920.0, 1080.0) # the T-1183 eyeball's own viewport
|
||||
v.enter({"body_id": "T1189_extent_letterbox_test_body", "body_radius_km": 6371.0}, {})
|
||||
TestStepCanvasViewer._land_global_canvas(v, GJ1C_GLOBAL_EXTENT.x, GJ1C_GLOBAL_EXTENT.y)
|
||||
|
||||
v._scroll_rung(1, Vector2(960.0, 540.0)) # descend to Region — fires the capped request
|
||||
v._scroll_rung(1, Vector2(960.0, 540.0)) # descend to Region
|
||||
var extent: Vector2i = v._request_extent()
|
||||
|
||||
assert_int(extent.x).override_failure_message(
|
||||
"Region's requested extent must never exceed the body's own region-grid width"
|
||||
).is_less_equal(GJ1C_GLOBAL_EXTENT.x)
|
||||
assert_int(extent.y).override_failure_message(
|
||||
"Region's requested extent must never exceed the body's own region-grid height"
|
||||
).is_less_equal(GJ1C_GLOBAL_EXTENT.y)
|
||||
assert_that(extent).is_equal(GJ1C_GLOBAL_EXTENT) # 1920x1080 viewport-fit exceeds 177x88 on both axes
|
||||
# No longer capped to the body grid — the cell count is the window.
|
||||
assert_that(extent).is_equal(StepCanvasTransport.viewport_fit_extent(v.size, "Region"))
|
||||
|
||||
# ...and the ground it covers is one region across the short axis, which
|
||||
# is what actually prevents the sideways-repeat / pole-smear defect.
|
||||
var spacing: float = StepCanvasTransport.spacing_for_rung(
|
||||
"Region", extent, v.get_body_radius_km()
|
||||
)
|
||||
var short_axis_m: float = spacing * float(mini(extent.x, extent.y))
|
||||
assert_float(short_axis_m).override_failure_message(
|
||||
"Region must span exactly one region cell on the short axis, got %f m" % short_axis_m
|
||||
).is_equal_approx(StepCanvasTransport.RUNG_EXTENT_M["Region"], 0.01)
|
||||
|
||||
# The whole body is 40,030 km around; this canvas must be a small fraction
|
||||
# of it, not a wrap-around.
|
||||
var circumference_m: float = TAU * 6371.0 * 1000.0
|
||||
assert_bool(spacing * float(extent.x) < circumference_m).override_failure_message(
|
||||
"a Region canvas must never span more ground than the body has"
|
||||
).is_true()
|
||||
|
||||
|
||||
## Cold-start fallback (documented on StepCanvasViewer._request_extent()):
|
||||
@@ -554,13 +571,15 @@ func test_region_request_extent_is_uncapped_before_the_global_echo_lands() -> vo
|
||||
).is_equal(uncapped)
|
||||
|
||||
|
||||
## Cache-key discipline (T-1182/T-1183, ticket's own explicit call-out): the
|
||||
## cap must be applied BEFORE _fire_request() builds the request, so the
|
||||
## extent that becomes part of the cache key is the SAME capped value that
|
||||
## gets served — a request for "the same spot" must always resolve to the
|
||||
## same key, capped or not, never a key built from one extent and served
|
||||
## under another.
|
||||
func test_capped_extent_matches_what_the_request_actually_sends() -> void:
|
||||
## Cache-key discipline (T-1182/T-1183, ticket's own explicit call-out),
|
||||
## outliving the cap it was written for: the extent that becomes part of the
|
||||
## cache key must be the SAME value the request actually carries — a request
|
||||
## for "the same spot" must always resolve to the same key, never a key built
|
||||
## from one extent and served under another. The inversion makes this MORE
|
||||
## load-bearing, not less: the extent now also determines gridunit spacing, so
|
||||
## a key/request divergence would mean a canvas served at the wrong scale
|
||||
## rather than merely the wrong size.
|
||||
func test_request_extent_matches_what_the_request_actually_sends() -> void:
|
||||
var v: StepCanvasViewer = _make_viewer()
|
||||
add_child(v)
|
||||
v.size = Vector2(1920.0, 1080.0)
|
||||
@@ -573,20 +592,22 @@ func test_capped_extent_matches_what_the_request_actually_sends() -> void:
|
||||
# idempotent and match what was actually requested (no separate,
|
||||
# divergent cap path).
|
||||
var extent_now: Vector2i = v._request_extent()
|
||||
assert_that(extent_now).is_equal(GJ1C_GLOBAL_EXTENT)
|
||||
assert_that(extent_now).is_equal(StepCanvasTransport.viewport_fit_extent(v.size, "Region"))
|
||||
|
||||
# The Tier-1 cache key StepCanvasCache builds from this SAME extent must
|
||||
# be a real, findable key once a response for it lands — proving the
|
||||
# capped extent (not the raw viewport-fit one) is what keys the cache.
|
||||
# extent that keys the cache is the one the request carries.
|
||||
var req: Variant = v.get_request()
|
||||
var center: Vector2i = StepCanvasTransport.snap_to_gridunit(v._world_center, "Region")
|
||||
var canvas := TestStepCanvasViewer._synthetic_canvas(GJ1C_GLOBAL_EXTENT.x, GJ1C_GLOBAL_EXTENT.y)
|
||||
var center: Vector2i = StepCanvasTransport.snap_to_gridunit(
|
||||
v._world_center, "Region", extent_now, v.get_body_radius_km()
|
||||
)
|
||||
var canvas := TestStepCanvasViewer._synthetic_canvas(extent_now.x, extent_now.y)
|
||||
req.get_cache().put("T1189_extent_letterbox_test_body", "Region", center, extent_now, canvas)
|
||||
assert_bool(
|
||||
req.get_cache().has("T1189_extent_letterbox_test_body", "Region", center, GJ1C_GLOBAL_EXTENT, 0)
|
||||
req.get_cache().has("T1189_extent_letterbox_test_body", "Region", center, extent_now, 0)
|
||||
).override_failure_message(
|
||||
"a cache entry stored under the CAPPED extent must be reachable"
|
||||
+ " under that same capped extent — key consistency"
|
||||
"a cache entry stored under the REQUESTED extent must be reachable"
|
||||
+ " under that same extent — key consistency"
|
||||
).is_true()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user