Rewrites the committed .pql/changelog/ from the old T-NNN-keyed format to the record_id identity model (pql 1.10.0, D-26): tickets keyed by a ULID record_id, the friendly T-NNN in ticket_idmap, references and hashes recomputed. Produced by the one-off cmd/migrate-ids in the pql repo. Other clones: install pql >= 1.10.0, then rm .pql/pql.db && pql plan rebuild to regenerate the local DB from this changelog. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
699 lines
248 KiB
SQL
699 lines
248 KiB
SQL
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 ('06FB0TNSRYHQNG0D04Z1NBB7F8', 'story', '06FB0TNSRXERQG6GFS85FRJ5HW', 'Track D: West Reach body catalogs (48 systems)', 'Author body catalogs for 48 west_reach systems (hops 4-11). Germanic/Scandinavian naming register. Compact of Westphalia dissenter gradient applies at outer hops. Process in hop order using /atlas author-system pipeline.', 'done', 'high', NULL, 'copy', NULL, '2026-03-25 13:22:49', '2026-04-03 13:27:20', NULL, '092f85f490a874bc9b3417e96d62b6ae', 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 ('06FB0TNSRW0K86C3HZAC516YEM', 'story', '06FB0TNSRXERQG6GFS85FRJ5HW', 'Track E: Deep Frontier body catalogs (73 systems)', 'Author body catalogs for 73 deep_frontier systems (hops 5-12). Mixed/frontier naming register — cultural corridor attenuation at these distances, more exceptions, more isolated communities. Process in hop order using /atlas author-system pipeline.', 'done', 'high', NULL, 'copy', NULL, '2026-03-25 13:23:03', '2026-04-03 13:27:22', NULL, 'f7549c0a195f091efbb3798e802fcd13', 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 ('06FB0TNSRZ3A6ND0PNYGMTNP9G', 'bug', NULL, 'Fix Pereira''s Rest wiki: population 800 → 42K', 'The wiki for Pereira''s Rest (GJ 208) says ''approximately eight hundred'' in Faction Notes. The body catalog sets population to 42,000 per authoring decision (800 was deemed implausibly small for a multi-generational wave_4 settlement). The wiki narrative needs updating: revise the 800 figure to 42K, and adjust the consensus governance description accordingly (the governance model designed for 60 should feel more strained at 42K than at 800). The silence topic about household voting weight scales up rather than down.', 'done', 'medium', NULL, 'copy', NULL, '2026-03-30 07:24:03', '2026-04-03 17:36:48', NULL, '71fa1aef1c1ba5de3e003206b473a189', 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 ('06FB0TNSRXSZPH95SQVST64YS8', 'bug', NULL, 'fix(wiki): Langemark (GJ42) celestial bodies table uses non-schema values', 'PR #103 review: GJ42 wiki table uses breathable (should be standard), rivers-lakes (invalid biome), west_reach as economy/industrial_corridor. Values need normalizing to match atlas schema.', 'done', 'medium', NULL, 'copy', NULL, '2026-03-30 13:48:28', '2026-04-03 17:36:48', NULL, '96e045dcf64a5b1b38aa45da8d6ad55c', 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 ('06FB0TNSRZ1883JAQ0BB6EYYZ4', 'bug', NULL, 'fix(wiki): GJ-147 etymology says ''passagem'' but system is named Entremeio', 'Wiki text at wiki/star-systems/GJ-147/index.md:21 explains ''The name passagem is Portuguese'' but the system is named Entremeio (meaning ''in-between''). Fix wiki text, then update proposal JSON to match.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-03 13:07:43', '2026-04-03 17:36:48', NULL, 'd4b25f110431465759dcef0aa8c7431c', 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 ('06FB0TNSRXV4XSQ9NRXPY71X6M', 'bug', NULL, 'fix(wiki): GJ-875 header says G-type but System Profile shows K5', 'Wiki header classifies as G-type while System Profile table shows K5. A Calibration Note acknowledges this but the header was never corrected. Fix the header, simplify or remove the Calibration Note.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-03 13:07:43', '2026-04-03 17:36:48', NULL, 'e0ea1f8a857d5bdbe43578d47f9147ba', 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 ('06FB0TNSRWDSCAYB8A88D99QAR', 'bug', NULL, 'fix(wiki): Solheim (GJ19) topology disconnect — narrative references unlinked systems', 'PR #103 review: Solheim wiki references Caldwell Point for food routing and describes food exports to loop neighbors, but no adjacent-system topology links visible. Either topology data missing or narrative outruns actual connections.', 'done', 'medium', NULL, 'copy', NULL, '2026-03-30 13:48:30', '2026-04-03 17:56:09', NULL, 'ddd6d6c57c8c5cca8c0fabf6ba11c689', 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 ('06FB0TNSRYCHRZXPW6RSDZR1Z8', 'bug', NULL, 'fix(atlas): GJ707 star_type/spectral_class fields swapped', 'PR #105 review: GJ707 (Dois Sóis) has star_type unusual and spectral_class binary — these are inverted. Should be star_type binary with actual spectral class. Body_ids also use single-star convention (GJ707b) but notes describe circumbinary orbits. Either make it a true binary (star_type binary, composite spectral pair, circumbinary body_ids) or strip binary framing.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-03 06:38:23', '2026-04-03 17:58:30', NULL, '67d8c8961a1ab367a1cbbd9b8cc5a86d', 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 ('06FB0TNSRYF4JZ9AY21XWTJESG', 'bug', NULL, 'fix(atlas): GJ1111 star_type reverted to unusual — regression from PR #101', 'PR #104: GJ1111 star_type changed back to unusual from M. This was specifically corrected in PR #101 review. M6.5 is an extreme red dwarf but still classifiable as M. If unusual has been redefined to cover flare-active M-dwarfs, document it. Otherwise revert to M.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-01 08:45:26', '2026-04-03 17:58:30', NULL, '83b32e0667f73b67fcf11e637c6ee356', 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 ('06FB0TNSRYM1W8YE0G07JA2HWG', 'bug', NULL, 'fix(wiki): GJ541 header says G-type, proposal says K (K2IIIp)', 'PR #102 review: wiki header for GJ541 (Chandra Deep) says G-type but proposal has star_type K, spectral K2IIIp. Calibration Note documents the mismatch but header should be updated to K-type. Wiki leads.', 'done', 'low', NULL, 'copy', NULL, '2026-03-29 16:07:22', '2026-04-03 20:20:23', NULL, '61f7f04122ab881b0d3a18d446bae461', 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 ('06FB0TNSRYE15B2F8ZRBT1JH54', 'bug', NULL, 'fix(wiki): update stale Calibration Notes on GJ1128, GJ136, GJ625', 'PR #102 review found 3 wiki pages where Calibration Notes still describe pre-fix header mismatches that no longer exist. GJ1128 note says K-type preserved but header is now M-type. GJ136 note says M-type preserved but header is now G-type. GJ625 note says header specifies K-type but header is now M-type. One-line fixes each.', 'done', 'low', NULL, 'copy', NULL, '2026-03-29 16:07:20', '2026-04-03 20:20:23', NULL, '6ddf851c5ea8f8596a8fc507f83c7c27', 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 ('06FB0TNSRY9PWAN3CHE4HKRE6R', 'bug', NULL, 'fix(wiki): GJ432A wiki prose still says Punjabi-Canadian', 'PR #102 review: JSON proposal fixed to Punjabi heritage research tradition but wiki/star-systems/GJ-432A/index.md line 25 still reads Punjabi-Canadian research tradition. One-line change to match JSON.', 'done', 'low', NULL, 'copy', NULL, '2026-03-29 16:07:21', '2026-04-03 20:20:23', NULL, 'ba38422e5acd793211daa2ce420fd823', 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 ('06FB0TNSRZ7EA8F5DEQ9WAMDM0', 'bug', NULL, 'fix(atlas): GJ601A needs F2III stellar evolution context in notes', 'PR #103 review: GJ601A (Ostmark) has spectral F2III bright giant. Proposal needs note acknowledging finite habitability window, increasing UV load, and polar settlement as response. Transforms physics concern into setting texture.', 'done', 'low', NULL, 'copy', NULL, '2026-03-30 13:48:33', '2026-04-03 20:21:35', NULL, '07c57aab5dab8a9e1da195326af7f006', 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 ('06FB0TNSRYZ3XJZPG35MHKC0CC', 'bug', NULL, 'fix(atlas): GJ4056 spectral_class ''g'' is malformed', 'PR #103 review: GJ4056 has spectral_class g (lowercase, no subtype). Should be proper classification like G5V or similar.', 'done', 'low', NULL, 'copy', NULL, '2026-03-30 13:48:34', '2026-04-03 20:21:35', NULL, 'e6c729545aa84a8c5dcfc57c5cc55369', 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 ('06FB0TNSRY9860C8C54B0YPQ44', 'bug', NULL, 'fix(wiki): South Reach rebalanced systems need calibration notes documenting intentional small populations', 'PR #104 review: GJ54.1, GJ1111, GJ905 populations diverge significantly from heuristics table. No marker in proposals or wiki to prevent future authors from treating these as errors. Add calibration notes for most divergent systems.', 'done', 'low', NULL, 'copy', NULL, '2026-04-01 08:45:29', '2026-04-03 20:22:50', NULL, '3ce260d7b01197a5f710e727c545a06c', 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 ('06FB0TNSRZ90VDSDX4WD569GEG', 'bug', NULL, 'fix(atlas): GJ189 wave_2 at hop 8-11 needs reconciliation', 'PR #105 review: Altgrund (GJ189) is wave_2 (early settlement) but at hop 8-11 (deep frontier). Either wave is wrong, hop is wrong, or there is an in-setting explanation (old route, late gate connection). Notes should be explicit about this.', 'done', 'low', NULL, 'copy', NULL, '2026-04-03 06:38:26', '2026-04-03 20:23:37', NULL, '034898d7d1d6327d13c31b6473d9d88f', 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 ('06FB0TNSRX9A2SBQ7K3W13B3XM', 'bug', NULL, 'fix(wiki): GJ-7547 and GJ-6711 spectral class truncated to bare ''K''', 'System Profile tables show ''K'' instead of full ''K4V'' from JSON proposals. Update wiki to use full spectral classification.', 'done', 'low', NULL, 'copy', NULL, '2026-04-03 13:07:45', '2026-04-03 20:24:08', NULL, '0245de547b274c7439cf15369ad33c6a', 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 ('06FB0TNSRY4VE2PRGE00YXVXGC', 'bug', NULL, 'Fix Mabuhay wiki: GJ 482A continuity error', 'The Mabuhay (GJ 1073) wiki references GJ 482A as an unsurveyed system in the silence topic and narrative hook, but GJ 482A is Dagat — a 300-year-old wave_3 settlement with 210K people. The unauthorized-survey concept should point at an actually unsurveyed hop-10 stub beyond Dagat or Trung''s Crossing. Flagged by Ozzie during Sprint 29 Track C review.', 'done', 'medium', NULL, 'copy', NULL, '2026-03-29 15:26:44', '2026-04-04 20:51:10', NULL, '3898ca2629c80425b414c14a11be1d93', 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 ('06FB0TNSRWZCHENXZEJXK5BBN0', 'bug', NULL, 'fix(wiki): GJ1111 and GJ54.1 wiki prose not updated for population rebalance', 'PR #104 review: Both five-gate hub wikis have prose written for 500M/800M tiers but populations reduced to 380K/320K. Institutional depth, guild curricula, transit apparatus descriptions no longer match settlement scale. GJ1111 station pop (1M) exceeds planet pop (380K) — sum is 1.47M not 380K. GJ54.1 Supply Dependency claims food from Isibaya (now 45K). Either update prose to match new tier or reconsider population figures for hub systems.', 'done', 'high', NULL, 'copy', NULL, '2026-04-01 08:45:23', '2026-04-04 20:51:10', NULL, '7cf229a85879974a234b3d7a87133e92', 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 ('06FB0TNSRY3TWN4RZMECJC80SM', 'story', '06FB0TNSRXZK7C4X2DHQ6A0CKR', 'Star map insert module — concentric hop-ring view of the Settled Reach gate network, sector-colored, accessible from the player''s insert UI as a navigation/orientation tool', NULL, 'done', 'medium', NULL, 'client', NULL, '2026-03-15 10:19:58', '2026-04-04 22:19:05', NULL, 'd941526b4b630326ea50817cbea752ff', 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 ('06FB0TNSRXW4A76J1WZSFZM758', 'story', NULL, 'Add BoneAttachment3D marker above Head bone for floating icons', 'Add an empty/Marker3D node above the Head bone as a BoneAttachment3D anchor point for floating UI elements (status indicators, thought bubbles, alert markers, speech icons). Offset ~0.3m above Head bone tail. Expose as named node (overhead_anchor). Use cases: status indicators, thought/speech bubbles, selection indicator, NPC interaction prompts. Ref: Head bone tail at z=1.8034 from Regular_Male armature.', 'done', 'medium', NULL, 'client', NULL, '2026-03-22 14:06:18', '2026-04-04 22:19:06', NULL, '98f751c9faa46b8aefa25ec1c538fe33', 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 ('06FB0TNSRY6HFFKW81NJBP7GAC', 'task', NULL, 'Add settings.db creation-on-missing routine + gitignore', 'server/src/main.rs references settings.db but has no creation-on-missing logic. If the file doesn''t exist the server likely crashes. Add: 1) Create settings.db with default schema if missing at startup. 2) After the routine is in place, add server/settings.db to .gitignore.', 'done', 'medium', NULL, 'server', NULL, '2026-03-25 13:49:25', '2026-04-04 22:19:08', NULL, '34a10ea2e57937c8e5ecb662b5500d5a', 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 ('06FB0TNSRZ0DAY43H85FK6EZX8', 'task', '06FB0TNSRXERQG6GFS85FRJ5HW', 'Add corridor-status command to atlas CLI', 'Add a ''corridor-status'' subcommand to the atlas Rust binary that shows remaining unfinished systems grouped by geographic_sector and hop_distance. Currently done via raw SQL.', 'done', 'medium', NULL, 'server', NULL, '2026-03-25 13:23:13', '2026-04-04 22:19:08', NULL, '5165da5018daa7d5d80ef5e9b4f9d04e', 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 ('06FB0TNSRW343TDP38GEKPWEQ4', 'bug', NULL, 'fix(atlas): habitable_planet_count filter uses ''breathable'' but proposals use ''standard''', 'PR #103 review (pre-existing): atlas.rs cmd_commit_system line ~1293 filters atmosphere == breathable for habitable count, but all Track B/C/D proposals use standard. Habitable count written as 0 for all committed systems. Fix should include standard alongside breathable, or derive from wiki_data.habitable_count.', 'done', 'medium', NULL, 'server', NULL, '2026-03-30 13:48:37', '2026-04-04 22:19:09', NULL, 'e64602d211336a00dc24f4880052690a', 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 ('06FB0TNSRYZ3R19MM7FVCASN7M', 'story', NULL, 'Persist CharacterVisualDescriptor on new game start', 'The client sends a CharacterVisualDescriptor when creating a new game. The server must receive it, store it, and include it in ObserverSnapshot so the descriptor survives save/load. The descriptor has to_dict()/from_dict() serialization already. Without this, character appearance is lost on save/load.', 'done', 'high', NULL, 'client', NULL, '2026-03-22 16:33:02', '2026-04-04 22:37:30', NULL, 'ec74b88f901bf15f01ba0d5a0ecb9285', 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 ('06FB0TNSRWAC28B1GF39PSDJQ0', 'task', NULL, 'content(wiki): Afrikaans cultural stereotype imbalance at ~15:1 ratio', 'Cultural audit flagged Afrikaans at 12:1 confirming:subverting. Recent additions (Eerste Wacht, Helderoog, Skemeraand) push to ~15:1. Next Afrikaans-adjacent system should subvert the pastoral/frontier pattern. Audit recommends tech hub, academic center, commercial dynasty, or artistic community.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-03 13:07:47', '2026-04-04 22:37:31', NULL, '10c997098a43cfe3cd6428ac01d33f6d', 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 ('06FB0TNSRWFHF2G4NDCRWNM3P8', 'story', NULL, 'Replace DirAccess asset scanning with manifest JSON for export builds', 'character_creation.gd uses DirAccess.open("res://...") to scan for available assets (hair, clothing, accessories, heads). DirAccess cannot enumerate res:// paths inside exported PCK builds. Replace with a manifest JSON generated at build time that lists available asset IDs per category. The TODO is already in the code at lines 1392 and 1409.', 'done', 'medium', NULL, 'client', NULL, '2026-03-22 16:33:05', '2026-04-04 22:37:31', NULL, '69341c2bb9b6edb7e6ba3fc4f7191914', 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 ('06FB0TNSRXGMMGNRZSYZ1TN710', 'story', NULL, 'Hair highlight: add descriptor field or make swatch read-only', 'The hair highlight swatch in the character creator accepts user input but the override is a no-op — CharacterVisualDescriptor has no hair_highlight_tint field, and the color parameter in _on_hair_highlight_changed() is silently discarded. Either add hair_highlight_tint to the descriptor and wire it through the compositor, or make the highlight swatch display-only (auto-derived from primary, not clickable).', 'done', 'medium', NULL, 'client', NULL, '2026-03-22 16:33:04', '2026-04-04 22:37:31', NULL, 'ee07bfef2786d41914be627b459de51e', 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 ('06FB0TNSRZ0DH2GAC1RN3Y92GW', 'story', '06FB0TNSRZDA414TMQBXY3BHJ0', 'Sprite layer compositor', 'Godot client system that assembles a 3D character from segmented body meshes, head templates, hair, facial hair, eyebrows, clothing, and accessories on the shared 65-bone skeleton. Applies skin tone tinting, hair/clothing recoloring via mask sidecars, handles clothing segment coverage (hides body segments per coverage.json), and manages BoneAttachment3D for head/hair/accessories.
|
||
|
||
Input: CharacterVisualDescriptor (body_type, head_id, hair_id, skin_tone, clothing_slots, etc.).
|
||
Output: assembled 3D character node ready for scene insertion.
|
||
|
||
Port from spike: spikes/quaternius-aesthetic/scripts/spike/character_visual.gd — update for new directory structure (docs/architecture/character-asset-organization.md Section 6), 18-segment body types, and mask-based recoloring.
|
||
|
||
Key features:
|
||
- Load 18 body segments per body type onto shared armature
|
||
- Attach head template via BoneAttachment3D on Head bone
|
||
- Attach hair/facial_hair/eyebrows via BoneAttachment3D on Head bone
|
||
- Apply skin tone via toon shader tinting
|
||
- Load clothing variants matching body type, apply coverage.json segment hiding
|
||
- Expose overhead_anchor marker above Head bone for floating UI icons (#712)
|
||
|
||
Decisions: D-149 (3D live rendering), D-160 (segmented bodies), D-161 (separate head), D-162 (pre-baked clothing), D-164 (Quaternius skeleton)
|
||
Ref: docs/architecture/character-asset-organization.md', 'cancelled', 'high', NULL, 'client', NULL, '2026-03-17 08:21:44', '2026-04-05 06:14:23', NULL, '816f78d97282327a441f7f1382212e42', 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 ('06FB0TNSRX8XWG6B8341W1JMN8', 'task', '06FB0TNSRXBP82ANSVAFMACCHW', 'Cultural diversity sweep — wiki naming and heritage asymmetry', 'Wiki founding-culture palette heavily weighted toward Portuguese, Afrikaans, German, Zulu, Dutch. Almost no Greek, Italian, Catalan, Maghreb, Latin American, Central/East Asian, Caribbean, Pacific Island representation. Needs systematic review at wiki level, then cascade to atlas proposals.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-02 18:55:27', '2026-04-05 07:54:12', NULL, 'd08a65ce2bc9fc4f4da50b58624cb462', 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 ('06FB0TNSRW760V9S946RZYDM88', 'task', '06FB0TNSRXBP82ANSVAFMACCHW', 'content(wiki): evaluate Iserlohn (GJ-532) planet name for IP originality', 'Planet ''Iserlohn'' references real German city but is also the iconic location in Legend of the Galactic Heroes. Deliberate decision needed: keep with documented rationale, or rename to another Sauerland-region reference.', 'done', 'low', NULL, 'copy', 'D-168', '2026-04-03 13:07:48', '2026-04-05 07:54:13', NULL, '0a4d456cc8982566086e3074e2d09261', 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 ('06FB0TNSRZQ6Y1HKEEEVBZYNGW', 'task', '06FB0TNSRXBP82ANSVAFMACCHW', 'content(wiki): enrich GJ-672 (Nova Estrada) and GJ-147 (Entremeio) wiki entries', 'Paula''s narrative review flagged both as noticeably thinner than the batch standard. Nova Estrada is mostly functional description; Entremeio''s gttr lacks the drifter''s voice. Compare to Kettenschmied''s gttr for the target quality.', 'done', 'low', NULL, 'copy', NULL, '2026-04-03 13:07:49', '2026-04-05 07:54:14', NULL, 'aaccefd9eacc76a69250907d30c5b439', 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 ('06FB0TNSRWKJ3ATWAWVP8SX3GC', 'task', NULL, 'refactor(client): decompose main.gd and game_state.gd god objects', 'main.gd (28KB) and game_state.gd (19KB) are oversized. Extract focused components: UI management, input handling, state transitions from main.gd. Move non-state logic out of game_state.gd. Note: GDScript autoload parse-order constraints (documented in CLAUDE.md) limit how aggressively autoloads can be split — class_name types can''t be referenced at autoload compile time.', 'done', 'medium', NULL, 'client', NULL, '2026-04-04 22:35:41', '2026-04-05 08:17:11', NULL, 'dccf8c16f2583aca3b9fe1d0897de9b2', 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 ('06FB0TNSRXSHKM02TAWVP159V0', 'story', '06FB0TNSRXBP82ANSVAFMACCHW', 'Star map click-through — wiki/GTTR popup on system select', 'Phase 1 deliverable. When player clicks a system in the star map insert (#674), show a popup with the wiki/GTTR content for that system. Data already exists in star_map_data.json. Requires: popup UI panel, GTTR text rendering, system profile summary, link to full wiki if available.
|
||
|
||
EDGE VISIBILITY RULE: The full edge web is too dense to be readable (see Sprint 31 screenshot). Change edge rendering so that:
|
||
- Default (no selection): show NO edges, just the system dots
|
||
- When a system is selected: show ONLY the portal lines from the selected system to its adjacent systems
|
||
- Travel planner (future #675): show only the hops between start and destination
|
||
|
||
This is a UX rule, not just a visual preference — the map must be legible at 301 systems.', 'done', 'high', NULL, 'client', NULL, '2026-04-05 06:11:06', '2026-04-05 08:20:18', NULL, '715ea657363c3decda6f5634813b772e', 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 ('06FB0TNSRWJVATWATN1F3GESGM', 'task', NULL, 'refactor(simulation): split atlas.rs subcommands into modules', 'atlas.rs is 2000+ lines with all CLI subcommands in one file. Extract each subcommand (author, commit-system, corridor-status, list-systems, etc.) into separate modules under src/bin/atlas/ or src/atlas/. Keep the main dispatch in atlas.rs thin.', 'done', 'medium', NULL, 'server', NULL, '2026-04-04 22:35:44', '2026-04-05 08:20:19', NULL, '5ba766a9bb9c0392980bda8486737bd6', 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 ('06FB0TNSRY0QJR1RV8Y4V5FSX0', 'task', NULL, 'chore(tooling): add ruff linting + shared DB path module for Python scripts', 'Python scripts in tooling/ lack linting and share duplicated patterns (DB path resolution, config loading). Add pyproject.toml with ruff config, extract shared module (e.g. tooling/db/common.py) for DB_PATH resolution via SR_DB_PATH env var, config loading, and connection setup. Run ruff in pre-push hook alongside GDScript and Rust checks.', 'done', 'medium', NULL, 'ci', NULL, '2026-04-04 22:35:46', '2026-04-05 08:20:19', NULL, '611b4fd15e3a559e745bb5c05e11d349', 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 ('06FB0TNSRX9GWFB7G4DN7FC8JG', 'story', '06FB0TNSRXBP82ANSVAFMACCHW', 'Per-body GTTR entries for moons and stations', 'Phase 1 deliverable. Many systems have system-level GTTR only. Significant moons and stations need their own GTTR entries. Prioritize inhabited bodies with population >10K. Reference existing patterns in wiki/star-systems/*/gttr.md.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-05 06:11:11', '2026-04-05 08:20:19', NULL, 'b3482491e1fa6b4c616bc6d8a82771fa', 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 ('06FB0TNSRZXGK1RMPYXRBMA6TG', 'task', NULL, 'fix(client): resolve all 354 gdlint warnings — zero warnings policy', '354 gdlint warnings accumulated across client/scripts/ and client/ui/. Breakdown: 194 class-definitions-order, 138 max-line-length (updating to 120), 22 code issues (unused args, no-else-return, naming). Fix all or suppress with commented justification. Target: gdlint reports 0 issues. Part of zero-warnings policy added to pr-push and pr-review skills.', 'done', 'medium', NULL, 'client', NULL, '2026-04-05 06:38:29', '2026-04-05 08:20:20', NULL, 'fac2d62e3ed11de6902321e5e522745e', 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 ('06FB0TNSRWKAS60B0F9E8QHZ10', 'task', NULL, 'feat(ui): status/buff icon bar docked to HUD panel', 'Replace standalone stance indicator with an icon bar docked to the HUD status panel. Shows active states as small icons: stance (walk/sprint/crouch/careful), perception mode, future buffs/debuffs, implant status. Each icon color-coded per existing stance colors. Tooltip on hover shows label. Bar sits above or beside the HUD status ImplantPanel. Requires: icon set design (Araminta), bar layout component (ImplantIconBar), stance indicator refactored from panel to icon.', 'backlog', 'medium', NULL, 'client', NULL, '2026-04-05 10:28:05', '2026-04-05 10:28:05', NULL, 'ebf2a2f6272d1bc097452ae400a888b6', 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 ('06FB0TNSRZRBE6WJ21DEBX3P88', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Phase 2 economics design kickoff', 'Break down Phase 2 epic (#747) into implementable stories. Define the economics data model: production chains, corporations, supply/demand, trade routes, political/social pressure. Output: D-records in decisions/economics.md + child tickets under #747 ready for Sprint 33 implementation. Agents: Gestalt, Miri, Tyre, Paula, Nigel, Qatux, SI.', 'done', 'high', NULL, 'planning', NULL, '2026-04-05 13:37:57', '2026-04-05 15:21:53', NULL, 'a36046d25fc645fdfb77de76f2c23ba1', 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 ('06FB0TNSRY5BKJVZN0TF7RJKPG', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Define commodity catalog (TOML)', 'Delivered wiki/economics/commodities.toml (36 commodities: 9 raw, 10 intermediate, 9 final, 5 professional services, 3 luxury services) and wiki/economics/production_chains.toml (21 Leontief recipes). Schema at wiki/economics/schema.md. D-184 through D-187 filed. Follow-up tickets #811-#815 created.', 'done', 'high', NULL, 'planning', NULL, '2026-04-05 16:51:22', '2026-04-05 19:51:40', NULL, 'cbe080bcced0a18c49148662ffc7a3aa', 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 ('06FB0TNSRWJ5AAYSJDTM92RVM0', 'task', NULL, 'refactor(ui): convert interaction prompt to implant component', 'Bottom-center ''E - Examine NPC'' interaction prompt uses a different visual style from the rest of the HUD. Convert to ImplantPanel or ImplantDataRow with consistent implant theme. Should match the diegetic neural overlay aesthetic. Reference D-169.', 'done', 'medium', NULL, 'client', NULL, '2026-04-05 08:47:36', '2026-04-05 20:44:35', NULL, 'bde65466cde14c2163fd3a5174493e56', 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 ('06FB0TNSRWYW46ABBS92EK89XW', 'task', NULL, 'fix(ui): HUD layout pass — resolve overlapping elements', 'Multiple HUD elements overlap or share positions improperly:
|
||
1. Debug panel overlays the daytime/clock display — move debug below clock
|
||
2. Stance indicator sits on top of the minimap — relocate (will become icon bar per #791)
|
||
3. Interaction prompt (E - Examine NPC) shares position with dialogue text window — move to non-conflicting location
|
||
|
||
These are layout anchor/position fixes, not component rewrites. The implant theme (D-169) gives all elements consistent chrome — now they need consistent placement. Reference the HUD visibility groups (D-170) for z-ordering.', 'done', 'high', NULL, 'client', NULL, '2026-04-05 10:30:20', '2026-04-05 20:44:35', NULL, 'e11bfd1d0fd937a35f10987345b220bb', 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 ('06FB0TNSRZMV4RYGCJGV8BW08C', 'task', NULL, 'refactor(ui): convert HUD status display to implant components', 'Top-left HUD shows Health, Time, Mode, Perception as raw overlapping debug text. Convert to ImplantPanel with ImplantDataRow components. Should display cleanly in a themed panel anchored to top-left. Reference D-169 component library at client/ui/implant/.', 'done', 'high', NULL, 'client', NULL, '2026-04-05 08:47:31', '2026-04-05 20:57:00', NULL, '4ef6235e536426ee8bc23b6bba93b875', 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 ('06FB0TNSRWDG2BKBAQRN2EGS7R', 'story', '06FB0TNSRXBP82ANSVAFMACCHW', 'Heightmap pipeline spike — single example for review', 'Produce ONE annotated heightmap for a single inhabited planet to validate the pipeline approach. Annotate with cities, rivers, roads, biomes. User reviews before batch (#794) proceeds. Output: one example heightmap + pipeline documentation.', 'done', 'high', NULL, 'visual', NULL, '2026-04-05 06:11:02', '2026-04-06 14:24:35', NULL, '11e49c6f5dabebd1bf719618dfe089f1', 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 ('06FB0TNSRYA81AD4AYBKDFWVQ0', 'story', '06FB0TNSRXBP82ANSVAFMACCHW', 'Planetary shader screenshots for wiki/GTTR arrival window', 'Phase 1 deliverable. Generate visual screenshots for all inhabited planets using planetary shaders (earthlike, desert, ocean, jungle, mars-like, etc.). Screenshots appear in wiki pages and the diegetic GTTR arrival window in-game. Requires shader pipeline + batch generation tooling.', 'done', 'high', NULL, 'visual', NULL, '2026-04-05 06:11:03', '2026-04-06 14:24:43', NULL, '69be7aa9587fc80b42e8c1c45f9b7514', 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 ('06FB0TNSRWWEK165FFMY95MZZ0', 'story', NULL, 'Icon set design for implant HUD components', 'Design the icon vocabulary for implant HUD: stance indicators, status badges, perception mode icons, interaction prompt icons. Output: SVG icon set following D-086 constraints (custom SVG, 1px stroke, implant chrome color). Blocks #787 (minimap + stance label conversion needs these icons).', 'done', 'high', NULL, 'visual', NULL, '2026-04-05 13:37:53', '2026-04-06 14:24:51', NULL, '43cc380c7325af86f252dcf4eb2224f0', 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 ('06FB0TNSRZEM5K9S179SEFG5Z0', 'task', NULL, 'refactor(ui): convert minimap + stance label to implant components', 'Top-right shows ''Walk'' label floating above minimap circle with no visual container. Convert to ImplantPanel — stance badge inside a themed panel alongside the minimap. The minimap itself may stay as a custom-drawn Control but its container should be an implant panel. Reference D-169.', 'done', 'high', NULL, 'client', NULL, '2026-04-05 08:47:34', '2026-04-06 14:30:26', NULL, '42b190bc26fb83da6ef07fc203243d61', 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 ('06FB0TNSRXTQ03BW22WCRQBDJ8', 'story', '06FB0TNSRXBP82ANSVAFMACCHW', 'Economic profile fields — trade imports/exports for all 301 systems', 'Phase 1 deliverable (feeds Phase 2). Populate industries[], trade_imports[], trade_exports[] fields for all systems in proposals/wiki. These drive the economics simulation in Phase 2 and determine store shelf contents. Start with hub systems, cascade outward by hop distance.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-05 06:11:10', '2026-04-06 14:33:14', NULL, 'c0ad05b8da144ca0e6520b5134dd9b37', 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 ('06FB0TNSRZ48W5JJNHXQY1V8T4', 'task', '06FB0TNSRXBP82ANSVAFMACCHW', 'Cultural diversity audit & remediation plan (analysis only)', 'Full analysis of cultural distribution across 301 systems. Produce docs/design/cultural-diversity-audit.md with: current culture counts per corridor, gaps and over-representation, from/to remediation plan. Must also cover: (1) non-culture exodus groups — corporations, religions, fan communities, families whose identity is not traceable to an Earth culture, (2) great-scientist/space-pioneer/philosopher naming for stations (like Webb/Hubble). Some cultures may be more prevalent due to colonization patterns — that is OK if justified. NO wiki edits — user reviews the plan first. Batch edits happen in #793.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-05 07:24:24', '2026-04-06 14:33:15', NULL, '91a9fad29c68523406f47a2fa2ffaa0f', 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 ('06FB0TNSRWK05D00VH9EJHRSKM', 'task', NULL, 'fix(wiki): add Bodies and Population rows to wiki System Profile tables', 'Most wiki index.md files lack | **Bodies** | and | **Population** | rows in the System Profile table. The star map generator now reads from systems.db directly, but the wiki should also show this data for consistency. Add these rows to all 301 system wiki pages.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-05 10:10:51', '2026-04-06 14:33:15', NULL, 'e16b8bd8e9d175dd393b9e5db9292cc4', 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 ('06FB0TNSRW96VE8PA8WNH3T8ZW', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Define corporation archetype taxonomy', 'Formalize 28 lore-taxonomy archetypes (Miri) and 6 behavioral archetypes (Burnelli-Sheldon) as TOML templates in wiki/economics/archetypes/. These are the generation templates for Tier 2 and Tier 3 corporations. Parent: #747.', 'done', 'high', NULL, 'copy', NULL, '2026-04-05 16:51:08', '2026-04-06 14:33:16', NULL, '0b6c8bd89361d70ea5e2add7868ab3f3', 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 ('06FB0TNSRZDQ6RFTW8T0PVE2S4', 'story', '06FB0TNSRXBP82ANSVAFMACCHW', 'Cultural diversity sweep — apply approved plan', 'Apply the cultural diversity remediation plan from #784 analysis. Includes non-culture exodus groups (corporations, religions, fan communities, families), great-scientist/pioneer naming for stations, and rebalancing underrepresented cultures across 301 systems. Blocked by #784 (analysis must be reviewed and approved first).', 'done', 'high', NULL, 'copy', NULL, '2026-04-05 13:37:47', '2026-04-06 14:33:16', NULL, '7e3a58cb0dca9028e1342b0d893ebac3', 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 ('06FB0TNSRW53PGJ08NHSA9B3A0', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Author 25 new Tier-1 corporation profiles', 'Create 25 new named corporations with full identity (political relationships, administered silences, NPC archetype). Priority gaps: financial services, re-embodiment, Groombridge clearing house, Compact-affiliated distributor, east reach anchors (2+), information brokerage. Output: wiki pages + TOML records in wiki/economics/corporations/tier1/. Parent: #747.', 'done', 'high', NULL, 'copy', NULL, '2026-04-05 16:51:04', '2026-04-06 14:33:16', NULL, 'c4dac62861daa9b1d685b68355ef7dde', 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 ('06FB0TNSRZHCJS9J3T4VRW71XC', 'task', NULL, 'Rename biome_summary to planet_class in systems.db', 'The biome_summary column in bodies table describes the overall planetary character (temperate, arid, frozen, etc.) — this is a planet class, not a biome. Biomes are per-zone classifications within a planet (Whittaker table). Rename column, update all consumers: wiki generation scripts, atlas CLI, client lookup code, planetary screenshot spec.', 'done', 'medium', NULL, 'server', NULL, '2026-04-06 14:55:51', '2026-04-06 15:02:30', NULL, 'b0f3f3c362c2f1b9198ee3bbb085bc8d', 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 ('06FB0TNSRYGCM1AJNE1BJRBRF0', 'story', '06FB0TNSRXBP82ANSVAFMACCHW', 'Heightmap batch — annotated heightmaps for all inhabited planets', 'Run the heightmap pipeline for all inhabited planets after the spike (#778) is reviewed and approved. Annotate with cities, rivers, roads, biomes. Blocked by #778 (spike must validate the approach first).', 'done', 'high', NULL, 'visual', NULL, '2026-04-05 13:37:50', '2026-04-06 21:03:46', NULL, '3ad6f806a0e7ac9f00e5d1398af00dca', 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 ('06FB0TNSRXKSHS71KCJD01HB3W', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Extend systems.db schema for economics', 'Add tables: gate_links (from star-map.json), commodities, production_chains, chain_inputs, corp_presence. Add columns: currency_zone on star_systems, corporation extensions (generated, supply_chain_role, market_share, price_strategy, revenue_tier). Import gate adjacency from star-map.json. Parent: #747.', 'done', 'high', NULL, 'server', NULL, '2026-04-05 16:51:38', '2026-04-06 21:31:11', NULL, '5ca197e97f8809b51e663c2131c98f22', 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 ('06FB0TNSRWA31RZ69841RMKYGM', 'story', '06FB0TNSRXBP82ANSVAFMACCHW', 'Batch planet generation — all bodies unattended', 'Run the planet generator pipeline across all ~3240 bodies in 301 systems without manual intervention. Inputs: wiki index.md files + optional overrides JSON. Outputs: per-body heightmap PNG + globe PNG + terrain data. Prerequisites: all planet types render correctly (arid, frozen, barren, moon, volcanic, gas giant, gas giant ringed, temperate, oceanic). Pipeline at tooling/planet-gen/. Spike output at spikes/heightmap-pipeline/output/ validated all types.', 'done', 'high', NULL, 'visual', NULL, '2026-04-06 11:41:38', '2026-04-06 21:42:44', NULL, '0b9bf32088a141f52c6aa91fe2ba43d8', 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 ('06FB0TNSRY3SPBCMNM05S4ZWE4', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Build make economy-db pipeline', 'Python script that compiles wiki/economics/commodities.toml + production_chains.toml into SQLite tables. Validation rules from wiki/economics/schema.md. Reference: D-182 (TOML source of truth).', 'done', 'high', NULL, 'server', NULL, '2026-04-05 19:51:25', '2026-04-06 21:44:32', NULL, '0658767d28a3febac50710c4ef674ac3', 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 ('06FB0TNSRZBXJPZP5CKKC2QWKC', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Assign currency zones to all 301 systems', 'Set currency_zone flag (TRACTUS_PRIMARY / MARK_PRIMARY / MIXED) for all 301 systems in wiki/economics/currency_zones.toml. Derive from Compact membership and political affiliation, not hop distance. Parent: #747.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-05 16:51:29', '2026-04-06 21:46:10', NULL, '8fc4c64da640845c8926c3d724541cda', 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 ('06FB0TNSRWKKAP47T1NFCT6A0C', 'task', NULL, 'Create icon_tint.gdshader for runtime icon recoloring', 'The implant HUD icon set (D-086, #795) references icon_tint.gdshader for runtime color replacement via ShaderMaterial. The shader must handle both stroke-based icons (most icons) and fill-based icons (health cross). See docs/design/icon-set-v01.md §3.2 for Godot integration spec.', 'done', 'medium', NULL, 'client', NULL, '2026-04-06 14:17:17', '2026-04-07 06:55:26', NULL, '32ecfd41a4af9eef1f52bf4bf2825189', 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 ('06FB0TNSRZE6H91V9YRRDAYFAR', 'task', NULL, 'Remove Qdrant semantic search infrastructure', 'The Qdrant index (475 points in ''commonwealth'' collection) is stale — pointing at old worktree paths from previous sprints. Nobody maintains the index and grep covers search needs. Remove: (1) Drop the Qdrant collection on tower-of-joy:6333, (2) Remove tooling/db/qdrant_connector.py, (3) Remove the /docs-search skill, (4) Remove Qdrant references from tooling/db/config.json and .claude/rules/local-services.md, (5) Remove qdrant-search and qdrant-index from CLI tool table in CLAUDE.md.', 'done', 'low', NULL, 'ci', NULL, '2026-04-05 20:46:10', '2026-04-07 06:59:45', NULL, '80f0d7aeed39d67642009072434234b5', 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 ('06FB0TNSRZ3K94563EWKKHBC4M', 'task', NULL, 'Author MARK_PRIMARY currency zone assignments for Compact systems', 'currency_zone column exists on star_systems (D-172) but all systems default to TRACTUS_PRIMARY. Need to identify Compact of Westphalia member systems and set them to MARK_PRIMARY. Sol (GJ 0) is already MIXED. Zone assignment is authorable, not derived from hop_distance — requires Miri/lore input on which systems are Compact-affiliated.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-06 21:29:46', '2026-04-07 11:48:49', NULL, '0be6382a5f9084002fc549f18bc75d13', 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 ('06FB0TNSRYA4CY4X1G4GM4KEWW', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Define shadow economy intensity ranges', 'Author wiki/economics/shadow_economy.toml with per-system-type intensity ranges. Core 0.0-0.2, mid-reach 0.3-0.6, Compact/frontier 0.6-0.9. Compact membership elevates independently of distance. Parent: #747.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-05 16:51:33', '2026-04-07 11:48:50', NULL, '66a2b60fcbe11174022043bc829ec8a0', 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 ('06FB0TNSRXJRQXYKQ4CM048VM8', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Wiki commodity copy pass', 'Flesh out the 36 stub pages at wiki/economics/commodities/ with flavor text, lore context, and production chain descriptions. Currently auto-generated field tables only. Reference: wiki/economics/commodities/index.md', 'done', 'medium', NULL, 'copy', NULL, '2026-04-05 19:50:50', '2026-04-07 11:48:51', NULL, '6e718b2a4e8f40b01d6e3c0f1e24c492', 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 ('06FB0TNSRWEZPB7YYJ75H2RVAG', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Generate ~150 Tier-2 regional corporations', 'Using archetype templates, create ~150 regional firms with proper identity: name, sector, corridor, backstory, distinct character. Distributed across all corridors including east reach. Each corporation also generates 2-5 branded product names based on primary commodity and cultural corridor — brands are authored, not templated. Output: TOML records in wiki/economics/corporations/tier2/, each including a products[] list. Parent: #747. Blocked by: archetype taxonomy ticket.', 'done', 'high', NULL, 'copy', NULL, '2026-04-05 16:51:13', '2026-04-07 11:48:51', NULL, '7af5006753b0e567ad5ff39287236a41', 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 ('06FB0TNSRZPHRKN8XGR0DEDKJM', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Build corporation generation pipeline for Tier-3', 'Rust binary (generate_corporations) that reads archetype templates + systems.db population data, generates ~5,000+ named template-instance businesses distributed by population. 5,000 is a floor, not a cap. Coverage rule: every inhabited system must have corporate presence — if population-based distribution leaves gaps, generate more until coverage is complete. Each Tier-3 instance is assigned a curated brands[] list pulled from Tier-1 and Tier-2 corps in its supply chain within the same corridor/system — shops stock brands, they do not create them. Output: generated_corporations.toml. Coverage validation: every commodity category has producers, every inhabited system >100K pop has corporate presence. Parent: #747. Blocked by: archetype taxonomy ticket.', 'done', 'medium', NULL, 'server', NULL, '2026-04-05 16:51:18', '2026-04-08 11:59:22', NULL, '16d9e0e8e22e16684e329e1a2c881166', 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 ('06FB0TNSRYHBP3BCTSDE2CKH84', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Add trade flows and stability testing', 'Extend economy_sim with inter-system trade flows (spatial price equilibrium), stockpile buffers, and stability test mode (--stability-check). Must pass Tests 1-2 (cold start convergence, long-run stability). Parent: #747. Blocked by: skeleton sim.', 'done', 'medium', NULL, 'server', NULL, '2026-04-05 16:52:01', '2026-04-08 11:59:22', NULL, '1a194c0f459af0b59e5c82502878d1b0', 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 ('06FB0TNSRX2NW7A04JDNXW27B8', 'task', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Energy-over-gate schema extension', 'Add gate_energy_connected boolean to node table in systems.db. Default MARK_PRIMARY zones to false. Implement demand reduction modifier (~0.3x utility demand) in sim. Reference: workshop D-record for gate transmission levels.', 'done', 'medium', NULL, 'server', NULL, '2026-04-05 19:51:15', '2026-04-08 11:59:22', NULL, '1af3796e5c9cc108e4a636db5aea5f2c', 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 ('06FB0TNSRXCQH6EQN7FR3RQT1R', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Add corporate agent behavior', 'Extend economy_sim with 6 behavioral archetypes (Monopolist, Distributor, Producer, Specialist, Cooperative, Intermediary). Corporations read from populated DB. Template-instantiated parameters. Parent: #747. Blocked by: currency zones ticket + corporation corpus.', 'done', 'medium', NULL, 'server', NULL, '2026-04-05 16:52:13', '2026-04-08 11:59:22', NULL, '44a10718188f59d16100412f1c326d77', 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 ('06FB0TNSRZC4YP1MD4WQ3FMRP0', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Add currency zones and exchange rates', 'Extend economy_sim with Tractus/Mark zones, cross-zone conversion friction (~3%), exchange rate float driven by trade balance. Shadow economy modifier per node. Must pass Tests 3-4 (shock response, cross-zone balance). Parent: #747. Blocked by: trade flows ticket.', 'done', 'medium', NULL, 'server', NULL, '2026-04-05 16:52:09', '2026-04-08 11:59:22', NULL, '7ceb4ca996f1c8c3bedf31e55a77e07b', 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 ('06FB0TNSRZ5Z2KAVFRTTNGMA54', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Extend economy-db with corporation pipeline and validation', 'Extend make economy-db with corporation pipeline: populate corp_presence from wiki/corporations/ data, validate wiki corp names match DB records, enforce coverage rules (3+ corps per major commodity, 1+ per inhabited system >100K pop). Add chain completeness validation (every intermediate commodity has at least one production chain producing it). Base import pipeline (commodities, chains, gate_links) already exists in tooling/economy-db/import_economics.py.', 'done', 'high', NULL, 'server', NULL, '2026-04-05 16:51:51', '2026-04-08 11:59:22', NULL, '7d2cb2088c855958719264ff8fd724bf', 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 ('06FB0TNSRWPFGMQ7G5BHBXXCQ8', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Build skeleton economy_sim binary', 'Standalone Rust binary (tooling/econ-sim/) that loads transport graph from systems.db, reads economy config from built .db, seeds productivity from PRNG, runs economy in fast-forward. Initial scope: production + consumption + price adjustment (no trade, no currency, no corporate behavior). Outputs per-node CSV. Parent: #747. Blocked by: schema + economy-db pipeline.', 'done', 'high', NULL, 'server', NULL, '2026-04-05 16:51:57', '2026-04-08 11:59:22', NULL, '99b71ca068f7872c83723bb8d96f6ff4', 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 ('06FB0TNSRZSZF15J4YY3PBKHJ0', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Economics insert panel — price history charts and GDP display', 'New implant insert panel: Economics Monitor. Accessible from implant navigation (INSERT mode, D-170). Uses implant UI component library (D-169, client/ui/implant/). Panels: (1) System selector — searchable list of systems from star map data. (2) Price chart — sparkline-style price_current over last N ticks for selected system''s top commodities. (3) GDP strip — total system economic activity as a bar/strip updated each tick. (4) Trade flow summary — top import/export commodities for selected system. Data source: EconomySnapshot in ObserverSnapshot (v21 IPC, ticket #822). The panel subscribes to snapshot data and rings in real time. Godot Control scene, composed from ImplantPanel, ImplantHeader, ImplantDataRow, ImplantTextBlock. No custom canvas drawing — use RichTextLabel for sparklines or the Control _draw() override for the chart only. Key decisions: D-169 (component library), D-170 (HUD groups), D-181 (signals).', 'done', 'high', NULL, 'client', NULL, '2026-04-08 12:23:40', '2026-04-10 11:21:31', NULL, '106f2e034a1b537c1dcfbec3f6f1892b', 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 ('06FB0TNSRZCASZYJ3N0HN306YG', 'task', NULL, 'feat(ui): add system population and GDP to star map info panel', 'When a system is selected in the star map, the info panel should show total system population and GDP alongside the existing fields (name, star type, hop, corridor, GTTR excerpt, bodies, adjacents). Data source: star_map_data.json — may need extending via tooling/generate-star-map-data.py to include population sum and economic indicators from systems.db.', 'done', 'medium', NULL, 'client', NULL, '2026-04-05 08:16:43', '2026-04-10 11:21:31', NULL, 'db0327509b0e4c8c6224f89d1df9a05c', 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 ('06FB0TNSRWVGQGVBRFSQ4KDTDC', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Economics debug console commands — event triggers and param sliders', 'Extend the existing debug console (client/ui/debug_console.gd + .tscn) with economics-specific commands that call the server''s new DebugCommandKind economics variants (ticket #823 on server side). New commands: ''econ inject <system> <commodity> <shock|boost> <magnitude>'' — fires InjectEconEvent. ''econ param <alpha|beta|friction> <value>'' — fires SetEconParam. ''econ inspect <system>'' — fires GetEconState and pretty-prints all 7 signals in the console output. Command parsing goes in _parse_command() / _dispatch_command(). Help text updated. Key decisions: D-178 (α β params), D-180 (event port), D-181 (signals). Blocked by #823 (server must handle the commands first).', 'done', 'high', NULL, 'client', NULL, '2026-04-08 12:23:46', '2026-04-10 11:21:32', NULL, 'd33f60b1f3a75bab130305939d38567e', 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 ('06FB0TNSRXYFDFF3YWNBDYKYVM', 'task', NULL, 'Author overheard conversations for remaining 24 zone types', 'overheard.ron currently covers 5 of 29 zone types (17% coverage). Need conversations for the remaining 24 types before playtest sprint. Each zone type needs 2-4 role-pair conversations in the generator-compatible RON format established in #664.', 'done', 'medium', NULL, 'copy', NULL, '2026-03-17 11:19:08', '2026-04-10 12:18:01', NULL, '80760d575625b479377ef210f2aef6ab', 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 ('06FB0TNSRZHEA166R3SJ3AGEVG', 'task', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Rail infrastructure corporation gap', 'No wiki corporation currently produces rail_infrastructure. Needs a Tier 1 or 2 corporation assigned (MVG candidate, or new corp). Flagged by Miri validation F-1.', 'done', 'low', NULL, 'copy', NULL, '2026-04-05 19:51:20', '2026-04-10 12:18:01', NULL, 'f95c6f984d40c5a056498bcc646eeb5a', 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 ('06FB0TNSRYJMG0RGZ280F7Q8Z8', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Event input port implementation', 'Add event injection interface to economy_sim (stdin or event file). EconEvent with target/effect/duration/visibility. Hidden events create effects without knowledge flags. Test: inject supply shock, verify cascade + recovery. Parent: #747. Blocked by: corporate agent behavior.', 'done', 'low', NULL, 'server', NULL, '2026-04-05 16:52:16', '2026-04-10 12:18:17', NULL, '74aed2902f9b560b320193bf841b726a', 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 ('06FB0TNSRW2WFC68F8Z12KNV20', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Expose economy state over IPC bridge to client', 'Blocked by #821 (server tick loop integration must exist first).', 'done', 'high', NULL, 'server', NULL, '2026-04-08 12:23:26', '2026-04-10 12:18:18', NULL, '78df5bbb8f463c2813947a48711c8909', 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 ('06FB0TNSRX19RSQPJZVM5H1F8C', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Integrate econ-sim into game server tick loop', 'Wire the standalone econ-sim binary output into the game server''s main tick loop. The econ-sim currently runs standalone (CLI binary in tooling/econ-sim/). This ticket makes the simulation run inside the server process, advancing one or more economy ticks per game tick. Expose per-node economy state (7 D-181 signals) as a queryable resource in bevy_ecs so the bridge can serialize it. Does NOT yet expose state over IPC — that is the next ticket. Integration points: server/src/simulation/ticker.rs, server/src/bridge/types.rs. Key decisions: D-178 (model arch), D-183 (iterative dev cycle).', 'done', 'high', NULL, 'server', NULL, '2026-04-08 12:23:18', '2026-04-10 12:18:18', NULL, 'a78f1dd69596bcd87eb0bf0597df93b5', 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 ('06FB0TNSRX9ATZ6WWBNT85TFFM', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Economics debug command handler — event injection and parameter mutation', 'Extend DebugCommandKind (server/src/bridge/types.rs) with economics-specific debug commands: (1) InjectEconEvent { target, effect, magnitude, duration_ticks } — fires an EconEvent (D-180) into the running simulation. (2) SetEconParam { param, value } — mutates α (tâtonnement step), β (damping), or per-corridor friction at runtime. (3) GetEconState { system_id } — returns all 7 D-181 signals for a named system. Server processes these via existing PlayerAction::DebugCommand → DebugCommandKind flow. Response returns in DebugResponsePayload. Key decisions: D-180 (event input port), D-181 (signals), D-178 (α and β parameters).', 'done', 'high', NULL, 'server', NULL, '2026-04-08 12:23:32', '2026-04-10 12:18:19', NULL, '470a1295af6780612e481d208706e128', 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 ('06FB0TNSRWCRXC5Z6T4T26TZYC', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Brand layer design', 'Design the brand/luxury goods system that sits on top of the commodity layer. Brands consume commodities as inputs. Brand pricing is driven by emotional/cultural/want mechanics, not tatonnement. Per brand, per location, per currency pricing. Brand revenue as GDP income cluster. Future DLC deliverable — design now, implement later. Reference: workshop D-records for ''Brands Are Not Commodities''.', 'done', 'medium', NULL, 'planning', NULL, '2026-04-05 19:50:46', '2026-04-10 13:37:32', NULL, 'f18ee02dec295a2fb5ac77eb2ede9415', 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 ('06FB0TNSRWK90BT1ATFCNKSBHG', 'epic', '06FB0TNSRZE4CSS8YR0FCEXMK8', 'Phase 3: Planetary/moon maps and station layouts — Atlas of the Reach', 'Deliverable: Atlas of the Reach (implant app). Region-level maps (hundreds of km scale). Cities, named rivers, mountain ranges, towns, rail lines, gate/portal locations, road hierarchy, named areas/provinces, villages, biome types. Tectonic-first tile generation pipeline (PerfectWorld/PlaTec approach). Depends on Phase 1 (body catalog) + Phase 2 (economic profiles inform settlement placement).', 'done', 'high', NULL, 'planning', NULL, '2026-03-25 13:29:36', '2026-04-10 19:00:34', NULL, '329dbea87b39825d9e42f1af651a1ca4', 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 ('06FB0TNSRXZSXNPA5Q55JN5K54', 'task', NULL, 'Keybind document and settings keybind mapper', 'Two deliverables: (1) A keybind reference document listing all current key bindings (InputMap actions + hardcoded _unhandled_key_input keys like M/J/N/[/]). (2) A keybind mapper in the settings dialog that lets the player rebind keys at runtime. Triggered by Sprint 34 E-key conflict where economics panel was bound to a key already used by InputMap interact action.', 'backlog', 'medium', NULL, 'client', NULL, '2026-04-10 20:20:28', '2026-04-10 20:20:28', NULL, 'ab5bace846469b5569cdc6081187ce6c', 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 ('06FB0TNSRYKD0QAB4W9KDHR47G', 'task', NULL, 'Refactor server tick cycle — system set phases replacing ad-hoc ordering', 'The server tick loop uses ~40+ ad-hoc .after()/.before() constraints scattered across BridgePlugin and SimulationPlugin. Sprint 34 added .after(tick_economy_simulation) to handle_debug_commands which created a schedule cycle (debug → observer → advance_tick → econ → debug). The constraint had to be removed. This is fragile and will get worse as more systems are added. Refactor to named Bevy system sets with a linear phase pipeline: InputPhase → SimulationPhase → EconomyPhase → PerceptionPhase → OutputPhase → TickAdvance. Each system belongs to exactly one phase. Phases are ordered linearly. No cross-phase .after()/.before() needed. Prevents cycles by construction. Do this with Jeroen directly — pair session, not autonomous agent work.', 'done', 'high', NULL, 'server', NULL, '2026-04-10 20:43:23', '2026-04-10 20:43:23', NULL, '334fffa78a4f571e04bbfce5ea1ad86b', 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 ('06FB0TNSRWA68M9DHX975087T0', 'story', '06FB0TNSRWK90BT1ATFCNKSBHG', 'Hand-author atlas templates — Lendel and 4-5 core systems', 'Hand-author complete markers.json content for Lendel (GJ 380c) and 4-5 other core systems as templates. Full treatment: named geographic features, city placements validated against terrain, roads/rail following terrain corridors, institutional POIs. These templates establish the quality bar for the generator and serve as few-shot examples for the Gemma 2 naming prompts. Per D-191.', 'done', 'high', NULL, 'copy', NULL, '2026-04-10 19:00:01', '2026-04-12 17:47:36', NULL, 'd4f7180303918403f48c8d23aa0c29bb', 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 ('06FB0TNSRY70G46FTDF7SN12YM', 'task', NULL, 'Wiki glossary — canonical proper nouns, factions, locations, terminology', 'Create a glossary page at wiki/glossary.md (or wiki/index-glossary.md) listing canonical proper nouns: faction names, precursor civilization terms (Founders, not Gatebuilders), currency names, corridor names, key locations. Quick-reference for content authors to avoid inventing terms that conflict with established canon. Triggered by Sprint 34 copy review where ''Gatebuilder'' was used instead of canonical ''Founders''.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-10 20:20:25', '2026-04-12 17:47:53', NULL, '135b7d8e5495abdff86ee59675dd9d1a', 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 ('06FB0TNSRXRV21TCSY3FVE52E8', 'task', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Add Calloway, VGV, thrds, Bífröst Marmor to tier1.toml', 'The 4 canonical brand corps (Calloway Distillery, Vins de Grand Vide, thrds, Bífröst Marmor) exist in wiki/ but are missing from wiki/economics/corporations/tier1.toml. Add them with full TOML records: corp_id, proper_name, behavioral_archetype, primary_commodities (consumed as inputs), branded_products, headquarters system. Per D-189 gap analysis.', 'done', 'high', NULL, 'copy', NULL, '2026-04-10 13:33:30', '2026-04-12 17:49:38', NULL, '5baaad16ee8995a256aebe57d255da96', 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 ('06FB0TNSRZV4ES4MNSBGK07VC4', 'task', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Author brand_templates.toml — 120-130 archetypes with corridor naming patterns', 'Create wiki/economics/archetypes/brand_templates.toml with ~35-40 archetypes × 3 sub-variants = ~120-130 templates. Each template defines: brand_category, commodity_inputs with quantity ranges, premium_range, scarcity_class, value_trajectory, naming_pattern (corridor-specific), scale_tier (local/regional/reach-wide). Naming patterns per D-189: north_reach (British/Australian), east_reach (Korean/Japanese), west_reach (German/Dutch/Nordic), south_reach (Portuguese/Swahili), inner (pan-corridor neutral), frontier (founder+noun).', 'done', 'medium', NULL, 'copy', NULL, '2026-04-10 13:33:38', '2026-04-12 17:49:49', NULL, '2779dade6f885bfdb208e9c35b315aa6', 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 ('06FB0TNSRYKEQE6145NNF5WXQR', 'task', '06FB0TNSRX19RSQPJZVM5H1F8C', 'Thread world seed from StartupMessage into economy simulation', 'EconSimResource is currently initialized with seed 0 in SimulationPlugin::build(). It should use the world_seed from StartupMessage (received by the server during the handshake protocol). Wire the seed through from the startup sequence into try_load_economy(). Reference: server/src/simulation/mod.rs try_load_economy(0).', 'done', 'low', NULL, 'server', NULL, '2026-04-10 11:57:48', '2026-04-14 15:21:57', NULL, 'a806e892625d25bc3ecc0ee97cddbd52', 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 ('06FB0TNSRXESDXS47F4ZJPH7R0', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Add brand_products, brand_inputs, system_fiscal schema and Phase 2 demand stubs', 'Add brand layer DB tables (brand_products, brand_inputs, system_fiscal, corp_financial_state, corp_lifecycle_events) to systems-schema.sql per D-189. Author brands.toml with the 4 canonical brand corps (Calloway, VGV, thrds, Bífröst) + mirror products as Phase 2 commodity demand stubs. Extend make economy-db to compile brand tables. Add validation rules (V-B01 through V-B05). Brand corps register commodity demand at home market nodes.', 'done', 'high', NULL, 'server', NULL, '2026-04-10 13:33:00', '2026-04-14 15:24:54', NULL, '291629ba6cdaea1203d15a6abfd78a12', 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 ('06FB0TNSRZWJA6AJJRJKTKQ6YC', 'task', '06FB0TNSRWK90BT1ATFCNKSBHG', 'Batch populate terrain_reference column in systems.db bodies table', 'terrain_reference column in bodies table is NULL for all 273 inhabited bodies. Write a batch script to populate it from wiki heightmap paths (wiki/star-systems/{system}/bodies/{body_id}/heightmap.png). Simple path-mapping script. Per D-191 gap analysis.', 'done', 'medium', NULL, 'server', NULL, '2026-04-10 19:00:16', '2026-04-14 15:26:00', NULL, '3263853837a7b1c6056470f3dc6a8809', 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 ('06FB0TNSRW099WFPGAKW3SV2YC', 'story', '06FB0TNSRWK90BT1ATFCNKSBHG', 'Build generate_atlas.py — terrain-aware sequential city placement and infrastructure generation', 'New Python pipeline at tooling/planet-gen/generate_atlas.py. Reuses planet_simulation.simulate() for terrain data. Implements: continent detection (flood-fill), habitability scoring, river mouth identification, sequential city placement (capital at river mouth → rail corridor growth → new continent ports at cities 3-4), A* pathfinding for roads/rail on terrain cost grid (MST network), quadrant distribution constraint. Settlement pattern modifies spacing. ±25% noise for variation. Population-scaled city count: floor(log10(pop/1M)). Writes to markers.json per body. make atlas-generate target. Deterministic per seed. Per D-191.', 'done', 'high', NULL, 'server', NULL, '2026-04-10 18:59:18', '2026-04-15 06:47:00', NULL, 'bf6a068fc5cc1f8c2fbe4ea1d7ae8b3b', 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 ('06FB0TNSRXMTJBWMXJBANMD6C4', 'task', NULL, 'Unit tests for generate-star-map-data.py helpers', 'Review follow-up from PR #128 (Hoshe #17). Add unit-test coverage for compute_gdp, infer_tier_from_population, build_adjacency, parse_wiki_index in tooling/generate-star-map-data.py. Explicit boundary-condition test worth adding: compute_gdp at exactly 1T Tr (the BTr → TTr format switch). Non-blocker on the atlas landing PR but the generator is now on the pre-pr-client path, so it earns the regression coverage.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-15 07:06:33', '2026-04-15 07:06:33', NULL, 'd8b9fab33d38525cee02250a96842d4a', 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 ('06FB0TNSRZN95D8BBZ28Q92BQW', 'task', NULL, 'Amend D-191 §8 markers schema to formalize overlay arrays', 'Review follow-up from PR #128 (blocker #3 fix). AtlasMarkerOverlay currently derives production_zones / shadow_economy / corp_presence from cities[].primary_function and cities[].commission_presence because D-191 §8''s schema (cities, roads, railroads, pois, rivers, oceans, mountain_ranges) has no dedicated arrays for production zones, shadow bands, or per-corp dots. Options: (a) amend D-191 §8 to list these explicitly and update the server generator, or (b) keep deriving from cities forever. Work with server team to pick and land the schema change so the MVP overlays read first-class data.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-15 07:06:42', '2026-04-15 07:06:42', NULL, '34ff625d80e041667e1316a3c2d6d205', 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 ('06FB0TNSRY964P8BYB5954GS28', 'story', '06FB0TNSRWK90BT1ATFCNKSBHG', 'Atlas implant panel — system picker, orbital diagram, body navigation', 'New implant app extending implant/map. Register with HudGroups as FULLSCREEN (z=20). 3 navigation levels: system picker (reuse from economics panel) → orbital diagram (star center, bodies by orbit_index, click-to-select) → body atlas entry point. Station mini data panel on click (name, operator, currency zone — no drill-down). Back navigation at each level. Per D-191.', 'done', 'high', NULL, 'client', NULL, '2026-04-10 18:59:35', '2026-04-15 07:17:21', NULL, '149489b7a166c9cf67d02d36fb30fca2', 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 ('06FB0TNSRYMCRQ39W7T8F6HCY8', 'story', '06FB0TNSRWK90BT1ATFCNKSBHG', 'Atlas heightmap viewer — pan/zoom, marker overlay, city data panel', 'Body atlas level: load heightmap PNG as Texture2D in SubViewportContainer with pan/zoom. MarkerOverlay (Node2D _draw()) renders cities (dots scaled by population_tier), roads (polylines), rail (dashed polylines), POIs (diamonds), named features (labels) from markers.json. Click city → City Data Panel sidebar (name, population, currency zone, Commission presence, shadow economy zone, gate distance, economics panel link). Economics panel link opens Phase 2 panel pre-filtered to node. Per D-191.', 'done', 'high', NULL, 'client', NULL, '2026-04-10 18:59:45', '2026-04-15 07:17:30', NULL, '022a5957cceeda18a40b230eb88b0619', 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 ('06FB0TNSRX2DNGM846NC6EH1WM', 'story', '06FB0TNSRWK90BT1ATFCNKSBHG', 'Atlas overlay system — 9 MVP overlays with visibility tiers', 'Overlay toggle bar at top-right of regional view. 5 always-on (terrain, infrastructure, named features, gate/spaceport, political zones). 4 toggleable (population density, production zones, shadow economy zones as broad bands, corporate presence Tier 1). Deferred overlays visible but greyed/locked with unlock requirement tooltip. Maps to D-181 signal visibility ladder. Per D-191.', 'done', 'medium', NULL, 'client', NULL, '2026-04-10 18:59:53', '2026-04-15 07:17:33', NULL, '06a751f16a14d6569c72fdee7ac105fe', 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 ('06FB0TNSRX6RK3GGV1A1TWQSMC', 'task', NULL, 'sr-voice release binary: multi-backend build (ROCm + CUDA + Vulkan + CPU)', 'The game will ship on multiple GPU vendors. The current sr-voice Cargo.toml has optional feature flags for metal / vulkan / cuda / rocm but default = [] — which means `cargo build --release` produces a CPU-only binary. Release binaries need to cover at minimum:
|
||
|
||
- NVIDIA: --features cuda (Windows, Linux gaming rigs)
|
||
- AMD: --features rocm (Linux) or vulkan (Windows, macOS, broader)
|
||
- Apple Silicon: --features metal (macOS)
|
||
- Fallback: CPU-only, always available
|
||
|
||
Options to cover this from the build pipeline:
|
||
|
||
A) Multiple release artifacts — sr-voice-cuda, sr-voice-rocm, sr-voice-vulkan, sr-voice-cpu — selected at game startup based on detected hardware. Biggest artifact count but best performance.
|
||
|
||
B) Single Vulkan release + CPU fallback — Vulkan compute works on NVIDIA, AMD, and Intel integrated GPUs with shipping drivers. One binary, acceptable perf on all GPUs, CPU-only binary for everyone else.
|
||
|
||
C) Dynamic feature detection at runtime — one binary with all backends compiled in, selects at load time. Largest binary, simplest distribution.
|
||
|
||
Also needs: release build pipeline (CI / cross-compilation) for each target platform, dev package installation instructions for each backend (e.g. ROCm rocm-hip-devel on Fedora is required for --features rocm to build), runtime hardware detection in the game launcher to pick the right binary.
|
||
|
||
Filed during the #833 naming pipeline work — the ROCm rebuild on the dev machine surfaced that the current Makefile target `build-sr-voice` produces CPU-only binaries regardless of the hardware present, which is fine for the dev''s #833 batch but absolutely wrong for shipped release binaries. Parent work: D-138 (Gemma 2 voice pipeline).', 'backlog', 'medium', NULL, 'server', NULL, '2026-04-15 10:57:11', '2026-04-15 10:57:11', NULL, 'b94d4bfa60d1a2b2fb7cea9f31ef6bb8', 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 ('06FB0TNSRWFV6DE3X9KXFAEQB8', 'task', '06FB0TNSRWK90BT1ATFCNKSBHG', 'Review hand-authored template names (Estrade, Vuurkloof)', 'Merged into #838.', 'cancelled', 'low', NULL, 'server', NULL, '2026-04-17 22:47:30', '2026-04-17 22:47:30', NULL, 'cdd20ba9ca952ad2c500843980474783', 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 ('06FB0TNSRZ8PJYNWGMZD2TZENR', 'story', '06FB0TNSRWK90BT1ATFCNKSBHG', 'Gemma 2 batch naming pipeline for atlas geographic features', 'Extend generate_atlas.py with gemma_naming.py — batch client for sr-voice binary. Sends corridor-appropriate naming prompts per body (planet_class, cultural_corridor, settlement_pattern, atmospheric_tone + corridor palette). Names rivers, oceans, mountains, regions, cities. Earth-name blocklist post-processing. Dedup check against full name corpus. ~80 min batch for 2,394 bodies. Dual purpose: Phase 3 content AND Gemma 2 pipeline quality test. Per D-191.', 'done', 'high', NULL, 'server', NULL, '2026-04-10 18:59:27', '2026-04-17 22:47:34', NULL, 'bcced1acbb9fea4f4f21d7f861ba0145', 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 ('06FB0TNSRZBV3S6HV2AF16H24W', 'story', '06FB0TNSRWK90BT1ATFCNKSBHG', 'Review and hand-refine generated atlas content across all inhabited bodies', 'After generate_atlas.py runs across all 2,394 bodies: review generated output for quality. Check city placements (not in water, not on mountains, reasonable distribution). Check names (culturally appropriate, no Earth-name leaks, no duplicates). Check roads/rail (follow terrain, don''t cross water without reason). Hand-author refinements and corrections. Focus on the ~273 inhabited bodies; uninhabited bodies get geographic names only. Per D-191.
|
||
|
||
--- Merged from #851 (PR #130 review findings) ---
|
||
|
||
PR #130 review surfaced quality concerns in hand-authored template bodies from prior sprints. These templates serve as few-shot examples for the Gemma 4 naming pipeline, so issues cascade. Evaluate whether fixes are needed:
|
||
|
||
- Estrade (GJ280Ad): rivers named ''Circumflex'', ''Contraflow'', ''Sunwise Current'' — navigational/abstract terms, not river vocabulary
|
||
- Estrade (GJ280Ad): all 3 mountains are directional compass labels (''Eastern Shelf'', ''Western Range'', ''Southern Heights'')
|
||
- Vuurkloof (GJ380c): zero cross-cultural mixing despite GTTR stating 3 centuries of Kumasi corridor influence — pure Afrikaans monoculture
|
||
- Vuurkloof (GJ380c): 65% of mountains end in -rant suffix (monotony)
|
||
- ''Westwall'' appears on both Edict (GJ244Ad) and Cairnside (GJ892d) — cross-body stem repetition
|
||
|
||
These are in wiki/star-systems/*/bodies/*/markers.json. May not need fixing if the templates are not used as few-shot examples by the batch pipeline. Evaluate before committing work.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-10 19:00:10', '2026-04-19 10:33:56', NULL, 'b7d98288eb36daa610c0fc6534692696', 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 ('06FB0TNSRY5G9GMPV8B0RDD1JR', 'initiative', NULL, 'Fog of perception non-negotiable', NULL, 'review', 'medium', NULL, NULL, 'D-011', '2026-02-09 15:21:44', '2026-04-19 11:19:24', NULL, '9a3d67aa2d6a6d6ed154d6a5e5ed6fef', 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 ('06FB0TNSRZAGFE5N6NNJTYWTMC', 'task', NULL, 'Retire implant/map/starchart zombie path', 'Follow-up to #844 atlas unification. Remove the dead starchart HudGroups registration now that the unified implant/map app has soaked.
|
||
|
||
Scope:
|
||
- Remove star_map.gd''s HudGroups.register_app("implant/map/starchart", ...) call
|
||
- Drop set_insert_active plumbing from snapshot_consumers.gd:60 (guard is always false now, close_app call is dead)
|
||
- Consider deleting client/ui/star_map.gd + client/ui/star_map.tscn entirely
|
||
- Remove star_map node refs from client/ui/hud.tscn (and the stale TODO comment at line 19-20 if not already swept in #844 cleanup)
|
||
- Remove star_map node refs from main.gd if any linger
|
||
|
||
Prerequisite: one sprint of soak on unified atlas with no regressions. Do NOT schedule before Sprint 37.
|
||
|
||
Verification: grep for ''implant/map/starchart'' and ''star_map'' — should yield only deleted-file residue or this ticket.', 'done', 'low', NULL, 'client', NULL, '2026-04-19 09:45:44', '2026-04-19 11:22:12', NULL, 'adcb604e70a11773fcf21da66ba68704', 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 ('06FB0TNSRXPYZED88G4JZCMF54', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Author 120-170 notable brand corps across all 8 categories', 'Author brands.toml entries for 120-170 notable brand corps per D-189 census targets. 8 categories: terroir, heritage_craft, tech_premium, cultural, service_premium, commodity_branded, design_heritage, platform_catalogue. Each entry needs: corp_id link, brand_category, commodity inputs, pricing stub parameters, product_subcategory, halo/volume tier structure. ~28 corps already named; remaining ~100-140 need creation with corridor-appropriate identities. Wiki pages for top-tier brands.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-10 13:33:15', '2026-04-19 12:23:47', NULL, '217cb31b7898dc1241c72e12c9ca5c0b', 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 ('06FB0TNSRXHXPMXC7SDHJFN320', 'story', '06FB0TNSRXD5W32VCV5YZY3NX0', 'Bookmark definition system', 'System for defining and selecting CK3-style bookmarks. A bookmark = skills + starting state + context. Tycoon is the first bookmark. Bookmark shapes character creation screen and initial world state. Decision #2 (skills + bookmark only for character creation).', 'done', 'high', NULL, 'server', NULL, '2026-03-05 23:12:32', '2026-04-19 16:21:05', NULL, 'ba5c7014d32f54139992730bd89a1bd0', 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 ('06FB0TNSRZTA6ETT53NTHS8AAR', 'story', '06FB0TNSRXE0VWDHVQTXPVPEW0', 'Location-to-culture resolution system (server)', 'Server implementation: when a bookmark places the player in a location, resolve the culture that location implies. Van Maanen''s Star start = Van Maanen''s Star culture. This resolved culture is passed to the NPC generator, voice pipeline, and apartment generator as the primary cultural context. Unblocks 5 downstream pipelines (voice cards, zone templates, NpcBlueprint culture field, cultural visual grammar, AI pipeline). Decision D-128 (culture implicit in starting location). Blocks #621 (NPC personality surface area) and #620b (client location picker).', 'done', 'high', NULL, 'server', NULL, '2026-03-17 06:47:09', '2026-04-19 16:21:05', NULL, 'e1dd83a60cd07729fbeb3b9b2308a79a', 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 ('06FB0TNSRW11RQE7YET39TEBPM', 'story', '06FB0TNSRY23YPP1Q0TYJ816HW', 'Build generate_brands pipeline — 10K minor brands from templates', 'New generate_brands binary (Rust). Reads corp table + brand templates (brand_templates.toml, ~120-130 template definitions). Generates 10,000 minor brand products with corridor-specific procedural names, 3 scale tiers (local/regional/reach-wide budget), assigned to Tier 2/3 corps. Output to generated_brands.toml → brand_products + brand_inputs tables. Runs after generate_corporations in make economy-db pipeline. Per D-189.', 'done', 'medium', NULL, 'server', NULL, '2026-04-10 13:33:22', '2026-04-19 16:21:06', NULL, '67867f5e715ff6f19c77e239bf6e936a', 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 ('06FB0TNSRY2SW0FYSPHCN90XM8', 'task', NULL, 'Clean out orphaned NPC and environment interaction systems', 'The NPC ambient interaction model (overheard conversations, room grammar, behavior engine, zone-type NPC population) has been scrapped (R-012). Clean out orphaned code and content: (1) server/content/npc-conversations/overheard.ron — 1635 lines of orphaned content, (2) server/src/npc/overheard.rs references — if any exist, (3) any overheard.yaml.deprecated files, (4) D-078 cross-references in other D-records that point to the scrapped system (D-079, D-080 reference D-078), (5) zone-type template role IDs in D-142 that only existed to serve the overheard system. Audit and remove dead references. Do not touch working systems (dialogue, monologue, knowledge graph). KEEP the Gemma 2 voice pipeline (server/src/voice/, sr-voice binary, D-138) — it will be reused for Phase 3 geographic naming (D-191) and future systems.', 'done', 'low', NULL, 'server', NULL, '2026-04-10 20:30:18', '2026-04-19 16:21:07', NULL, '172c8f89a0ad201a80a6f51796f705c3', 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 ('06FB0TNSRZ0BEE6QCEA1C2WNPR', 'task', NULL, 'Migrate bincode v1.x to v2.x', 'cargo audit flagged bincode v1.3.3 as unmaintained (RUSTSEC-2025-0141). No current vulnerabilities but will not receive future patches. Migrate to bincode v2.x stable. Low priority — no immediate risk, but should not drift indefinitely.', 'done', 'low', NULL, 'server', NULL, '2026-03-07 10:58:13', '2026-04-19 16:21:08', NULL, 'e492d76192292812804f2c4602f7805b', 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 ('06FB0TNSRW9RMGTX4SCWGQQ1JR', 'task', NULL, 'Configure cargo deny.toml for license and advisory checking', 'cargo-deny is installed but needs a deny.toml config in server/ to define allowed licenses (MIT, Apache-2.0, BSD-2/3, ISC, Unlicense, Zlib, CC0). Without it, cargo deny rejects all dependencies. Also configure advisory database checks and duplicate dependency detection. Pre-push hook is already wired to run it when deny.toml exists.', 'done', 'medium', NULL, 'server', NULL, '2026-03-23 18:06:39', '2026-04-19 16:53:40', NULL, '202d8d7d65f07b48bec7633574e4fda5', 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 ('06FB0TNSRXKRSBNZCPTWE25DYM', 'task', '06FB0TNSRZBV3S6HV2AF16H24W', 'Core-world atlas cohesion pass — hand-refine high-visibility systems', 'After generate_atlas.py + gemma_naming.py (#832, #833) complete the batch, the load-bearing core systems need a white-glove hand-refine pass above the baseline refinement in #838. These are systems the player will visit repeatedly across every playthrough — they carry disproportionate narrative weight and need a cohesive, lived-in, internally-referential feel that batch LLM naming cannot reliably produce.
|
||
|
||
===================================================================
|
||
Step 1 — START WITH A DATABASE ANALYSIS, NOT BY OPENING JSON FILES
|
||
===================================================================
|
||
|
||
Before editing anything, run an analysis pass against `server/data/systems.db` to find the hotspots worth hand-fixing. The atlas_* tables are the scalar mirror of every markers.json and they make this a set of SQL queries, not a file-scan exercise. Worth building a small analysis script the team can re-run across future refine passes.
|
||
|
||
Suggested queries to start from:
|
||
|
||
- Stem frequency across atlas_cities/rivers/oceans/mountain_ranges: find which root tokens (Arcturus, Meridian, Holm, Kita, …) dominate the corpus, and whether any hit the per-run --stem-cap (20). Over-represented stems are the first place to look for a trim.
|
||
|
||
- Cross-body name collisions: same name, different body, same feature type — probably fine in different corridors, noisy in the same corridor.
|
||
|
||
- Cross-feature-type same-body near-duplicates: ''Aureus River'' + ''Aureus Range'' on the same body. Dedup catches exact matches, not stems.
|
||
|
||
- Cardinal direction density per body: a body with 6 mountain ranges all named ''Western X / Northern X / Eastern X'' is statistically impossible — the generator''s few-shot pool hit hard.
|
||
|
||
- Generic / lazy outputs: LIKE ''Great %'', LIKE ''The %'', LIKE ''Hilly %'', LIKE ''Sector %'' — each of these is legal per the grounding-overhaul intent but their frequency is the signal. High counts on one system = hand-refine target.
|
||
|
||
- Earth-echo concentration: LIKE ''Manchester'' / ''London'' / ''Paris'' / ''Route %'' / ''Sector %'' across the core systems. Earth-echo is allowed (#833 product decision), but if Sirius alone has 12 Earth-echoes the concentration reads as laziness, not flavour.
|
||
|
||
- Empty or single-character names, stem-cap fallbacks (Concord Range / Foro Spine / Meridian Ridge patterns from the palette fallback), and preserved-but-drifted names where hand-authored bodies'' derived features don''t match the template''s canonical tone.
|
||
|
||
The analysis pass produces a ranked list of bodies + systems that most need hand-touching. Do NOT start editing core worlds before this list exists — going body-by-body through 2394 files by hand is the wrong scale.
|
||
|
||
===================================================================
|
||
Step 2 — DUAL DELIVERABLE: markers.json AND atlas_* tables
|
||
===================================================================
|
||
|
||
Every hand-refine change touches BOTH sides:
|
||
|
||
1. `wiki/star-systems/<sys>/bodies/<body>/markers.json` — source-of-truth file next to the heightmap. This is what the renderer loads.
|
||
|
||
2. `systems.db` atlas_* tables (atlas_cities, atlas_rivers, atlas_oceans, atlas_mountain_ranges, atlas_pois, atlas_body_grids, atlas_roads, atlas_railroads) — scalar mirror the implant atlas app queries at runtime. These MUST stay in sync. A markers.json edit that doesn''t propagate to the DB will show old names in the atlas UI and break the cross-body queries from Step 1.
|
||
|
||
The easy way to keep both sides synced: after hand-editing a body''s markers.json, run `python3 tooling/planet-gen/generate_atlas.py --body <body_id>`. It detects the already-populated file, skips regeneration, and calls sync_markers_to_db which DELETEs and re-INSERTs every atlas_* row for that body. One command, both sides consistent.
|
||
|
||
Verification query per touched body:
|
||
tooling/db/sqlite-query --db server/data/systems.db \
|
||
"SELECT body_id, local_id, name FROM atlas_cities WHERE body_id = ''<id>''"
|
||
Should return the hand-edited names, not the batch ones.
|
||
|
||
===================================================================
|
||
Step 3 — SCOPE
|
||
===================================================================
|
||
|
||
Load-bearing core systems (process in this order):
|
||
- Sol (GJ 0) + its inhabited bodies
|
||
- Tau Ceti (GJ 71)
|
||
- Sirius (whichever GJ catalog is assigned)
|
||
- Ran (GJ 144)
|
||
- Groombridge (GJ 380)
|
||
- Any other hop 0–1 system the analysis flags as load-bearing
|
||
- Hand-authored templates (Lendel, Edict, Vuurkloof, Røros, Cairnside, Estrade) are already polished and do NOT need re-work unless their derived features on the same body drifted during the #833 run
|
||
|
||
Quality bar for this tier (higher than general #838):
|
||
- Place names should cross-reference each other where plausible (a river passing through a town named after the same founder; a ridge line visible from the capital; a secondary city at the mouth of the main river)
|
||
- At least 1-2 names per body with a narrative hook (founder story, historical event, shared stem across sibling features)
|
||
- Zero generic / lazy outputs on named bodies (no ''Hilly Range'', ''Great Ranges'', ''Sector Seven'' on a core body)
|
||
- Cardinal-direction names (Western Ridge, Kita-sato) should correlate with actual map orientation on the heightmap where possible, or be replaced
|
||
- Earth-echo names (Manchester, Route 41, the occasional New London) are explicitly allowed — they fit the blended-reality head-canon — but they should feel intentional per-body, not coincidental
|
||
|
||
===================================================================
|
||
Definition of done
|
||
===================================================================
|
||
|
||
- Analysis script committed under `tooling/planet-gen/` or `tooling/db/` so the next refine pass can reuse it.
|
||
- Each touched body has: updated markers.json committed, DB atlas_* rows refreshed via generate_atlas.py, a short entry in a hand-refine log noting which bodies were touched and why.
|
||
- Re-run the analysis script at the end and confirm the target metrics improved (fewer cardinals, fewer stem-cap fallbacks, fewer cross-feature near-duplicates on core bodies).
|
||
- Spot-check verification query passes on at least one body per core system.
|
||
|
||
Observed during the #833 run: Sirius was being named when this ticket was created. That was the trigger — the observation that frequently-visited systems need a pass above what a 2B model can deliver, and that the pass should start by letting the database tell us what to fix rather than scanning files.', 'done', 'high', NULL, 'copy', NULL, '2026-04-15 09:58:42', '2026-04-19 16:53:40', NULL, 'ea9cbcdd3855085cddf64bdcaf5ad1f9', 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 ('06FB0TNSRYC99HFBA9SJJG47YG', 'task', NULL, 'Add --help flag to custom DB scripts', 'Add standard --help flag to tooling/db/ scripts (ticket, sprint, decision, sqlite-query, sqlite-exec). Scripts already have usage output on bad args — wire it to --help for discoverability. Low priority housekeeping.', 'done', 'low', NULL, 'client', NULL, '2026-03-22 18:03:51', '2026-04-19 16:53:41', NULL, '732ecdea6b29a140215d29de4420cdb6', 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 ('06FB0TNSRZYYDQC16CQRBXE784', 'story', NULL, 'Unify star map and atlas into single implant/map chain (D-191 criterion 1)', 'Review follow-up from PR #128. star_map.gd still registers as implant/map/starchart (hop-ring view) and AtlasPanel registers as implant/map/atlas — they''re technically two separate HudGroups apps, so the full 4-level nav chain Reach → system → planet → regional requires a manual app switch. Migrate star_map.gd to share the AtlasPanel root (or add a level-0 in AtlasPanel that embeds the hop-ring view), so D-191 criterion 1 is end-to-end. Tyre flagged this as acceptable for #834/#835/#836 but not end-to-end until resolved.', 'done', 'medium', NULL, 'client', NULL, '2026-04-15 07:06:25', '2026-04-19 16:53:41', NULL, 'ee34fe74d78a2e746dc956e91ab02dd8', 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 ('06FB0TNSRZ41DF9G40YFRXFJFR', 'story', NULL, 'Retire v0.1 PoC NPC system and content/global/', 'Retire the scrapped v0.1 proof-of-concept NPC system. Per memory (feedback_cascade_no_phase6_content): NPC systems, overheard conversations, room grammar, and NPC ambient behavior were all scrapped — to be rebuilt from scratch after the walkable environment exists (Phase 4+). The current ~11k lines of Rust code and accompanying content are stale plumbing kept alive only because nothing else removed them.
|
||
|
||
SCOPE (phased — code first, then content, then docs):
|
||
|
||
Phase 1 — Audit (do not delete anything yet)
|
||
- Confirm with project lead that nothing in storyteller/perception/knowledge/monologue systems is silently depending on server/src/npc/ types (Npc, InteractionMemory, MoodState, RelationshipEdge, RelationshipGraph, etc.).
|
||
- Grep for cross-module imports: ''use.*::npc::'' across server/src/. Anything outside server/src/npc/ that imports these is a dependency that must be removed or refactored first.
|
||
- Check bridge/protocol types — does the client receive any npc-related messages? If so, those protocol types need to be dropped from protocol.ron too.
|
||
|
||
Phase 2 — Remove Rust code
|
||
- Delete server/src/npc/ (14 files, ~11k LOC: awareness, background, blueprint, disclosure, generate, interaction, mod, mood, relationships, routine, tell_state, tolerance, trait_modifiers, vision).
|
||
- Delete server/src/bin/generator_spike.rs (standalone binary).
|
||
- Delete server/src/bin/validate_ron.rs IF its only consumers are in npc/ (it validates zone-type/culture/zone RONs which only exist for the npc system).
|
||
- Remove ''pub mod npc;'' from server/src/lib.rs.
|
||
- Remove NpcPlugin registration from server/src/main.rs (currently 2 sites: main.rs:153 production, main.rs:376 dump_schedule_graph).
|
||
- Remove NpcPlugin registration and npc imports from server/src/test_world/mod.rs (currently uses Npc, InteractionMemory, MoodState in Gauntlet test fixtures). Prune any Gauntlet tests that only exercise npc state; keep the room geometry and walkability tests untouched.
|
||
- Run cargo check --all-targets; cargo test. Expect a clean compile. Any remaining references surface here.
|
||
|
||
Phase 3 — Remove stale content (AFTER Phase 2 is green)
|
||
- Delete server/content/global/ in full. Currently contains: culture-*.ron (osse, vael, van-maanens-star), van-maanens-star-*-zone.ron, trait-modifiers.ron, zone-identity-spec.example.ron, enums/ (moods, activities, patterns, triggers, topics, trust-tiers), factions/, knowledge/, zone-types/, contraband/, technology/.
|
||
- Delete tooling/validate-ron IF it exists as a separate script (CLI wrapper around validate_ron.rs).
|
||
- Verify no tooling/ scripts reference content/global/ paths.
|
||
|
||
Phase 4 — Retire docs
|
||
- Mark docs/design/content-directory-structure.md as superseded, OR delete it and cite this ticket in the commit. The doc references D-024 (10-axis NPC model), D-027, D-028 (dialogue architecture), D-032 (monologue partition), D-034 (THE FRIEND), D-035 (tag taxonomy), D-036 (Sova Transit setting), D-049 (YAML format), D-057 — check whether those decisions should be marked as superseded too, or whether they apply to the eventual rebuild.
|
||
- Remove docs/backups/settledreach.db.backup entries of these tickets at release time (normal sprint lifecycle handles this).
|
||
|
||
Phase 5 — Commit and PR
|
||
- Separate commits per phase for reviewability: ''refactor(simulation): retire v0.1 NPC module code'', ''chore(content): remove stale content/global/'', ''docs: retire v0.1 content-directory-structure design''.
|
||
- Run make pre-pr-server to catch anything missed.
|
||
|
||
ACCEPTANCE
|
||
- Server compiles and passes all non-npc tests with npc module removed.
|
||
- Gauntlet Phase 4 walkability tests still pass.
|
||
- No dead references to ''npc'' or ''content/global'' anywhere in server/, tooling/, or docs/.
|
||
- Client is unaffected (npc data was server-internal; bridge protocol had no npc messages OR they have been removed in Phase 1).
|
||
|
||
NOTE: This is a substantial removal (~11k LOC + a design doc + a binary). It is not urgent — the stale plumbing compiles cleanly today and costs no runtime. Schedule when the team has bandwidth and there is no in-flight work touching server/src/npc/ or content/global/. Do not start Phase 2 without completing the Phase 1 audit.', 'done', 'low', NULL, 'server', NULL, '2026-04-15 08:37:04', '2026-04-19 16:53:42', NULL, '3bce12f6d8ebc110817c37352cc0be63', 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 ('06FB0TNSRWB6XNA9FCAXE370D4', 'task', NULL, 'Show client and server version on loading screen', 'Display the current client version (from project.yaml) and server version on the loading/main menu screen. Use git describe or the project.yaml version field — no plugin needed. Inspired by Godot Git Describe (https://godotengine.org/asset-library/asset/3290) but we roll our own. Show both client and server versions so mismatches are immediately visible during development.', 'done', 'low', NULL, 'client', NULL, '2026-03-23 17:28:12', '2026-04-19 16:53:42', NULL, 'acbac599f0a21235ed091cb39fd91c79', 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 ('06FB0TNSRWBJ1XC9V5ZQHSXAXG', 'bug', NULL, 'Rewrite P2-U01 monologue_display_visible_hidden test against current _visible array API', 'test_monologue_display_visible_hidden in test_client_p2.gd accessed mono.is_visible (a custom bool property). MonologueDisplay was refactored to use _visible: Array[Dictionary] instead. Test skipped (skip_test_) pending rewrite. New test should check _visible.size() > 0 after show_monologue, and == 0 when idle.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-20 11:17:20', '2026-04-20 11:17:20', NULL, 'bb1c0cd98fe9a17c1dd4327a2e964e79', 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 ('06FB0TNSRWH4N5VEB4J86GVPNG', 'story', NULL, 'Drop PROTOCOL_VERSION lockstep handshake (D-192)', 'Implement D-192: remove the snapshot envelope ''version'' field, the PROTOCOL_VERSION constants on server (server/src/bridge/types.rs) and client (client/scripts/protocol/protocol.gd), and the version-mismatch guard in Protocol.decode_snapshot(). Update server snapshot encode + client decode + any fixture-replay paths that read ''version''. Keep field-presence and roundtrip behavioral tests; delete only assertions that re-check the version literal. Cross-team: server + client coordination (one PR each, lockstep merge). Sprint 36 already deleted the two test_protocol_version_is_NN tautological assertions as part of the triage that surfaced this.', 'cancelled', 'medium', NULL, NULL, 'D-192', '2026-04-21 07:27:47', '2026-04-21 07:27:47', NULL, '796053afbe90386d288ed620ea687e87', 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 ('06FB0TNSRW2GTJPBSKP1W3T79W', 'story', '06FB0TNSRXE0VWDHVQTXPVPEW0', 'Location picker in character creation UI (client)', 'Client implementation: location/bookmark picker in the character creation screen. Player selects which starting location their bookmark places them in. Location selection triggers culture resolution server-side (#679). Visual representation of the location (world map node, location description, cultural context summary). Blocked by #679 (server culture resolution must exist to confirm what culture each location implies). Decision D-128 (culture implicit in location), D-115 (bookmark selection at creation).', 'done', 'high', NULL, 'client', NULL, '2026-03-17 06:47:15', '2026-04-21 13:11:50', NULL, '09b431a7d0c6bb1c9cc70b64475b4de9', 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 ('06FB0TNSRXNY465GW7W3SPPWJM', 'story', '06FB0TNSRXE0VWDHVQTXPVPEW0', 'CK3-style character creation screen', 'UI screen for character creation: skills + bookmark selection. CK3 bookmark style — player selects a pre-defined starting context (tycoon for v0.2), then customises skills within it. Decision D-115 (skills + bookmark only). Q-WTF-039 resolved: tile-scale in-world preview (not portrait render).', 'done', 'high', NULL, 'client', NULL, '2026-03-05 23:12:50', '2026-04-21 13:11:50', NULL, '757ad92b0b14243aa036531b5e9cb03d', 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 ('06FB0TNSRYPF0NA5DVVMWPSS08', 'story', NULL, 'Add decision-to-ticket coverage report', 'Add a decisions-linked report showing which tickets implement each decision. The data already exists: tickets have a decision_ref field. No schema change needed — just a query/report tool.\n\nAcceptance criteria:\n1. make decisions-coverage shows each decision with its implementing ticket(s)\n2. make decisions-orphan shows decisions with no implementing tickets (already exists, verify it works)\n3. tooling/db/decision show D-159 includes linked ticket IDs in output\n\nThe reverse link (decision→tickets) is a SELECT query, not a new column. Avoids the fragile two-way sync problem of maintaining a separate implementing_tickets column alongside decisions-sync.', 'done', 'medium', NULL, 'ci', NULL, '2026-03-22 18:04:17', '2026-04-21 14:48:33', NULL, '1872bca1310916b9b7b677cec05955df', 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 ('06FB0TNSRZGSKN39GSW39JNZDG', 'task', NULL, 'Revive journal panel tests (player_knowledge, UIStrings, state colors)', 'test_journal_sprint18.gd was deleted in Sprint 37 (#870 parse-error cleanup). It contained unique tests for: GameState.player_knowledge snapshot parsing/persistence, journal_panel.tscn scene lifecycle, entry rendering from player_knowledge entities, UIStrings confidence/source keys (D-042), _state_color() for Contradicted/Stale/Active states. No other journal-specific test file exists. Spec: D-041, D-042, #264.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-21 15:01:17', '2026-04-21 15:01:17', NULL, '7b70105abee1072396e82b0c9de09e55', 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 ('06FB0TNSRYDPBFJVAQAN7T56VR', 'task', NULL, 'Revive minimap rendering tests (discovered POIs, circular overlay, insert visibility)', 'test_minimap_sprint18.gd was deleted in Sprint 37 (#870 parse-error cleanup). It contained unique tests for: minimap.tscn scene, POI rendering from GameState.discovered_pois, circular insert overlay visibility, insert_active toggle behavior. No other minimap test file exists. Spec: D-013, D-015, D-049, #151.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-21 15:01:23', '2026-04-21 15:01:23', NULL, '9b823f5bfff65fa2cdc787fb4dd1bb9f', 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 ('06FB0TNSRZ7H6QMDZ502MX45XW', 'task', '06FB0TNSRZ55SFZCFCQ0H8G32M', 'Document the source-canonical rule (.claude/rules/asset-pipeline.md + DEVOPS)', 'Document the asset pipeline discipline so agents and humans share the model. The rules are pointless without discipline, and discipline requires the rules to be written down and cross-referenced from the places agents already read.
|
||
|
||
Deliverables:
|
||
|
||
1. **`.claude/rules/asset-pipeline.md`** — the canonical rules file. Covers:
|
||
- `server/data/systems.db` is a **read-only canonical snapshot**; sources (markers.json, *.toml, generator code) are authoritative.
|
||
- How to make a DB change: edit source, run generator, commit both.
|
||
- Direct DB edits are forbidden except when mirrored back to source (e.g. a one-off atlas_* tweak followed by a markers.json change that reproduces it).
|
||
- The `meta` table stamp and what it means.
|
||
- The pre-push hook and how to install it (`make install-hooks`).
|
||
- Why `/pr-push` regenerates (cross-team collision prevention).
|
||
- Future-facing note: savegame DBs will branch from this snapshot; the stamp is how savegames track lineage.
|
||
|
||
2. **`CLAUDE.md` hook** — one-line reference under a new "### Asset pipeline" subsection, pointing at `.claude/rules/asset-pipeline.md`. Same pattern as existing team-boundaries/git-safety references.
|
||
|
||
3. **`docs/DEVOPS.md`** — short section on the pipeline: the `meta` table, `make install-hooks`, and the regenerate-before-push workflow. This is the entry point for humans (non-Claude contributors).
|
||
|
||
4. **Agent briefing template update** — if the sprint-start skill or per-agent briefing template has a standard "rules" block, add asset-pipeline.md to it so agents read it on spawn.
|
||
|
||
DoD:
|
||
- All four files exist and cross-reference each other.
|
||
- A fresh agent spawned into any team reads `asset-pipeline.md` before touching source files that feed systems.db (verify via prompt review).
|
||
- `docs/DEVOPS.md` explains the hook install in under 30 seconds of reading.', 'done', 'medium', NULL, 'ci', NULL, '2026-04-19 11:09:48', '2026-04-21 15:03:31', NULL, '6a60f11c4c7bf08dcb954f897fd99135', 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 ('06FB0TNSRXCA01S8H5Z9REVNSR', 'task', '06FB0TNSRZ55SFZCFCQ0H8G32M', 'Pre-push git hook for systems.db consistency', 'Pre-push git hook that blocks the push if `server/data/systems.db` is inconsistent with the source files in the tree. Fast (sub-second), non-invasive, and bypass-able only with `--no-verify` (which CLAUDE.md forbids without explicit permission).
|
||
|
||
Behaviour:
|
||
- Hook reads `meta.generator_sha` from `systems.db`.
|
||
- Compares against `git rev-parse HEAD` (the commit being pushed).
|
||
- If equal → pass.
|
||
- If DB stamp is an ancestor of HEAD and none of the source files changed between them → pass (no regen needed).
|
||
- Otherwise → block with a clear message pointing to `make economy-db && make atlas-generate` and a hint that `/pr-push` handles this automatically.
|
||
|
||
Source-file watch list (if ANY of these have changed between stamp SHA and HEAD, the DB is stale):
|
||
- `wiki/star-systems/**/markers.json`
|
||
- `tooling/planet-gen/**.py`
|
||
- `tooling/economy-db/**.py`
|
||
- `server/src/bin/generate_brands/**.rs`
|
||
- `server/src/bin/generate_corporations/**.rs`
|
||
- `db/schema.sql`, `server/data/systems-schema.sql`
|
||
- `content/economics/**.toml` (or wherever brand_templates.toml / currency zones live)
|
||
|
||
Installation:
|
||
- Hook script at `.githooks/pre-push` (tracked in the repo).
|
||
- `make install-hooks` target runs `git config core.hooksPath .githooks`.
|
||
- Document in `docs/DEVOPS.md`: new clones must run `make install-hooks` once.
|
||
- CI is out of scope (CI regenerates from scratch anyway); this hook is purely a local safety net.
|
||
|
||
DoD:
|
||
- Hook blocks when systems.db is stale relative to sources in HEAD.
|
||
- Hook passes on a clean tree (no source changes since stamp).
|
||
- `make install-hooks` wires the hook into a fresh clone.
|
||
- Exits fast (< 1 second) on the clean-pass path.
|
||
- Error message is actionable — names the missing `make` target and mentions `/pr-push` as the "just fix it" path.', 'done', 'high', NULL, 'ci', NULL, '2026-04-19 11:09:47', '2026-04-21 15:04:45', NULL, '82db4b2aa68607981a9f3d5e48681b63', 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 ('06FB0TNSRZJ62CYHKA419D8P0G', 'task', '06FB0TNSRZ55SFZCFCQ0H8G32M', 'Stamp systems.db with generator metadata (meta table)', 'Add a `meta` table to `systems.db` that records the generator context of the current DB state. Every generator writes this stamp on run so downstream consumers (pre-push hook, `/pr-push`, future savegame bootstrap, migrations) can detect mismatch between DB and tree.
|
||
|
||
Schema:
|
||
```sql
|
||
CREATE TABLE IF NOT EXISTS meta (
|
||
key TEXT PRIMARY KEY,
|
||
value TEXT NOT NULL
|
||
);
|
||
-- Required keys:
|
||
-- schema_version INTEGER — bumped by schema migrations
|
||
-- generator_sha TEXT — git HEAD SHA at regen time (or "dirty" if tree is dirty)
|
||
-- generated_at TEXT — ISO8601 UTC
|
||
```
|
||
|
||
Writers (all must stamp on run, last-writer-wins is fine since a full pipeline run touches everything):
|
||
- `tooling/planet-gen/generate_atlas.py`
|
||
- `tooling/planet-gen/gemma_naming.py` (if it commits changes)
|
||
- `tooling/economy-db/import_economics.py`
|
||
- `server/src/bin/generate_brands` (if/when built)
|
||
- `server/src/bin/generate_corporations`
|
||
|
||
Helper: a small `tooling/db/stamp_meta.py` (or Rust crate equivalent) that each generator calls. Should resolve the git SHA from the repo HEAD, detect dirty tree via `git status --porcelain`, and emit "dirty-<shortsha>" when uncommitted changes exist.
|
||
|
||
Schema version bump: initial value = 1. Increments happen in tickets that change atlas_* / brand_* / economy table shape.
|
||
|
||
DoD:
|
||
- `meta` table exists on a fresh regenerated DB.
|
||
- `tooling/db/sqlite-query "SELECT * FROM meta"` returns the three expected keys after `make economy-db && make atlas-generate`.
|
||
- Running a generator on a dirty tree writes a `dirty-<sha>` marker (not a clean SHA).
|
||
- Integration test that runs a generator and asserts the stamp matches `git rev-parse HEAD`.', 'done', 'high', NULL, 'ci', NULL, '2026-04-19 11:09:43', '2026-04-21 15:23:29', NULL, '383594e6d40e062ff17bba247838d29e', 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 ('06FB0TNSRZ55SFZCFCQ0H8G32M', 'story', '06FB0TNSRZP2QA7EYBASHW0BY0', 'systems.db regeneration with versioning awareness', 'Pair session with Jeroen (per CLAUDE.md pair-session protocol — load-bearing Makefile/hook/skill/rule changes).
|
||
|
||
**Scheduling: pulled out of Sprint 36 on 2026-04-20. Targeted for Sprint 37 kickoff — ideally first work of the sprint.**
|
||
|
||
**Parallelism rule:** This story can run in parallel with other Sprint 37 team work ONLY if no other ticket touches systems.db, its generators (generate_atlas.py, generate_brands, import_economics.py), or the source files feeding those generators (markers.json, brands.toml, generated_brands.toml, brand_templates.toml).
|
||
|
||
If any Sprint 37 ticket touches those files, this story BLOCKS that ticket — the stamping/hook/regen infrastructure must land first so the merge discipline is in place before the second systems.db writer lands.
|
||
|
||
At Sprint 37 planning: scan the proposed ticket list, flag any systems.db-touchers, and wire blocked_by relationships from them to #855.
|
||
|
||
---
|
||
|
||
Implement the core pipeline discipline for systems.db: version stamping, pre-push consistency check, pr-push rebase+regen, and documentation.
|
||
|
||
Four tasks, mostly linear — stamping is the foundation, the hook and skill both depend on it, documentation wraps it up.
|
||
|
||
Definition of done:
|
||
- All generators stamp the DB on run.
|
||
- Pre-push hook installed via make install-hooks and wired through core.hooksPath.
|
||
- /pr-push rebases and regenerates before pushing.
|
||
- Rules file exists and is referenced from CLAUDE.md.
|
||
- Verified end-to-end: a simulated two-team PR collision (both branches touch systems.db) now resolves cleanly when the second PR runs /pr-push.', 'done', 'high', NULL, 'ci', NULL, '2026-04-19 11:01:35', '2026-04-21 15:23:29', NULL, 'c007810c443f9cc873732eaa79160718', 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 ('06FB0TNSRZP2QA7EYBASHW0BY0', 'epic', NULL, 'Generator-driven asset pipeline — regeneration discipline and versioning', '`server/data/systems.db` is a checked-in 5.2MB binary game asset produced by several generators (import_economics.py, generate_atlas.py, generate_brands). Today there is no discipline: any developer/agent can hand-edit the DB, and two parallel branches that both commit DB changes produce unmergeable binary conflicts on main.
|
||
|
||
This epic establishes a clear mental model for systems.db:
|
||
|
||
1. **Source-of-truth files** (markers.json, brand_templates.toml, generated_brands.toml, generator code) are canonical.
|
||
2. **`server/data/systems.db` is a read-only canonical snapshot** — the deterministic serialization of the sources at a given generator SHA. Already loaded once at startup (see `server/src/simulation/economy.rs`) and never rewritten by the running server.
|
||
3. **Future savegame DBs are mutable runtime copies** bootstrapped from this canonical snapshot. That infrastructure is not built yet, but this epic establishes the versioning primitives it will need: the canonical DB carries a `meta` stamp so a savegame can record which canonical version it derives from (enabling migration when the canonical bumps).
|
||
|
||
Concrete deliverables:
|
||
|
||
- Every generator stamps the DB with `(schema_version, generator_sha, generated_at)`.
|
||
- A pre-push git hook enforces stamp-matches-tree before push.
|
||
- `/pr-push` regenerates the DB after rebasing on main so the committed DB reflects combined source changes.
|
||
- Direct DB edits are forbidden except when mirrored back to a source file.
|
||
- `.claude/rules/asset-pipeline.md` documents the rule so agents and humans share the model.
|
||
|
||
Driver: Sprint 36 surfaced a collision risk between #849 (copy, atlas hand-refine) and #829 (server, generate_brands) — both write to systems.db on separate branches. Sprint 36 is being mitigated manually by serializing PR merges; this epic prevents the class of problem going forward AND unblocks the future savegame work.
|
||
|
||
Out of scope: actual savegame plumbing (spawn savegame DB from canonical, runtime writes, migration tool). This epic creates the primitives; savegame work picks them up later.', 'done', 'high', NULL, 'ci', NULL, '2026-04-19 11:01:06', '2026-04-21 15:26:35', NULL, '6344deecee910a0a8919dac3d874da42', 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 ('06FB0TNSRXVAZTJZFD6Y7H6VMM', 'task', '06FB0TNSRZ55SFZCFCQ0H8G32M', 'Extend /pr-push with rebase + regen + stage', 'Extend the `/pr-push` skill so that any PR touching source files which feed `systems.db` automatically produces a clean, regenerated DB on top of current main. This is the mechanism that actually prevents cross-team merge conflicts on the binary.
|
||
|
||
New workflow inside `/pr-push` (after the current "commit changes" step, before push):
|
||
|
||
1. **Detect DB-relevant changes.** Diff HEAD against `origin/main` for any file in the source-file watch list (same list as the pre-push hook — keep in sync via a shared script if possible).
|
||
2. **If any, rebase on main.** Fetch + rebase onto `origin/main`. Abort with clear message if rebase has conflicts in source files (user handles manually).
|
||
3. **Regenerate.** Run `make economy-db && make atlas-generate` (or a narrower target if we add one — see future work below).
|
||
4. **Stage the refreshed DB.** `git add server/data/systems.db`.
|
||
5. **Commit.** If the DB actually changed: `chore(db): regenerate systems.db against rebased sources`. If not (regen produced no diff), skip the commit.
|
||
6. **Force-push with lease.** Since rebase rewrote history, `git push --force-with-lease`. Only safe on sprint branches; never on protected branches.
|
||
7. **Proceed with normal `/pr-push` flow** (create/update PR via `tea`).
|
||
|
||
Edge cases to handle explicitly:
|
||
- Rebase conflicts in source files → stop, report which files conflict, ask the user.
|
||
- Regen fails (generator crash) → stop, report stderr, leave the branch in pre-rebase state if possible.
|
||
- Regen succeeds but produces no DB diff → skip the regen commit; source changes alone are the PR.
|
||
- Branch already force-pushed by another actor in the interim → `--force-with-lease` will reject; report clearly.
|
||
|
||
Future work (NOT this ticket):
|
||
- Narrower regen modes (`generate_atlas.py --bodies-touched-since <sha>`) for faster incremental rebuilds.
|
||
- CI gate that re-runs regen and diffs against the committed DB to catch stamp-but-no-regen tampering.
|
||
|
||
DoD:
|
||
- `/pr-push` skill file (`.claude/skills/pr-push/SKILL.md`) updated with the new steps.
|
||
- A dry-run mode (`/pr-push --dry-run`) that shows what regen would do without pushing.
|
||
- Verified end-to-end: on a branch that modifies markers.json, running `/pr-push` produces the expected "regenerated systems.db" commit and pushes cleanly.
|
||
- Verified collision scenario: two branches each change different bodies'' markers.json, merge first, then `/pr-push` on second → clean rebase, clean regen, no binary conflict.', 'done', 'high', NULL, 'ci', NULL, '2026-04-19 11:09:48', '2026-04-21 15:26:35', NULL, '7aa97c65b67bb4d600025a37745b4b4e', 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 ('06FB0TNSRZM815DKRJ0K7Q6SP8', 'task', NULL, 'Strip archetype trace from client (mirror server #878)', 'Server-side archetype trace has been stripped (Sprint 37, #878). Client side still contains archetype-driven code that must be cleaned up to match:
|
||
|
||
**Stay (production):**
|
||
- Character creation UI (bookmark / starting-location selection)
|
||
- Insert screens / implant panels
|
||
|
||
**Strip (Phase 6 detail-coloring, pre-cascade cruft):**
|
||
- `character.txt` session file handling (if any lingers)
|
||
- `lattice_profile` / detective-vs-smuggler monologue color palette branching
|
||
- Any `CharacterArchetype` / `character_archetype` references in protocol decoding or session bootstrap
|
||
- Phase-2 verb relabeling consumers (open→"Move"/"Stash" or "Scan"/"Flag") — server now emits base labels only
|
||
- Opening-monologue character-pool filtering
|
||
|
||
**Context:**
|
||
- Cascade principle (CLAUDE.md): character/NPC detail is Phase 6. Currently-executing ≠ production when the topic sits below the current cascade phase.
|
||
- Server protocol: `StartupMessage` no longer carries `character_archetype` (protocol comment notes the removal).
|
||
- D-032 is now SUPERSEDED (development cascade — no longer D-117, since v0.2 is dropped).
|
||
- D-057 is now PARTIALLY SUPERSEDED (archetype verb relabeling portion deleted; vertical list + Phase 1/2 split retained).
|
||
|
||
**Verification:**
|
||
- `grep -r "character_archetype\|CharacterArchetype\|archetype_verb_label\|DramaModule\|smuggling_ring_v0_1" client/` → zero hits (outside tests stripping these)
|
||
- Client boots against a server that doesn''t send `character_archetype` in StartupMessage (serde default handling on client StartupMessage struct, or remove the field).
|
||
|
||
---
|
||
CANCELLED 2026-04-21: duplicate of #882 (team lead pre-filed the canonical client follow-up ticket with a more detailed strip list). Use #882 instead.', 'cancelled', 'low', NULL, 'client', NULL, '2026-04-21 15:27:02', '2026-04-21 20:10:38', NULL, 'ef384b6c72ca4f380f68d2e805629065', 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 ('06FB0TNSRYFMSGP36JD4PA281M', 'task', NULL, 'refactor(server): remove HeritageRoot type alias and ZonePaletteModifier::Heritage variant (D-167)', 'D-167 (2026-03-24) retired the 7 abstract heritage roots in favor of corridors. Code still defines pub type HeritageRoot = String; stub and ZonePaletteModifier::Heritage(HeritageRoot) variant at server/src/simulation/generator.rs:76,369. Exact D-192 pattern (decision without follow-through). Delete type alias, drop enum variant, remove Heritage modifier construction sites. Decision ref: D-167.', 'done', 'medium', NULL, 'server', NULL, '2026-04-21 13:47:52', '2026-04-21 20:25:00', NULL, '536f7aa6f985758b9a62a60c864418c6', 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 ('06FB0TNSRXRQHFJ7RWDFT8EXWM', 'task', NULL, 'Wire SelectedBookmark into SaveState (Sprint 37 scope)', 'Per PR #132 review (Sprint 36, comment #4): SelectedBookmark deliberately omits Serialize/Deserialize in v0.2; save/load wiring is deferred to Sprint 37.
|
||
|
||
Scope:
|
||
- Add Serialize, Deserialize derives to SelectedBookmark in server/src/bookmark/mod.rs
|
||
- Register SelectedBookmark as a serializable resource in server/src/simulation/save_state.rs
|
||
- Round-trip test: save with bookmark selected → load → SelectedBookmark survives
|
||
- Update bookmark spec §4.4 (docs/architecture/sprint-36-bookmark-spec.md) — remove the v0.2-deferred scope note
|
||
|
||
Replaces the inline TODO at server/src/bookmark/mod.rs:95-99.
|
||
|
||
Driven by Tyre''s spec amendment 2026-04-19. Reviewer accepted as follow-up.', 'done', 'medium', NULL, 'server', NULL, '2026-04-19 15:43:03', '2026-04-21 20:25:00', NULL, '78a3183d27ae8ffe2abe034ae43b1958', 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 ('06FB0TNSRXH2HAW6N7NKGTXW9W', 'task', NULL, 'Determinism smoke test for generate_atlas.py', 'Per PR #129 review polish #18 (Hoshe): add a tests/smoke test that runs generate_atlas.py --body <small-body> --force --seed 42 twice and diffs the resulting markers.json byte-for-byte. Fails if output differs. Purpose: cheap guardrail against determinism regressions in terrain analysis, city placement, infrastructure MST, and A*. Estimated ~60 lines of bash or pytest. Consistent with the project pattern of leaving Python tooling untested except for high-risk surfaces.', 'done', 'low', NULL, 'server', NULL, '2026-04-15 07:24:34', '2026-04-21 20:25:00', NULL, '907c357dfa2076d732f35721e67a1ea6', 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 ('06FB0TNSRYQ2C58JA575CFPYB0', 'task', NULL, 'Refactor BookmarkPlugin to accept injected registry', 'Per PR #132 review (Sprint 36, comment #12): BookmarkPlugin::build calls register_default_bookmarks(&mut registry) unconditionally — no hook to substitute a test registry. Spec §5 anticipates promotion to TOML, where the loading code will need to be factored out of Plugin::build anyway.
|
||
|
||
Proposed: BookmarkPlugin::new(registry) injection. Default constructor still wires the canonical tycoon registry; the injection variant is for tests and future TOML loading.
|
||
|
||
File: server/src/bookmark/mod.rs:107-118
|
||
Reviewer accepted as follow-up.', 'done', 'low', NULL, 'server', NULL, '2026-04-19 15:41:15', '2026-04-21 20:25:00', NULL, 'a3664a97fc9abf5d7ab484ff03831337', 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 ('06FB0TNSRW0YKYC5CXFV4NKS68', 'task', NULL, 'Drop PROTOCOL_VERSION on server (D-192)', 'Server side of D-192 implementation. Remove: the ''version'' field from the snapshot envelope struct in server/src/bridge/types.rs, the PROTOCOL_VERSION constant, and the version stamp in the snapshot encode path. Keep all field-presence and roundtrip behavioral tests — only delete the tautological version-literal assertions (already done in sprint 36). Coordinate with client ticket #868-client: both PRs must land in lockstep (server PR first, then client). After this lands, client decode will get a MessagePack missing-field error on any genuine schema drift — that is the intended signal. Refs: D-192, D-005.', 'done', 'medium', NULL, 'server', 'D-192', '2026-04-21 13:38:25', '2026-04-21 20:25:00', NULL, 'a394c862a5bb60fcf3f46b44e8f19044', 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 ('06FB0TNSRWVFCVWD3S8B79B9MM', 'task', NULL, 'refactor(server+content): audit and purge dead smuggler/detective character enum (D-032 obsolete)', 'D-032 explicitly says ''[Obsolete post-D-117: smuggler/detective eliminated. v0.2 uses culture-driven voice per D-121; this enum is unused.]'' but code still references it in server/src/bridge/types.rs, server/src/perception/observer/mod.rs, server/tests/archetype_monologue.rs, and content schemas. Audit scope first — some usages may be load-bearing, not all are dead. Then remove the dead surface. Decision ref: D-032.', 'done', 'medium', NULL, 'server', NULL, '2026-04-21 13:47:54', '2026-04-21 20:25:00', NULL, 'a8c807cdb23e32499fb4aece1ace7609', 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 ('06FB0TNSRWJEQN15RS4Q6ZMANR', 'bug', NULL, 'fix(simulation): storyteller activation_pass log should be DEBUG not WARN', 'Storyteller logs ''activation_pass: no Simmering triangles — holding'' as WARN every few seconds. This is normal state during early gameplay when no NPC relationships have escalated. Should be DEBUG or TRACE — WARN implies something is wrong.', 'done', 'low', NULL, 'server', NULL, '2026-04-05 09:39:49', '2026-04-21 20:25:00', NULL, 'b7203c1a675f1d9d204091558a82010a', 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 ('06FB0TNSRZNY30THM4WVAH2RDC', 'task', NULL, 'Resolve 21 raw-commodity / system coverage gate gaps in tier1 corps', 'Discovered during Sprint 36 #828 brand corps authoring (Mellanie).
|
||
|
||
`make economy-db` Phase 2 coverage gate fails on 21 raw-commodity/system coverage gaps in existing tier1 corp tags (pre-existing issue, not in the new brand layer).
|
||
|
||
Brand layer V-B01..V-B06 validation passes cleanly with 124 brand corps. The failure is upstream in the tier1 corp configuration — specific commodities or systems have no supplier corp tagged, causing the Phase 2 coverage gate to reject.
|
||
|
||
Deliverable:
|
||
- Identify the 21 specific gaps (commodity_id or system_id missing supplier tag).
|
||
- Either backfill tier1 corp tags, or relax the coverage gate if any of the gaps are intentional (e.g. commodity deliberately imported from outside the Reach).
|
||
- `make economy-db` must pass end-to-end before Phase 2 demand simulation can run in anger.
|
||
|
||
Not blocking Sprint 36 merge — brand layer itself is clean.', 'done', 'medium', NULL, 'server', NULL, '2026-04-19 12:23:55', '2026-04-21 20:25:00', NULL, 'e1d278f39b2e3864a59e3675f6f49e6e', 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 ('06FB0TNSRYTK723NJY1F5F8NWW', 'task', '06FB0TNSRZBV3S6HV2AF16H24W', 'Generator-patch follow-up: cross-system dedup, empty mountains, suffix monotony, compass-name defaults', 'Discovered during Sprint 36 #838 atlas systems pass (docs/design/atlas-generator-refinement-notes.md). Scale too large for hand-editing — needs generator fixes.
|
||
|
||
Systematic issues to patch in tooling/planet-gen/generate_atlas.py + gemma_naming.py:
|
||
|
||
1. Cross-body city name dedup (severe): ''Jade Harbor'' on 20 bodies, ''Fort Iron'' on 10 — 49 total cross-body city name collisions. Dedup currently only runs per-body. Needs cross-system + cross-corridor uniqueness pass.
|
||
2. Cross-body mountain name dedup (severe): 186 bodies with empty mountain names + ''Riverbend'' range on 39 bodies. Same root cause as #1.
|
||
3. Suffix monotony: -rant clustering (Afrikaans palette), -berg clustering (west_reach/Germanic). Needs post-gen suffix distribution check.
|
||
4. Compass-direction feature default: generator falls back to ''Eastern X / Western Y'' too often. Add negative few-shot example or forbid the pattern.
|
||
5. Zero cultural crossmix on founding-culture/corridor mismatches: gttr_hook carries the data (3 centuries of Kumasi influence on Vuurkloof) but the pipeline doesn''t feed it into the naming prompt. Thread corridor + cultural-history into the few-shot context.
|
||
6. River ''Flow/Current'' vocabulary bleeding from navigational terms (Circumflex/Contraflow on Estrade). Blocklist navigational terms in river few-shot.
|
||
|
||
Not in scope for Sprint 36 (hand-refine sprint). Refinement notes file is the primary artifact.
|
||
|
||
Verification after patch: re-run the analysis script Paula is building for #849 and confirm collision counts drop.
|
||
|
||
--- Additional finding from Sprint 36 #838 infrastructure spot-check ---
|
||
|
||
7. Unnamed infrastructure at generator output: 37/46 roads (80%) and 37/44 railroads (~84%) had empty names. Systematic pipeline gap. Gestalt named all existing instances using city-pair convention, but generator needs to emit named infrastructure going forward. Naming convention to adopt: "<City-A>-<City-B>" for direct links, or cultural-toponym when the connection is a named route (e.g. GJ66Bc Gruve Express — intentional mine rail, left as-is).', 'done', 'medium', NULL, 'server', NULL, '2026-04-19 10:05:54', '2026-04-22 06:20:50', NULL, '51927c9c472c319df90dc9fbc29cb032', 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 ('06FB0TNSRYHFKSTSPCQG2SXQ7W', 'bug', NULL, 'dialogue_box _escape_bbcode chained replace corrupts [lb] escapes', 'dialogue_box.gd:628 _escape_bbcode chains .replace(''['', ''[lb]'').replace('']'', ''[rb]''). The second replace turns ''[lb]'' into ''[lb[rb]'', corrupting the escape. Output does not contain ''[lb]'' and still begins with ''[''. BBCode injection guard is effectively broken for server-sourced text. Fix: escape only ''['' (not '']''), since unmatched ] in RichTextLabel renders as literal. Test: test_escape_bbcode_brackets_in_server_text in test_dialogue_sprint18.gd (currently skipped).', 'done', 'high', NULL, 'client', NULL, '2026-04-20 16:09:45', '2026-04-22 06:23:00', NULL, 'e0a3e5da73493afc969320ea9a5e9603', 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 ('06FB0TNSRWNJ8F8BJY11FFGYPM', 'bug', NULL, 'Fix MetaScreen test helper regression — anti_tedium suite (7 fails)', 'Sprint 36 Workstream 2 migrated bug_report_dialog.gd from ''extends Control'' to ''extends MetaScreen''. test_anti_tedium.gd:94 builds the dialog via ''Control.new() + set_script(BugReportDialogScript)'', which no longer satisfies the MetaScreen base contract — every call to dialog.start_capture() fails with ''Nonexistent function in base Control''. 7 failing tests: test_bug_report_sends_pause_on_open, test_bug_report_sends_unpause_on_close, test_bug_report_not_double_activatable, test_bug_report_render_text_contains_tick_and_entities, test_bug_report_render_text_with_monologue_and_dialogue, test_bug_report_render_text_empty_snapshot, test_gauntlet_snapshot_roundtrip_via_apply. Fix: instantiate the .tscn (preserves the MetaScreen runtime stack) instead of building from script, OR have the test instantiate a MetaScreen-rooted node. Related to ticket #618/#680 MetaScreen pattern work.', 'done', 'high', NULL, 'client', NULL, '2026-04-21 07:29:23', '2026-04-22 06:23:03', NULL, '6d7478c5e46535088ce4122b1b1dc808', 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 ('06FB0TNSRYD1EHH9MNJAZJMMQ4', 'bug', NULL, 'Delete or revive 8 parse-error test files', 'These 8 test files fail to PARSE (not just fail tests) and contribute to the gdunit error count without exercising anything: test_debug_overlay_sprint19.gd, test_entanglement_sprint22.gd, test_fog_sprint22.gd, test_journal_sprint18.gd, test_minimap_sprint18.gd, test_session_manager_sprint19.gd, test_sprint30.gd, test_sprite_integration.gd. They reference removed/renamed APIs from previous sprints. Each is 5-25KB. Decision needed per file: rewrite against current API, or delete. Default: delete and file a fresh ticket if/when the underlying coverage is needed again. Surfaced during sprint-36 client triage.', 'done', 'medium', NULL, 'client', NULL, '2026-04-21 07:29:28', '2026-04-22 06:23:08', NULL, '3cea8b18d71f21c2c5817bc51a547e56', 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 ('06FB0TNSRXYR06AERJXEBX3ER0', 'bug', NULL, 'New Game flow hangs on ''connecting'' after sprint-36 Option A handoff', 'Manual repro during sprint-36 PR #134 smoke test: make game → main menu → New Game → loading screen shows ''connecting'' and never progresses. Reporter did not capture a console trace; Jeroen to supplement if recoverable.
|
||
|
||
Likely suspects (sprint-36 changes):
|
||
|
||
1. client/ui/meta/screens/main_menu/main_menu.gd — _process() polls SimBridge.poll_snapshot() while _waiting_for_catalog is true. If bookmark_catalog never arrives (or arrives but the flag isn''t cleared), the loop runs forever with the loading screen visible. Investigate whether GameState.bookmark_catalog is set by apply_snapshot and whether main_menu is observing that state or waiting on a different signal.
|
||
|
||
2. client/ui/meta/screens/loading/loading_screen.gd — BG is now opaque (Color(0.05,0.05,0.08,1.0)) and mouse_filter = MOUSE_FILTER_STOP. If the loading state is never dismissed, it looks identical to ''hung connecting'' since nothing underneath is visible or clickable. This is a UX/observability concern even if the root cause is elsewhere.
|
||
|
||
3. client/scripts/protocol/protocol.gd — bookmark_catalog decode landed in v23 (commit 41e89579). Verify the server is actually sending bookmark_catalog in the first snapshot after connect, and that Protocol.decode_snapshot is populating it.
|
||
|
||
4. Option A scene transition flow — main_menu initiates connect and waits for catalog; eventually scene changes to character_creation.tscn which reads from GameState. Confirm the handoff path (main_menu → character_creation) triggers on the right signal, not a polled flag that might race.
|
||
|
||
Repro context: sprint-36/client branch at HEAD (commit 53fbce08). Blocking the final test-plan checkbox on PR #134. Not blocking merge per reviewer (Jeroen) — deferred to sprint 37 pickup.
|
||
|
||
Suggested investigation order: add trace prints in main_menu._process to confirm SimBridge.state and GameState.bookmark_catalog contents during the hang; that will disambiguate 1 vs 3 in minutes.', 'done', 'high', NULL, 'client', NULL, '2026-04-21 10:29:32', '2026-04-22 06:23:10', NULL, '30b4f32c38b4e716217bab52f0528876', 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 ('06FB0TNSRW18FSKK90Q3JTM8VR', 'story', NULL, 'Scene-level merge-path UI flow tests (gdUnit4)', 'Add gdUnit4 scene-level tests for merge-path UI flows so regressions like #872 (New Game hangs on ''connecting'') are caught pre-merge instead of post-merge.
|
||
|
||
Problem: PR #134 shipped with the New Game flow broken because the author-side manual smoke box was unchecked. The bug surfaced as #872 only after merge. We have scene-level test infrastructure (gdUnit4, test_character_creation_sprint28.gd pattern) but it doesn''t cover the merge-path flows.
|
||
|
||
Scope:
|
||
- One scene-level test per merge-path flow: main menu → new game → character creation → confirm → connected state; main menu → load game → save picker → selected; character creation → submit → sim_bridge receives correct payload; bookmark tab → select location → confirm → server gets bookmark action.
|
||
- Tests must run headless via tests/run-godot (no display required).
|
||
- Pattern: load scene → simulate input via _input() or button.pressed.emit() → await signals or poll state with timeout → assert terminal state (e.g. SimBridge.state == CONNECTED after T=5s).
|
||
- Deliberately NOT pixel/screenshot diffing — that''s a separate ticket if desired.
|
||
- Coordinate with pr-review SKILL.md merge-path gate added in sprint 36 retro — these tests are the mechanism the gate assumes exists.
|
||
|
||
Reference: #872 is the concrete motivating bug. The test that would have caught it: load main menu → simulate New Game click → await sim_bridge.connected signal with 5s timeout → assert emitted.
|
||
|
||
Not in scope:
|
||
- RPA / xdotool / pyautogui (brittle, needs display, low leverage).
|
||
- Screenshot regression testing (worth a separate ticket).
|
||
- CI integration (existing tests/run-godot already runs in CI via make test-client).', 'done', 'high', NULL, 'client', NULL, '2026-04-21 13:36:18', '2026-04-22 06:23:13', NULL, 'd45ffa9eef6aeee18272bb3e05e323ae', 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 ('06FB0TNSRY1TYR56TNC2C8NTPW', 'task', NULL, 'Drop PROTOCOL_VERSION on client (D-192)', 'Client side of D-192 implementation. Remove: the ''version'' field read in client/scripts/protocol/protocol.gd (Protocol.decode_snapshot), the PROTOCOL_VERSION constant, and the version-mismatch guard. Update any fixture-replay paths that read ''version''. Keep all field-presence and roundtrip behavioral tests. Blocked by server ticket #874 — merge server PR first, then this. After merge, genuine schema mismatches surface as MessagePack decode/missing-field errors downstream. Refs: D-192, D-005.', 'done', 'medium', NULL, 'client', 'D-192', '2026-04-21 13:38:32', '2026-04-22 06:23:19', NULL, '423de9eeeaf674d820d1e16f99117360', 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 ('06FB0TNSRWYRBKFQ1W3S8DS21W', 'task', NULL, 'Revive EntityRenderer sprite constants coverage (D-044 ENTITY_WIDTH/HEIGHT)', 'test_sprite_integration.gd was deleted in Sprint 37 (#870 parse-error cleanup). It was the sole asserter of D-044 sprite dimensions: EntityRenderer.ENTITY_WIDTH == 24 and ENTITY_HEIGHT == 32 (client/scripts/rendering/entity_renderer.gd:19-20). These values are load-bearing for tile-anchored y-sort (ENTITY_OFFSET_Y = TILE_SIZE - ENTITY_HEIGHT, line 22, D-019 tilt). Revive a focused test that asserts both constants and the derived offset — rewrite against current EntityRenderer API. Surfaced in PR #135 review (Tyre T2). Spec: D-044, D-019, D-049.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-22 07:56:26', '2026-04-22 07:56:26', NULL, 'c4df23b8d24c37a7c3baf45e25341a4b', 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 ('06FB0TNSRY05Z5JJRN1ND5ZFGC', 'story', NULL, 'UI timeout fallback for bookmark catalog wait (main_menu)', 'main_menu.gd:72-74 _process loop polls SimBridge.poll_snapshot while _waiting_for_catalog is true. If the server never delivers bookmark_catalog (crash, new-server bug, decode dropout), the loading screen hangs forever. #872 patched the specific TCP-batch race where catalog was overwritten in receive_bytes, but the systemic class — ''catalog never arrives'' — remains.
|
||
|
||
Add a ~10s timer on _waiting_for_catalog = true. On expiry: show ''Server did not respond. Try again.'', re-enable the menu buttons, allow the user to retry or quit. Surfaced in PR #135 review (Tyre T4).
|
||
|
||
Spec: #872 (TCP-batch race fix), #258 (main menu flow).', 'backlog', 'low', NULL, 'client', NULL, '2026-04-22 07:56:41', '2026-04-22 07:56:41', NULL, '564973cb1b5a377938e20f687677b7d4', 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 ('06FB0TNSRXT5QXNT1QST51NKZR', 'story', NULL, 'Scene-flow test tier: doc + encapsulated reset helpers', 'Scene-level UI flow tests landed as a 4th tier beyond the 3 in CLAUDE.md (live Gauntlet / MessagePack replay / TestHarness mock). test_merge_path_flows_sprint37.gd is the first concrete example. Two rough edges surfaced in PR #135 review (Tyre T5, T6):
|
||
|
||
1. **Doc the tier model.** Update CLAUDE.md test tiers section to name this tier explicitly — ''scene-flow tests: load .tscn headless, simulate input via signal emit, assert terminal state''. Include when to reach for it vs MessagePack replay vs mock.
|
||
|
||
2. **Test-only reset helpers.** before_test() in test_merge_path_flows_sprint37.gd reaches into SimBridge._last_snapshot, SimBridge._outbound_buffer, MetaStack._stack. Same reach-in pattern appeared in test_anti_tedium.gd before_test (PR #135 commit bc310a3c added MetaStack._stack.clear). Expose:
|
||
- SimBridge.reset_for_test() — clears _last_snapshot, _outbound_buffer, disconnects; test-only, guarded by test_mode.
|
||
- MetaStack.reset_for_test() — clears _stack.
|
||
Replace per-test reach-ins with these helpers.
|
||
|
||
3. **Minimal public API for scene state.** Current flow tests couple to private fields (_waiting_for_catalog, _selected_bookmark_id, _loading_screen, _new_game_btn). UI refactor renames will break all 4 tests simultaneously. Consider: is_waiting_for_catalog(), has_selected_bookmark(), pressed_new_game() signal — a minimal public surface that test-and-refactor can share.
|
||
|
||
Not blocking PR #135 but the coupling will bite the next UI refactor.
|
||
|
||
Spec: #873 (merge-path tests), D-020 (IPC architecture — test harness layer).', 'backlog', 'low', NULL, 'client', NULL, '2026-04-22 07:57:10', '2026-04-22 07:57:10', NULL, 'a1d283d3b839c4456576e3371c317930', 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 ('06FB0TNSRZBH1C2R0DXM00C66R', 'task', NULL, 'D-027 criterion 4: Layer 2/3 E2E test for RoutineDeviation tell after triangle activation', 'v01_integration_playthrough.rs was deleted in #878 as archetype-dependent. Its only non-archetype coverage — D-027 criterion 4 (RoutineDeviation tell after triangle activation) — was already #[ignore]-blocked on #589 (escalate_tells_on_activation). Layer 1 tell priority is covered by tell_escalation.rs. This ticket tracks the missing Layer 2 ECS-world test: activation event → RoutineDeviation insertion, and (optionally) a Layer 3 subprocess proof once #589 lands. Non-blocking for sprint 37 merge.', 'backlog', 'low', NULL, 'server', NULL, '2026-04-22 08:06:52', '2026-04-22 08:06:52', NULL, '981da7ec4c509958a0fa940ec496fa73', 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 ('06FB0TNSRYYB37EVE7CGWCEGWG', 'task', NULL, 'Expand check-systems-db-stamp GENERATOR_SOURCES to cover naming pipeline helpers', '**Filed from PR #137 Tyre review (2026-04-22).**
|
||
|
||
tooling/check-systems-db-stamp currently stamps only tooling/planet-gen/generate_atlas.py as an atlas generator source. But generate_atlas.py imports gemma_naming.py and naming_core.py at runtime — changes to those helpers can silently alter atlas output without tripping the stamp, breaking the pre-push guarantee that systems.db matches its sources.
|
||
|
||
**Fix options:**
|
||
1. Expand GENERATOR_SOURCES in tooling/check-systems-db-stamp to explicitly include gemma_naming.py and naming_core.py.
|
||
2. (Better) Compute the SHA transitively via an import manifest — parse generate_atlas.py''s imports and hash every local module it pulls in.
|
||
|
||
**Scope:** small — 20-40 lines in check-systems-db-stamp + potentially a manifest file.
|
||
|
||
**Context:** Sprint 37 PR #137 landed ~170 lines of changes to gemma_naming.py and naming_core.py as part of #853 (atlas naming polish). systems.db was regenerated, so the stamp stays coherent this sprint, but the loophole remains.
|
||
|
||
---
|
||
|
||
**CANCELLED 2026-04-22 (duplicate of #892).** Tyre filed #892 earlier with the same scope while working task #18; team lead filed this ticket concurrently not realizing the duplicate. Canonical ticket: #892.', 'cancelled', 'low', NULL, 'server', NULL, '2026-04-22 08:08:11', '2026-04-22 08:08:11', NULL, '43da66445c91e0f668324c18c3fb6fb7', 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 ('06FB0TNSRY041CT8EBHHRJNZWM', 'task', NULL, 'Add cross-team carveout to CLAUDE.md: server may write wiki/ when closing coverage gates', '**Filed from PR #137 Tyre/Hoshe review (2026-04-22).**
|
||
|
||
Sprint 37 PR #137 modified 21 wiki/corporations/*.md files as server-team work closing the D-175 Phase 2 coverage gate (#860). Per CLAUDE.md''s cross-team scope rule, wiki/ is copy-team territory — the rule as written forbids this write pattern. Writes were accepted pragmatically by lead for this sprint (maintenance sweep); copy review filed as post-merge follow-up #884.
|
||
|
||
**Problem:** The rule has no carveout for this case. Future sprints will either (a) ask for permission each time (friction), (b) silently normalize cross-team writes without review (quality risk), or (c) block on copy-team authoring capacity before server can close a data gate (coordination cost).
|
||
|
||
**Task:** Add either a one-line carveout to CLAUDE.md OR a D-record documenting the policy. Two options:
|
||
|
||
- **Carveout:** ''Server team may write wiki/ to close data-coverage gates; a copy-team review ticket MUST be filed before merge.''
|
||
- **Pre-merge review:** Change #884-style follow-ups to pre-merge gates — server can''t merge until copy has reviewed.
|
||
|
||
**Decision needed:** which option, or a third. Belongs to a planning sprint, not a team sprint.
|
||
|
||
---
|
||
|
||
**CANCELLED 2026-04-22 (duplicate of #893).** Tyre filed #893 earlier with the same scope while working task #19; team lead filed this ticket concurrently not realizing the duplicate. Canonical ticket: #893.', 'cancelled', 'low', NULL, 'planning', NULL, '2026-04-22 08:08:12', '2026-04-22 08:08:12', NULL, '1f29abe9ae642bc94bdf3557a9d4506b', 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 ('06FB0TNSRW0ATAJK4PMR6AF6G8', 'task', NULL, 'decide(content): Commission formal name — canonical long-form designation (Q-095)', 'One-conversation resolution. Drift between ''Concord Commission'' / ''Lattice Commission'' blocks institutional POI signage and tractus fee legal text. Jeroen picks the long-form name; Mellanie/Paula codify everywhere. Decision ref: Q-095.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-21 13:47:51', '2026-04-22 08:30:07', NULL, '6f609ea537e2e8158442135f4726fc44', 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 ('06FB0TNSRY89AAPK3YK4JDJW7R', 'task', '06FB0TNSRXPYZED88G4JZCMF54', 'Author 112 brand corp wiki stubs to three-layer narrative depth', 'Sprint 36 PR #133 review (Paula + Miri) flagged that the 112 new corp wiki pages in wiki/corporations/ (created during #828) are 24-line frontmatter-only placeholders ("X is a Y operating out of Z. Details to be expanded."). The canonical stubs Calloway/Thrds/VGV/Thalassa run 95-125 lines with the three-layer content standard: (1) public identity, (2) actual operation, (3) one concealed fact.
|
||
|
||
Deliverable: every corp wiki page in wiki/corporations/ for the 112 new entries authored to the three-layer minimum. Use the canonical stubs as the reference template.
|
||
|
||
DoD (narrative completion):
|
||
- Each stub ≥95 lines.
|
||
- Each stub has public-identity, actual-operation, and one-concealed-fact sections.
|
||
- Cross-refs populated where prose asserts relationships with other corps.
|
||
- Corridor/founding-system specificity — not generic boilerplate.
|
||
|
||
Coordinate with Paula for narrative review as authoring progresses. Size: likely a full sprint''s worth of work — do NOT try to cram into a review-fix pass. PR #133 ships with the stubs as-is under the reviewer-accepted split protocol.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-19 13:30:11', '2026-04-22 08:30:07', NULL, '844748300d21d82edf0550a95a2ad9cd', 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 ('06FB0TNSRXCSEG6BY5QDMQ8TMR', 'story', NULL, 'Purge remaining v0.1 Sova/Van Maanen''s residue from wiki', 'Vestigial v0.1 vertical-slice content remains scattered across the wiki after the v0.1 scope was dropped (cascade-first, CLAUDE.md). The wiki/index.md, factions/index.md, and factions/the-ring.md were cleaned in a prior pass; this ticket covers the rest.
|
||
|
||
Scope:
|
||
- wiki/star-systems/GJ-35/sova/ — Station Sova + Transit District content still nested inside Vuurkloof (GJ-35). Parent system was renamed but the v0.1 station tree was left in place with tags: [v0.1] and references to ''Van Maanen''s Star''. Decide: delete, or reparent/rewrite as a legitimate Vuurkloof station.
|
||
- Dropped NPC references (Kael Davan, Sera Venn, Devra, Voss, Torek, Renn, Pell, Tav, Lera Sessik, Sabel, Nils Davan, etc.) appear across:
|
||
- wiki/contraband/{lattice-components,medical-grade-replacements,severance-equipment}.md
|
||
- wiki/technology/{span-gates,founder-gates,meridian,severance-tech}.md
|
||
- wiki/corporations/{gate-corporation,mastroianni-vehicle-group,prometheus-labs,ferreira-monteiro,stalownia-kowalski,meridian-risk}.md
|
||
- wiki/factions/{concord-assembly,lattice-commission,guardians-of-autonomy,syndics,the-unbound}.md
|
||
- wiki/glossary.md, wiki/GOVERNANCE.md
|
||
- wiki/authoring/{base-text,cultural-generation,culture,dual-lens,monologue,monologue-voice,tier1-module}-authoring-guide.md, environmental-text-examples.md, npc-patterns/the-mirror.md
|
||
- wiki/_templates/{star-system,station,district,faction,institution,character-exemplar,cultural-group}.md
|
||
- wiki/economics/archetypes/{behavioral,lore}.toml
|
||
- Cross-refs to characters/* pages (directory no longer exists) will 404.
|
||
|
||
Decision points:
|
||
1. Is the Sova/Transit tree worth keeping as a sample station (retag, reparent cleanly to Vuurkloof, drop Van Maanen''s naming), or delete outright?
|
||
2. For example references in authoring guides/templates: keep as illustrative (they demonstrate voice/pattern) or replace with galactic-scope examples?
|
||
3. For decision/lore files that cite Kael/Sera/etc. as canonical: rewrite to generic or delete those sections?
|
||
|
||
Start by running this grep to scope the work:
|
||
grep -rln ''v0\.1\|Sova Transit\|Van Maanen\|Kael Davan\|Sera Venn\|Nils Davan\|the-ring'' wiki/
|
||
|
||
Then confirm the decision points with Jeroen before editing — this is a judgment-heavy cleanup, not a mechanical find/replace.
|
||
|
||
Related context: wiki/index.md rewrite (prior conversation) dropped the v0.1 vertical-slice framing. CLAUDE.md cascade phase 1 is galactic wiki completeness, not a local slice.', 'done', 'medium', NULL, 'copy', NULL, '2026-04-20 11:57:25', '2026-04-22 08:30:07', NULL, 'a9697a3d6b4b0cc04a897a4145cb8612', 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 ('06FB0TNSRW77B3T7GXT6ZASX88', 'task', NULL, 'CLAUDE.md carveout for server wiki writes driven by coverage gates', '**Follow-up to PR #137 / Hoshe review H8.**
|
||
|
||
PR #137 includes 21 file edits under `wiki/` authored by the server team (6 new corp wiki pages + 15 tag updates, shipped under #860 — "Close D-175 Phase 2 coverage gate"). `CLAUDE.md` team-boundaries policy says: *"Stay within your team''s scope. Server team modifies `server/`. Copy team modifies `wiki/`."* The wiki writes were accepted for this sprint as a pragmatic fix (and copy-team follow-up review filed as #884), but Hoshe correctly flagged the precedent concern:
|
||
|
||
> "If cross-scope writes are structurally necessary for coverage gates, process should note this explicitly rather than route as a copy-team follow-up after merge."
|
||
|
||
The server team''s Phase 2 economy coverage gate requires that every referenced commodity / system / corporation has a corresponding wiki page — otherwise the gate fails. That coupling is real and will recur. Routing it as an after-the-fact copy-team review works once; it''s not a stable process.
|
||
|
||
**Scope:**
|
||
|
||
1. Amend `CLAUDE.md` team-boundaries section to note an explicit carveout: when a server-side coverage gate requires wiki writes to close (economy coverage, asset coverage, future gates), the server team may write under `wiki/` provided:
|
||
- The writes are mechanical / gate-driven (page creation to satisfy a lookup, tag updates to satisfy a filter), not voice/lore authoring.
|
||
- A copy-team follow-up ticket is filed in the same PR body for voice/consistency review.
|
||
- The PR body explicitly lists the wiki files touched and the coverage gate that required them.
|
||
2. Decide whether the same carveout applies in reverse (copy team writing to `server/` for a gate closure — probably N/A, but worth calling out to avoid asymmetry surprises later).
|
||
3. Alternative framing to consider: instead of the carveout, extract the coverage-gate-driven file generation into a tooling script under `tooling/` that creates *stub* pages for copy to flesh out. The server team commits the stubs; copy replaces with real content. Evaluate vs. direct-write carveout; the carveout is less infrastructure but the stub pipeline is cleaner process-wise.
|
||
4. Update `.claude/rules/project-structure.md` if needed to match the CLAUDE.md change.
|
||
|
||
**Cross-reference:** PR #137, #860 (D-175 Phase 2 coverage gate), #884 (copy-team voice/lore review of the wiki writes), `CLAUDE.md` "Agent Instructions → Team boundaries" section.
|
||
|
||
**Rationale:** The boundary exists to keep voice/lore authoring in copy-team hands and prevent drift. Coverage gates create legitimate cross-scope writes that aren''t authoring. The boundary should accommodate this or provide an alternative that keeps the boundary clean.', 'backlog', 'low', NULL, 'planning', NULL, '2026-04-22 08:00:12', '2026-04-22 08:35:28', NULL, 'bd669bee9d096a2241f6062522e0ac01', 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 ('06FB0TNSRXFPQ7EVBWXHVNAZPG', 'task', NULL, 'Generation pipeline cascade — map all layers from heightmap to tile, produce D-records', 'Map the full generation cascade from planetary heightmaps down to walkable tile environments. Produce D-records for each layer.
|
||
|
||
Current state:
|
||
- Galactic → system → planetary: done (heightmaps, atlas markers, city placement via generate_atlas.py)
|
||
- server/src/simulation/generator.rs: DistrictSkeleton, BlockSkeleton, ChunkData data model exists but all generation logic is stubs
|
||
- No actual generator produces tiles from city/planet data
|
||
|
||
Cascade layers to map and decide:
|
||
1. Planetary heightmap → regional zones (city footprints, biome regions, terrain features)
|
||
2. Regional zone → district skeleton (DistrictSkeleton: block grid, setting type, zone palette, reservations)
|
||
3. District skeleton → block → chunk (64x64 tile grids, Phase 2 fill)
|
||
4. Chunk → tile (walkable floor, walls, doors, objects)
|
||
|
||
Output required:
|
||
- D-records for each layer''s generation contract (inputs, outputs, algorithm)
|
||
- Identify what exists vs what is stub vs what is missing
|
||
- Produce a ticket dependency chain locking character/apartment work behind generation completion
|
||
- Confirm or amend the Phase 4 / Phase 5 cascade epic scope (tickets #749, #750)
|
||
|
||
Participants: Gestalt (systems), Tyre (technical architecture), Miri (worldbuilding/geography)
|
||
Documenter: Qatux
|
||
SI: creates follow-up tickets after D-records confirmed', 'done', 'high', NULL, 'planning', NULL, '2026-04-24 10:56:41', '2026-04-24 10:57:21', NULL, '55e7ce66f5f93c84bdce08c155086968', 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);
|