From edde411fb64a7e2a073d3d7d98d881f9f4ef2ca9 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Fri, 17 Jul 2026 09:33:54 +0200 Subject: [PATCH] =?UTF-8?q?chore(meta):=20close=20companion=20wave=201=20?= =?UTF-8?q?=E2=80=94=20T-1129/T-1130/T-1132=20done=20(PR=20#183=20merged);?= =?UTF-8?q?=20D-254=20synced?= 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 | 3 +++ .pql/changelog/tickets/2026-07.sql | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/.pql/changelog/ticket_history/2026-07.sql b/.pql/changelog/ticket_history/2026-07.sql index 45e330271..43876ac93 100644 --- a/.pql/changelog/ticket_history/2026-07.sql +++ b/.pql/changelog/ticket_history/2026-07.sql @@ -1503,3 +1503,6 @@ 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 ('06FPX7HZY1CK3VSTRXP1NP9VYW', 'status', 'in_progress', 'review', NULL, '2026-07-17 07:16:47', '2026-07-17 07:16:47.103', '2026-07-17 07:16:47.103', NULL, 'd8b73dc6faef3d1a5d3573045c475b62', 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 ('06FPXAS26J3BS7ZJVRFT5JDXP8', 'status', 'in_progress', 'review', NULL, '2026-07-17 07:16:47', '2026-07-17 07:16:47.106', '2026-07-17 07:16:47.106', NULL, '3b30b41a05b18914a5664024712e3435', 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 ('06FPXAWGRH9QK5QKV7584Q92Z8', 'status', 'in_progress', 'review', NULL, '2026-07-17 07:16:47', '2026-07-17 07:16:47.106', '2026-07-17 07:16:47.106', NULL, 'db5fa6e8953f5df39e0c49c81d06be74', 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 ('06FPX7HZY1CK3VSTRXP1NP9VYW', 'status', 'review', 'done', NULL, '2026-07-17 07:33:14', '2026-07-17 07:33:14.221', '2026-07-17 07:33:14.221', NULL, '8e59f6cc9dcc0967b6a2c77b444d3baa', 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 ('06FPXAS26J3BS7ZJVRFT5JDXP8', 'status', 'review', 'done', NULL, '2026-07-17 07:33:14', '2026-07-17 07:33:14.223', '2026-07-17 07:33:14.223', NULL, 'f95e0e0fa6a14edb36ef926a094eb550', 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 ('06FPXAWGRH9QK5QKV7584Q92Z8', 'status', 'review', 'done', NULL, '2026-07-17 07:33:14', '2026-07-17 07:33:14.224', '2026-07-17 07:33:14.224', NULL, '7b6bed8f8be45d9ed6bfad8ffb52d599', 2) ON CONFLICT(hash) DO NOTHING; diff --git a/.pql/changelog/tickets/2026-07.sql b/.pql/changelog/tickets/2026-07.sql index b330bf1a2..825297377 100644 --- a/.pql/changelog/tickets/2026-07.sql +++ b/.pql/changelog/tickets/2026-07.sql @@ -2148,3 +2148,10 @@ Correction: the Makefile target name in the line above is ''atlas'' (make atlas) Jeroen''s requirement (2026-07-17, mid-implementation — now D-254 SS3): the standalone shell is a GENERIC IMPLANT HOST, not an Atlas launcher. Every ImplantRegistry app is automatically available in the companion; the manifest (app.tres) gains available_in_companion: bool = true (OPT-OUT — set false only for apps that need a playing character/gameplay context). Shell consults the flag at instantiate_all/app-open time and in any app-switching surface; the in-game implant ignores it. Both current apps (Atlas, Economics) stay true. Jeroen''s suggested name availableInAtlasApp recorded in D-254 with the available_in_companion rename rationale (GDScript snake_case + avoids colliding with apps/atlas).', 'review', 'high', 'stig', 'client', NULL, '2026-07-17 06:02:45.316', '2026-07-17 07:16:47.106', NULL, '775c513c295216c2f2892585d3183516', 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 ('06FPXAS26J3BS7ZJVRFT5JDXP8', 'task', '06FPX7FKG0Y6SYWEDPG4PJQHQ8', 'Reader connection: multi-connection bridge + ConnectionRole gate', 'D-254 SS1/SS2 (record on the atlas-companion-app branch; ref attaches after merge+sync). THE GATING TICKET — everything else in T-1128 needs a server that can hold a second connection without hanging it (today: main.rs single blocking accept at ~line 120; a second client hangs silently forever). Scope: ConnectionRole field on StartupMessage (Player | Reader, serde default Player for back-compat, enum shaped for future TradingReader); TcpListener blocking single-accept -> non-blocking per-tick accept loop; BridgeResource becomes 0-1 Player + 0-N Reader collection (NOT general N-player — D-009 scope stays separate); Reader never enters the character-spawn path and receives NO ObserverSnapshot (structural, not filtered); per-connection response tagging for atlas/starmap/citynames request-response buffers; Player-only whole-server-shutdown-on-disconnect (Reader disconnects must never affect the player session); permitted-message matrix enforcement server-side — violation = log + drop frame, repeated = disconnect the reader; lower per-reader inbound frame cap. Deterministic sim unaffected by reader presence. Oscar''s design, Oscar implements.', 'review', 'high', 'oscar', 'server', NULL, '2026-07-17 06:02:17.012', '2026-07-17 07:16:47.106', NULL, 'ee8ec1772f97e0bbbbf877ad0773945f', 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 ('06FPX7HZY1CK3VSTRXP1NP9VYW', 'task', '06FPX7FKG0Y6SYWEDPG4PJQHQ8', 'Design pass: D-254 companion-app architecture — connection model, reader protocol, app shell, data browser, save/load seam', 'Produce and record D-254 (id claimed). Participants: Tyre (architecture lead, writes the record) + Oscar (protocol/connection model — his activation). Must pin: (1) CONNECTION MODEL — attach to the running game server vs spawn-own (--test-mode? which world?) incl. discovery (port/SR_ADDR), and the multi-connection reality of the bridge today (recon: almost certainly single-connection; a second reader connection is new protocol work); (2) READER CONNECTION CLASS — handshake variant that never spawns a character and cannot send inputs (read-only enforced SERVER-side, not client courtesy — future market trading would widen this deliberately per-verb, design the enum now); (3) APP SHELL — how make atlas launches the existing implant Atlas UI standalone (second main scene vs feature flag vs export preset; keep the implant aesthetic — the diegetic second-monitor pattern is a product goal); (4) DATA BROWSER — Jeroen wants to scan ALL database data: define the browse surface (entity list/detail screens from implant components: systems, bodies, corps, settlements, markets) and its data path (existing wire requests vs a generic read API vs local systems.db read for static data + wire for dynamic — mind the D-010 information-boundary rules for what a reader may see); (5) SAVE/LOAD SEAM — saves are Phase 5+; design the interaction now (attach = inherits the running world; spawn = pick seed today, pick save later), record the hook; (6) FUTURE TRADING note — what changes when the app gains write verbs (auth? per-verb allowlist on the reader class?). Deliverable: D-254 record written in governance/decisions/architecture.md + a proposed implementation ticket tree under T-1128. Wiring is NOT this ticket.', 'done', 'high', NULL, 'server', NULL, '2026-07-17 05:48:12.656', '2026-07-17 07:33:14.221', NULL, '4dc5624d213d5435919f86a698657681', 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 ('06FPXAS26J3BS7ZJVRFT5JDXP8', 'task', '06FPX7FKG0Y6SYWEDPG4PJQHQ8', 'Reader connection: multi-connection bridge + ConnectionRole gate', 'D-254 SS1/SS2 (record on the atlas-companion-app branch; ref attaches after merge+sync). THE GATING TICKET — everything else in T-1128 needs a server that can hold a second connection without hanging it (today: main.rs single blocking accept at ~line 120; a second client hangs silently forever). Scope: ConnectionRole field on StartupMessage (Player | Reader, serde default Player for back-compat, enum shaped for future TradingReader); TcpListener blocking single-accept -> non-blocking per-tick accept loop; BridgeResource becomes 0-1 Player + 0-N Reader collection (NOT general N-player — D-009 scope stays separate); Reader never enters the character-spawn path and receives NO ObserverSnapshot (structural, not filtered); per-connection response tagging for atlas/starmap/citynames request-response buffers; Player-only whole-server-shutdown-on-disconnect (Reader disconnects must never affect the player session); permitted-message matrix enforcement server-side — violation = log + drop frame, repeated = disconnect the reader; lower per-reader inbound frame cap. Deterministic sim unaffected by reader presence. Oscar''s design, Oscar implements.', 'done', 'high', 'oscar', 'server', NULL, '2026-07-17 06:02:17.012', '2026-07-17 07:33:14.223', NULL, '9b4572b19e21a76292d33bad4ac9310b', 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 ('06FPXAWGRH9QK5QKV7584Q92Z8', 'task', '06FPX7FKG0Y6SYWEDPG4PJQHQ8', 'Standalone entry scene + attach-or-spawn boot + make atlas target', 'D-254 SS1/SS3/SS5. client/scenes/atlas_standalone.tscn + atlas_standalone.gd (modeled on visual_capture.gd''s boot shape — NOT a flag on main.tscn, which is saturated with player-only paths): attach-mode = TCP connect SR_PORT-or-9876 with ~500ms timeout; ECONNREFUSED falls through to spawn-mode = own child server via the server_process.gd ownership pattern with --port 0 + LISTENING:{port} parse, REAL systems.db (no --test-mode); sends Reader-role StartupMessage; opens implant/map fullscreen (skips main menu/character creation); window title branding via DisplayServer.window_set_title; intercept atlas close-to-gameplay in atlas_standalone.gd (do not modify atlas_app.gd). Makefile: target = trivial build+launch (the scene owns the attach-or-spawn decision — no Makefile orchestration; and per Oscar''s flag this simplicity does NOT shrink the T-1130 server work). Exportable later as a Godot export preset, no architecture change. Blocked by T-1130 for real attach-mode testing (developable against spawn-mode before that). Blocks the browser-UI ticket (needs a shell to launch from). + +Correction: the Makefile target name in the line above is ''atlas'' (make atlas) — shell backticks ate the word during filing. + +Jeroen''s requirement (2026-07-17, mid-implementation — now D-254 SS3): the standalone shell is a GENERIC IMPLANT HOST, not an Atlas launcher. Every ImplantRegistry app is automatically available in the companion; the manifest (app.tres) gains available_in_companion: bool = true (OPT-OUT — set false only for apps that need a playing character/gameplay context). Shell consults the flag at instantiate_all/app-open time and in any app-switching surface; the in-game implant ignores it. Both current apps (Atlas, Economics) stay true. Jeroen''s suggested name availableInAtlasApp recorded in D-254 with the available_in_companion rename rationale (GDScript snake_case + avoids colliding with apps/atlas).', 'done', 'high', 'stig', 'client', NULL, '2026-07-17 06:02:45.316', '2026-07-17 07:33:14.224', NULL, 'afe855927790e15891e9ac9492f54642', 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);