## T-1182/T-1183 tests: step_canvas_request.gd — request lifecycle (cache ## hit/miss, staleness gate, the extent ECHO rule) plus the T-1183 disk-tier ## integration (Tier-2-before-wire miss path, write-through to both tiers). ## Live mode is required for SimBridge.request_step_canvas() to actually send ## (test_mode short-circuits it), so these tests exercise ## on_response()/request_now() against a directly-constructed ## StepCanvasRequest node without a live bridge connection — request_now() ## on a cache MISS calls into SimBridge, which is a silent no-op in ## test_mode (SimBridge.test_mode defaults true outside SR_LIVE=1), so no ## live server is needed for these assertions. ## ## Every test constructs its StepCanvasRequest with an INJECTED disk-cache ## root (never the real user://atlas_cache/ — see step_canvas_request.gd's ## `_init()` doc) and removes it in after_test(), matching ## test_step_canvas_disk_cache.gd's own isolation discipline. class_name TestStepCanvasRequest extends GdUnitTestSuite const StepCanvasRequestScript := preload("res://ui/implant/apps/atlas/step_canvas/step_canvas_request.gd") const StepCanvasDiskCache := preload( "res://ui/implant/apps/atlas/step_canvas/step_canvas_disk_cache.gd" ) var _test_disk_root: String = "" func before_test() -> void: _test_disk_root = "user://test_step_canvas_request/%d/" % Time.get_ticks_usec() func after_test() -> void: StepCanvasDiskCache.new(_test_disk_root).clear_all() func _make_request() -> Variant: var req = auto_free(StepCanvasRequestScript.new(null, _test_disk_root)) add_child(req) return req func test_cache_hit_emits_canvas_ready_synchronously_with_no_pending_state() -> void: var req = _make_request() var canvas := {"width": 64, "height": 64} req.get_cache().put("GJ1c", "District", Vector2i(0, 0), Vector2i(64, 64), canvas) var received: Array = [] req.canvas_ready.connect(func(c: Dictionary) -> void: received.append(c)) req.request_now("GJ1c", "District", Vector2i(0, 0), Vector2i(64, 64)) assert_int(received.size()).is_equal(1) assert_that(received[0]).is_equal(canvas) assert_bool(req.is_pending()).is_false() func test_cache_miss_sets_pending_true() -> void: var req = _make_request() req.request_now("GJ1c", "Chunk", Vector2i(0, 0), Vector2i(64, 64)) assert_bool(req.is_pending()).is_true() func test_on_response_ignores_a_response_for_a_different_body() -> void: var req = _make_request() req.request_now("GJ1c", "District", Vector2i(0, 0), Vector2i(64, 64)) var received: Array = [] req.canvas_ready.connect(func(c: Dictionary) -> void: received.append(c)) req.on_response( { "body_id": "SomeOtherBody", "rung": "District", "center": Vector2i(0, 0), "min_wl_m": 0, "status": "Ready", "canvas": {"width": 1}, } ) assert_int(received.size()).is_equal(0) func test_on_response_ignores_a_response_for_a_different_rung() -> void: var req = _make_request() req.request_now("GJ1c", "District", Vector2i(0, 0), Vector2i(64, 64)) var received: Array = [] req.canvas_ready.connect(func(c: Dictionary) -> void: received.append(c)) req.on_response( { "body_id": "GJ1c", "rung": "Chunk", # a different rung answering — must be ignored "center": Vector2i(0, 0), "min_wl_m": 0, "status": "Ready", "canvas": {"width": 1}, } ) assert_int(received.size()).is_equal(0) func test_on_response_ignores_a_stale_center_for_a_fixed_rung() -> void: var req = _make_request() req.request_now("GJ1c", "District", Vector2i(0, 0), Vector2i(64, 64)) var received: Array = [] req.canvas_ready.connect(func(c: Dictionary) -> void: received.append(c)) req.on_response( { "body_id": "GJ1c", "rung": "District", "center": Vector2i(999, 999), # answers a since-panned-away-from center "min_wl_m": 0, "status": "Ready", "canvas": {"width": 1}, } ) assert_int(received.size()).is_equal(0) ## Global ignores center/extent server-side — a Global response's staleness ## check must NOT compare center at all (an echoed (0,0) sentinel must not ## be rejected as "stale" against whatever was requested). func test_on_response_global_rung_ignores_center_in_staleness_check() -> void: var req = _make_request() req.request_now("GJ1c", "Global", Vector2i.ZERO, Vector2i.ZERO) var received: Array = [] req.canvas_ready.connect(func(c: Dictionary) -> void: received.append(c)) req.on_response( { "body_id": "GJ1c", "rung": "Global", "center": Vector2i.ZERO, "extent": Vector2i.ZERO, "min_wl_m": 0, "status": "Ready", "canvas": {"width": 19_139, "height": 9_569}, } ) assert_int(received.size()).is_equal(1) ## The extent ECHO rule (T-1181 wire addendum, mandatory): held extent comes ## from the RESPONSE's own echoed extent, never the requested one — a ## server-side clamp can shrink the actual canvas below what was asked for. func test_on_response_holds_the_echoed_extent_not_the_requested_one() -> void: var req = _make_request() req.request_now("GJ1c", "Chunk", Vector2i(0, 0), Vector2i(9_999, 9_999)) req.on_response( { "body_id": "GJ1c", "rung": "Chunk", "center": Vector2i(0, 0), "extent": Vector2i(3_840, 2_160), # server-clamped echo, smaller than requested "min_wl_m": 0, "status": "Ready", "canvas": {"width": 3_840, "height": 2_160}, } ) assert_that(req.get_held_extent()).is_equal(Vector2i(3_840, 2_160)) ## Global's held extent comes from the canvas's own width/height (the wire ## extent echo is a fixed (0,0) sentinel for that rung — nothing to read). func test_on_response_global_held_extent_derives_from_canvas_dimensions() -> void: var req = _make_request() req.request_now("GJ1c", "Global", Vector2i.ZERO, Vector2i.ZERO) req.on_response( { "body_id": "GJ1c", "rung": "Global", "center": Vector2i.ZERO, "extent": Vector2i.ZERO, "min_wl_m": 0, "status": "Ready", "canvas": {"width": 19_139, "height": 9_569}, } ) assert_that(req.get_held_extent()).is_equal(Vector2i(19_139, 9_569)) func test_on_response_ready_with_null_canvas_retries_rather_than_adopting() -> void: var req = _make_request() req.request_now("GJ1c", "District", Vector2i(0, 0), Vector2i(64, 64)) var received: Array = [] req.canvas_ready.connect(func(c: Dictionary) -> void: received.append(c)) req.on_response( { "body_id": "GJ1c", "rung": "District", "center": Vector2i(0, 0), "min_wl_m": 0, "status": "Ready", "canvas": null, } ) assert_int(received.size()).is_equal(0) assert_bool(req.is_pending()).is_true() func test_on_response_not_found_gives_up_immediately() -> void: var req = _make_request() req.request_now("GJ1c", "Chunk", Vector2i(0, 0), Vector2i(64, 64)) req.on_response({"body_id": "GJ1c", "rung": "Chunk", "status": "NotFound"}) assert_bool(req.is_pending()).is_false() func test_on_response_stores_a_fresh_ready_canvas_in_the_cache() -> void: var req = _make_request() req.request_now("GJ1c", "District", Vector2i(5, 5), Vector2i(64, 64)) req.on_response( { "body_id": "GJ1c", "rung": "District", "center": Vector2i(5, 5), "extent": Vector2i(64, 64), "min_wl_m": 0, "status": "Ready", "canvas": {"width": 64, "height": 64}, } ) assert_bool(req.get_cache().has("GJ1c", "District", Vector2i(5, 5), Vector2i(64, 64))).is_true() # ============================================================================= # T-1183: Tier-2 (disk) integration # ============================================================================= ## A fresh Ready response must write through to BOTH tiers, not just Tier 1 ## — the whole point of the disk tier is that a LATER, separate ## StepCanvasRequest instance (e.g. after a Tier-1 LRU eviction in this ## session, or a full app restart) can still serve this key without a wire ## round-trip. func test_on_response_writes_through_to_both_the_memory_and_disk_tiers() -> void: var req = _make_request() req.request_now("GJ1c", "Quarter", Vector2i(3, 3), Vector2i(64, 64)) req.on_response( { "body_id": "GJ1c", "rung": "Quarter", "center": Vector2i(3, 3), "extent": Vector2i(64, 64), "min_wl_m": 0, "status": "Ready", "canvas": {"width": 64, "height": 64}, } ) assert_bool(req.get_cache().has("GJ1c", "Quarter", Vector2i(3, 3), Vector2i(64, 64))).is_true() assert_bool( req.get_disk_cache().has("GJ1c", "Quarter", Vector2i(3, 3), Vector2i(64, 64)) ).override_failure_message("a fresh Ready response must ALSO land in the disk tier").is_true() ## A Tier-1 miss that IS present on disk must be served from disk — ## synchronously, no Pending state — and promoted into Tier 1 so the next ## identical request is a pure in-memory hit. func test_disk_hit_on_tier1_miss_is_served_without_going_pending() -> void: var req = _make_request() var canvas := {"width": 64, "height": 64, "morphology": PackedByteArray([1, 2, 3])} req.get_disk_cache().put("GJ1c", "Block", Vector2i(9, 9), Vector2i(64, 64), canvas) # Confirm this is genuinely a Tier-1 miss before the request. assert_bool(req.get_cache().has("GJ1c", "Block", Vector2i(9, 9), Vector2i(64, 64))).is_false() var received: Array = [] req.canvas_ready.connect(func(c: Dictionary) -> void: received.append(c)) req.request_now("GJ1c", "Block", Vector2i(9, 9), Vector2i(64, 64)) assert_int(received.size()).is_equal(1) assert_that(received[0]).is_equal(canvas) assert_bool(req.is_pending()).override_failure_message( "a disk-tier hit must be served synchronously, never leave the request Pending" ).is_false() ## A disk hit promotes into Tier 1 — the NEXT identical request must be ## servable purely from memory (this is what makes the disk tier "cache- ## accelerated": the second lookup for the same key never touches disk ## again this session). func test_disk_hit_promotes_into_tier1_for_the_next_lookup() -> void: var req = _make_request() var canvas := {"width": 32, "height": 32} req.get_disk_cache().put("GJ1c", "Block", Vector2i(1, 1), Vector2i(64, 64), canvas) req.request_now("GJ1c", "Block", Vector2i(1, 1), Vector2i(64, 64)) assert_bool(req.get_cache().has("GJ1c", "Block", Vector2i(1, 1), Vector2i(64, 64))).override_failure_message( "a disk-tier hit must be promoted into Tier 1 on read" ).is_true() ## A Global-rung write-through must set the disk tier's retention-floor flag ## — the client-side mechanism for "never evicted by either sweep axis" ## (D-255(d)). func test_global_rung_write_through_sets_the_disk_retention_floor() -> void: var req = _make_request() req.request_now("GJ1c", "Global", Vector2i.ZERO, Vector2i.ZERO) req.on_response( { "body_id": "GJ1c", "rung": "Global", "center": Vector2i.ZERO, "extent": Vector2i.ZERO, "min_wl_m": 0, "status": "Ready", "canvas": {"width": 19_139, "height": 9_569}, } ) var key := StepCanvasDiskCache.make_key("GJ1c", "Global", Vector2i.ZERO, Vector2i.ZERO) # Backdate to ancient, then run the visit sweep — a floored entry must # survive regardless of age, proving the write-through path (not just # put() called directly, as the disk-cache unit tests already cover) # correctly threads the Global rung into the floor flag. req.get_disk_cache()._debug_backdate_entry("GJ1c", key, 0, 0) req.get_disk_cache().run_visit_sweep("GJ1c") assert_bool(req.get_disk_cache().has("GJ1c", "Global", Vector2i.ZERO, Vector2i.ZERO)).is_true() ## Neither tier is touched by a miss that never resolves (still Pending) — ## write-through only happens on an adopted Ready response. func test_disk_tier_is_not_written_while_still_pending() -> void: var req = _make_request() req.request_now("GJ1c", "Chunk", Vector2i(0, 0), Vector2i(64, 64)) assert_bool(req.get_disk_cache().has("GJ1c", "Chunk", Vector2i(0, 0), Vector2i(64, 64))).is_false()