fix(client): T-1153 — clamp _held_n at the viewer's single write site (live eyeball round blocker)
The live round against a real server caught what 3518 unit tests missed: enter_orbital stored the UNCLAMPED n (Lendel: 19139 raw circumference cols) into _held_n while AtlasWindowRequest clamped independently to 6400 before sending — every orbital response on a real-sized body was dropped by the viewer's own w_n != _held_n staleness check. Permanently blank ladder. The PR #191 C1 clamp-mirror lesson, one layer up: the mirror must apply wherever held/expected state is recorded, not only at the request layer. _enter_at_rung now clamps via _clamp_window_n_mirror_v2 before storing (the file's only _held_n write site — reselect/refloat read and forward). Regression closes the coverage hole: the oversized-orbital RESPONSE round-trip (enter_orbital on GJ380c -> deliver echo n=6400 Region -> assert accepted). Both new tests verified to fail against the reverted fix before trusting green. Full suite 3520/3520.
This commit is contained in:
@@ -59,16 +59,89 @@ func test_enter_orbital_requests_region_granularity() -> void:
|
||||
assert_str(v._held_granularity_v2).is_equal("Region")
|
||||
|
||||
|
||||
## enter_orbital()'s `n` must equal the body's full equatorial circumference
|
||||
## enter_orbital()'s `n` intent is the body's full equatorial circumference
|
||||
## in districts (district_extent().cols) — the whole body fitted to the
|
||||
## canvas, per Jeroen's HARD condition wording.
|
||||
func test_enter_orbital_n_covers_the_full_circumference() -> void:
|
||||
## canvas, per Jeroen's HARD condition wording — BUT `_held_n` is what
|
||||
## actually gets STORED/SENT, and that must be the CLAMPED value
|
||||
## (live-round finding: the raw cols value, routinely tens of thousands at
|
||||
## Region granularity, was stored unclamped while AtlasWindowRequest clamped
|
||||
## before sending — see _enter_at_rung()'s own doc for the full C1-one-layer-up
|
||||
## story). GJ380c's real cols (~19,139 per the live repro) exceeds
|
||||
## DISTRICT_WINDOW_MAX_N_REGION's clamp ceiling, so this body is the exact
|
||||
## regression case, not a hypothetical.
|
||||
func test_enter_orbital_n_is_the_clamped_value_not_raw_circumference() -> void:
|
||||
var v: AtlasWindowViewer = auto_free(AtlasWindowViewer.new())
|
||||
add_child(v)
|
||||
var radius_km := 6238.4
|
||||
var radius_km := 6238.4 # GJ380c (Lendel) — the live-repro body
|
||||
var extent: Dictionary = AtlasDescendGeometry.district_extent(radius_km)
|
||||
var raw_cols: int = int(extent["cols"])
|
||||
v.enter_orbital({"body_id": "GJ380c", "body_radius_km": radius_km}, {})
|
||||
assert_int(v._held_n).is_equal(int(extent["cols"]))
|
||||
|
||||
var expected_clamped: int = AtlasWindowRequest._clamp_window_n_mirror_v2(raw_cols, "Region")
|
||||
var failure_msg: String = (
|
||||
"_held_n must be the CLAMPED n (%d), matching what the server will echo —"
|
||||
+ " not the raw circumference (%d), which the server would clamp down and"
|
||||
+ " every response would then fail the w_n != _held_n staleness check"
|
||||
) % [expected_clamped, raw_cols]
|
||||
assert_int(v._held_n).override_failure_message(failure_msg).is_equal(expected_clamped)
|
||||
# GJ380c's raw circumference must actually exceed the clamp — otherwise this
|
||||
# test would pass trivially without exercising the clamp at all.
|
||||
assert_int(raw_cols).override_failure_message(
|
||||
"GJ380c's raw district-column count must exceed the Region clamp ceiling"
|
||||
+ " for this to be a real regression guard, not a no-op"
|
||||
).is_greater(expected_clamped)
|
||||
|
||||
|
||||
## **The live-round regression, end to end:** enter_orbital() on a
|
||||
## real-sized body (GJ380c/Lendel, radius 6238.4 km, raw cols far past the
|
||||
## Region clamp ceiling) followed by a server response echoing the CLAMPED
|
||||
## n + "Region" granularity must be ACCEPTED and become the held window — not
|
||||
## silently dropped as stale forever (the exact live bug: `wv._held_n =
|
||||
## 19139` vs. echoed `6400`, blank ladder on every real-sized body). This is
|
||||
## the round-trip the existing suite never exercised — every prior
|
||||
## enter_orbital() test asserted on request-side state only, never delivered
|
||||
## a response.
|
||||
func test_enter_orbital_oversized_body_accepts_the_clamped_region_response() -> void:
|
||||
var v: AtlasWindowViewer = auto_free(AtlasWindowViewer.new())
|
||||
add_child(v)
|
||||
var radius_km := 6238.4 # GJ380c (Lendel) — the live-repro body
|
||||
var extent: Dictionary = AtlasDescendGeometry.district_extent(radius_km)
|
||||
var raw_cols: int = int(extent["cols"])
|
||||
var clamped_n: int = AtlasWindowRequest._clamp_window_n_mirror_v2(raw_cols, "Region")
|
||||
# Sanity: this body must actually need clamping, or the test proves nothing.
|
||||
assert_int(raw_cols).is_greater(clamped_n)
|
||||
|
||||
v.enter_orbital({"body_id": "GJ380c", "body_radius_km": radius_km}, {})
|
||||
assert_that(v.get_district_window()).override_failure_message(
|
||||
"no response delivered yet — must still be null"
|
||||
).is_null()
|
||||
|
||||
# The server's real response: echoes the CLAMPED n, "Region" granularity,
|
||||
# center (0,0) — exactly what handle_atlas_request/clamp_window_n_v2
|
||||
# actually produces for an oversized orbital request.
|
||||
var region_window: Dictionary = {
|
||||
"center": [0, 0],
|
||||
"n": clamped_n,
|
||||
"granularity_v2": "Region",
|
||||
"morphology": PackedByteArray([8, 14, 0, 1]),
|
||||
"elev_q": PackedByteArray([40, 90, 5, 60]),
|
||||
"temp_dc": [120, 95, -32768, 60],
|
||||
"moisture_q": PackedByteArray([50, 30, 90, 20]),
|
||||
"vegetation": PackedByteArray([2, 1, 6, 3]),
|
||||
"glaciation": PackedByteArray([0, 0, 1, 2]),
|
||||
}
|
||||
SimBridge.atlas_layers_received.emit(_mock_response("GJ380c", region_window))
|
||||
|
||||
var failure_msg: String = (
|
||||
"a response echoing the server's own clamped n + Region granularity must be"
|
||||
+ " ACCEPTED and become the held window — the live bug left this permanently"
|
||||
+ " null (w_n=%d never matched a stale unclamped _held_n=%d) on every"
|
||||
+ " real-sized body"
|
||||
) % [clamped_n, raw_cols]
|
||||
assert_that(v.get_district_window()).override_failure_message(failure_msg).is_equal(
|
||||
region_window
|
||||
)
|
||||
assert_str(v._held_granularity_v2).is_equal("Region")
|
||||
|
||||
|
||||
## A no-radius body (tiny test body) has no circumference concept —
|
||||
|
||||
@@ -330,6 +330,21 @@ func enter_orbital(body: Dictionary, system: Dictionary) -> void:
|
||||
## no canonicalization; enter()'s does its own before calling in). Resets
|
||||
## every piece of held/request state for a fresh descent, exactly as the
|
||||
## pre-T-1153 enter() always did, plus the new _held_granularity_v2 tracking.
|
||||
##
|
||||
## **The C1 clamp-mirror lesson, one layer up (live-round finding):** `n`
|
||||
## MUST be clamped via `_clamp_window_n_mirror_v2()` BEFORE it becomes
|
||||
## `_held_n` — mirroring exactly what AtlasWindowRequest.request_now()
|
||||
## already does to ITS OWN `_n` before storing/sending (see that function's
|
||||
## own doc for the original PR #191 Tyre C1 finding). Storing the RAW `n`
|
||||
## here (e.g. enter_orbital()'s full district_extent().cols, routinely tens
|
||||
## of thousands at Region granularity, versus the server's clamped echo of
|
||||
## at most DISTRICT_WINDOW_MAX_N_REGION=6,400) left `_held_n` permanently
|
||||
## disagreeing with what the server would ever actually echo — every
|
||||
## orbital-rung response was silently rejected as stale by
|
||||
## _on_window_ready()'s `w_n != _held_n` check, hanging the ladder on every
|
||||
## real-sized body. `_maybe_reselect_rung()`/`_maybe_refloat_window()` both
|
||||
## read `_held_n` (never re-derive it), so clamping here — the ONE write
|
||||
## site — fixes every downstream caller too, not just entry.
|
||||
func _enter_at_rung(
|
||||
body: Dictionary,
|
||||
system: Dictionary,
|
||||
@@ -337,17 +352,20 @@ func _enter_at_rung(
|
||||
n: int,
|
||||
granularity_v2: String
|
||||
) -> void:
|
||||
var clamped_n: int = AtlasWindowRequest._clamp_window_n_mirror_v2(n, granularity_v2)
|
||||
_body = body
|
||||
_system = system
|
||||
_held_center = district_center
|
||||
_held_n = n
|
||||
_held_n = clamped_n
|
||||
_held_granularity_v2 = granularity_v2
|
||||
_window = null
|
||||
_user_adjusted = false
|
||||
_awaiting_first_window = true
|
||||
_fit_and_center()
|
||||
_window_request.reset()
|
||||
_window_request.request_now(_dict_str(_body, "body_id", ""), _held_center, n, granularity_v2)
|
||||
_window_request.request_now(
|
||||
_dict_str(_body, "body_id", ""), _held_center, clamped_n, granularity_v2
|
||||
)
|
||||
_refresh_screen_header()
|
||||
grab_focus()
|
||||
queue_redraw()
|
||||
|
||||
Reference in New Issue
Block a user