From b56f6b0bc8f49aa77ce59c851dd0772b7f64f1fa Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Tue, 21 Jul 2026 08:59:08 +0200 Subject: [PATCH 1/4] fix(ui): T-1140 overlay bar wraps instead of overflowing; strip dev ids from tooltips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Jeroen's first make atlas hands-on: 17 overlay chips in a single HBoxContainer row ran off the right screen edge (positioning also guessed the bar's width with a 520px fallback). The bar is now an HFlowContainer with ALIGNMENT_END; the viewer gives it everything right of the header (OVERLAY_BAR_HEADER_RESERVE) and rows wrap right-aligned — verified via live capture, all 18 chips visible. OVERLAY_DEFS tooltips leaked dev provenance into player-facing text — ticket ids (#960, T-960, T-1046, T-1118, T-1119) and decision ids (D-181, D-226, D-243) mean nothing in-game. Stripped to plain language; the visibility-ladder semantics (public signal / observable / needs corporate contact / needs insider access) stay. Co-Authored-By: Claude Fable 5 --- .pql/changelog/ticket_history/2026-07.sql | 8 ++++ .pql/changelog/tickets/2026-07.sql | 7 ++++ .../implant/apps/atlas/atlas_overlay_bar.gd | 11 ++++- client/ui/implant/apps/atlas/atlas_viewer.gd | 41 +++++++++++-------- 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/.pql/changelog/ticket_history/2026-07.sql b/.pql/changelog/ticket_history/2026-07.sql index 3a7a1c372..51ecc40ee 100644 --- a/.pql/changelog/ticket_history/2026-07.sql +++ b/.pql/changelog/ticket_history/2026-07.sql @@ -1573,3 +1573,11 @@ Design change from the PR #185 Troblum review (binding, folded into the amendmen 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 ('06FPRZZ0P42NHC1QR5S3737EV4', 'status', 'review', 'done', NULL, '2026-07-18 10:47:49', '2026-07-18 10:47:49.025', '2026-07-18 10:47:49.025', NULL, 'ba6fc0953709dac9cc737c7f5899fa6d', 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 ('06FPQXFFHXEEDQEM7PGXAH3534', 'status', 'review', 'done', NULL, '2026-07-18 10:47:49', '2026-07-18 10:47:49.028', '2026-07-18 10:47:49.028', NULL, '4ae28f9b2965c36f1c4b7e6f88c5355f', 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 ('06FPQXHDSMSVD3VADV38NG9STW', 'status', 'review', 'done', NULL, '2026-07-18 10:47:49', '2026-07-18 10:47:49.029', '2026-07-18 10:47:49.029', NULL, 'f329401a96278d3e8ee18598e2bc601a', 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 ('06FQ9B977KGH3BWP1YQTN32TYM', 'description', 'Implement the D-226 T-1124 amendment SS5 (client half). protocol.gd passthrough: encode_atlas_layer_request gains the window params (serde-default absent = whole-body); atlas_response_from_raw gains district_window passthrough (the doc comment near protocol.gd:801 names this the one client-side spot). New regional viewing mode per SS5: zoom-threshold LOD swap in the existing AtlasViewer (new DISTRICT_WINDOW_MIN_ZOOM past SETTLEMENT_LABEL_MIN_ZOOM — not a new screen, not a nav push); morphology base layer lightness-modulated by elev_q (probe MORPHOLOGY_RGB hues); gen_dw_temp/gen_dw_moisture/gen_dw_veg toggle overlays (temp reuses the T-1118 region-ramp colorizer EXACTLY — one colorizer across both zoom levels; Marine=6 renders transparent; glaciation is an always-on ice-tint modifier, not a toggle); GENERATION_LEGEND entries with the 17-zone base folded to ~5 family rows. Client window cache keyed (body_id, center, n), LRU-evict only (D-227 determinism — no freshness check). Re-request on PAN ONLY when the view passes the held window''s edge (zoom never refetches); 150ms post-drag-release debounce; windows float on the pan center (not grid-snapped). Implant chrome: ImplantHeader anchor name + extent subtitle; map palettes stay out of theme accent roles (ACCENT_ACTIVE gold is the settlement marker''s). + +Implementation note (Tyre, T-1124 report): DISTRICT_WINDOW_MIN_ZOOM proposed at 6.0 but atlas_viewer.gd caps _view_zoom at MAX_ZOOM = 8.0 — only a 6.0-8.0 band for the whole in-window-zoom detail story the SS5 legibility argument depends on. Tunable client constant, not wire contract: either lower the swap threshold or raise MAX_ZOOM; decide with on-screen-scale math at implementation.', 'Implement the D-226 T-1124 amendment SS5 (client half). protocol.gd passthrough: encode_atlas_layer_request gains the window params (serde-default absent = whole-body); atlas_response_from_raw gains district_window passthrough (the doc comment near protocol.gd:801 names this the one client-side spot). New regional viewing mode per SS5: zoom-threshold LOD swap in the existing AtlasViewer (new DISTRICT_WINDOW_MIN_ZOOM past SETTLEMENT_LABEL_MIN_ZOOM — not a new screen, not a nav push); morphology base layer lightness-modulated by elev_q (probe MORPHOLOGY_RGB hues); gen_dw_temp/gen_dw_moisture/gen_dw_veg toggle overlays (temp reuses the T-1118 region-ramp colorizer EXACTLY — one colorizer across both zoom levels; Marine=6 renders transparent; glaciation is an always-on ice-tint modifier, not a toggle); GENERATION_LEGEND entries with the 17-zone base folded to ~5 family rows. Client window cache keyed (body_id, center, n), LRU-evict only (D-227 determinism — no freshness check). Re-request on PAN ONLY when the view passes the held window''s edge (zoom never refetches); 150ms post-drag-release debounce; windows float on the pan center (not grid-snapped). Implant chrome: ImplantHeader anchor name + extent subtitle; map palettes stay out of theme accent roles (ACCENT_ACTIVE gold is the settlement marker''s). + +Implementation note (Tyre, T-1124 report): DISTRICT_WINDOW_MIN_ZOOM proposed at 6.0 but atlas_viewer.gd caps _view_zoom at MAX_ZOOM = 8.0 — only a 6.0-8.0 band for the whole in-window-zoom detail story the SS5 legibility argument depends on. Tunable client constant, not wire contract: either lower the swap threshold or raise MAX_ZOOM; decide with on-screen-scale math at implementation. + +SUPERSEDED ENTRY MECHANIC (Jeroen, 2026-07-21 companion hands-on — recorded as the D-226 T-1124 SS5 entry revision): NO zoom-threshold LOD swap and NO DISTRICT_WINDOW_MIN_ZOOM — the earlier zoom-headroom note is moot. The planetary heightmap view becomes FIXED: remove drag-pan/wheel-zoom of the planetary canvas IN THIS TICKET, same change as the replacement (never strand close inspection), and update the header hint text accordingly. Entry: hovering the planetary heightmap shows a rectangle cursor representing the regional-mode bounds; click descends into the regional map centered on the click point''s derived DistrictPos (float-on-center rules carry over with pan-center read as click-point). In-mode behavior unchanged (pan-only refetch, 150ms debounce, D-227 cache, border-fade). Morph transition between modes explicitly deferred — the descent may cut. Open design point: the rectangle cursor is an affordance, not to scale (n=64 = ~131km = a few px on a planetary canvas) — resolve the honest representation (true-extent rectangle + zoom-in cut, or not-to-scale reticle with the real extent labeled) without implying more coverage than real. Note: set_view/get_view_offset (T-1120 capture API) must survive for the visual-golden harness even after user pan/zoom is removed.', NULL, '2026-07-21 06:58:26', '2026-07-21 06:58:26.870', '2026-07-21 06:58:26.870', NULL, '60f8b73d47b3a1ec7ddf8f6024f640b7', 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 ('06FR6Y1CNA5JJ68RN897RM7FBC', 'status', 'backlog', 'in_progress', NULL, '2026-07-21 06:58:48', '2026-07-21 06:58:48.125', '2026-07-21 06:58:48.125', NULL, '07436c6c5318eca6cd011f2dd67c2dc1', 2) ON CONFLICT(hash) DO NOTHING; diff --git a/.pql/changelog/tickets/2026-07.sql b/.pql/changelog/tickets/2026-07.sql index 7d1d639c9..7d4aad061 100644 --- a/.pql/changelog/tickets/2026-07.sql +++ b/.pql/changelog/tickets/2026-07.sql @@ -2301,3 +2301,10 @@ Client anchors: SETTLEMENT_LABEL_MIN_ZOOM = 2.0 at atlas_marker_overlay.gd:113; IN-SCOPE boilerplate not named in the six points: the get/set_generation_quarter_footprints accessor pair on atlas_viewer.gd (folded into touch point 4, exactly as region_grid''s accessors ride its OVERLAY_DEFS entry; protocol dispatch calls the setter — see protocol.gd:436 pattern). Batch split (lead): points 1-2 (server) = Dudley, who also owns the gen_fixtures.rs edits for this batch (consider adding a populated quarter_footprints literal alongside T-1118''s region_grid literal — reviewers will expect the new layer to have fixture coverage); points 3-6 (client) + T-1118 = Stig. Dudley pins the quarter_footprints wire field names/types FIRST and messages Stig the shape before Stig wires the client half.', 'done', 'medium', NULL, 'server', 'D-226', '2026-07-16 17:25:23.533', '2026-07-18 10:47:49.028', NULL, '8b740a6c9acd80c1a96141ebf05d491b', 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 ('06FQ9B977KGH3BWP1YQTN32TYM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Atlas regional map screen — client half (D-226 T-1124 amendment SS5)', 'Implement the D-226 T-1124 amendment SS5 (client half). protocol.gd passthrough: encode_atlas_layer_request gains the window params (serde-default absent = whole-body); atlas_response_from_raw gains district_window passthrough (the doc comment near protocol.gd:801 names this the one client-side spot). New regional viewing mode per SS5: zoom-threshold LOD swap in the existing AtlasViewer (new DISTRICT_WINDOW_MIN_ZOOM past SETTLEMENT_LABEL_MIN_ZOOM — not a new screen, not a nav push); morphology base layer lightness-modulated by elev_q (probe MORPHOLOGY_RGB hues); gen_dw_temp/gen_dw_moisture/gen_dw_veg toggle overlays (temp reuses the T-1118 region-ramp colorizer EXACTLY — one colorizer across both zoom levels; Marine=6 renders transparent; glaciation is an always-on ice-tint modifier, not a toggle); GENERATION_LEGEND entries with the 17-zone base folded to ~5 family rows. Client window cache keyed (body_id, center, n), LRU-evict only (D-227 determinism — no freshness check). Re-request on PAN ONLY when the view passes the held window''s edge (zoom never refetches); 150ms post-drag-release debounce; windows float on the pan center (not grid-snapped). Implant chrome: ImplantHeader anchor name + extent subtitle; map palettes stay out of theme accent roles (ACCENT_ACTIVE gold is the settlement marker''s). + +Implementation note (Tyre, T-1124 report): DISTRICT_WINDOW_MIN_ZOOM proposed at 6.0 but atlas_viewer.gd caps _view_zoom at MAX_ZOOM = 8.0 — only a 6.0-8.0 band for the whole in-window-zoom detail story the SS5 legibility argument depends on. Tunable client constant, not wire contract: either lower the swap threshold or raise MAX_ZOOM; decide with on-screen-scale math at implementation. + +SUPERSEDED ENTRY MECHANIC (Jeroen, 2026-07-21 companion hands-on — recorded as the D-226 T-1124 SS5 entry revision): NO zoom-threshold LOD swap and NO DISTRICT_WINDOW_MIN_ZOOM — the earlier zoom-headroom note is moot. The planetary heightmap view becomes FIXED: remove drag-pan/wheel-zoom of the planetary canvas IN THIS TICKET, same change as the replacement (never strand close inspection), and update the header hint text accordingly. Entry: hovering the planetary heightmap shows a rectangle cursor representing the regional-mode bounds; click descends into the regional map centered on the click point''s derived DistrictPos (float-on-center rules carry over with pan-center read as click-point). In-mode behavior unchanged (pan-only refetch, 150ms debounce, D-227 cache, border-fade). Morph transition between modes explicitly deferred — the descent may cut. Open design point: the rectangle cursor is an affordance, not to scale (n=64 = ~131km = a few px on a planetary canvas) — resolve the honest representation (true-extent rectangle + zoom-in cut, or not-to-scale reticle with the real extent labeled) without implying more coverage than real. Note: set_view/get_view_offset (T-1120 capture API) must survive for the visual-golden harness even after user pan/zoom is removed.', 'backlog', 'high', NULL, 'client', NULL, '2026-07-18 10:02:12.668', '2026-07-21 06:58:26.869', NULL, '946d4b4a331ee0dd7bf0ae1e08bb2da1', 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 ('06FR6Y1CNA5JJ68RN897RM7FBC', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Companion Atlas friction — overlay bar overflows right edge; dev ticket ids in tooltips', 'Jeroen''s first make atlas hands-on (2026-07-21). Two UI defects on the shared Atlas viewer (visible in-game too): (1) the overlay toggle bar is a single HBoxContainer row — 17 chips at 42px min overflow the right screen edge (his 2000px window cut the bar mid-BAS); positioning also measured the bar''s own width with a 520px fallback, aggravating the overflow. Fix: HFlowContainer with ALIGNMENT_END, viewer gives it everything right of the header (OVERLAY_BAR_HEADER_RESERVE) and rows wrap right-aligned. (2) OVERLAY_DEFS tooltips leaked dev provenance into player-facing text — ticket ids (#960, T-960, T-1046, T-1118, T-1119) and decision ids (D-181, D-226, D-243) mean nothing in-game; stripped to plain language keeping the semantic content (visibility-ladder wording like observable/needs corporate contact stays). His third point — planetary map fixed + rectangle-cursor click-through entry — is a design revision recorded on D-226 (T-1124 SS5 entry revision) and folded into T-1138, not this bug.', 'backlog', 'medium', NULL, 'client', NULL, '2026-07-21 06:58:38.890', '2026-07-21 06:58:38.890', NULL, '685d1e4e2587c40abb524d7a9a64c4d7', 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 ('06FR6Y1CNA5JJ68RN897RM7FBC', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Companion Atlas friction — overlay bar overflows right edge; dev ticket ids in tooltips', 'Jeroen''s first make atlas hands-on (2026-07-21). Two UI defects on the shared Atlas viewer (visible in-game too): (1) the overlay toggle bar is a single HBoxContainer row — 17 chips at 42px min overflow the right screen edge (his 2000px window cut the bar mid-BAS); positioning also measured the bar''s own width with a 520px fallback, aggravating the overflow. Fix: HFlowContainer with ALIGNMENT_END, viewer gives it everything right of the header (OVERLAY_BAR_HEADER_RESERVE) and rows wrap right-aligned. (2) OVERLAY_DEFS tooltips leaked dev provenance into player-facing text — ticket ids (#960, T-960, T-1046, T-1118, T-1119) and decision ids (D-181, D-226, D-243) mean nothing in-game; stripped to plain language keeping the semantic content (visibility-ladder wording like observable/needs corporate contact stays). His third point — planetary map fixed + rectangle-cursor click-through entry — is a design revision recorded on D-226 (T-1124 SS5 entry revision) and folded into T-1138, not this bug.', 'in_progress', 'medium', NULL, 'client', NULL, '2026-07-21 06:58:38.890', '2026-07-21 06:58:48.125', NULL, '1944f85140fa14cfe8a5676b6452bdf2', 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); diff --git a/client/ui/implant/apps/atlas/atlas_overlay_bar.gd b/client/ui/implant/apps/atlas/atlas_overlay_bar.gd index 64e3b3028..fe7418701 100644 --- a/client/ui/implant/apps/atlas/atlas_overlay_bar.gd +++ b/client/ui/implant/apps/atlas/atlas_overlay_bar.gd @@ -1,4 +1,4 @@ -extends HBoxContainer +extends HFlowContainer ## Overlay toggle bar for #835 AtlasViewer — nine MVP overlays plus two locked ## layers (#836, D-191 §7, D-181 signal visibility ladder). @@ -11,6 +11,11 @@ extends HBoxContainer ## Layout: [ALWAYS-ON] [TOGGLEABLE] [LOCKED]. Each row in viewer.get_overlay_defs() ## produces exactly one button, so adding or retiring an overlay is a one-file ## change — the bar and marker renderer stay in lockstep (review #7). +## +## HFlowContainer, not HBoxContainer: the overlay count outgrew one row +## (17 chips at 42px min overflowed the right screen edge — Jeroen, +## companion feedback 2026-07-21). The viewer gives the bar a constrained +## width (everything right of the header) and rows wrap right-aligned. const COLOR_PINNED: Color = Color("#c8d0e0") const COLOR_ACTIVE: Color = Color("#f0d060") @@ -23,7 +28,9 @@ var _buttons: Dictionary = {} # overlay_id -> Button func _init(viewer_ref = null) -> void: _viewer = viewer_ref - add_theme_constant_override("separation", 4) + alignment = FlowContainer.ALIGNMENT_END + add_theme_constant_override("h_separation", 4) + add_theme_constant_override("v_separation", 4) func _ready() -> void: diff --git a/client/ui/implant/apps/atlas/atlas_viewer.gd b/client/ui/implant/apps/atlas/atlas_viewer.gd index 20eff46b5..de09f16e4 100644 --- a/client/ui/implant/apps/atlas/atlas_viewer.gd +++ b/client/ui/implant/apps/atlas/atlas_viewer.gd @@ -33,6 +33,9 @@ const ZOOM_STEP: float = 1.15 const PANEL_WIDTH: float = 320.0 const PANEL_MARGIN: float = 16.0 +# Width reserved for the top-left header block (title + hint lines) that the +# wrapping overlay bar must not overlap. +const OVERLAY_BAR_HEADER_RESERVE: float = 360.0 # ── Colors ──────────────────────────────────────────────────────────────────── const COLOR_BG: Color = Color("#0d1117") @@ -96,80 +99,80 @@ const OVERLAY_DEFS: Array = [ "id": "population_density", "label": "POP", "group": "toggle", - "tooltip": "Population density (D-181 public)." + "tooltip": "Population density (public signal)." }, { "id": "production_zones", "label": "PRD", "group": "toggle", - "tooltip": "Production zones (D-181 observable — requires presence)." + "tooltip": "Production zones (observable — requires presence)." }, { "id": "corp_presence", "label": "CRP", "group": "toggle", - "tooltip": "Corporate presence — Tier 1 only (D-181 observable)." + "tooltip": "Corporate presence — Tier 1 only (observable)." }, { "id": "stockpile_weeks", "label": "STK", "group": "locked", - "tooltip": "Stockpile weeks — LOCKED. Needs corporate contact (D-181 semi-private)." + "tooltip": "Stockpile weeks — LOCKED. Needs corporate contact." }, { "id": "production_vs_baseline", "label": "BSL", "group": "locked", - "tooltip": "Production vs baseline — LOCKED. Needs insider access (D-181 private)." + "tooltip": "Production vs baseline — LOCKED. Needs insider access." }, { "id": "gen_l1_rivers", "label": "RVR", "group": "toggle", - "tooltip": "Layer 1 — river network (generation overlay, #960)." + "tooltip": "River network (generation overlay)." }, { "id": "gen_l1_basins", "label": "BAS", "group": "toggle", - "tooltip": "Layer 1 — drainage basins (generation overlay, #960)." + "tooltip": "Drainage basins (generation overlay)." }, { "id": "gen_l1_attractors", "label": "ATR", "group": "toggle", - "tooltip": "Layer 1 — geographic attractors (generation overlay, #960)." + "tooltip": "Geographic attractors (generation overlay)." }, { "id": "gen_district", "label": "MRPH", "group": "toggle", - "tooltip": "District morphology zones (generation overlay, T-1046/D-226)." + "tooltip": "District morphology zones (generation overlay)." }, { "id": "gen_l2_roads", "label": "RDS", "group": "toggle", "tooltip": - "Layer 2 — inter-settlement road/rail graph, colored by maintenance authority (generation overlay, T-960)." + "Inter-settlement road/rail graph, colored by maintenance authority (generation overlay)." }, { "id": "gen_l3_settlements", "label": "STL", "group": "toggle", - "tooltip": "Layer 3 — settlement placements, sized by population (generation overlay, T-960)." + "tooltip": "Settlement placements, sized by population (generation overlay)." }, { "id": "gen_region_grid", "label": "TMP", "group": "toggle", - "tooltip": "Region climate grid — mean temperature (generation overlay, T-1118/D-243)." + "tooltip": "Region climate — mean temperature (generation overlay)." }, { "id": "gen_l4_quarters", "label": "QTR", "group": "toggle", - "tooltip": "Layer 4 — quarter footprint, color=density shape=type (generation overlay, T-1119)." + "tooltip": "Quarter footprints — color is density, shape is district type (generation overlay)." }, ] @@ -949,9 +952,15 @@ func _position_overlay_bar() -> void: var sz: Vector2 = get_rect().size if sz == Vector2.ZERO: sz = Vector2(1280.0, 720.0) - # Top-right, leaving room for the header text - var bar_w: float = _overlay_bar.size.x if _overlay_bar.size.x > 0.0 else 520.0 - _overlay_bar.position = Vector2(sz.x - bar_w - PANEL_MARGIN, PANEL_MARGIN) + # Top-right, constrained to everything right of the header. The bar is an + # HFlowContainer with ALIGNMENT_END: give it the available width and it + # wraps into as many right-aligned rows as the chip count needs (17 chips + # overflowed the screen edge as a single HBox row — companion feedback, + # 2026-07-21). Height is Control-clamped to the flow's minimum, so it + # grows per row on its own. + var avail_w: float = maxf(sz.x - OVERLAY_BAR_HEADER_RESERVE - PANEL_MARGIN * 2.0, 200.0) + _overlay_bar.position = Vector2(sz.x - avail_w - PANEL_MARGIN, PANEL_MARGIN) + _overlay_bar.size = Vector2(avail_w, 0.0) # ============================================================================= From 69123904a50980b47baa519d1ac69c46b31c55b6 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Tue, 21 Jul 2026 08:59:30 +0200 Subject: [PATCH 2/4] =?UTF-8?q?docs(meta):=20D-226=20T-1124=20SS5=20entry?= =?UTF-8?q?=20revision=20=E2=80=94=20fixed=20planetary=20map=20+=20rectang?= =?UTF-8?q?le-cursor=20click-through=20(Jeroen,=20companion=20hands-on)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The regional-map entry changes from zoom-threshold LOD swap to explicit click-through: the planetary heightmap view becomes FIXED (pan/zoom removed together with its replacement in T-1138, never before); hovering shows a rectangle cursor representing the regional-mode bounds; click descends centered on the click point's derived DistrictPos. DISTRICT_WINDOW_MIN_ZOOM retired before ever being built; D-013's zoom-owns-descent superseded for this seam only (click owns descent). In-mode behavior unchanged (pan-only refetch, debounce, cache, border-fade). Morph transition explicitly deferred. Open at T-1138: the rectangle is an affordance, not to scale — n=64 is ~131 km = a few px on a planetary canvas; resolve the honest representation in the screen design. T-1138 description updated; T-1140 filed for the two companion UI defects fixed alongside. Co-Authored-By: Claude Fable 5 --- governance/decisions/architecture.md | 1 + 1 file changed, 1 insertion(+) diff --git a/governance/decisions/architecture.md b/governance/decisions/architecture.md index 74205a403..9925998cb 100644 --- a/governance/decisions/architecture.md +++ b/governance/decisions/architecture.md @@ -1664,6 +1664,7 @@ Technical foundation decisions that constrain implementation: engine, client-ser - **What renders during the wait** (the "invisible re-fetch"): the previous composite, panned to its new screen position, with a **border-fade to the underlying whole-body heightmap** (already resident, coarser `district_grid`/`region_grid` data — real data seen through, not a placeholder) at the newly-exposed edge; **no black, no spinner** unless the wait exceeds a ~0.5 s grace window (reusing the existing `_gen_pending_indicator`, not a new mechanism). Because §4's cache is D-227-valid indefinitely, a pan back toward a recently-cached window composites from cache with zero wait — the genuine-miss `Pending`/re-poll path (D-225's existing loop) becomes the minority case, not the default. - **Overlay/legend reuse against §2–§4.** The base layer is **morphology, lightness-modulated by `elev_q`** (one `0.7 + 0.3*(elev_q/100)` multiply per cell — relief read without a second draw call, the T-1112 "shape=identity, cheap second channel=magnitude" instinct as hue=type / lightness=elevation), reusing the T-1123 probe's 17-entry `MORPHOLOGY_RGB` hues verbatim; it is always-on once the LOD threshold is crossed (it *is* this screen's `terrain` layer), so it takes no toggle id. Three switchable overlays get new `gen_dw_temp` / `gen_dw_moisture` / `gen_dw_veg` `OVERLAY_DEFS` ids (`group: "toggle"`, the `gen_l1_*` multi-toggle-over-one-base precedent): **temperature** reuses T-1118's region-grid ramp *exactly* (same `i16` deci-°C domain + `REGION_TEMP_NONE_DC` sentinel disposition — one colorizer across both zoom levels, §2's consistency ruling); **moisture** reuses the existing `SUB_BIOME_COLORS` dry-sand→wet-teal endpoints; **vegetation** is a green-family ramp with **`Marine = 6` rendered transparent** (lets the morphology water-blue show through — `Marine` is `derive_vegetation`'s bookkeeping answer for already-`OpenOcean`/`Lake` districts, not new player information; a second blue would fight or duplicate the morphology read — this is the exhaustive disposition §3 mandates). **Glaciation is a modifier, not a toggle**: an ice-tint wash gated on `glaciation_grade >= Light` (alpha scaling with grade) composited over whichever layer shows — the `aliveness_probe::apply_ice_tint` approach ported to the player composite; it keeps sea-ice (tint over `OpenOcean` navy → whitened blue) visually distinct from open ocean and from ice-capped land (tint over alpine grey → near-white) by alpha-compositing over different bases rather than three drifting hard-coded colors. Legend: one `GENERATION_LEGEND` entry per new id (existing data-driven `atlas_legend_panel.gd` table, no new panel class); the morphology base folds its 17 zones into ~5 family rows (water / coastal-transition / plains-river / upland / volcanic) with the full mapping in the city-click sidebar, mirroring T-1112's "not everything earns permanent screen space" discipline. Implant chrome discipline (D-169/D-170): `ImplantHeader` carries a location label (the nearest settlement's name when the window is over/near one, else a coordinate/region label — the window is not settlement-anchored, per the entry clause above) + extent-in-real-units subtitle (e.g. "4.1 × 4.1 km · 2.0 km/cell") + one optional flavor line; the map-data palettes stay **out of** the theme's semantic accent roles (especially `ACCENT_ACTIVE` gold, which the settlement marker owns and must not compete with); no scanline/glitch dressing (the implant is confident working tech — a signal-quality state, if ever needed, rides `_gen_pending_indicator`, not cosmetic noise). Full color/ramp/compositing/legibility rationale and the n=32↔n=64 on-screen-scale math live in Araminta's companion T-1124 sections (visual encoding / implant aesthetic / legibility constraints), not re-derived here. + **Amended 2026-07-21 (T-1124 §5 entry revision — Jeroen, first companion hands-on):** the regional-map **entry mechanic changes from zoom-threshold LOD swap to explicit click-through**. Jeroen's ruling after using `make atlas`: the planetary pixel-scaling pan/zoom "is only messing with the pixels of the map and the interaction is weird" — (a) the **planetary heightmap view becomes FIXED** (no drag-pan / wheel-zoom of the planetary canvas; the current pan/zoom ships until T-1138 replaces it, then is removed *in the same change* as the replacement so close inspection is never stranded); (b) **entry is a click-through**: hovering the planetary heightmap shows a **rectangle cursor** representing the regional-mode bounds, and clicking descends into the regional map centered on the click point's derived `DistrictPos` — §5's float-on-center/first-window rules carry over with "pan center" read as "click point". `DISTRICT_WINDOW_MIN_ZOOM` is retired before ever being built (the T-1138 zoom-headroom note is moot); the §5 cross-reference reading of D-013 ("the zoom gesture owns spatial descent") is superseded **for this seam only** — click owns descent. Everything *inside* the regional mode stands unchanged (§4 pan-only refetch, debounce, float-on-center, D-227 cache, border-fade). A **morphing transition** between map modes is explicitly deferred (Jeroen: nice, too ambitious for now) — the descent may cut. **Open at T-1138:** the rectangle cursor is an affordance, not to scale — an n=64 window (~131 km) is a few pixels on a planetary canvas; the screen design must resolve the honest representation (rectangle at true extent with a zoom-in cut on click, or a not-to-scale reticle with the real extent labeled beside it) without implying the regional view covers more planet than it does. - **Rationale:** Reusing the real UI — rather than a parallel offline renderer or dumped files — means the debug/review surface never diverges from what ships, and a dropped artifact can't go stale. Agent-navigability converts qualitative "does the synthesis look natural?" review from a manual eyeball pass into an automatable sweep that flags the few outliers for a human. The harness rides seams that already exist (`TickRate::Paused`, the paused-allowlist, `gameplay_occluded`, the bridge framing, the `run-visual` capture primitive) — a naming-and-contract exercise, not a new subsystem. - **New surface:** server pause-gating (run-conditions on the world phases keyed to a pause command); client `AtlasAgentInterface` (`observe`/`act`, Control-tree walker) + its local transport; the generation overlay rendering + selector + legend; interactive capture wired to `run-visual`. - **Implementation:** Phase 4 (epic T-750), built bottom-up — auto-pause substrate, T-969 proxy (D-225), T-960 viewer, agent channel, agent capture. Geography is the first consumer. From 872aea041f2d0d128e84b1b294a60dcddcef4deb Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Tue, 21 Jul 2026 09:26:02 +0200 Subject: [PATCH 3/4] fix(ui): overlay bar empty flow area must not eat map input (PR #186 review) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hoshe's finding: the wrap fix gave the bar container the full header-adjacent width, and with ALIGNMENT_END + the pre-existing MOUSE_FILTER_STOP that left a ~700px dead strip (1920px screens) left of the chips silently swallowing map clicks/drags near the top edge — a regression the wrap change introduced by widening the rect without revisiting the filter. Two edits: the container is now MOUSE_FILTER_IGNORE (the legend-panel/header/empty-notice idiom; chip Buttons STOP their own events so toggles and tooltips are unaffected), and _is_over_ui() no longer checks the bar rect (with IGNORE, chip events never reach the viewer — checking the wide rect would recreate the dead strip). Regression test pins both: filter mode + an empty-strip point not registering as UI. Co-Authored-By: Claude Fable 5 --- client/tests/test_atlas_overlays.gd | 29 +++++++++++++++++++ .../implant/apps/atlas/atlas_overlay_bar.gd | 9 +++++- client/ui/implant/apps/atlas/atlas_viewer.gd | 8 +++-- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/client/tests/test_atlas_overlays.gd b/client/tests/test_atlas_overlays.gd index 0fca3c4eb..8b3f408fc 100644 --- a/client/tests/test_atlas_overlays.gd +++ b/client/tests/test_atlas_overlays.gd @@ -510,3 +510,32 @@ func test_legend_panel_shows_active_overlay_and_hides_when_toggled_off() -> void ).is_false() v.queue_free() + + +## PR #186 regression: the overlay bar spans the full header-adjacent width +## so rows can wrap (ALIGNMENT_END right-aligns the chips), which leaves a +## wide EMPTY strip inside the container rect on wide screens. That strip +## must never eat map input: the container is MOUSE_FILTER_IGNORE (chip +## Buttons STOP their own events) and _is_over_ui() must not treat the bar +## rect as UI — both are pinned here because no other test exercises them. +func test_overlay_bar_empty_area_does_not_block_map_input() -> void: + var v: AtlasViewer = AtlasViewer.new() + add_child(v) + v.size = Vector2(1920.0, 1080.0) + v._position_overlay_bar() + await get_tree().process_frame + + assert_int(v._overlay_bar.mouse_filter).override_failure_message( + "overlay bar container must be MOUSE_FILTER_IGNORE — STOP turns the" + + " empty flow area into a dead strip that swallows map clicks" + ).is_equal(Control.MOUSE_FILTER_IGNORE) + + # A point just inside the bar's top-left is empty flow area (chips are + # right-aligned and occupy well under the full width at 1920px). + var strip_point: Vector2 = v._overlay_bar.global_position + Vector2(8.0, 8.0) + assert_bool(v._is_over_ui(strip_point)).override_failure_message( + "_is_over_ui must not claim the overlay bar's empty strip — map" + + " pan/click near the top edge would silently die there" + ).is_false() + + v.queue_free() diff --git a/client/ui/implant/apps/atlas/atlas_overlay_bar.gd b/client/ui/implant/apps/atlas/atlas_overlay_bar.gd index fe7418701..8d14a0537 100644 --- a/client/ui/implant/apps/atlas/atlas_overlay_bar.gd +++ b/client/ui/implant/apps/atlas/atlas_overlay_bar.gd @@ -34,7 +34,14 @@ func _init(viewer_ref = null) -> void: func _ready() -> void: - mouse_filter = Control.MOUSE_FILTER_STOP + # IGNORE, not STOP (PR #186 review): the container spans the full + # header-adjacent width so rows can wrap, and with ALIGNMENT_END most of + # that rect is empty space left of the chips — STOP made it a dead strip + # that swallowed map clicks/drags near the top edge. The chip Buttons + # STOP their own input (Godot Button default), so toggling and tooltips + # are unaffected; empty flow area passes through to the map. Same idiom + # as the legend panel / screen header / empty notice. + mouse_filter = Control.MOUSE_FILTER_IGNORE if _viewer == null: return for def: Dictionary in _viewer.get_overlay_defs(): diff --git a/client/ui/implant/apps/atlas/atlas_viewer.gd b/client/ui/implant/apps/atlas/atlas_viewer.gd index de09f16e4..44cdfc668 100644 --- a/client/ui/implant/apps/atlas/atlas_viewer.gd +++ b/client/ui/implant/apps/atlas/atlas_viewer.gd @@ -707,8 +707,12 @@ static func _dict_str(d: Dictionary, key: String, fallback: String) -> String: func _is_over_ui(pos: Vector2) -> bool: - if _overlay_bar and _overlay_bar.get_global_rect().has_point(pos): - return true + # The overlay bar is deliberately NOT checked here (PR #186 review): its + # container spans the full header-adjacent width for row wrapping but is + # MOUSE_FILTER_IGNORE — chip Buttons STOP their own events (they never + # reach this viewer), and the empty flow area left of the right-aligned + # chips must stay interactive map surface. Checking the wide bar rect + # would re-create the ~700px dead strip the review caught. if _city_panel and _city_panel.visible and _city_panel.get_global_rect().has_point(pos): return true return false From 6db63d033bd8063c049e1b5ab3b516266499c72f Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Tue, 21 Jul 2026 09:28:51 +0200 Subject: [PATCH 4/4] =?UTF-8?q?chore(meta):=20T-1140=20to=20review=20?= =?UTF-8?q?=E2=80=94=20PR=20#186=20up?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- .pql/changelog/ticket_history/2026-07.sql | 1 + .pql/changelog/tickets/2026-07.sql | 1 + 2 files changed, 2 insertions(+) diff --git a/.pql/changelog/ticket_history/2026-07.sql b/.pql/changelog/ticket_history/2026-07.sql index 51ecc40ee..9f0be89c1 100644 --- a/.pql/changelog/ticket_history/2026-07.sql +++ b/.pql/changelog/ticket_history/2026-07.sql @@ -1581,3 +1581,4 @@ Implementation note (Tyre, T-1124 report): DISTRICT_WINDOW_MIN_ZOOM proposed at SUPERSEDED ENTRY MECHANIC (Jeroen, 2026-07-21 companion hands-on — recorded as the D-226 T-1124 SS5 entry revision): NO zoom-threshold LOD swap and NO DISTRICT_WINDOW_MIN_ZOOM — the earlier zoom-headroom note is moot. The planetary heightmap view becomes FIXED: remove drag-pan/wheel-zoom of the planetary canvas IN THIS TICKET, same change as the replacement (never strand close inspection), and update the header hint text accordingly. Entry: hovering the planetary heightmap shows a rectangle cursor representing the regional-mode bounds; click descends into the regional map centered on the click point''s derived DistrictPos (float-on-center rules carry over with pan-center read as click-point). In-mode behavior unchanged (pan-only refetch, 150ms debounce, D-227 cache, border-fade). Morph transition between modes explicitly deferred — the descent may cut. Open design point: the rectangle cursor is an affordance, not to scale (n=64 = ~131km = a few px on a planetary canvas) — resolve the honest representation (true-extent rectangle + zoom-in cut, or not-to-scale reticle with the real extent labeled) without implying more coverage than real. Note: set_view/get_view_offset (T-1120 capture API) must survive for the visual-golden harness even after user pan/zoom is removed.', NULL, '2026-07-21 06:58:26', '2026-07-21 06:58:26.870', '2026-07-21 06:58:26.870', NULL, '60f8b73d47b3a1ec7ddf8f6024f640b7', 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 ('06FR6Y1CNA5JJ68RN897RM7FBC', 'status', 'backlog', 'in_progress', NULL, '2026-07-21 06:58:48', '2026-07-21 06:58:48.125', '2026-07-21 06:58:48.125', NULL, '07436c6c5318eca6cd011f2dd67c2dc1', 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 ('06FR6Y1CNA5JJ68RN897RM7FBC', 'status', 'in_progress', 'review', NULL, '2026-07-21 07:16:21', '2026-07-21 07:16:21.984', '2026-07-21 07:16:21.984', NULL, 'c17c3d899e4addd70522da86c66db245', 2) ON CONFLICT(hash) DO NOTHING; diff --git a/.pql/changelog/tickets/2026-07.sql b/.pql/changelog/tickets/2026-07.sql index 7d4aad061..36fd9d675 100644 --- a/.pql/changelog/tickets/2026-07.sql +++ b/.pql/changelog/tickets/2026-07.sql @@ -2308,3 +2308,4 @@ Implementation note (Tyre, T-1124 report): DISTRICT_WINDOW_MIN_ZOOM proposed at SUPERSEDED ENTRY MECHANIC (Jeroen, 2026-07-21 companion hands-on — recorded as the D-226 T-1124 SS5 entry revision): NO zoom-threshold LOD swap and NO DISTRICT_WINDOW_MIN_ZOOM — the earlier zoom-headroom note is moot. The planetary heightmap view becomes FIXED: remove drag-pan/wheel-zoom of the planetary canvas IN THIS TICKET, same change as the replacement (never strand close inspection), and update the header hint text accordingly. Entry: hovering the planetary heightmap shows a rectangle cursor representing the regional-mode bounds; click descends into the regional map centered on the click point''s derived DistrictPos (float-on-center rules carry over with pan-center read as click-point). In-mode behavior unchanged (pan-only refetch, 150ms debounce, D-227 cache, border-fade). Morph transition between modes explicitly deferred — the descent may cut. Open design point: the rectangle cursor is an affordance, not to scale (n=64 = ~131km = a few px on a planetary canvas) — resolve the honest representation (true-extent rectangle + zoom-in cut, or not-to-scale reticle with the real extent labeled) without implying more coverage than real. Note: set_view/get_view_offset (T-1120 capture API) must survive for the visual-golden harness even after user pan/zoom is removed.', 'backlog', 'high', NULL, 'client', NULL, '2026-07-18 10:02:12.668', '2026-07-21 06:58:26.869', NULL, '946d4b4a331ee0dd7bf0ae1e08bb2da1', 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 ('06FR6Y1CNA5JJ68RN897RM7FBC', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Companion Atlas friction — overlay bar overflows right edge; dev ticket ids in tooltips', 'Jeroen''s first make atlas hands-on (2026-07-21). Two UI defects on the shared Atlas viewer (visible in-game too): (1) the overlay toggle bar is a single HBoxContainer row — 17 chips at 42px min overflow the right screen edge (his 2000px window cut the bar mid-BAS); positioning also measured the bar''s own width with a 520px fallback, aggravating the overflow. Fix: HFlowContainer with ALIGNMENT_END, viewer gives it everything right of the header (OVERLAY_BAR_HEADER_RESERVE) and rows wrap right-aligned. (2) OVERLAY_DEFS tooltips leaked dev provenance into player-facing text — ticket ids (#960, T-960, T-1046, T-1118, T-1119) and decision ids (D-181, D-226, D-243) mean nothing in-game; stripped to plain language keeping the semantic content (visibility-ladder wording like observable/needs corporate contact stays). His third point — planetary map fixed + rectangle-cursor click-through entry — is a design revision recorded on D-226 (T-1124 SS5 entry revision) and folded into T-1138, not this bug.', 'backlog', 'medium', NULL, 'client', NULL, '2026-07-21 06:58:38.890', '2026-07-21 06:58:38.890', NULL, '685d1e4e2587c40abb524d7a9a64c4d7', 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 ('06FR6Y1CNA5JJ68RN897RM7FBC', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Companion Atlas friction — overlay bar overflows right edge; dev ticket ids in tooltips', 'Jeroen''s first make atlas hands-on (2026-07-21). Two UI defects on the shared Atlas viewer (visible in-game too): (1) the overlay toggle bar is a single HBoxContainer row — 17 chips at 42px min overflow the right screen edge (his 2000px window cut the bar mid-BAS); positioning also measured the bar''s own width with a 520px fallback, aggravating the overflow. Fix: HFlowContainer with ALIGNMENT_END, viewer gives it everything right of the header (OVERLAY_BAR_HEADER_RESERVE) and rows wrap right-aligned. (2) OVERLAY_DEFS tooltips leaked dev provenance into player-facing text — ticket ids (#960, T-960, T-1046, T-1118, T-1119) and decision ids (D-181, D-226, D-243) mean nothing in-game; stripped to plain language keeping the semantic content (visibility-ladder wording like observable/needs corporate contact stays). His third point — planetary map fixed + rectangle-cursor click-through entry — is a design revision recorded on D-226 (T-1124 SS5 entry revision) and folded into T-1138, not this bug.', 'in_progress', 'medium', NULL, 'client', NULL, '2026-07-21 06:58:38.890', '2026-07-21 06:58:48.125', NULL, '1944f85140fa14cfe8a5676b6452bdf2', 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 ('06FR6Y1CNA5JJ68RN897RM7FBC', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Companion Atlas friction — overlay bar overflows right edge; dev ticket ids in tooltips', 'Jeroen''s first make atlas hands-on (2026-07-21). Two UI defects on the shared Atlas viewer (visible in-game too): (1) the overlay toggle bar is a single HBoxContainer row — 17 chips at 42px min overflow the right screen edge (his 2000px window cut the bar mid-BAS); positioning also measured the bar''s own width with a 520px fallback, aggravating the overflow. Fix: HFlowContainer with ALIGNMENT_END, viewer gives it everything right of the header (OVERLAY_BAR_HEADER_RESERVE) and rows wrap right-aligned. (2) OVERLAY_DEFS tooltips leaked dev provenance into player-facing text — ticket ids (#960, T-960, T-1046, T-1118, T-1119) and decision ids (D-181, D-226, D-243) mean nothing in-game; stripped to plain language keeping the semantic content (visibility-ladder wording like observable/needs corporate contact stays). His third point — planetary map fixed + rectangle-cursor click-through entry — is a design revision recorded on D-226 (T-1124 SS5 entry revision) and folded into T-1138, not this bug.', 'review', 'medium', NULL, 'client', NULL, '2026-07-21 06:58:38.890', '2026-07-21 07:16:21.984', NULL, '9f48ccd62c0fde1c731362c426f82e79', 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);