From 7ab15baed522c850a461211e12dde96e5fb14c2e Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Sat, 25 Jul 2026 12:18:55 +0200 Subject: [PATCH] =?UTF-8?q?chore(meta):=20pql=20changelog=20=E2=80=94=20T-?= =?UTF-8?q?1183=20done,=20T-1191/T-1192=20filed,=20T-1189=20escalated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit T-1191: atlas edge-scroll pans on unfocused mouse motion (eyeball nit). T-1192: Global rung canvas fit/center presentation. T-1189: raised to high — Region-rung extent exceeds body on both axes at standard viewports (continent repeats + south-pole stripe smear), per the T-1183 eyeball captures Jeroen flagged. Co-Authored-By: Claude Fable 5 --- .pql/changelog/ticket_history/2026-07.sql | 26 +++++++++++++++++++++++ .pql/changelog/ticket_idmap/2026-07.sql | 2 ++ .pql/changelog/tickets/2026-07.sql | 24 +++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/.pql/changelog/ticket_history/2026-07.sql b/.pql/changelog/ticket_history/2026-07.sql index 64edbd8d5..bfa3c7935 100644 --- a/.pql/changelog/ticket_history/2026-07.sql +++ b/.pql/changelog/ticket_history/2026-07.sql @@ -1898,3 +1898,29 @@ INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, chang INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XZF4A978WS1J66Q2JBK8C', 'status', 'review', 'done', NULL, '2026-07-25 08:39:14', '2026-07-25 08:39:14.797', '2026-07-25 08:39:14.797', NULL, 'e766df18190ba474631380d40af1d295', 2) ON CONFLICT(hash) DO NOTHING; INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XW0ZMPVYA2CPBBTP88TQC', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 08:40:03', '2026-07-25 08:40:03.632', '2026-07-25 08:40:03.632', NULL, '52b02d51cae9a585e561b1354529b50a', 2) ON CONFLICT(hash) DO NOTHING; INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XW0ZMPVYA2CPBBTP88TQC', 'status', 'in_progress', 'review', NULL, '2026-07-25 09:11:50', '2026-07-25 09:11:50.463', '2026-07-25 09:11:50.463', NULL, '6373f0431b384b13ca6bb8fbc88d92ff', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD6EKPBQE08NA8VHP692W8', 'description', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward. + +Live round 4 addendum: client/tests/test_atlas_window_overlay_draw_smoke.gd (3 scenarios -> now 2 after removing a flaky harness-sanity check: single-window draw + tile-mosaic draw, both asserting real composited pixels via SubViewport render) is a standalone gdUnit file with its own headless-skip guard, added because this redesign hadn''t landed yet. When this ticket lands, migrate its 2 scenarios into the redesigned tests/visual.json harness (folding the standalone file away) for consistency with the rest of the real-rendering test suite — see docs/DEVOPS.md''s ''Real-rendering test exception'' note for the interim rationale. + +RE-SCOPED by D-255 (2026-07-24, body-map-viewer workshop): this becomes the capture harness for the STEPPED render architecture — goldens key on (body, step) canvases, not the retired continuous-zoom frames. The T-1152/T-1153 test suites (coverage-walk, continuous-zoom seams, compute_tile_grid mosaic) retire with their code in T-1182''s change; this re-scoped harness is their replacement and the eyeball-check substrate for every step canvas. More needed than ever — keep, don''t cancel. + +PR #203 fix-round inventory (2026-07-25): the retirement is now TOTAL — AtlasViewer and its whole cluster (atlas_viewer, atlas_marker_overlay, atlas_descend_geometry, atlas_legend_panel, atlas_generation_proxy, atlas_generation_state) are deleted. visual_scenarios.gd (_setup_atlas_golden_shot, 6 of 12 atlas_GJ* z2_0/z4_0 non-fit scenarios) and visual_capture.gd (_run_atlas_matrix) now call StepCanvasViewer methods that do not exist: get_heightmap_texture(), set_view(zoom, offset), get_view_offset() — the fit-zoom shots early-return before hitting them. Ruled in PR #203: NO shim (would resurrect the retired continuous-zoom API D-255 kills); the redesign here keys captures on (body, rung) via StepCanvasViewer''s real surface (enter/_scroll_rung/rung state + the echoed extent). get_overlay_defs()/set_overlay_visible() duck-type fine and survive. Until this lands, those 6 goldens + atlas_matrix are knowingly dead (manual make targets only, gate-invisible — confirmed again).', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward. + +Live round 4 addendum: client/tests/test_atlas_window_overlay_draw_smoke.gd (3 scenarios -> now 2 after removing a flaky harness-sanity check: single-window draw + tile-mosaic draw, both asserting real composited pixels via SubViewport render) is a standalone gdUnit file with its own headless-skip guard, added because this redesign hadn''t landed yet. When this ticket lands, migrate its 2 scenarios into the redesigned tests/visual.json harness (folding the standalone file away) for consistency with the rest of the real-rendering test suite — see docs/DEVOPS.md''s ''Real-rendering test exception'' note for the interim rationale. + +RE-SCOPED by D-255 (2026-07-24, body-map-viewer workshop): this becomes the capture harness for the STEPPED render architecture — goldens key on (body, step) canvases, not the retired continuous-zoom frames. The T-1152/T-1153 test suites (coverage-walk, continuous-zoom seams, compute_tile_grid mosaic) retire with their code in T-1182''s change; this re-scoped harness is their replacement and the eyeball-check substrate for every step canvas. More needed than ever — keep, don''t cancel. + +PR #203 fix-round inventory (2026-07-25): the retirement is now TOTAL — AtlasViewer and its whole cluster (atlas_viewer, atlas_marker_overlay, atlas_descend_geometry, atlas_legend_panel, atlas_generation_proxy, atlas_generation_state) are deleted. visual_scenarios.gd (_setup_atlas_golden_shot, 6 of 12 atlas_GJ* z2_0/z4_0 non-fit scenarios) and visual_capture.gd (_run_atlas_matrix) now call StepCanvasViewer methods that do not exist: get_heightmap_texture(), set_view(zoom, offset), get_view_offset() — the fit-zoom shots early-return before hitting them. Ruled in PR #203: NO shim (would resurrect the retired continuous-zoom API D-255 kills); the redesign here keys captures on (body, rung) via StepCanvasViewer''s real surface (enter/_scroll_rung/rung state + the echoed extent). get_overlay_defs()/set_overlay_visible() duck-type fine and survive. Until this lands, those 6 goldens + atlas_matrix are knowingly dead (manual make targets only, gate-invisible — confirmed again). + +Harness techniques inventory addition (from the PR #204 / T-1183 restart-persistence eyeball, 2026-07-25) — proven live-rendering eyeball patterns for shared-desktop sessions: + +1. InputSwallower pattern: root-level Node (added first, low process_priority), _input()+_unhandled_input() both call get_viewport().set_input_as_handled() unconditionally — neutralizes real desktop input reaching a `-s` SceneTree driver''s real window (X11/XWayland delivers pointer events to unfocused windows under the cursor). Verify via a per-capture-window intercept counter: N>0 intercepted AND zero resulting view drift is proof; 0 intercepted proves nothing. +2. In-process navigation via viewer methods, not OS input: call the same methods the app''s own gdUnit suite exercises (StepCanvasViewer.enter()/_scroll_rung(); RegionalScreen.enter() atlas-matrix precedent in visual_capture.gd) — identical production code path, no OS injection needed (Wayland/KWin blocks synthetic X11 injection for XWayland clients entirely). +3. View-transform logging at every capture: world_center, view_offset, the drawing Node2D''s canvas position, footprint_px alongside every screenshot — turns "pixels don''t match" into a root-causable mechanism (PR #204: drift matched PAN_SPEED_PX_S*frame_time*held-frames to 0.02px, identifying unfocused edge-scroll bleed, now T-1191). +4. Full-run-restart-on-anomaly, never partial retry: any mid-sequence assertion failure discards the whole run (cold-wipe for a cold-role attempt; fresh-process-only for a revisit-role attempt) — partial retries silently corrupt the state the comparison depends on. +5. Fixed-center revisit mode: record a prior run''s actual derived centers and re-request them literally on the comparison run, bypassing cursor-anchored re-derivation — required when run 2 must land on run 1''s exact cache keys, not merely repeat the gesture.', NULL, '2026-07-25 10:11:48', '2026-07-25 10:11:48.141', '2026-07-25 10:11:48.141', NULL, '83de23f3aa4c3087e6147b768a0646de', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8PRRFJQ3Y2V3R348DDRRM', 'description', 'Found in the T-1182 eyeball (2026-07-25): on Arbour (R=6711km, circumference ~42,166km), the Region rung''s viewport-fit canvas (~200x210 cells x 204.8km) slightly exceeds the body circumference, so derive_orbital_at_metres'' deliberate longitude wrap (rem_euclid) makes the continent visibly repeat side-by-side. Not a math bug — the world legitimately wraps in view. UX question: clamp the Region-rung viewport extent to the body circumference (extent is already server-clamped per D-255(b) — a per-body circumference cap on the requested extent would be a client-side transport refinement), or draw a wrap seam indicator. Smaller bodies make it worse. Captures: .cache/screenshots/t1182-eyeball/rung-ladder/02-region.png. Related: D-243 elastic seam, D-255(a).', 'Found in the T-1182 eyeball (2026-07-25): on Arbour (R=6711km, circumference ~42,166km), the Region rung''s viewport-fit canvas (~200x210 cells x 204.8km) slightly exceeds the body circumference, so derive_orbital_at_metres'' deliberate longitude wrap (rem_euclid) makes the continent visibly repeat side-by-side. Not a math bug — the world legitimately wraps in view. UX question: clamp the Region-rung viewport extent to the body circumference (extent is already server-clamped per D-255(b) — a per-body circumference cap on the requested extent would be a client-side transport refinement), or draw a wrap seam indicator. Smaller bodies make it worse. Captures: .cache/screenshots/t1182-eyeball/rung-ladder/02-region.png. Related: D-243 elastic seam, D-255(a). + +ESCALATION from the T-1183 eyeball captures (2026-07-25, GJ1c, .cache/screenshots/t1183-eyeball-run2/02-region.png): this is NOT a small-body edge case and it is TWO axes, not one. At a 1920x1080 viewport the Region rung requested extent 384x216 cells x 204.8 km = 78,643 x 44,237 km — exceeding even an Earth-class circumference (~40,000 km) roughly 2x horizontally, so the continents repeat side-by-side on EVERY body at Region rung, and the vertical span overruns both poles: rows past the pole clamp to the last row and render as smeared vertical stripes filling the bottom ~40% of the frame (much uglier than the longitude repeat — looks like corrupted data, not a wrapped map). Jeroen flagged the frame as looking broken. Fix shape: cap the Region-rung request extent to the body''s region grid (circumference in the x axis, pole-to-pole in the y axis — both already known client-side from the Global canvas extent echo), letterbox the remainder, and consider the same guard for any rung whose footprint can exceed the body. Priority raised low->high: this makes the Region rung look broken on every body at standard viewports.', NULL, '2026-07-25 10:17:29', '2026-07-25 10:17:29.416', '2026-07-25 10:17:29.416', NULL, '85ba92e8f7082cc30b1a60f86556b714', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8PRRFJQ3Y2V3R348DDRRM', 'priority', 'low', 'high', NULL, '2026-07-25 10:17:39', '2026-07-25 10:17:39.835', '2026-07-25 10:17:39.835', NULL, 'f9ed56ae2da9e57b3a1179fb72112226', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XW0ZMPVYA2CPBBTP88TQC', 'status', 'review', 'done', NULL, '2026-07-25 10:17:42', '2026-07-25 10:17:42.701', '2026-07-25 10:17:42.701', NULL, '4f651c137c2744d831d8b13a786fca08', 2) ON CONFLICT(hash) DO NOTHING; diff --git a/.pql/changelog/ticket_idmap/2026-07.sql b/.pql/changelog/ticket_idmap/2026-07.sql index 763437c20..69a607974 100644 --- a/.pql/changelog/ticket_idmap/2026-07.sql +++ b/.pql/changelog/ticket_idmap/2026-07.sql @@ -104,3 +104,5 @@ INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_ INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8P6C6WXEG3X81PVCQ833M', 'T-1188', '2026-07-25 07:17:23.684', '2026-07-25 07:17:23.684', NULL, 'f49c406f5369a03b4286ca068fab95c5', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash); INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8PRRFJQ3Y2V3R348DDRRM', 'T-1189', '2026-07-25 07:17:28.388', '2026-07-25 07:17:28.388', NULL, '14e7563bd5e58b24ab9406713769258f', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash); INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSH4VE4TTJGFGVVQWHACDBTM', 'T-1190', '2026-07-25 09:20:26.664', '2026-07-25 09:20:26.664', NULL, '773167921a274a9d43a49cea6d3ff65b', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash); +INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSHEPE2Q7GRKYJARH8Z8RPMR', 'T-1191', '2026-07-25 10:03:27.132', '2026-07-25 10:03:27.132', NULL, '572c6d4e5698b1f6a49e9126005e7c04', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash); +INSERT INTO ticket_idmap (record_id, ticket_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSHHXXTS56ZBB78N2W43DD2G', 'T-1192', '2026-07-25 10:17:34.935', '2026-07-25 10:17:34.935', NULL, 'c3f3e8674c19ed92f246c8090bbcd8ea', 2) ON CONFLICT(record_id) DO UPDATE SET ticket_id=excluded.ticket_id, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_idmap.updated_at OR (excluded.updated_at = ticket_idmap.updated_at AND excluded.hash > ticket_idmap.hash); diff --git a/.pql/changelog/tickets/2026-07.sql b/.pql/changelog/tickets/2026-07.sql index b7e9572de..75a613fe2 100644 --- a/.pql/changelog/tickets/2026-07.sql +++ b/.pql/changelog/tickets/2026-07.sql @@ -2747,3 +2747,27 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, stat INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XW0ZMPVYA2CPBBTP88TQC', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Client cache store: FileAccess dir, two-axis eviction, version tag, retention cap (D-255)', 'The client-side cache tiers per D-255(d) and Stig''s three-tier spec (stig-round2.md (c)): in-memory LRU (adapting atlas_window_tile_set.gd''s surviving LRU skeleton from the map-component ticket) + disk-backed FileAccess cache dir with index. Two-axis eviction per D-227 amendment (1) — staleness and storage are DISTINCT: geometry entries never go stale (determinism; byte-valid forever) and are evicted only by (2a) time-since-last-visit (Jeroen''s storage-thrift ruling) and (2b) LRU capacity budget, two independent sweeps kept separate; sim-state entries (frozen/flooded planes) carry the real staleness TTL (SIM_STATE_TTL formula — served/invalidated per the serving ticket''s server-side formula). Rung-0 Global entries: retention floor, never swept. HARDENING REQUIREMENTS from D-255(d), both mandatory: (i) per-body deep-rung retention cap (max resident chunk/block-spacing tile count or disk quota per body, independent of the rung-0 floor — the structural closure of the D-226(d) accumulation gap; the AtlasAgentInterface QA channel inherits the same cap); (ii) every persistent entry carries a schema/version tag (project version or generator stamp) — read-time mismatch = cache miss + re-fetch, NEVER decode (the D-192 co-ship boundary; a disk cache survives game updates). Index-entry schema sketch in stig-round2.md (key/file_path/tier/written_at/last_read_at/size_bytes/sim_ttl/retention_floor); sweep triggers on body-open + coarse background timer, never per-frame. Explicitly rejected by the workshop: SQLite in any shape (server-side relocation, godot-sqlite addon) — plain FileAccess + index won on both agents'' independent analyses. Design sources: stig-round2.md (c), dudley-round2.md (d), D-255(d), D-227 amendments (1)(2).', 'in_progress', 'high', NULL, 'client', 'D-255', '2026-07-24 07:12:01.789', '2026-07-25 08:40:03.632', NULL, 'a08751277ca8c113ad7b9427c8b9a579', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XW0ZMPVYA2CPBBTP88TQC', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Client cache store: FileAccess dir, two-axis eviction, version tag, retention cap (D-255)', 'The client-side cache tiers per D-255(d) and Stig''s three-tier spec (stig-round2.md (c)): in-memory LRU (adapting atlas_window_tile_set.gd''s surviving LRU skeleton from the map-component ticket) + disk-backed FileAccess cache dir with index. Two-axis eviction per D-227 amendment (1) — staleness and storage are DISTINCT: geometry entries never go stale (determinism; byte-valid forever) and are evicted only by (2a) time-since-last-visit (Jeroen''s storage-thrift ruling) and (2b) LRU capacity budget, two independent sweeps kept separate; sim-state entries (frozen/flooded planes) carry the real staleness TTL (SIM_STATE_TTL formula — served/invalidated per the serving ticket''s server-side formula). Rung-0 Global entries: retention floor, never swept. HARDENING REQUIREMENTS from D-255(d), both mandatory: (i) per-body deep-rung retention cap (max resident chunk/block-spacing tile count or disk quota per body, independent of the rung-0 floor — the structural closure of the D-226(d) accumulation gap; the AtlasAgentInterface QA channel inherits the same cap); (ii) every persistent entry carries a schema/version tag (project version or generator stamp) — read-time mismatch = cache miss + re-fetch, NEVER decode (the D-192 co-ship boundary; a disk cache survives game updates). Index-entry schema sketch in stig-round2.md (key/file_path/tier/written_at/last_read_at/size_bytes/sim_ttl/retention_floor); sweep triggers on body-open + coarse background timer, never per-frame. Explicitly rejected by the workshop: SQLite in any shape (server-side relocation, godot-sqlite addon) — plain FileAccess + index won on both agents'' independent analyses. Design sources: stig-round2.md (c), dudley-round2.md (d), D-255(d), D-227 amendments (1)(2).', 'review', 'high', NULL, 'client', 'D-255', '2026-07-24 07:12:01.789', '2026-07-25 09:11:50.463', NULL, '04e69662c15ff8d68e447fd1fd2f4403', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSH4VE4TTJGFGVVQWHACDBTM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Step-canvas wire staleness signal + client sim_ttl threading (D-253 clock seam)', 'Client disk cache (T-1183) and server StepCanvasCache (T-1181) both carry wired-ahead sim-state TTL machinery for glaciation/flooded_q, but no staleness signal crosses the wire: the server SIM_STATE_TTL formula is tick-based and server-side only, and step_canvas_request.gd calls disk_cache.put() without sim_ttl_sec, so every canvas is (correctly, today) Tier-2 geometry — flooded_q is hardwired 0 and glaciation is the static classification, byte-identical to a fresh derive (server/src/atlas/step_canvas.rs module doc, D-253 wired-ahead). The moment D-253''s sim-state driving clock lands and glaciation/flooded values actually vary with sim time, StepCanvasResponse must carry a TTL (or equivalent staleness signal) and on_response must thread it into the existing put(sim_ttl_sec) parameter so client disk-cached canvases re-request instead of serving stale sim-state indefinitely. Raised by tyre in PR #204 review; adjudicated as a future seam, not a live gap. Blocked conceptually on the D-253 driving clock existing.', 'backlog', 'low', NULL, 'client', 'D-227', '2026-07-25 09:20:26.662', '2026-07-25 09:20:26.662', NULL, '33e980c6a5a4d49fb8b6f2c56a69c274', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSHEPE2Q7GRKYJARH8Z8RPMR', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Atlas edge-scroll pans on mouse motion while window unfocused', 'Found during the PR #204 restart-persistence eyeball: StepCanvasViewer._process() edge-scroll (_is_cursor_edge_scrolling / EDGE_SCROLL_MARGIN_PX=24) acts on _last_mouse_pos updated from real InputEventMouseMotion, which X11/XWayland delivers to the window whenever the pointer is over it — focus not required. Quantitatively proven in the eyeball forensics (drift = PAN_SPEED_PX_S * frame_time * held-frames, 102.69px observed vs 102.67px predicted): a windowed-mode player mousing over the unfocused game window drifts the atlas map. Fix direction: gate edge-scroll (and likely other cursor-anchored viewer reactions) on window focus (DisplayServer window focus / Window.has_focus()), matching standard windowed-game behavior. Low priority — cosmetic in practice, no data effect.', 'backlog', 'low', NULL, 'client', NULL, '2026-07-25 10:03:27.125', '2026-07-25 10:03:27.125', NULL, '6f4a4281ad8eb68ba4343e2254955180', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD6EKPBQE08NA8VHP692W8', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Redesign the atlas visual-capture goldens for the zoom ladder (visual_scenarios/visual_capture)', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward. + +Live round 4 addendum: client/tests/test_atlas_window_overlay_draw_smoke.gd (3 scenarios -> now 2 after removing a flaky harness-sanity check: single-window draw + tile-mosaic draw, both asserting real composited pixels via SubViewport render) is a standalone gdUnit file with its own headless-skip guard, added because this redesign hadn''t landed yet. When this ticket lands, migrate its 2 scenarios into the redesigned tests/visual.json harness (folding the standalone file away) for consistency with the rest of the real-rendering test suite — see docs/DEVOPS.md''s ''Real-rendering test exception'' note for the interim rationale. + +RE-SCOPED by D-255 (2026-07-24, body-map-viewer workshop): this becomes the capture harness for the STEPPED render architecture — goldens key on (body, step) canvases, not the retired continuous-zoom frames. The T-1152/T-1153 test suites (coverage-walk, continuous-zoom seams, compute_tile_grid mosaic) retire with their code in T-1182''s change; this re-scoped harness is their replacement and the eyeball-check substrate for every step canvas. More needed than ever — keep, don''t cancel. + +PR #203 fix-round inventory (2026-07-25): the retirement is now TOTAL — AtlasViewer and its whole cluster (atlas_viewer, atlas_marker_overlay, atlas_descend_geometry, atlas_legend_panel, atlas_generation_proxy, atlas_generation_state) are deleted. visual_scenarios.gd (_setup_atlas_golden_shot, 6 of 12 atlas_GJ* z2_0/z4_0 non-fit scenarios) and visual_capture.gd (_run_atlas_matrix) now call StepCanvasViewer methods that do not exist: get_heightmap_texture(), set_view(zoom, offset), get_view_offset() — the fit-zoom shots early-return before hitting them. Ruled in PR #203: NO shim (would resurrect the retired continuous-zoom API D-255 kills); the redesign here keys captures on (body, rung) via StepCanvasViewer''s real surface (enter/_scroll_rung/rung state + the echoed extent). get_overlay_defs()/set_overlay_visible() duck-type fine and survive. Until this lands, those 6 goldens + atlas_matrix are knowingly dead (manual make targets only, gate-invisible — confirmed again). + +Harness techniques inventory addition (from the PR #204 / T-1183 restart-persistence eyeball, 2026-07-25) — proven live-rendering eyeball patterns for shared-desktop sessions: + +1. InputSwallower pattern: root-level Node (added first, low process_priority), _input()+_unhandled_input() both call get_viewport().set_input_as_handled() unconditionally — neutralizes real desktop input reaching a `-s` SceneTree driver''s real window (X11/XWayland delivers pointer events to unfocused windows under the cursor). Verify via a per-capture-window intercept counter: N>0 intercepted AND zero resulting view drift is proof; 0 intercepted proves nothing. +2. In-process navigation via viewer methods, not OS input: call the same methods the app''s own gdUnit suite exercises (StepCanvasViewer.enter()/_scroll_rung(); RegionalScreen.enter() atlas-matrix precedent in visual_capture.gd) — identical production code path, no OS injection needed (Wayland/KWin blocks synthetic X11 injection for XWayland clients entirely). +3. View-transform logging at every capture: world_center, view_offset, the drawing Node2D''s canvas position, footprint_px alongside every screenshot — turns "pixels don''t match" into a root-causable mechanism (PR #204: drift matched PAN_SPEED_PX_S*frame_time*held-frames to 0.02px, identifying unfocused edge-scroll bleed, now T-1191). +4. Full-run-restart-on-anomaly, never partial retry: any mid-sequence assertion failure discards the whole run (cold-wipe for a cold-role attempt; fresh-process-only for a revisit-role attempt) — partial retries silently corrupt the state the comparison depends on. +5. Fixed-center revisit mode: record a prior run''s actual derived centers and re-request them literally on the comparison run, bypassing cursor-anchored re-derivation — required when run 2 must land on run 1''s exact cache keys, not merely repeat the gesture.', 'backlog', 'medium', NULL, 'client', NULL, '2026-07-22 09:42:47.197', '2026-07-25 10:11:48.141', NULL, 'af61dc6cbe10368f5a6ee32397c3a71e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8PRRFJQ3Y2V3R348DDRRM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Region-rung viewport can exceed small-body circumference — continent visibly repeats (longitude wrap UX)', 'Found in the T-1182 eyeball (2026-07-25): on Arbour (R=6711km, circumference ~42,166km), the Region rung''s viewport-fit canvas (~200x210 cells x 204.8km) slightly exceeds the body circumference, so derive_orbital_at_metres'' deliberate longitude wrap (rem_euclid) makes the continent visibly repeat side-by-side. Not a math bug — the world legitimately wraps in view. UX question: clamp the Region-rung viewport extent to the body circumference (extent is already server-clamped per D-255(b) — a per-body circumference cap on the requested extent would be a client-side transport refinement), or draw a wrap seam indicator. Smaller bodies make it worse. Captures: .cache/screenshots/t1182-eyeball/rung-ladder/02-region.png. Related: D-243 elastic seam, D-255(a). + +ESCALATION from the T-1183 eyeball captures (2026-07-25, GJ1c, .cache/screenshots/t1183-eyeball-run2/02-region.png): this is NOT a small-body edge case and it is TWO axes, not one. At a 1920x1080 viewport the Region rung requested extent 384x216 cells x 204.8 km = 78,643 x 44,237 km — exceeding even an Earth-class circumference (~40,000 km) roughly 2x horizontally, so the continents repeat side-by-side on EVERY body at Region rung, and the vertical span overruns both poles: rows past the pole clamp to the last row and render as smeared vertical stripes filling the bottom ~40% of the frame (much uglier than the longitude repeat — looks like corrupted data, not a wrapped map). Jeroen flagged the frame as looking broken. Fix shape: cap the Region-rung request extent to the body''s region grid (circumference in the x axis, pole-to-pole in the y axis — both already known client-side from the Global canvas extent echo), letterbox the remainder, and consider the same guard for any rung whose footprint can exceed the body. Priority raised low->high: this makes the Region rung look broken on every body at standard viewports.', 'backlog', 'low', NULL, 'client', NULL, '2026-07-25 07:17:28.388', '2026-07-25 10:17:29.416', NULL, '9da309bf615eaf4aa6422a02418f6f83', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSHHXXTS56ZBB78N2W43DD2G', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Global rung presentation: fit/center the canvas in the viewport (currently top-left anchored at raw scale)', 'From the T-1183 eyeball captures (2026-07-25, .cache/screenshots/t1183-eyeball-run2/01-global.png): the Global rung canvas (GJ1c: 177x88 texels) draws top-left-anchored at its raw integer scale, occupying only the upper-left ~885x440 of a 1920x1080 viewport — the remaining ~60% of the screen is empty background, and the Atlas legend panel overlaps the canvas itself. The body-surface opener is the first thing a player sees in the Atlas; it should fit-scale (integer multiple preserving texel-exactness per D-255, or letterboxed non-integer if ruled acceptable) and center in the available viewport, with the legend laid out beside rather than over it. Pure client map-art presentation — no wire/server change; D-255(e) unaffected (same input set, different placement/scale).', 'backlog', 'medium', NULL, 'client', NULL, '2026-07-25 10:17:34.934', '2026-07-25 10:17:34.934', NULL, 'bab4e2b53aa50f7f825551f68f7e086d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8PRRFJQ3Y2V3R348DDRRM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Region-rung viewport can exceed small-body circumference — continent visibly repeats (longitude wrap UX)', 'Found in the T-1182 eyeball (2026-07-25): on Arbour (R=6711km, circumference ~42,166km), the Region rung''s viewport-fit canvas (~200x210 cells x 204.8km) slightly exceeds the body circumference, so derive_orbital_at_metres'' deliberate longitude wrap (rem_euclid) makes the continent visibly repeat side-by-side. Not a math bug — the world legitimately wraps in view. UX question: clamp the Region-rung viewport extent to the body circumference (extent is already server-clamped per D-255(b) — a per-body circumference cap on the requested extent would be a client-side transport refinement), or draw a wrap seam indicator. Smaller bodies make it worse. Captures: .cache/screenshots/t1182-eyeball/rung-ladder/02-region.png. Related: D-243 elastic seam, D-255(a). + +ESCALATION from the T-1183 eyeball captures (2026-07-25, GJ1c, .cache/screenshots/t1183-eyeball-run2/02-region.png): this is NOT a small-body edge case and it is TWO axes, not one. At a 1920x1080 viewport the Region rung requested extent 384x216 cells x 204.8 km = 78,643 x 44,237 km — exceeding even an Earth-class circumference (~40,000 km) roughly 2x horizontally, so the continents repeat side-by-side on EVERY body at Region rung, and the vertical span overruns both poles: rows past the pole clamp to the last row and render as smeared vertical stripes filling the bottom ~40% of the frame (much uglier than the longitude repeat — looks like corrupted data, not a wrapped map). Jeroen flagged the frame as looking broken. Fix shape: cap the Region-rung request extent to the body''s region grid (circumference in the x axis, pole-to-pole in the y axis — both already known client-side from the Global canvas extent echo), letterbox the remainder, and consider the same guard for any rung whose footprint can exceed the body. Priority raised low->high: this makes the Region rung look broken on every body at standard viewports.', 'backlog', 'high', NULL, 'client', NULL, '2026-07-25 07:17:28.388', '2026-07-25 10:17:39.835', NULL, 'a033d5af39befbb1b60d945dcf0ff078', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XW0ZMPVYA2CPBBTP88TQC', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Client cache store: FileAccess dir, two-axis eviction, version tag, retention cap (D-255)', 'The client-side cache tiers per D-255(d) and Stig''s three-tier spec (stig-round2.md (c)): in-memory LRU (adapting atlas_window_tile_set.gd''s surviving LRU skeleton from the map-component ticket) + disk-backed FileAccess cache dir with index. Two-axis eviction per D-227 amendment (1) — staleness and storage are DISTINCT: geometry entries never go stale (determinism; byte-valid forever) and are evicted only by (2a) time-since-last-visit (Jeroen''s storage-thrift ruling) and (2b) LRU capacity budget, two independent sweeps kept separate; sim-state entries (frozen/flooded planes) carry the real staleness TTL (SIM_STATE_TTL formula — served/invalidated per the serving ticket''s server-side formula). Rung-0 Global entries: retention floor, never swept. HARDENING REQUIREMENTS from D-255(d), both mandatory: (i) per-body deep-rung retention cap (max resident chunk/block-spacing tile count or disk quota per body, independent of the rung-0 floor — the structural closure of the D-226(d) accumulation gap; the AtlasAgentInterface QA channel inherits the same cap); (ii) every persistent entry carries a schema/version tag (project version or generator stamp) — read-time mismatch = cache miss + re-fetch, NEVER decode (the D-192 co-ship boundary; a disk cache survives game updates). Index-entry schema sketch in stig-round2.md (key/file_path/tier/written_at/last_read_at/size_bytes/sim_ttl/retention_floor); sweep triggers on body-open + coarse background timer, never per-frame. Explicitly rejected by the workshop: SQLite in any shape (server-side relocation, godot-sqlite addon) — plain FileAccess + index won on both agents'' independent analyses. Design sources: stig-round2.md (c), dudley-round2.md (d), D-255(d), D-227 amendments (1)(2).', 'done', 'high', NULL, 'client', 'D-255', '2026-07-24 07:12:01.789', '2026-07-25 10:17:42.696', NULL, 'fba61e686d33cc2a162aa081fd1a925d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);