## PR #192 cold-start dossier (BUG 2): RegionalScreen.enter() tests. Split ## into its own file rather than folded into test_atlas_zoom_ladder.gd — ## these exercise the NAV-LAYER re-entry guard (RegionalScreen itself), not ## AtlasWindowViewer's own zoom-ladder mechanics that suite already owns. class_name TestRegionalScreen extends GdUnitTestSuite const AtlasWindowRequest := preload("res://ui/implant/apps/atlas/atlas_window_request.gd") ## Dudley's WINDOW_GRANULARITY_REGION_KEY sentinel — mirrors ## test_atlas_zoom_ladder.gd's own constant (see that file's doc for why the ## real wire value matters, not a convenient placeholder). const SERVER_LEGACY_GRANULARITY_REGION_SENTINEL: int = 4294967295 static func _mock_response(body_id: String, window: Variant) -> Dictionary: return {"body_id": body_id, "status": "Ready", "district_window": window} ## BUG 2 root cause: ImplantApp._on_screen_changed() calls enter() ## UNCONDITIONALLY on every screen_changed, including a repeat ## nav.push("regional", ...) landing on the SAME screen already showing ## (reachable from more than one input path — body-click, panel+Enter — and ## plausible for a player to trigger twice on a slow cold server before the ## first descent settles). Without RegionalScreen's own guard, a repeat ## entry re-ran the FULL enter_orbital() teardown/rebuild — tearing down ## every in-flight tile request node and rebuilding fresh (null-window) ones ## — orphaning whatever had already arrived, plus refreshing the legend ## from scratch each time (the confirmed ~10x legend stack). Proven here by ## an ARRIVED tile's data: a teardown+rebuild resets it to null; a genuine ## no-op leaves it exactly as it was — `is_same()` on `_tile_set` itself ## can't tell (that Node is a fixed field, never reassigned — only its ## INTERNAL request children get torn down and rebuilt). func test_repeat_enter_for_the_same_body_does_not_orphan_an_arrived_tile() -> void: var screen: RegionalScreen = auto_free(RegionalScreen.new()) add_child(screen) var body: Dictionary = {"body_id": "GJ380c", "body_radius_km": 6238.4} screen.enter({"body": body, "system": {}}) var tile_set = screen._viewer.get_tile_set() var first_tile_center: Vector2i = tile_set.get_tiles()[0]["center"] var arrived_window: Dictionary = { "center": [first_tile_center.x, first_tile_center.y], "n": AtlasWindowRequest.SERVER_DISTRICT_WINDOW_MAX_N_REGION, "granularity": SERVER_LEGACY_GRANULARITY_REGION_SENTINEL, "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", arrived_window)) assert_that(tile_set.get_tiles()[0]["window"]).override_failure_message( "sanity: the first tile's response must have been adopted before the repeat enter()" ).is_equal(arrived_window) screen.enter({"body": body, "system": {}}) assert_that(screen._viewer.get_tile_set().get_tiles()[0]["window"]).override_failure_message( "a repeat enter() for the SAME body must not orphan an already-arrived" + " tile — a teardown+rebuild resets every tile's window back to null," + " which is the confirmed source of the cold-start legend stacking bug" ).is_equal(arrived_window) ## A GENUINE body change (different body_id) must still enter fresh — the ## guard is scoped to "the same body, re-entered", never a blanket "ignore ## the second enter() call ever". func test_enter_for_a_different_body_still_re_enters() -> void: var screen: RegionalScreen = auto_free(RegionalScreen.new()) add_child(screen) screen.enter({"body": {"body_id": "GJ380c", "body_radius_km": 6238.4}, "system": {}}) screen.enter({"body": {"body_id": "OtherBody", "body_radius_km": 100.0}, "system": {}}) assert_str(screen._viewer.get_body_id()).override_failure_message( "a genuinely different body must still re-enter — not be swallowed by" + " the same-body guard" ).is_equal("OtherBody") ## get_body_id() itself: empty before any entry, the entered body's id after. func test_get_body_id_reflects_the_currently_held_body() -> void: var v: AtlasWindowViewer = auto_free(AtlasWindowViewer.new()) add_child(v) assert_str(v.get_body_id()).is_equal("") v.enter_orbital({"body_id": "GJ380c", "body_radius_km": 6238.4}, {}) assert_str(v.get_body_id()).is_equal("GJ380c")