diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..788efb114 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +.pql/changelog/*.sql merge=union diff --git a/.pql/changelog/ticket_deps/0000-schema.sql b/.pql/changelog/ticket_deps/0000-schema.sql new file mode 100644 index 000000000..55e0b02b1 --- /dev/null +++ b/.pql/changelog/ticket_deps/0000-schema.sql @@ -0,0 +1,114 @@ +-- Auto-generated by pql init. CREATE TABLE statements +-- for the planning schema; per-table dir keeps the changelog +-- self-describing per D-15. CREATE TABLE IF NOT EXISTS is +-- idempotent so running schema files from each directory in +-- replay order is harmless. +-- +-- Importer parses the markers below to detect schema drift +-- between the producing pql version and the local one — a +-- bumped canonical_version means projection rules changed +-- and replay must refuse rather than silently corrupt state. +-- pql:created_by: 1.6.2 +-- pql:canonical_version: 1 + + +CREATE TABLE IF NOT EXISTS decisions ( + id TEXT PRIMARY KEY, + type TEXT NOT NULL CHECK(type IN ('confirmed','question','rejected')), + domain TEXT NOT NULL, + title TEXT NOT NULL, + status TEXT NOT NULL DEFAULT 'active' + CHECK(status IN ('active','superseded','resolved','open')), + date TEXT, + file_path TEXT NOT NULL, + synced_at TEXT NOT NULL DEFAULT (datetime('now')), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER +); + +CREATE TABLE IF NOT EXISTS decision_refs ( + source_id TEXT NOT NULL REFERENCES decisions(id) ON DELETE CASCADE, + target_id TEXT NOT NULL REFERENCES decisions(id) ON DELETE CASCADE, + ref_type TEXT NOT NULL + CHECK(ref_type IN ('supersedes','references','resolves','depends_on','amends')), + note TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER, + PRIMARY KEY (source_id, target_id, ref_type) +); + +CREATE TABLE IF NOT EXISTS tickets ( + id TEXT PRIMARY KEY, + type TEXT NOT NULL CHECK(type IN ('initiative','epic','story','task','bug')), + parent_id TEXT REFERENCES tickets(id), + title TEXT NOT NULL, + description TEXT, + status TEXT NOT NULL DEFAULT 'backlog' + CHECK(status IN ('backlog','ready','in_progress','review','done','cancelled')), + priority TEXT DEFAULT 'medium' + CHECK(priority IN ('critical','high','medium','low')), + assigned_to TEXT, + team TEXT, + decision_ref TEXT REFERENCES decisions(id), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER +); + +CREATE TABLE IF NOT EXISTS ticket_deps ( + blocker_id TEXT NOT NULL REFERENCES tickets(id), + blocked_id TEXT NOT NULL REFERENCES tickets(id), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER, + PRIMARY KEY (blocker_id, blocked_id) +); + +CREATE TABLE IF NOT EXISTS ticket_history ( + ticket_id TEXT NOT NULL REFERENCES tickets(id), + field TEXT NOT NULL, + old_value TEXT, + new_value TEXT, + changed_by TEXT, + changed_at TEXT NOT NULL DEFAULT (datetime('now')), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT UNIQUE, + canonical_version INTEGER +); + +CREATE TABLE IF NOT EXISTS ticket_labels ( + ticket_id TEXT NOT NULL REFERENCES tickets(id), + label TEXT NOT NULL, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER, + PRIMARY KEY (ticket_id, label) +); + +CREATE TABLE IF NOT EXISTS meta ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL, + updated_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE INDEX IF NOT EXISTS idx_tickets_status ON tickets(status); +CREATE INDEX IF NOT EXISTS idx_tickets_team ON tickets(team); +CREATE INDEX IF NOT EXISTS idx_tickets_decision_ref ON tickets(decision_ref); +CREATE INDEX IF NOT EXISTS idx_tickets_assigned ON tickets(assigned_to); +CREATE INDEX IF NOT EXISTS idx_decisions_domain ON decisions(domain); +CREATE INDEX IF NOT EXISTS idx_decisions_type ON decisions(type); +CREATE INDEX IF NOT EXISTS idx_decision_refs_target ON decision_refs(target_id); diff --git a/.pql/changelog/ticket_deps/2026-06.sql b/.pql/changelog/ticket_deps/2026-06.sql new file mode 100644 index 000000000..9ecf4c655 --- /dev/null +++ b/.pql/changelog/ticket_deps/2026-06.sql @@ -0,0 +1,481 @@ +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-35', 'T-38', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-36', 'T-38', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-37', 'T-38', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-65', 'T-66', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-66', 'T-67', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-67', 'T-68', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-75', 'T-76', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-75', 'T-77', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-76', 'T-78', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-77', 'T-79', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-78', 'T-81', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-79', 'T-81', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-81', 'T-82', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-82', 'T-83', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-39', 'T-40', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-39', 'T-41', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-39', 'T-42', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-86', 'T-92', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-87', 'T-101', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-43', 'T-47', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-110', 'T-111', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-111', 'T-112', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-112', 'T-113', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-39', 'T-54', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-54', 'T-53', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-158', 'T-159', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-55', 'T-59', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-189', 'T-190', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-189', 'T-191', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-189', 'T-192', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-193', 'T-190', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-193', 'T-191', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-193', 'T-192', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-57', 'T-60', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-58', 'T-60', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-59', 'T-60', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-153', 'T-188', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-185', 'T-188', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-186', 'T-188', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-187', 'T-188', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-214', 'T-215', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-214', 'T-216', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-214', 'T-217', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-236', 'T-237', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-237', 'T-238', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-236', 'T-83', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-238', 'T-101', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-25', 'T-88', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-240', 'T-168', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-240', 'T-241', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-240', 'T-242', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-88', 'T-243', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-103', 'T-250', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-105', 'T-250', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-252', 'T-133', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-255', 'T-124', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-255', 'T-125', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-269', 'T-199', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-261', 'T-190', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-261', 'T-191', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-261', 'T-192', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-239', 'T-119', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-259', 'T-260', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-256', 'T-257', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-275', 'T-33', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-275', 'T-57', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-275', 'T-58', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-275', 'T-59', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-275', 'T-60', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-278', 'T-286', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-279', 'T-286', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-280', 'T-286', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-281', 'T-286', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-282', 'T-286', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-283', 'T-286', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-284', 'T-286', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-285', 'T-286', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-287', 'T-296', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-288', 'T-296', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-289', 'T-296', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-290', 'T-296', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-291', 'T-296', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-292', 'T-296', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-293', 'T-296', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-294', 'T-296', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-295', 'T-296', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-278', 'T-279', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-279', 'T-280', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-279', 'T-281', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-280', 'T-282', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-287', 'T-288', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-288', 'T-289', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-289', 'T-290', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-261', 'T-297', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-261', 'T-298', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-261', 'T-299', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-261', 'T-300', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-261', 'T-310', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-261', 'T-328', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-302', 'T-190', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-302', 'T-191', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-302', 'T-192', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-302', 'T-306', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-303', 'T-304', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-303', 'T-311', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-303', 'T-312', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-303', 'T-313', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-303', 'T-314', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-303', 'T-315', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-303', 'T-316', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-303', 'T-317', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-303', 'T-318', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-303', 'T-333', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-303', 'T-334', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-301', 'T-319', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-301', 'T-320', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-308', 'T-305', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-308', 'T-326', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-310', 'T-299', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-310', 'T-300', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-310', 'T-297', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-310', 'T-298', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-297', 'T-332', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-298', 'T-332', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-297', 'T-318', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-298', 'T-318', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-297', 'T-329', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-298', 'T-329', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-319', 'T-320', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-320', 'T-335', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-321', 'T-190', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-321', 'T-191', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-321', 'T-192', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-305', 'T-338', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-309', 'T-299', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-309', 'T-300', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-326', 'T-305', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-326', 'T-193', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-323', 'T-337', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-311', 'T-190', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-312', 'T-191', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-313', 'T-192', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-315', 'T-299', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-315', 'T-300', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-299', 'T-330', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-300', 'T-330', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-351', 'T-352', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-129', 'T-131', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-112', 'T-356', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-113', 'T-356', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-356', 'T-357', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-116', 'T-357', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-25', 'T-357', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-358', 'T-112', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-358', 'T-113', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-358', 'T-25', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-359', 'T-110', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-360', 'T-130', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-361', 'T-112', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-362', 'T-112', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-362', 'T-360', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-366', 'T-356', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-368', 'T-309', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-361', 'T-182', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-237', 'T-88', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-376', 'T-377', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-382', 'T-373', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-319', 'T-378', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-319', 'T-379', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-374', 'T-379', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-380', 'T-379', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-382', 'T-379', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-374', 'T-381', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-374', 'T-382', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-381', 'T-383', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-384', 'T-385', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-384', 'T-386', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-385', 'T-387', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-385', 'T-388', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-385', 'T-389', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-385', 'T-390', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-385', 'T-391', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-386', 'T-392', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-396', 'T-397', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-384', 'T-398', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-385', 'T-398', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-386', 'T-398', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-261', 'T-399', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-382', 'T-399', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-381', 'T-401', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-383', 'T-401', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-297', 'T-401', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-298', 'T-401', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-384', 'T-403', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-404', 'T-405', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-386', 'T-407', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-392', 'T-407', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-384', 'T-326', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-385', 'T-326', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-386', 'T-326', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-387', 'T-408', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-388', 'T-408', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-389', 'T-408', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-390', 'T-408', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-391', 'T-408', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-398', 'T-408', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-261', 'T-382', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-417', 'T-418', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-417', 'T-419', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-421', 'T-422', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-424', 'T-425', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-417', 'T-426', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-419', 'T-428', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-430', 'T-431', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-423', 'T-431', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-429', 'T-432', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-434', 'T-435', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-434', 'T-436', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-435', 'T-436', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-434', 'T-437', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-424', 'T-438', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-417', 'T-439', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-444', 'T-417', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-444', 'T-420', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-445', 'T-424', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-449', 'T-439', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-449', 'T-438', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-460', 'T-465', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-456', 'T-466', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-457', 'T-466', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-458', 'T-466', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-456', 'T-467', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-458', 'T-467', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-471', 'T-472', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-472', 'T-473', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-472', 'T-474', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-473', 'T-475', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-474', 'T-475', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-476', 'T-478', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-459', 'T-480', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-480', 'T-481', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-459', 'T-482', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-480', 'T-482', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-480', 'T-483', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-480', 'T-484', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-481', 'T-484', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-466', 'T-485', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-484', 'T-485', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-485', 'T-486', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-459', 'T-487', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-487', 'T-488', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-487', 'T-490', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-487', 'T-491', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-481', 'T-495', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-490', 'T-495', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-487', 'T-496', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-487', 'T-497', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-487', 'T-498', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-487', 'T-499', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-489', 'T-500', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-491', 'T-501', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-490', 'T-502', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-497', 'T-503', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-487', 'T-504', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-487', 'T-505', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-498', 'T-506', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-504', 'T-506', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-495', 'T-507', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-495', 'T-511', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-487', 'T-513', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-499', 'T-513', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-464', 'T-515', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-520', 'T-521', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-427', 'T-519', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-528', 'T-529', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-528', 'T-530', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-528', 'T-531', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-532', 'T-533', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-528', 'T-533', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-247', 'T-535', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-538', 'T-539', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-541', 'T-540', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-545', 'T-546', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-545', 'T-547', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-545', 'T-548', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-545', 'T-549', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-545', 'T-550', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-545', 'T-551', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-546', 'T-548', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-546', 'T-550', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-546', 'T-551', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-546', 'T-141', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-547', 'T-550', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-548', 'T-550', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-548', 'T-551', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-546', 'T-142', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-548', 'T-142', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-551', 'T-172', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-549', 'T-142', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-552', 'T-550', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-553', 'T-554', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-555', 'T-556', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-562', 'T-144', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-576', 'T-577', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-576', 'T-578', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-570', 'T-579', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-571', 'T-579', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-572', 'T-579', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-587', 'T-588', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-587', 'T-593', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-588', 'T-593', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-589', 'T-590', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-589', 'T-593', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-590', 'T-593', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-591', 'T-592', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-592', 'T-593', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-595', 'T-596', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-595', 'T-593', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-596', 'T-593', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-597', 'T-593', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-587', 'T-595', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-600', 'T-599', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-600', 'T-601', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-602', 'T-600', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-609', 'T-612', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-610', 'T-612', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-611', 'T-612', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-610', 'T-623', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-614', 'T-618', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-615', 'T-617', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-621', 'T-622', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-611', 'T-609', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-611', 'T-610', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-639', 'T-640', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-639', 'T-641', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-640', 'T-641', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-642', 'T-641', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-643', 'T-640', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-641', 'T-646', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-627', 'T-646', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-679', 'T-621', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-679', 'T-680', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-615', 'T-681', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-679', 'T-681', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-681', 'T-682', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-684', 'T-685', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-684', 'T-686', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-684', 'T-687', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-684', 'T-688', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-684', 'T-689', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-684', 'T-690', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-684', 'T-691', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-684', 'T-692', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-684', 'T-693', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-686', 'T-693', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-685', 'T-694', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-685', 'T-698', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-699', 'T-698', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-700', 'T-698', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-699', 'T-700', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-702', 'T-704', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-703', 'T-704', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-706', 'T-704', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-685', 'T-705', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-704', 'T-705', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-706', 'T-707', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-706', 'T-708', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-707', 'T-710', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-707', 'T-711', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-710', 'T-711', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-713', 'T-714', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-683', 'T-718', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-683', 'T-719', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-683', 'T-720', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-683', 'T-721', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-746', 'T-747', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-747', 'T-748', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-748', 'T-749', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-749', 'T-750', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-750', 'T-751', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-784', 'T-793', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-778', 'T-794', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-795', 'T-787', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-798', 'T-799', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-798', 'T-800', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-804', 'T-805', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-805', 'T-806', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-806', 'T-807', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-807', 'T-808', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-808', 'T-809', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-809', 'T-810', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-797', 'T-809', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-799', 'T-809', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-800', 'T-809', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-810', 'T-821', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-821', 'T-822', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-822', 'T-824', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-823', 'T-825', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-821', 'T-823', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-839', 'T-832', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-832', 'T-833', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-834', 'T-835', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-835', 'T-836', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-832', 'T-838', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-833', 'T-838', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-856', 'T-857', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-856', 'T-858', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-856', 'T-859', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-874', 'T-875', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-878', 'T-882', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-897', 'T-899', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-901', 'T-906', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-906', 'T-916', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-916', 'T-917', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-917', 'T-918', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-918', 'T-919', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-908', 'T-919', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-919', 'T-920', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-920', 'T-923', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-920', 'T-922', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-900', 'T-912', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-912', 'T-915', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-913', 'T-915', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-914', 'T-915', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-917', 'T-924', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-900', 'T-899', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-923', 'T-681', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-951', 'T-953', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-951', 'T-955', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-953', 'T-955', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-954', 'T-955', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-955', 'T-956', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-950', 'T-957', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-956', 'T-957', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-957', 'T-958', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-958', 'T-959', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-953', 'T-960', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-952', 'T-962', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-959', 'T-962', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-962', 'T-749', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-963', 'T-953', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-968', 'T-969', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-969', 'T-960', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-960', 'T-971', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-970', 'T-971', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-971', 'T-972', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-980', 'T-957', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-954', 'T-957', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-957', 'T-976', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-957', 'T-959', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-957', 'T-978', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-957', 'T-979', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-976', 'T-959', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-976', 'T-978', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-977', 'T-959', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-993', 'T-1005', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-995', 'T-1005', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1005', 'T-994', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1005', 'T-959', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1005', 'T-988', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1005', 'T-1003', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1006', 'T-954', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1006', 'T-957', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1006', 'T-977', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1001', 'T-954', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1010', 'T-1011', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1010', 'T-1012', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1011', 'T-1013', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1012', 'T-1013', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1013', 'T-1014', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-982', 'T-1014', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1011', 'T-1015', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1013', 'T-1015', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1012', 'T-1016', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1015', 'T-1016', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1010', 'T-1017', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1016', 'T-1017', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-993', 'T-1017', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1005', 'T-1017', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-977', 'T-1017', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); +INSERT INTO ticket_deps (blocker_id, blocked_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-957', 'T-1017', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(blocker_id, blocked_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash); diff --git a/.pql/changelog/ticket_history/0000-schema.sql b/.pql/changelog/ticket_history/0000-schema.sql new file mode 100644 index 000000000..55e0b02b1 --- /dev/null +++ b/.pql/changelog/ticket_history/0000-schema.sql @@ -0,0 +1,114 @@ +-- Auto-generated by pql init. CREATE TABLE statements +-- for the planning schema; per-table dir keeps the changelog +-- self-describing per D-15. CREATE TABLE IF NOT EXISTS is +-- idempotent so running schema files from each directory in +-- replay order is harmless. +-- +-- Importer parses the markers below to detect schema drift +-- between the producing pql version and the local one — a +-- bumped canonical_version means projection rules changed +-- and replay must refuse rather than silently corrupt state. +-- pql:created_by: 1.6.2 +-- pql:canonical_version: 1 + + +CREATE TABLE IF NOT EXISTS decisions ( + id TEXT PRIMARY KEY, + type TEXT NOT NULL CHECK(type IN ('confirmed','question','rejected')), + domain TEXT NOT NULL, + title TEXT NOT NULL, + status TEXT NOT NULL DEFAULT 'active' + CHECK(status IN ('active','superseded','resolved','open')), + date TEXT, + file_path TEXT NOT NULL, + synced_at TEXT NOT NULL DEFAULT (datetime('now')), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER +); + +CREATE TABLE IF NOT EXISTS decision_refs ( + source_id TEXT NOT NULL REFERENCES decisions(id) ON DELETE CASCADE, + target_id TEXT NOT NULL REFERENCES decisions(id) ON DELETE CASCADE, + ref_type TEXT NOT NULL + CHECK(ref_type IN ('supersedes','references','resolves','depends_on','amends')), + note TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER, + PRIMARY KEY (source_id, target_id, ref_type) +); + +CREATE TABLE IF NOT EXISTS tickets ( + id TEXT PRIMARY KEY, + type TEXT NOT NULL CHECK(type IN ('initiative','epic','story','task','bug')), + parent_id TEXT REFERENCES tickets(id), + title TEXT NOT NULL, + description TEXT, + status TEXT NOT NULL DEFAULT 'backlog' + CHECK(status IN ('backlog','ready','in_progress','review','done','cancelled')), + priority TEXT DEFAULT 'medium' + CHECK(priority IN ('critical','high','medium','low')), + assigned_to TEXT, + team TEXT, + decision_ref TEXT REFERENCES decisions(id), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER +); + +CREATE TABLE IF NOT EXISTS ticket_deps ( + blocker_id TEXT NOT NULL REFERENCES tickets(id), + blocked_id TEXT NOT NULL REFERENCES tickets(id), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER, + PRIMARY KEY (blocker_id, blocked_id) +); + +CREATE TABLE IF NOT EXISTS ticket_history ( + ticket_id TEXT NOT NULL REFERENCES tickets(id), + field TEXT NOT NULL, + old_value TEXT, + new_value TEXT, + changed_by TEXT, + changed_at TEXT NOT NULL DEFAULT (datetime('now')), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT UNIQUE, + canonical_version INTEGER +); + +CREATE TABLE IF NOT EXISTS ticket_labels ( + ticket_id TEXT NOT NULL REFERENCES tickets(id), + label TEXT NOT NULL, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER, + PRIMARY KEY (ticket_id, label) +); + +CREATE TABLE IF NOT EXISTS meta ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL, + updated_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE INDEX IF NOT EXISTS idx_tickets_status ON tickets(status); +CREATE INDEX IF NOT EXISTS idx_tickets_team ON tickets(team); +CREATE INDEX IF NOT EXISTS idx_tickets_decision_ref ON tickets(decision_ref); +CREATE INDEX IF NOT EXISTS idx_tickets_assigned ON tickets(assigned_to); +CREATE INDEX IF NOT EXISTS idx_decisions_domain ON decisions(domain); +CREATE INDEX IF NOT EXISTS idx_decisions_type ON decisions(type); +CREATE INDEX IF NOT EXISTS idx_decision_refs_target ON decision_refs(target_id); diff --git a/.pql/changelog/ticket_history/2026-02.sql b/.pql/changelog/ticket_history/2026-02.sql new file mode 100644 index 000000000..c178e034b --- /dev/null +++ b/.pql/changelog/ticket_history/2026-02.sql @@ -0,0 +1,16 @@ +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-103', 'priority', 'medium', 'high', 'si-workshop', '2026-02-11 00:00:09', '2026-02-11 00:00:09', '2026-02-11 00:00:09', NULL, '6d4ac570e2788dc4d5566f095bfa57845fa383911f80cb015a5ad6707a9d5235', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-105', 'priority', 'medium', 'high', 'si-workshop', '2026-02-11 00:00:09', '2026-02-11 00:00:09', '2026-02-11 00:00:09', NULL, 'bfbe52a09ba7b6d8fa6b1c2bbc9307331cd4ab479f81f341a6f52937c959c7ea', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-171', 'priority', 'medium', 'high', 'si-workshop', '2026-02-11 00:00:10', '2026-02-11 00:00:10', '2026-02-11 00:00:10', NULL, '505e24ea124372e8fec445c00f862e3348f8c0144a8968f38831e4767c3f0ed4', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-162', 'priority', 'low', 'high', 'si-workshop', '2026-02-11 00:00:14', '2026-02-11 00:00:14', '2026-02-11 00:00:14', NULL, '59bd514f47bcee902f036e42da3379c2ddfe77b8d05e696a6fea486a36243b31', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-172', 'priority', 'medium', 'high', 'si-workshop', '2026-02-11 00:00:14', '2026-02-11 00:00:14', '2026-02-11 00:00:14', NULL, '762c1c7ee95cfb3f72bf92c9af7d48921c12718d0308905f6c957f2f979a9be0', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-178', 'priority', 'low', 'high', 'si-workshop', '2026-02-11 00:00:15', '2026-02-11 00:00:15', '2026-02-11 00:00:15', NULL, '34fe40d55d59d0fc37593cee15f6fdcb4bdefb54a46e07e1ce80a6a0be2c921f', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-176', 'priority', 'medium', 'high', 'si-workshop', '2026-02-11 00:00:18', '2026-02-11 00:00:18', '2026-02-11 00:00:18', NULL, '0262004b4425ab920467a323e15a56ee87281ad4c7f41962a19c6c64f2695de1', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-175', 'priority', 'medium', 'high', 'si-workshop', '2026-02-11 00:00:18', '2026-02-11 00:00:18', '2026-02-11 00:00:18', NULL, 'ecc39036b0ecb664876b308e09b6446956cb7945896167906eaec59c0c4adab1', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-121', 'priority', 'medium', 'high', 'si-workshop', '2026-02-11 00:00:18', '2026-02-11 00:00:18', '2026-02-11 00:00:18', NULL, 'fab322ac3f6b10a13350998b606c96966f1e18d7e3f7230129e5b7f7c8567265', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-126', 'priority', 'medium', 'high', 'si-workshop', '2026-02-11 00:00:22', '2026-02-11 00:00:22', '2026-02-11 00:00:22', NULL, '51d6b892c98f94269d2ebf2d26ceb3e228ad2018a2a82a28aaa19ced8b7b6926', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-201', 'priority', 'high', 'critical', 'si-workshop', '2026-02-11 00:00:22', '2026-02-11 00:00:22', '2026-02-11 00:00:22', NULL, '5cc3041bda44019e851e1aa77686b3c2599b39930aeff0acbb76ecaf9b2b3339', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-182', 'priority', 'high', 'critical', 'si-workshop', '2026-02-11 00:00:23', '2026-02-11 00:00:23', '2026-02-11 00:00:23', NULL, '54d141b301aa7370e8f5a9f2b535566a118101eb32883cc34d495f598eeccba1', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-183', 'priority', 'high', 'critical', 'si-workshop', '2026-02-11 00:00:26', '2026-02-11 00:00:26', '2026-02-11 00:00:26', NULL, '5630f1f74a7d84b107533983fb94ed621d30bc1ee71cd22c0069b9fed5231a28', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-173', 'priority', 'medium', 'high', 'si-workshop', '2026-02-11 00:00:27', '2026-02-11 00:00:27', '2026-02-11 00:00:27', NULL, '77d5067e391bb9f61ee015c417a99cf000f101687d17afb668501382513f9e04', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-25', 'title', 'Time system', 'Game clock and day-phase system', 'si-workshop', '2026-02-11 00:00:35', '2026-02-11 00:00:35', '2026-02-11 00:00:35', NULL, '7200816c4d083e12bdb138ab544d17258b63b498025264eaafab7d013b421c1a', 1) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-25', 'priority', 'medium', 'high', 'si-workshop', '2026-02-11 00:00:35', '2026-02-11 00:00:35', '2026-02-11 00:00:35', NULL, '7ec0e3a781f0c184bb4955f3ee739a30ffd9009f59eea9ad21b5ef2b0a3dbb0d', 1) ON CONFLICT(hash) DO NOTHING; diff --git a/.pql/changelog/ticket_labels/0000-schema.sql b/.pql/changelog/ticket_labels/0000-schema.sql new file mode 100644 index 000000000..55e0b02b1 --- /dev/null +++ b/.pql/changelog/ticket_labels/0000-schema.sql @@ -0,0 +1,114 @@ +-- Auto-generated by pql init. CREATE TABLE statements +-- for the planning schema; per-table dir keeps the changelog +-- self-describing per D-15. CREATE TABLE IF NOT EXISTS is +-- idempotent so running schema files from each directory in +-- replay order is harmless. +-- +-- Importer parses the markers below to detect schema drift +-- between the producing pql version and the local one — a +-- bumped canonical_version means projection rules changed +-- and replay must refuse rather than silently corrupt state. +-- pql:created_by: 1.6.2 +-- pql:canonical_version: 1 + + +CREATE TABLE IF NOT EXISTS decisions ( + id TEXT PRIMARY KEY, + type TEXT NOT NULL CHECK(type IN ('confirmed','question','rejected')), + domain TEXT NOT NULL, + title TEXT NOT NULL, + status TEXT NOT NULL DEFAULT 'active' + CHECK(status IN ('active','superseded','resolved','open')), + date TEXT, + file_path TEXT NOT NULL, + synced_at TEXT NOT NULL DEFAULT (datetime('now')), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER +); + +CREATE TABLE IF NOT EXISTS decision_refs ( + source_id TEXT NOT NULL REFERENCES decisions(id) ON DELETE CASCADE, + target_id TEXT NOT NULL REFERENCES decisions(id) ON DELETE CASCADE, + ref_type TEXT NOT NULL + CHECK(ref_type IN ('supersedes','references','resolves','depends_on','amends')), + note TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER, + PRIMARY KEY (source_id, target_id, ref_type) +); + +CREATE TABLE IF NOT EXISTS tickets ( + id TEXT PRIMARY KEY, + type TEXT NOT NULL CHECK(type IN ('initiative','epic','story','task','bug')), + parent_id TEXT REFERENCES tickets(id), + title TEXT NOT NULL, + description TEXT, + status TEXT NOT NULL DEFAULT 'backlog' + CHECK(status IN ('backlog','ready','in_progress','review','done','cancelled')), + priority TEXT DEFAULT 'medium' + CHECK(priority IN ('critical','high','medium','low')), + assigned_to TEXT, + team TEXT, + decision_ref TEXT REFERENCES decisions(id), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER +); + +CREATE TABLE IF NOT EXISTS ticket_deps ( + blocker_id TEXT NOT NULL REFERENCES tickets(id), + blocked_id TEXT NOT NULL REFERENCES tickets(id), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER, + PRIMARY KEY (blocker_id, blocked_id) +); + +CREATE TABLE IF NOT EXISTS ticket_history ( + ticket_id TEXT NOT NULL REFERENCES tickets(id), + field TEXT NOT NULL, + old_value TEXT, + new_value TEXT, + changed_by TEXT, + changed_at TEXT NOT NULL DEFAULT (datetime('now')), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT UNIQUE, + canonical_version INTEGER +); + +CREATE TABLE IF NOT EXISTS ticket_labels ( + ticket_id TEXT NOT NULL REFERENCES tickets(id), + label TEXT NOT NULL, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER, + PRIMARY KEY (ticket_id, label) +); + +CREATE TABLE IF NOT EXISTS meta ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL, + updated_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE INDEX IF NOT EXISTS idx_tickets_status ON tickets(status); +CREATE INDEX IF NOT EXISTS idx_tickets_team ON tickets(team); +CREATE INDEX IF NOT EXISTS idx_tickets_decision_ref ON tickets(decision_ref); +CREATE INDEX IF NOT EXISTS idx_tickets_assigned ON tickets(assigned_to); +CREATE INDEX IF NOT EXISTS idx_decisions_domain ON decisions(domain); +CREATE INDEX IF NOT EXISTS idx_decisions_type ON decisions(type); +CREATE INDEX IF NOT EXISTS idx_decision_refs_target ON decision_refs(target_id); diff --git a/.pql/changelog/ticket_labels/2026-06.sql b/.pql/changelog/ticket_labels/2026-06.sql new file mode 100644 index 000000000..054cf3d3b --- /dev/null +++ b/.pql/changelog/ticket_labels/2026-06.sql @@ -0,0 +1,90 @@ +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-28', 'architecture', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-28', 'critical-path', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-29', 'simulation', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-29', 'critical-path', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-30', 'rendering', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-30', 'client', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-30', 'critical-path', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-31', 'architecture', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-31', 'map-system', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-32', 'content', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-32', 'templates', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-33', 'content', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-33', 'vertical-slice', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-33', 'critical-path', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-34', 'testing', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-34', 'infrastructure', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-34', 'needs-refinement', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-35', 'rust', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-35', 'critical-path', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-36', 'godot', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-36', 'critical-path', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-37', 'ipc', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-37', 'protocol', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-37', 'critical-path', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-38', 'integration', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-38', 'critical-path', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-39', 'npc-model', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-39', 'critical-path', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-57', 'characters', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-57', 'vertical-slice', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-57', 'critical-path', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-58', 'templates', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-58', 'vertical-slice', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-58', 'critical-path', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-59', 'authoring', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-59', 'vertical-slice', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-59', 'critical-path', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-189', 'blocking', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-189', 'miri', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-193', 'blocking', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-193', 'tyre', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-193', 'tool', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-214', 'blocking', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-214', 'needs-refinement', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-214', 'multi-agent', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-276', 'architect:tyre', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-277', 'architect:tyre', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-275', 'blocking', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-950', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-951', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-952', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-953', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-954', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-955', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-956', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-957', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-958', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-959', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-960', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-961', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-962', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-963', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-964', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-965', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-966', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-967', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-968', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-969', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-970', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-971', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-972', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-974', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-976', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-977', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-978', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-979', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-980', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-981', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1005', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1006', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1008', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1009', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1010', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1011', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1012', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1013', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1014', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1015', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1016', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); +INSERT INTO ticket_labels (ticket_id, label, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1017', 'phase:4', '2026-06-06 00:00:00', '2026-06-06 00:00:00', NULL, NULL, 1) ON CONFLICT(ticket_id, label) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_labels.updated_at OR (excluded.updated_at = ticket_labels.updated_at AND excluded.hash > ticket_labels.hash); diff --git a/.pql/changelog/tickets/0000-schema.sql b/.pql/changelog/tickets/0000-schema.sql new file mode 100644 index 000000000..55e0b02b1 --- /dev/null +++ b/.pql/changelog/tickets/0000-schema.sql @@ -0,0 +1,114 @@ +-- Auto-generated by pql init. CREATE TABLE statements +-- for the planning schema; per-table dir keeps the changelog +-- self-describing per D-15. CREATE TABLE IF NOT EXISTS is +-- idempotent so running schema files from each directory in +-- replay order is harmless. +-- +-- Importer parses the markers below to detect schema drift +-- between the producing pql version and the local one — a +-- bumped canonical_version means projection rules changed +-- and replay must refuse rather than silently corrupt state. +-- pql:created_by: 1.6.2 +-- pql:canonical_version: 1 + + +CREATE TABLE IF NOT EXISTS decisions ( + id TEXT PRIMARY KEY, + type TEXT NOT NULL CHECK(type IN ('confirmed','question','rejected')), + domain TEXT NOT NULL, + title TEXT NOT NULL, + status TEXT NOT NULL DEFAULT 'active' + CHECK(status IN ('active','superseded','resolved','open')), + date TEXT, + file_path TEXT NOT NULL, + synced_at TEXT NOT NULL DEFAULT (datetime('now')), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER +); + +CREATE TABLE IF NOT EXISTS decision_refs ( + source_id TEXT NOT NULL REFERENCES decisions(id) ON DELETE CASCADE, + target_id TEXT NOT NULL REFERENCES decisions(id) ON DELETE CASCADE, + ref_type TEXT NOT NULL + CHECK(ref_type IN ('supersedes','references','resolves','depends_on','amends')), + note TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER, + PRIMARY KEY (source_id, target_id, ref_type) +); + +CREATE TABLE IF NOT EXISTS tickets ( + id TEXT PRIMARY KEY, + type TEXT NOT NULL CHECK(type IN ('initiative','epic','story','task','bug')), + parent_id TEXT REFERENCES tickets(id), + title TEXT NOT NULL, + description TEXT, + status TEXT NOT NULL DEFAULT 'backlog' + CHECK(status IN ('backlog','ready','in_progress','review','done','cancelled')), + priority TEXT DEFAULT 'medium' + CHECK(priority IN ('critical','high','medium','low')), + assigned_to TEXT, + team TEXT, + decision_ref TEXT REFERENCES decisions(id), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER +); + +CREATE TABLE IF NOT EXISTS ticket_deps ( + blocker_id TEXT NOT NULL REFERENCES tickets(id), + blocked_id TEXT NOT NULL REFERENCES tickets(id), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER, + PRIMARY KEY (blocker_id, blocked_id) +); + +CREATE TABLE IF NOT EXISTS ticket_history ( + ticket_id TEXT NOT NULL REFERENCES tickets(id), + field TEXT NOT NULL, + old_value TEXT, + new_value TEXT, + changed_by TEXT, + changed_at TEXT NOT NULL DEFAULT (datetime('now')), + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT UNIQUE, + canonical_version INTEGER +); + +CREATE TABLE IF NOT EXISTS ticket_labels ( + ticket_id TEXT NOT NULL REFERENCES tickets(id), + label TEXT NOT NULL, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + deleted_at TEXT, + hash TEXT, + canonical_version INTEGER, + PRIMARY KEY (ticket_id, label) +); + +CREATE TABLE IF NOT EXISTS meta ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL, + updated_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE INDEX IF NOT EXISTS idx_tickets_status ON tickets(status); +CREATE INDEX IF NOT EXISTS idx_tickets_team ON tickets(team); +CREATE INDEX IF NOT EXISTS idx_tickets_decision_ref ON tickets(decision_ref); +CREATE INDEX IF NOT EXISTS idx_tickets_assigned ON tickets(assigned_to); +CREATE INDEX IF NOT EXISTS idx_decisions_domain ON decisions(domain); +CREATE INDEX IF NOT EXISTS idx_decisions_type ON decisions(type); +CREATE INDEX IF NOT EXISTS idx_decision_refs_target ON decision_refs(target_id); diff --git a/.pql/changelog/tickets/2026-02.sql b/.pql/changelog/tickets/2026-02.sql new file mode 100644 index 000000000..0da287cd3 --- /dev/null +++ b/.pql/changelog/tickets/2026-02.sql @@ -0,0 +1,801 @@ +INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-2', 'initiative', NULL, 'Commonwealth as first campaign', NULL, 'done', 'medium', NULL, NULL, 'D-003', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-3', 'initiative', NULL, 'Single character first-person story generator', NULL, 'done', 'medium', NULL, NULL, 'D-005', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-4', 'initiative', NULL, 'Prototype scenario — Institute/Armstrong City/Guardians', NULL, 'done', 'medium', NULL, NULL, 'D-006', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-5', 'initiative', NULL, 'Five pillars of game design', NULL, 'done', 'medium', NULL, NULL, 'D-007', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-6', 'initiative', NULL, 'Action pillar design principles', NULL, 'done', 'medium', NULL, NULL, 'D-008', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-7', 'initiative', NULL, 'Multiplayer — design for it, build single-player first', NULL, 'done', 'medium', NULL, NULL, 'D-009', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-8', 'initiative', NULL, 'Multiplayer-ready architectural baseline', NULL, 'done', 'medium', NULL, NULL, 'D-010', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-10', 'initiative', NULL, 'Chunk-based map architecture', NULL, 'done', 'medium', NULL, NULL, 'D-012', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-11', 'initiative', NULL, 'Diegetic insert/POI navigation', NULL, 'done', 'medium', NULL, NULL, 'D-013', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-12', 'initiative', NULL, 'v0.1 map specification', NULL, 'done', 'medium', NULL, NULL, 'D-014', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-13', 'initiative', NULL, 'Camera locked to character', NULL, 'done', 'medium', NULL, NULL, 'D-015', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-14', 'initiative', NULL, 'Internal monologue system', NULL, 'done', 'medium', NULL, NULL, 'D-016', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-15', 'initiative', NULL, 'Perception modes as character build', NULL, 'done', 'medium', NULL, NULL, 'D-017', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-16', 'initiative', NULL, 'Three-range sound model', NULL, 'done', 'medium', NULL, NULL, 'D-018', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-17', 'initiative', NULL, 'Top-down with 3D cutscenes', NULL, 'done', 'medium', NULL, NULL, 'D-019', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-20', 'story', NULL, 'Art direction', NULL, 'backlog', 'medium', NULL, NULL, 'Q-003', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-21', 'story', NULL, 'One campaign or separate eras', NULL, 'backlog', 'medium', NULL, NULL, 'Q-004', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-22', 'story', NULL, 'Prototype scale', NULL, 'backlog', 'medium', NULL, NULL, 'Q-005', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-23', 'story', NULL, 'Target platforms', NULL, 'backlog', 'medium', NULL, NULL, 'Q-007', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-24', 'story', NULL, 'Licensing/distribution', NULL, 'backlog', 'medium', NULL, NULL, 'Q-008', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-26', 'story', NULL, 'Storyteller AI design', NULL, 'backlog', 'medium', NULL, NULL, 'Q-010', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-27', 'story', NULL, 'Character selection roster', NULL, 'backlog', 'medium', NULL, NULL, 'Q-011', '2026-02-09 15:21:44', '2026-02-09 15:21:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-28', 'initiative', NULL, 'Engine Architecture - Godot + Rust IPC', 'Implement D-020: Godot 4 client + Rust/bevy_ecs simulation via subprocess/IPC. MessagePack protocol, ObserverSnapshot pattern, deterministic simulation.', 'backlog', 'critical', NULL, NULL, 'D-020', '2026-02-10 23:14:11', '2026-02-10 23:14:11', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-29', 'initiative', NULL, 'Core Simulation - NPCs & Tiers', 'Implement D-024 (NPC generation model with 10 axes), D-026 (simulation tiers with timestamp eviction). Foundation for all NPC behavior.', 'cancelled', 'critical', NULL, NULL, 'D-024, D-026', '2026-02-10 23:14:31', '2026-02-10 23:14:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-30', 'initiative', NULL, 'Rendering & Perception System', 'Implement D-011 (fog of perception), D-015 (locked camera), D-016 (internal monologue), D-017 (perception modes), D-018 (3-range sound), D-019 (top-down rendering). Client-side observation systems.', 'backlog', 'critical', NULL, NULL, 'D-011, D-015, D-016, D-017, D-018, D-019', '2026-02-10 23:14:31', '2026-02-10 23:14:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-31', 'initiative', NULL, 'Map & Navigation', 'Implement D-010 (information boundaries), D-012 (chunk-based maps), D-013 (diegetic insert/POI navigation), D-014 revised (station district map). World structure and player navigation.', 'backlog', 'high', NULL, NULL, 'D-010, D-012, D-013, D-014', '2026-02-10 23:14:31', '2026-02-10 23:14:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-32', 'initiative', NULL, 'Content Architecture', 'Implement D-023 (three-tier content model), D-025 (social site templates), D-028 (dialogue system), D-029 (population entanglement). Template system and dialogue.', 'backlog', 'high', NULL, NULL, 'D-023, D-025, D-028, D-029', '2026-02-10 23:14:31', '2026-02-10 23:14:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-33', 'initiative', NULL, 'Vertical Slice Content', 'Implement D-027: smuggler + detective playthrough, station district, workplace/bar/smuggling ring templates, 20-30 NPCs, 30-minute playable. The proof of concept. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. The workshop killed the detective/smuggler framing, named NPCs, and hand-built vertical slice approach in favour of a generator-first life sim with tycoon bookmark. See docs/workshops/wheres-the-fun/workshop-outcomes.md.', 'cancelled', 'critical', NULL, NULL, 'D-027', '2026-02-10 23:14:31', '2026-02-10 23:14:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-34', 'initiative', NULL, 'Testability Infrastructure', 'Build comprehensive testing framework for both Rust/bevy_ecs simulation and Godot 4 client. External test harness, minimal production code pollution. NEEDS REFINEMENT.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:14:31', '2026-02-10 23:14:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-39', 'epic', 'T-29', 'NPC Data Model', 'Implement 10-axis NPC generation: Want, Secret, Relationships (3), Tolerance, Routine, Information inventory, Contentment, Personality traits, Tell system, Skill set. CombatCapability as optional component.', 'cancelled', 'critical', NULL, NULL, 'D-024', '2026-02-10 23:15:58', '2026-02-10 23:15:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-40', 'epic', 'T-29', 'Simulation Tier System', 'Four-tier NPC simulation: Active (full sim), Background (state machines), State-saved (frozen structs), Ungenerated. Timestamp-based LRU eviction, scope tags.', 'backlog', 'critical', NULL, NULL, 'D-026', '2026-02-10 23:15:58', '2026-02-10 23:15:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-41', 'epic', 'T-29', 'NPC Behavior Systems', 'Daily routines, relationship dynamics, mood system, job performance. State machine ticks for Background tier, full behavior for Active tier.', 'cancelled', 'high', NULL, NULL, 'D-024, D-026', '2026-02-10 23:15:58', '2026-02-10 23:15:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-42', 'epic', 'T-29', 'Triangle Generation', 'Create 3-NPC conflicting interest clusters. Minimum 2 triangles per social site template, 1 cross-template triangle. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. The workshop killed the detective/smuggler framing, named NPCs, and hand-built vertical slice approach in favour of a generator-first life sim with tycoon bookmark. See docs/workshops/wheres-the-fun/workshop-outcomes.md.', 'cancelled', 'high', NULL, NULL, 'D-024', '2026-02-10 23:15:58', '2026-02-10 23:15:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-43', 'epic', 'T-30', 'Fog of Perception - Vision System', 'LOS-based shadowcasting per z-level. Vision cone (forward/peripheral/behind). Walls block vision, fog returns on departure. Universal for all entities.', 'backlog', 'critical', NULL, NULL, 'D-011', '2026-02-10 23:16:24', '2026-02-10 23:16:24', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-44', 'epic', 'T-30', 'Camera System', 'Locked to character, no panning. Optional rotation to facing direction (deferred to post-v0.1). Fixed-north for v0.1.', 'backlog', 'critical', NULL, NULL, 'D-015', '2026-02-10 23:16:24', '2026-02-10 23:16:24', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-45', 'epic', 'T-30', 'Internal Monologue System', 'Character voice narration for non-visual perception, atmosphere, diegetic hints. Contextual line selection based on situation, character personality, knowledge state.', 'backlog', 'high', NULL, NULL, 'D-016', '2026-02-10 23:16:24', '2026-02-10 23:16:24', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-46', 'epic', 'T-30', 'Sound Propagation Model', 'Three-range sound: Close (stereo audio), Medium (fog-edge indicators + monologue), Long (insert notifications - stretch). Event classification, directional info.', 'backlog', 'high', NULL, NULL, 'D-018', '2026-02-10 23:16:24', '2026-02-10 23:16:24', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-47', 'epic', 'T-30', 'Top-down Renderer', 'Tile-based rendering, sprite system, z-level visualization, fog overlay. 3D cutscenes deferred post-v0.1.', 'backlog', 'critical', NULL, NULL, 'D-019', '2026-02-10 23:16:24', '2026-02-10 23:16:24', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-48', 'epic', 'T-30', 'Perception Mode Framework', 'Natural vision baseline for v0.1. Modular architecture for future modes (thermal, camera feeds, unisphere tracking, audio analysis). Observer query pattern.', 'backlog', 'medium', NULL, NULL, 'D-017', '2026-02-10 23:16:24', '2026-02-10 23:16:24', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-49', 'epic', 'T-31', 'Information Boundary System', 'First-class information tagging. Every piece of game state tagged with observer access. Foundation for fog, perception modes, NPC knowledge.', 'backlog', 'critical', NULL, NULL, 'D-010', '2026-02-10 23:16:38', '2026-02-10 23:16:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-50', 'epic', 'T-31', 'Chunk-based Map System', 'Chunk generation and loading. Bounded maps with internal chunks for v0.1. Architecture supports future borderless generation.', 'backlog', 'high', NULL, NULL, 'D-012', '2026-02-10 23:16:38', '2026-02-10 23:16:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-51', 'epic', 'T-31', 'Diegetic Insert/Minimap', 'Neural insert UI. POI discovery system (background, NPC tips, research, discovery). Minimap with directional arrows for distant POIs.', 'backlog', 'high', NULL, NULL, 'D-013', '2026-02-10 23:16:38', '2026-02-10 23:16:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-52', 'epic', 'T-31', 'Station District Map - v0.1 Revision', 'Revise D-014 for vertical slice: station district layout, workplace/bar/smuggling ring locations, 15-40 tile functional clusters, 2-3 z-levels.', 'backlog', 'high', NULL, NULL, 'D-014, D-027', '2026-02-10 23:16:38', '2026-02-10 23:16:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-53', 'epic', 'T-32', 'Three-Tier Content Pipeline', 'Tier 1: Drama module pool system. Tier 2: Template instantiation engine. Tier 3: Procedural filler generation. Storyteller activation logic.', 'backlog', 'high', NULL, NULL, 'D-023', '2026-02-10 23:16:54', '2026-02-10 23:16:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-54', 'epic', 'T-32', 'Social Site Template System', 'Functional cluster definition: 4-8 NPC roles, 15-40 tile spaces, sightline requirements. Single-ownership with reference links. Template → instance lifecycle.', 'backlog', 'high', NULL, NULL, 'D-025', '2026-02-10 23:16:54', '2026-02-10 23:16:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-55', 'epic', 'T-32', 'Dialogue System Architecture', 'Tagged line pools with systemic selection. Four relational layers: access tiers, relationship history, trust-gated gossip, unprompted disclosure. Trait modifier system.', 'backlog', 'high', NULL, NULL, 'D-028', '2026-02-10 23:16:54', '2026-02-10 23:16:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-56', 'epic', 'T-32', 'Population Management', '30/50/20 entanglement ratio (flat/mundane/intrigue). Variable per seed. Module attachment to known NPCs (60-70/30-40 ratio, also variable).', 'backlog', 'medium', NULL, NULL, 'D-029', '2026-02-10 23:16:54', '2026-02-10 23:16:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-57', 'epic', 'T-33', 'Playable Characters - Smuggler & Detective', 'Two character builds with divergent starting knowledge, relationships, access permissions. Same templates, inverted perspectives. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. The workshop killed the detective/smuggler framing, named NPCs, and hand-built vertical slice approach in favour of a generator-first life sim with tycoon bookmark. See docs/workshops/wheres-the-fun/workshop-outcomes.md.', 'cancelled', 'critical', NULL, NULL, 'D-027', '2026-02-10 23:17:09', '2026-02-10 23:17:09', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-58', 'epic', 'T-33', 'Station District Content', 'Author three social site templates: workplace (logistics hub), social venue (bar), smuggling ring. Shared NPCs across templates, 20-30 total. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. The workshop killed the detective/smuggler framing, named NPCs, and hand-built vertical slice approach in favour of a generator-first life sim with tycoon bookmark. See docs/workshops/wheres-the-fun/workshop-outcomes.md.', 'cancelled', 'critical', NULL, NULL, 'D-027', '2026-02-10 23:17:09', '2026-02-10 23:17:09', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-59', 'epic', 'T-33', 'Vertical Slice Authoring', 'Write template content packs: role voice kits, situation scripts, monologue hooks, trait transformation guides. ~165-210 lines per template, 4x generation expansion. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. The workshop killed the detective/smuggler framing, named NPCs, and hand-built vertical slice approach in favour of a generator-first life sim with tycoon bookmark. See docs/workshops/wheres-the-fun/workshop-outcomes.md.', 'cancelled', 'high', NULL, NULL, 'D-027, D-028', '2026-02-10 23:17:09', '2026-02-10 23:17:09', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-60', 'epic', 'T-33', 'Success Criteria Validation', 'Playtest and validate: (1) 30-min daily life runway, (2) fundamentally different playthroughs, (3) emotional NPC attachment, (4) emergent observation mechanics. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. The workshop killed the detective/smuggler framing, named NPCs, and hand-built vertical slice approach in favour of a generator-first life sim with tycoon bookmark. See docs/workshops/wheres-the-fun/workshop-outcomes.md.', 'cancelled', 'high', NULL, NULL, 'D-027', '2026-02-10 23:17:09', '2026-02-10 23:17:09', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-61', 'epic', 'T-34', 'Rust/bevy_ecs Test Infrastructure', 'Test harness for simulation server. External test modules, deterministic replay, ECS state inspection, behavior validation. Minimal production code pollution.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-02-10 23:17:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-62', 'epic', 'T-34', 'Godot Client Test Infrastructure', 'Test harness for rendering client. Scene testing, input simulation, rendering verification, fog/UI validation.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-02-10 23:17:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-63', 'epic', 'T-34', 'Integration Test Framework', 'End-to-end tests across IPC boundary. Protocol validation, sync verification, full playthrough automation.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-02-10 23:17:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-64', 'epic', 'T-34', 'Testability Architecture Refinement', 'Discussion: Jeroen + Tyre + Gestalt + Hoshe + Troblum. Determine optimal testing approach for Claude Code execution. Define patterns, constraints, tooling needs.', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-02-10 23:17:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-69', 'story', 'T-35', 'Standalone CLI test harness', 'Run simulation headless via terminal. Log output for verification. No GUI dependency.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:17:59', '2026-02-10 23:17:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-80', 'story', 'T-37', 'NetworkBridge stub', 'TCP-based bridge for future multiplayer. Same interface as LocalBridge, deferred implementation.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:18:24', '2026-02-10 23:18:24', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-100', 'story', 'T-40', 'Ungenerated → instantiation', 'Lazy NPC generation. Template instantiation on-demand. Density follows player movement.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:19:08', '2026-02-10 23:19:08', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-102', 'story', 'T-41', 'Mood system', 'MoodState component. Mood affected by events, relationships, job satisfaction, contentment. Mood influences behavior.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:19:21', '2026-02-10 23:19:21', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-104', 'story', 'T-41', 'Job performance simulation', 'Work activity states. Job satisfaction tracking. Performance affects mood and relationships.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:19:21', '2026-02-10 23:19:21', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-114', 'story', 'T-43', 'Multi-z-level LOS', 'LOS calculation across floors. Stairs, vertical sightlines. Deferred for post-v0.1 if too complex.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:19:52', '2026-02-10 23:19:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-118', 'story', 'T-44', 'Camera rotation stub', 'Architecture for future facing-direction rotation. Disabled for v0.1. Fixed north-up orientation.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:20:20', '2026-02-10 23:20:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-123', 'story', 'T-45', 'Unreliable narrator mechanics', 'Monologue can be wrong. Character misinterpretations. Knowledge-gated accuracy.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:20:40', '2026-02-10 23:20:40', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-127', 'story', 'T-46', 'Long-range insert notifications', 'Insert alerts for distant events. Network-based, spoofable. Stretch goal for v0.1.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:20:58', '2026-02-10 23:20:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-128', 'story', 'T-46', 'Sound propagation physics', 'Wall attenuation, distance falloff, z-level muffling. Realistic sound travel.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:20:58', '2026-02-10 23:20:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-132', 'story', 'T-47', 'Lighting system', 'Ambient lighting, local light sources. Affects visibility and atmosphere. Basic implementation for v0.1.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:21:12', '2026-02-10 23:21:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-133', 'story', 'T-47', 'Placeholder art pipeline', 'Colored boxes, simple sprites, labels. Functional but not polished. Per D-014 guidance.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:21:12', '2026-02-10 23:21:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-134', 'story', 'T-48', 'Observer query abstraction', 'Generic observer interface. Different perception modes as different query implementations. Foundation for D-017.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:21:23', '2026-02-10 23:21:23', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-135', 'story', 'T-48', 'Natural vision mode', 'Baseline perception. Full color, detail, identity. Blocked by walls. Default for all characters.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:21:23', '2026-02-10 23:21:23', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-136', 'story', 'T-48', 'Perception mode selector - client', 'UI for switching modes (future). Keybindings, mode indicators. Stub for v0.1.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:21:23', '2026-02-10 23:21:23', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-137', 'story', 'T-48', 'Additional mode stubs', 'Thermal, camera feeds, unisphere tracking, audio analysis. Interface only, no implementation. Post-v0.1 features.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:21:23', '2026-02-10 23:21:23', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-146', 'story', 'T-50', 'Chunk serialization', 'Save/load chunk state. Modified tiles, placed objects, NPC spawn points.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:22:01', '2026-02-10 23:22:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-147', 'story', 'T-50', 'Borderless expansion stub', 'Architecture supports infinite generation. Disabled for v0.1. Remove boundary check post-v0.1.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:22:01', '2026-02-10 23:22:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-150', 'story', 'T-51', 'Character-specific POI filtering', 'Different characters see different POIs. Profession-based, faction-based, relationship-based visibility.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:22:17', '2026-02-10 23:22:17', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-152', 'story', 'T-51', 'POI manipulation mechanics', 'False POIs (traps), outdated locations, spoofed information. Trust/deception layer.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:22:17', '2026-02-10 23:22:17', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-156', 'story', 'T-52', 'Procedural district filler', 'Generate connecting corridors, residential areas, commercial spaces around authored locations. Tier 3 content.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:22:44', '2026-02-10 23:22:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-160', 'story', 'T-53', 'Tier 3 procedural generator', 'Generate filler locations from templates. Ambient NPCs, basic interactions, systemic hooks for template colonization.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:23:54', '2026-02-10 23:23:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-167', 'story', 'T-54', 'Cross-template reference system', 'Create reference links between templates. Shared NPCs, relationship propagation, contamination paths.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:24:06', '2026-02-10 23:24:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-177', 'story', 'T-56', 'Module attachment logic', '60-70/30-40 known vs stranger ratio for module attachment. Variable per seed. Anti-metagaming.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:24:37', '2026-02-10 23:24:37', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-195', 'story', 'T-60', 'Test plan creation - Hoshe', 'Define test scenarios for all four success criteria. Playthrough scripts, observation checklists, timing validation. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. Parent epic (#60 Success Criteria Validation) superseded — v0.1 vertical slice validation criteria no longer relevant.', 'cancelled', 'high', NULL, NULL, NULL, '2026-02-10 23:26:12', '2026-02-10 23:26:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-196', 'story', 'T-60', 'Criterion 1: 30-min daily life runway', 'Validate: player can spend 30 minutes in daily routine before intrigue contamination activates. Pacing test. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. Parent epic (#60 Success Criteria Validation) superseded — v0.1 vertical slice validation criteria no longer relevant.', 'cancelled', 'high', NULL, NULL, NULL, '2026-02-10 23:26:12', '2026-02-10 23:26:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-197', 'story', 'T-60', 'Criterion 2: Fundamentally different playthroughs', 'Validate: smuggler and detective playthroughs feel like different games. Same NPCs, inverted relationships, distinct experiences. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. Parent epic (#60 Success Criteria Validation) superseded — v0.1 vertical slice validation criteria no longer relevant.', 'cancelled', 'high', NULL, NULL, NULL, '2026-02-10 23:26:12', '2026-02-10 23:26:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-198', 'story', 'T-60', 'Criterion 3: Emotional NPC attachment', 'Validate: after playthrough, player names an NPC they felt conflicted about. Emotional engagement test. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. Parent epic (#60 Success Criteria Validation) superseded — v0.1 vertical slice validation criteria no longer relevant.', 'cancelled', 'high', NULL, NULL, NULL, '2026-02-10 23:26:12', '2026-02-10 23:26:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-199', 'story', 'T-60', 'Criterion 4: Emergent observation mechanics', 'Validate: observe→notice→follow→discover sequence emerges from systems, not scripts. Systemic gameplay test. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. Parent epic (#60 Success Criteria Validation) superseded — v0.1 vertical slice validation criteria no longer relevant.', 'cancelled', 'high', NULL, NULL, NULL, '2026-02-10 23:26:12', '2026-02-10 23:26:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-202', 'story', 'T-61', 'ECS state inspection', 'Query world state from tests. Component dumps, entity listings. Assert on simulation state.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:26:24', '2026-02-10 23:26:24', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-203', 'story', 'T-61', 'Behavior validation framework', 'Scenario setup, behavior triggers, outcome assertions. NPC routine tests, perception tests, tier transition tests.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:26:24', '2026-02-10 23:26:24', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-204', 'story', 'T-61', 'Performance benchmarks', 'Tick performance, eviction performance, reactivation performance. Track regressions. Budget enforcement.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:26:24', '2026-02-10 23:26:24', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-207', 'story', 'T-62', 'Input simulation', 'Programmatic input injection. Simulate keypresses, mouse movement, actions. UI interaction tests.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:26:33', '2026-02-10 23:26:33', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-208', 'story', 'T-62', 'Rendering verification', 'Screenshot comparison, fog state validation, sprite positioning. Visual regression tests.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:26:33', '2026-02-10 23:26:33', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-209', 'story', 'T-62', 'UI validation framework', 'HUD element tests, dialogue display, minimap correctness. UI component testing.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:26:33', '2026-02-10 23:26:33', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-210', 'story', 'T-63', 'IPC protocol tests', 'Verify MessagePack serialization/deserialization. Protocol versioning. Message framing correctness.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:26:53', '2026-02-10 23:26:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-211', 'story', 'T-63', 'Sync verification tests', 'Client-server state consistency. Desync detection. Recovery validation.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:26:53', '2026-02-10 23:26:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-212', 'story', 'T-63', 'Full playthrough automation', 'Scripted playthrough sequences. End-to-end scenario tests. Regression detection.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:26:53', '2026-02-10 23:26:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-213', 'story', 'T-63', 'Performance profiling', 'IPC latency measurement, serialization overhead, tick budget enforcement. Cross-boundary profiling.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:26:53', '2026-02-10 23:26:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-214', 'story', 'T-64', 'Refinement discussion - Multi-agent', 'NEEDS REFINEMENT. Jeroen + Tyre + Gestalt + Hoshe + Troblum. Determine optimal testing approach for Claude Code. External vs integrated, patterns, constraints.', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-10 23:27:10', '2026-02-10 23:27:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-215', 'story', 'T-64', 'Testing pattern documentation', 'Document agreed patterns. Test organization conventions, naming, structure. Developer guide.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:27:10', '2026-02-10 23:27:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-216', 'story', 'T-64', 'Tooling requirements spec', 'Define required tooling: test runners, assertion libraries, mocking frameworks. Installation/setup docs.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:27:10', '2026-02-10 23:27:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-217', 'story', 'T-64', 'Production code constraints', 'Define rules: what test hooks are acceptable in production code, what must stay external. Pollution boundaries.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:27:10', '2026-02-10 23:27:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-201', 'story', 'T-61', 'Deterministic replay system', 'Record input sequences, replay exactly. Verify identical outcomes. Debugging tool.', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-10 23:26:24', '2026-02-11 00:00:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-233', 'epic', 'T-29', 'Movement & Collision', 'Tile collision, pathfinding, NPC movement, and game clock systems. Hard blockers identified in v0.1 gap analysis workshop. Without these, NPCs cannot physically navigate the station.', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-11 00:00:57', '2026-02-11 00:00:57', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-234', 'epic', 'T-30', 'Observation & Interaction', 'Unified observation pipeline and player interaction systems. The experience layer that connects perception, knowledge, and monologue into the core gameplay loop. Identified as the missing spine in gap analysis workshop.', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-11 00:01:05', '2026-02-11 00:01:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-235', 'epic', 'T-28', 'Game State Management', 'Save/load, session management, and game state serialization systems. Required for playable v0.1 sessions.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-11 00:01:13', '2026-02-11 00:01:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-245', 'story', 'T-234', 'Wait/time-skip mechanic', 'Player can wait in place, advancing game time at accelerated rate. Useful for staking out locations and waiting for NPC schedule changes. Deferred observation verb — lower priority than follow/examine. Source: Gestalt R2 M-1.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-11 00:02:14', '2026-02-11 00:02:14', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-265', 'story', 'T-60', 'Demo scenario specification', '2-minute showcase scenario design. The split-screen demo moment: same world, two characters, different realities. Defines what to show to sell the concept. Source: Ozzie R1+R2 M-8. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. Parent epic (#60 Success Criteria Validation) superseded — v0.1 vertical slice validation criteria no longer relevant.', 'cancelled', 'medium', NULL, NULL, NULL, '2026-02-11 00:04:33', '2026-02-11 00:04:33', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-266', 'story', 'T-60', 'Same-character-different-seed validation test', 'Automated test: compare two smuggler playthroughs with different seeds. If not measurably different, seed variation has failed. Validates #178 seed-based variation. Source: Nigel R2 M-10. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. Parent epic (#60 Success Criteria Validation) superseded — v0.1 vertical slice validation criteria no longer relevant.', 'cancelled', 'medium', NULL, NULL, NULL, '2026-02-11 00:04:33', '2026-02-11 00:04:33', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-267', 'story', 'T-60', 'Playtest protocol definition', 'Structured form for D-027 success criteria evaluation. Who tests, how, what feedback is captured. Defines done for v0.1 beyond the four success criteria. Source: Hoshe R1 M-11. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. Parent epic (#60 Success Criteria Validation) superseded — v0.1 vertical slice validation criteria no longer relevant.', 'cancelled', 'medium', NULL, NULL, NULL, '2026-02-11 00:04:33', '2026-02-11 00:04:33', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-268', 'story', 'T-56', 'False positive NPC design', 'Unentangled NPCs with suspicious-looking-but-innocent routines. Essential anti-metagaming. Player who learned late-night meetings = suspicious gets burned when its just a romance in another seed. Source: Nigel R1+R2 M-9, endorsed by Gestalt.', 'cancelled', 'medium', NULL, NULL, NULL, '2026-02-11 00:04:39', '2026-02-11 00:04:39', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-273', 'story', 'T-64', 'Test output formatter CLI', 'Normalize cargo-nextest and gdUnit4 output into consistent JSON schema (suite, total, passed, failed, failures array). Low priority — gdUnit4 already outputs JSON natively. Source: Hoshe R1 T-3.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-11 00:05:00', '2026-02-11 00:05:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-276', 'epic', 'T-275', 'Server Boilerplate (Rust/bevy_ecs)', 'Initialize the Rust simulation server: Cargo project, module structure, core ECS types, plugin scaffolding, deterministic simulation resources, and test infrastructure. Must pass make ci-server when complete.', 'done', 'critical', 'dudley', NULL, 'D-020', '2026-02-11 11:56:08', '2026-02-11 15:53:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-278', 'story', 'T-276', 'Initialize Cargo project with dependencies', 'Create server/Cargo.toml with workspace setup. Dependencies: bevy_ecs (standalone, no renderer), serde + serde_derive, rmp-serde (MessagePack for client communication per D-020), bincode (reserved for future server-to-server sync). Dev dependencies: cargo-nextest. Set up src/main.rs and src/lib.rs entry points.', 'done', 'high', 'dudley', NULL, 'D-020', '2026-02-11 11:56:32', '2026-02-11 15:53:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-279', 'story', 'T-276', 'Create server module structure', 'Create Rust module hierarchy: simulation (tick loop, systems), perception (observer queries, information boundaries), bridge (SimBridge trait, LocalBridge, NetworkBridge stubs), input (PlayerInput types, InputQueue), time (SimulationTime, day phases per D-031), storyteller (placeholder module). Each module gets a mod.rs with public API stubs.', 'done', 'high', 'dudley', NULL, 'D-020', '2026-02-11 11:56:37', '2026-02-11 15:53:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-280', 'story', 'T-276', 'Define core types (ObserverSnapshot, PlayerInput, SimBridge)', 'Define the three key types that cross the client-server boundary (D-020): ObserverSnapshot (visible entities, fog state, sound events, monologue triggers, HUD widget data — variable shape per character build), PlayerInput (semantic actions: MoveNorth, Interact, UsePerceptionMode — timestamped for deterministic processing), SimBridge trait (abstracts transport, implemented by LocalBridge and NetworkBridge). All types derive Serialize/Deserialize.', 'done', 'high', 'dudley', NULL, 'D-020', '2026-02-11 11:56:44', '2026-02-11 15:53:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-281', 'story', 'T-276', 'Set up ECS plugin scaffolding', 'Create bevy_ecs App with plugin architecture. Define plugins: SimulationPlugin (tick loop, core systems), PerceptionPlugin (observer queries), BridgePlugin (communication layer), InputPlugin (input processing), TimePlugin (SimulationTime management per D-031). Each plugin registers its systems and resources. App should build and run (empty tick loop) as a standalone binary.', 'done', 'high', 'dudley', NULL, 'D-020', '2026-02-11 11:56:46', '2026-02-11 15:53:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-282', 'story', 'T-276', 'Set up deterministic simulation resources', 'Implement injectable resources required by D-010 principle 4 and D-030 sub-decision 7 (CRITICAL): SimulationTime (tick counter, game-time conversion at 10 ticks/game-minute per D-031), SimRng (seeded RNG, reproducible sequences), InputQueue (timestamped PlayerInput buffer). These resources are the ONLY sources of time, randomness, and input for the simulation. Tests inject controlled versions for deterministic replay.', 'done', 'critical', 'dudley', NULL, 'D-010', '2026-02-11 11:56:52', '2026-02-11 15:53:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-283', 'story', 'T-276', 'Create CauseChain component stub', 'Implement the CauseChain component as a production ECS component (not test-only, per D-030 sub-decision 4). CauseChain tracks information provenance: how did this NPC learn X? What caused this monologue line? Used for monologue provenance, journal entries, debugging, and test verification. Stub with basic chain operations (push cause, query chain, serialize).', 'done', 'high', 'dudley', NULL, 'D-030', '2026-02-11 11:56:55', '2026-02-11 15:53:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-284', 'story', 'T-276', 'Create simulation tier type stubs', 'Define the four simulation tier types per D-026: Active (full ECS simulation), Background (state machine with 4 machines: schedule, mood, relationships, job), StateSaved (frozen serialized struct ~1-2KB), Ungenerated (marker). Create tier component and transition interface stubs. Include scope tag types (neighborhood, active-quest, colleague, known-contact) for eviction priority.', 'done', 'medium', 'dudley', NULL, 'D-026', '2026-02-11 11:56:59', '2026-02-11 15:53:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-285', 'story', 'T-276', 'Set up server test infrastructure', 'Configure test infrastructure per D-030: Hybrid approach with #[cfg(test)] unit tests inside modules + tests/ directory for integration tests. Set up cargo-nextest as test runner. Create test utilities module with ECS World builders for common test scenarios. Ensure JSON summary output format. Create first smoke test that builds the App with all plugins and runs one tick.', 'done', 'high', 'dudley', NULL, 'D-030', '2026-02-11 11:57:03', '2026-02-11 15:53:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-286', 'task', 'T-276', 'Verify make ci-server passes', 'Final verification: run make ci-server (lint-server → build-server → test-server) and confirm green. This is the definition of done for the server boilerplate epic. Fix any issues found.', 'done', 'high', 'dudley', NULL, NULL, '2026-02-11 11:57:07', '2026-02-11 15:53:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-18', 'story', NULL, 'Game engine selection', NULL, 'done', 'critical', NULL, NULL, 'Q-001', '2026-02-09 15:21:44', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-35', 'epic', 'T-28', 'Rust Simulation Server Foundation', 'Standalone Rust binary with bevy_ecs. No Godot dependencies. Basic ECS world, entity management, deterministic tick system.', 'done', 'critical', NULL, NULL, 'D-020', '2026-02-10 23:15:13', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-36', 'epic', 'T-28', 'Godot Client Foundation', 'Pure rendering client in Godot 4/GDScript. Receives ObserverSnapshot, renders tiles/sprites/fog, captures input. No game logic.', 'done', 'critical', NULL, NULL, 'D-020', '2026-02-10 23:15:13', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-275', 'initiative', NULL, 'Boilerplate Code Organization', 'Set up foundational project scaffolding for client (Godot 4) and server (Rust/bevy_ecs). Blocks all vertical slice implementation (D-027). Both client/ and server/ directories are currently empty — this initiative establishes the build targets, module structure, core type stubs, and test infrastructure that all subsequent work depends on.', 'done', 'critical', NULL, NULL, 'D-020', '2026-02-11 11:55:51', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-277', 'epic', 'T-275', 'Client Boilerplate (Godot 4)', 'Initialize the Godot 4 client: project.godot, directory structure, autoloads, main scene, SimBridge stub, input system, rendering stubs, UI shell, and test infrastructure. Must pass make ci-client when complete.', 'done', 'critical', 'stig', NULL, 'D-020', '2026-02-11 11:56:22', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-287', 'story', 'T-277', 'Initialize Godot 4 project with project.godot', 'Create client/project.godot with project settings. Set up GDScript as primary language. Configure project name, window size, rendering settings for 2D top-down. Set minimum Godot version. Create .gdignore for build artifacts.', 'done', 'high', 'stig', NULL, 'D-020', '2026-02-11 11:57:20', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-288', 'story', 'T-277', 'Create client directory structure', 'Set up Godot project directories: scenes/ (game scenes), scripts/ (GDScript files organized by system), assets/ (sprites, tilesets, audio — placeholder), ui/ (UI scenes and scripts), tests/ (gdUnit4 test files). Follow Godot conventions for autoload, resource, and scene organization.', 'done', 'high', 'stig', NULL, 'D-020', '2026-02-11 11:57:24', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-289', 'story', 'T-277', 'Set up autoloads (SimBridge, GameState, InputMapper)', 'Create and register Godot autoload singletons: SimBridge (client-side bridge to Rust simulation — manages connection, sends PlayerInput, receives ObserverSnapshot), GameState (client-side game state derived from snapshots), InputMapper (maps raw input events to semantic PlayerInput actions per D-020). Register in project.godot.', 'done', 'high', 'stig', NULL, 'D-020', '2026-02-11 11:57:26', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-290', 'story', 'T-277', 'Create main scene tree structure', 'Build the main scene (main.tscn) with the core node hierarchy: root Game node, World node (holds TileMap, entities, fog), Camera2D (locked to player per D-016), UILayer (CanvasLayer for HUD elements), AudioManager node. Scene should load and display an empty world without errors.', 'done', 'high', 'stig', NULL, 'D-020', '2026-02-11 11:57:31', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-291', 'story', 'T-277', 'Implement SimBridge client stub (MessagePack)', 'Implement the client-side SimBridge autoload: connect to Rust simulation process via MessagePack over local socket (D-020). Stub methods: connect(), disconnect(), send_input(PlayerInput), poll_snapshot() -> ObserverSnapshot. Use hardcoded test data initially — actual connection to Rust binary comes later. Include connection state management (disconnected, connecting, connected, error).', 'done', 'high', 'stig', NULL, 'D-020', '2026-02-11 11:57:36', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-292', 'story', 'T-277', 'Create input system stub (semantic PlayerInput)', 'Implement InputMapper autoload: maps Godot InputEvents to semantic PlayerInput actions (MoveNorth/South/East/West, Interact, UsePerceptionMode, OpenMenu, etc.). Actions are timestamped per D-010 principle 4. Input is captured and queued, sent to SimBridge each frame. No raw key codes cross the bridge — only semantic actions.', 'done', 'high', 'stig', NULL, 'D-010', '2026-02-11 11:57:38', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-293', 'story', 'T-277', 'Create rendering stubs (TileMap, fog overlay, entity sprites)', 'Set up rendering infrastructure: TileMap node for world tiles (placeholder tileset), fog-of-war overlay (shader or TileMap layer — implements visual side of perception system D-011), entity sprite nodes (positioned from ObserverSnapshot data). All rendering is driven by snapshot data — no game logic. Placeholder art is fine.', 'done', 'medium', 'stig', NULL, 'D-020', '2026-02-11 11:57:41', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-294', 'story', 'T-277', 'Create UI shell stubs (HUD, minimap, monologue display)', 'Create UI CanvasLayer with stub scenes: HUD (health, perception mode indicator, time display per D-031), minimap (placeholder), internal monologue display (text panel for monologue lines per D-015). All UI elements are data-driven from ObserverSnapshot HUD widget data. Variable shape supports perception mode customization (D-017). Shell only — no logic.', 'done', 'medium', 'stig', NULL, 'D-020', '2026-02-11 11:57:43', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-295', 'story', 'T-277', 'Set up gdUnit4 test infrastructure', 'Install and configure gdUnit4 test framework per D-030 sub-decision 2. Set up test directory structure, configure headless test runner (GdUnitCmdTool), create first smoke test (main scene loads without errors). Ensure JSON summary output format. Configure GdUnitSceneRunner for scene lifecycle tests.', 'done', 'high', 'stig', NULL, 'D-030', '2026-02-11 11:57:46', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-296', 'task', 'T-277', 'Verify make ci-client passes', 'Final verification: run make ci-client (lint-client → build-client → test-client) and confirm green. This is the definition of done for the client boilerplate epic. Fix any issues found.', 'done', 'high', 'stig', NULL, NULL, '2026-02-11 11:57:49', '2026-02-11 17:37:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-65', 'story', 'T-35', 'Project structure setup', 'Create simulation/ directory with Cargo workspace. Set up bevy_ecs dependency, basic project structure.', 'done', 'critical', NULL, NULL, NULL, '2026-02-10 23:17:59', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-66', 'story', 'T-35', 'ECS world initialization', 'Basic World setup, resource management, entity spawning/despawning infrastructure.', 'done', 'critical', NULL, NULL, NULL, '2026-02-10 23:17:59', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-67', 'story', 'T-35', 'Deterministic tick system', 'Timestamped action queue, fixed timestep simulation loop, input event processing order.', 'done', 'critical', NULL, NULL, NULL, '2026-02-10 23:17:59', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-68', 'story', 'T-35', 'Basic entity components', 'Position, Facing, EntityType, ObserverId. Foundation components for all entities.', 'done', 'critical', NULL, NULL, NULL, '2026-02-10 23:17:59', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-70', 'story', 'T-36', 'Godot project initialization', 'Create client/ directory with Godot 4 project. Scene structure, basic camera setup.', 'done', 'critical', NULL, NULL, NULL, '2026-02-10 23:18:12', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-218', 'task', 'T-65', 'Create simulation/ directory structure', 'mkdir -p simulation/src, simulation/tests. Create subdirs: core, ecs, protocol, io.', 'done', 'critical', 'Tyre', NULL, NULL, '2026-02-10 23:27:28', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-219', 'task', 'T-65', 'Initialize Cargo workspace', 'Cargo.toml with workspace members. Set edition, dependencies: bevy_ecs, serde, rmp-serde.', 'done', 'critical', 'Tyre', NULL, NULL, '2026-02-10 23:27:28', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-220', 'task', 'T-65', 'Configure project metadata', 'Set name, version, authors. Configure build options, target.', 'done', 'critical', 'Tyre', NULL, NULL, '2026-02-10 23:27:28', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-221', 'task', 'T-65', 'Create main.rs entry point', 'Basic main() function. Logging setup. Argument parsing stub.', 'done', 'critical', 'Tyre', NULL, NULL, '2026-02-10 23:27:28', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-222', 'task', 'T-65', 'Set up CI placeholder', '.github/workflows or .gitignore for build artifacts. Prepare for future CI.', 'done', 'low', 'Tyre', NULL, NULL, '2026-02-10 23:27:28', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-223', 'task', 'T-70', 'Create client/ directory structure', 'mkdir -p client/scenes, client/scripts, client/assets. Godot project organization.', 'done', 'critical', 'Stig', NULL, NULL, '2026-02-10 23:27:37', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-224', 'task', 'T-70', 'Initialize Godot 4 project', 'project.godot file. Configure renderer, window settings, input map.', 'done', 'critical', 'Stig', NULL, NULL, '2026-02-10 23:27:37', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-225', 'task', 'T-70', 'Create main scene hierarchy', 'Main.tscn with World, Camera2D, HUD, UICanvas nodes. Basic scene structure.', 'done', 'critical', 'Stig', NULL, NULL, '2026-02-10 23:27:37', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-226', 'task', 'T-70', 'Configure camera settings', 'Camera2D with custom_viewport. Zoom levels, smoothing disabled initially.', 'done', 'critical', 'Stig', NULL, NULL, '2026-02-10 23:27:37', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-227', 'task', 'T-70', 'Set up project settings', 'Display settings, physics tick rate, input dead zones. Project configuration.', 'done', 'high', 'Stig', NULL, NULL, '2026-02-10 23:27:37', '2026-02-11 17:38:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-75', 'story', 'T-37', 'Protocol message definitions', 'Define ObserverSnapshot and PlayerInput structures. Create protocol/ directory with shared schemas.', 'done', 'critical', NULL, NULL, NULL, '2026-02-10 23:18:24', '2026-02-11 17:38:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-76', 'story', 'T-37', 'MessagePack serialization - Rust', 'Add rmp-serde dependency. Implement serialize/deserialize for protocol messages.', 'done', 'critical', NULL, NULL, NULL, '2026-02-10 23:18:24', '2026-02-11 17:38:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-228', 'task', 'T-75', 'Create protocol/ directory', 'mkdir protocol. Shared schema definitions accessible to both Rust and GDScript docs.', 'done', 'critical', 'Dudley', NULL, NULL, '2026-02-10 23:27:49', '2026-02-11 17:38:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-229', 'task', 'T-75', 'Define ObserverSnapshot structure', 'Document structure: visible_entities (id, pos, sprite_id), fog_state (tile visibility), sound_events, monologue_text, hud_data.', 'done', 'critical', 'Dudley', NULL, NULL, '2026-02-10 23:27:49', '2026-02-11 17:38:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-230', 'task', 'T-75', 'Define PlayerInput structure', 'Document structure: timestamp, action_type (enum: Move, Interact, UseMode, etc), action_data (direction, target_id, etc).', 'done', 'critical', 'Dudley', NULL, NULL, '2026-02-10 23:27:49', '2026-02-11 17:38:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-231', 'task', 'T-75', 'Define entity data structures', 'EntitySnapshot: id, position, entity_type, sprite_id, facing. Supporting structs.', 'done', 'critical', 'Dudley', NULL, NULL, '2026-02-10 23:27:49', '2026-02-11 17:38:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-37', 'epic', 'T-28', 'IPC Bridge & Protocol', 'MessagePack-based communication layer. ObserverSnapshot (server→client), PlayerInput (client→server). LocalBridge for subprocess, NetworkBridge for TCP.', 'done', 'critical', NULL, NULL, 'D-020', '2026-02-10 23:15:13', '2026-02-11 17:38:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-77', 'story', 'T-37', 'MessagePack serialization - GDScript', 'Integrate MessagePack library for Godot. Implement encode/decode for protocol messages.', 'done', 'critical', 'client', NULL, NULL, '2026-02-10 23:18:24', '2026-02-11 19:40:08', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-347', 'task', 'T-40', 'Document tier transition performance budgets', 'Document performance budgets for tier transitions:\n- Active → Background: <1 tick\n- Background → State-saved: <1 tick\n- State-saved → Active: <5ms\n\nAdd as commented-out benchmark tests. Enable when tier system is implemented.\n\nEffort: XS\nCodebase: docs + server\nSource: Architecture Review Audit 2026-02-11\nSprint: 2+', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-11 20:27:30', '2026-02-11 20:27:30', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-349', 'task', 'T-63', 'Timing assertions in integration tests', 'Add tick_completes_within_budget() integration test asserting <100ms tick time at 80 NPCs (20 Active + 60 Background). Regression test against performance degradation.\n\nEffort: S\nCodebase: server\nSource: Architecture Review Audit 2026-02-11\nSprint: 2+', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-11 20:27:41', '2026-02-11 20:27:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-350', 'story', 'T-38', 'Crash reporting infrastructure', 'Crash reporting infrastructure for both codebases:\n- Rust panic handler writes crash.log with backtrace\n- Godot push_error captures client crashes\n- Include version, platform, last 100 log lines\n- Needed before external playtesting\n\nEffort: M\nCodebase: server + client\nSource: Architecture Review Audit 2026-02-11\nSprint: 2+ (before vertical slice playtest)', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-11 20:27:45', '2026-02-11 20:27:45', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-351', 'epic', NULL, 'Workshop: Knowledge Graph & Information Boundaries', 'Design workshop for KnowledgeGraph component to replace Vec placeholder. + +Scope: +- Graph structure (nodes, edges, timestamps, certainty) +- Information boundaries (what NPCs know vs do not know) +- Propagation rules (gossip, observation, inference) +- Query interface for dialogue/behavior systems +- Memory limits and forgetting mechanics + +Pillar-1 mechanic. CRITICAL priority. +Sprint 2 blocker. + +Participants: Tyre (lead), Morve, Dudley, SI +Source: Architecture Review Audit 2026-02-11', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-11 20:27:52', '2026-02-11 20:27:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-352', 'epic', NULL, 'Workshop: Observer Snapshot Generation Pipeline', 'Design workshop for perception query algorithm that generates ObserverSnapshot. + +Pipeline stages: +1. Spatial query (entities in range) +2. Line-of-sight filtering +3. Sound propagation +4. Knowledge graph integration +5. Snapshot assembly + +CRITICAL priority. Sprint 2 blocker. +Depends on Workshop 1 (Knowledge Graph). + +Participants: Tyre (lead), Morve, Dudley, SI +Source: Architecture Review Audit 2026-02-11', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-11 20:28:05', '2026-02-11 20:28:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-353', 'epic', NULL, 'Workshop: NPC AI State Machines', 'Design workshop for Background-tier NPC behavior systems. + +Four state machines to specify: +1. Schedule FSM (work, home, social, sleep) +2. Mood FSM (calm, stressed, suspicious, friendly) +3. Relationship FSM (stranger, acquaintance, friend, enemy) +4. Job FSM (idle, working, break, commute) + +Define: states, transitions, day phase integration, tick budget. + +HIGH priority. Sprint 3 target. + +Participants: Tyre (lead), Morve, Mellanie, SI +Source: Architecture Review Audit 2026-02-11', 'cancelled', 'high', NULL, NULL, NULL, '2026-02-11 20:28:10', '2026-02-11 20:28:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-354', 'epic', NULL, 'Workshop: Save/Load Architecture', 'Design workshop for save/load system architecture. + +Key decisions: +- Custom SaveState struct vs bevy_reflect +- Version number scheme and migration strategy +- Relationship to tier system (serialize by tier?) +- Incremental saves vs full snapshots +- Quick save vs named saves + +MEDIUM priority. Must be resolved before vertical slice. + +Participants: Dudley (lead), Tyre, Morve, SI +Source: Architecture Review Audit 2026-02-11', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-11 20:28:16', '2026-02-11 20:28:16', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-355', 'epic', NULL, 'Workshop: Map Authoring Pipeline', 'Design workshop for map authoring toolchain and format. + +Key decisions: +- Tool selection: Tiled vs Godot TileMap vs YAML +- Map format (JSON, TMX, custom?) +- Collision layer specification +- Entity spawn points +- Loader implementation (server + client) +- Hot reload support for iteration + +MEDIUM priority. Sprint 2-3 target. + +Participants: Morve (lead), Tyre, Dudley, SI +Source: Architecture Review Audit 2026-02-11', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-11 20:28:22', '2026-02-11 20:28:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-79', 'story', 'T-37', 'LocalBridge implementation - GDScript', 'Subprocess spawn, socket connection, message send/receive, reconnection logic.', 'done', 'critical', 'client', NULL, NULL, '2026-02-10 23:18:24', '2026-02-11 20:29:30', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-82', 'story', 'T-38', 'Tick loop synchronization', 'Client sends input, server processes tick, server sends snapshot, client renders. Basic game loop.', 'done', 'critical', 'joint', NULL, NULL, '2026-02-10 23:18:35', '2026-02-11 20:29:30', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-83', 'story', 'T-38', 'Moving character proof', 'Player presses arrow key → Godot sends MoveNorth → Rust updates position → Godot receives snapshot → sprite moves. First gameplay.', 'done', 'critical', 'joint', NULL, NULL, '2026-02-10 23:18:35', '2026-02-11 20:29:30', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-78', 'story', 'T-37', 'LocalBridge implementation - Rust', 'Subprocess management, Unix socket (Linux) or localhost TCP, message framing, error handling.', 'done', 'critical', 'server', NULL, NULL, '2026-02-10 23:18:24', '2026-02-11 20:30:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-81', 'story', 'T-38', 'End-to-end connection test', 'Godot spawns Rust process, establishes connection, sends ping, receives pong. Basic handshake.', 'done', 'critical', 'joint', NULL, NULL, '2026-02-10 23:18:35', '2026-02-11 20:31:07', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-236', 'story', 'T-233', 'Tile collision system', 'Walkability map and movement validation. Each tile has walkable/blocked flag. Movement system checks can_move_to(tile) before allowing position change. Blocks all NPC and player movement. Source: Tyre R1, Gestalt R2 C-1.', 'done', 'critical', 'server', NULL, NULL, '2026-02-11 00:01:39', '2026-02-11 21:05:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1', 'initiative', NULL, 'Custom game, not a mod', NULL, 'done', 'medium', NULL, NULL, 'D-001', '2026-02-09 15:21:44', '2026-02-11 21:59:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-84', 'story', 'T-38', 'Multiple entity sync', 'Add 2-3 NPCs to simulation. Verify all entities render correctly on client from snapshot data.', 'done', 'medium', NULL, NULL, NULL, '2026-02-10 23:18:35', '2026-02-11 21:59:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-86', 'story', 'T-39', 'Core NPC components', 'NPCProfile component with Want, Secret, ToleranceThreshold, Contentment. Entity spawning with profiles.', 'done', 'medium', NULL, NULL, NULL, '2026-02-10 23:18:49', '2026-02-11 21:59:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-87', 'story', 'T-39', 'Relationship system', 'RelationshipGraph resource. Per-NPC relationship slots (3 key relationships). Relationship metadata (trust, history, type).', 'done', 'medium', NULL, NULL, NULL, '2026-02-10 23:18:49', '2026-02-11 21:59:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-88', 'story', 'T-39', 'Daily routine system', 'DailyRoutine component. Location schedule, activity states, time-based transitions.', 'done', 'medium', NULL, NULL, NULL, '2026-02-10 23:18:49', '2026-02-11 21:59:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-237', 'story', 'T-233', 'Tile-based A* pathfinding', 'A* pathfinding over walkability map using pathfinding crate. NPCs request paths between positions; system returns tile sequences. Blocks routine execution (#101). Source: Tyre R1, Gestalt R2 C-2a.', 'done', 'medium', NULL, NULL, NULL, '2026-02-11 00:01:39', '2026-02-11 21:59:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-238', 'story', 'T-233', 'NPC path following and movement', 'Per-tick NPC position updates along computed paths. Smooth interpolation between tiles. Separate from pathfinding — this is the movement execution system. Source: Tyre R1, Gestalt R2 C-2b.', 'done', 'medium', NULL, NULL, NULL, '2026-02-11 00:01:40', '2026-02-11 21:59:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-239', 'story', 'T-234', 'Observation event generator', 'The unified observation pipeline: compares ObserverSnapshot against character knowledge to generate ObservationEvents. Trigger types: routine deviation, absence detection, social anomaly, new information, contradiction. Character-specific — same NPC behavior generates different events for smuggler vs detective. The mechanical heart of the game per Gestalt R2 C-4. Absorbs: Ozzie observation event pipeline, routine deviation detection; Paula absence detection, knowledge-aware monologue integration; Gestalt NPC off-routine behavior.', 'done', 'medium', NULL, NULL, NULL, '2026-02-11 00:01:50', '2026-02-11 21:59:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-240', 'story', 'T-234', 'Player interaction system and dispatcher', 'Decomposed into #421 (ObjectType + verb sets) and #422 (Two-phase verb KG filter) from Control & Interaction workshop (D-057). Original: general dispatcher routing Interact input to subsystems.', 'done', 'medium', NULL, NULL, NULL, '2026-02-11 00:01:51', '2026-02-11 21:59:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-341', 'task', 'T-38', 'Basic IPC error handling implementation', 'Define minimal error handling for IPC bridge:\n- Deserialization failure: log error + dump raw bytes + show user-facing message\n- Server crash: detect SIGCHLD + display error dialog with last log lines\n- Pipe break: clean shutdown both processes\n\nEffort: S\nCodebase: server + client\nSource: Architecture Review Audit 2026-02-11\nSprint: 1', 'done', 'medium', NULL, NULL, NULL, '2026-02-11 20:26:52', '2026-02-11 21:59:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-89', 'story', 'T-39', 'Information inventory', 'KnowledgeBase component. What NPC knows (facts, secrets, locations). Discovery and sharing mechanics.', 'cancelled', 'high', NULL, NULL, NULL, '2026-02-10 23:18:49', '2026-02-11 22:15:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-269', 'story', 'T-49', 'CauseChain component', 'Information provenance tracking: every piece of new information tracks HOW it was learned. Chain traces through perception events (VisualObservation, AudioObservation, DialogueReveal) and flags scripted reveals. Production feature serving monologue integration, knowledge journal, debugging, and criterion 4 validation. Source: Hoshe R1, endorsed by Tyre R2, Gestalt, Paula, Ozzie, Gore.', 'done', 'high', NULL, NULL, NULL, '2026-02-11 00:04:43', '2026-02-11 22:15:14', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-140', 'story', 'T-351', 'Entity visibility filtering', 'ObserverSnapshot only includes entities/components visible to requesting observer. Privacy enforcement.', 'cancelled', 'critical', NULL, NULL, NULL, '2026-02-10 23:21:35', '2026-02-11 22:17:51', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-116', 'story', 'T-44', 'Camera lock to character', 'Camera follows player character position. No panning. Fixed viewport.', 'done', 'critical', 'client', NULL, NULL, '2026-02-10 23:20:20', '2026-02-11 22:32:39', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-129', 'story', 'T-47', 'Tile rendering engine', 'Multi-layer tilemap. Floor, walls, ceiling, objects. Z-level visualization (overlay or switching).', 'done', 'critical', 'client', NULL, NULL, '2026-02-10 23:21:12', '2026-02-11 22:38:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-131', 'story', 'T-47', 'Fog overlay rendering', 'Darkened tiles for fog. Gradient for fog edges. Visibility state per tile.', 'done', 'critical', 'client', NULL, NULL, '2026-02-10 23:21:12', '2026-02-11 22:43:57', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-358', 'task', 'T-38', 'Design ObserverSnapshot v2 schema', 'Expand ObserverSnapshot: add visible_tiles, player_facing, game_time fields. Contract needed before #112, #113, #25 integration.', 'done', 'critical', 'joint', NULL, 'D-020', '2026-02-11 21:20:58', '2026-02-11 23:10:16', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-25', 'story', 'T-233', 'Game clock and day-phase system', NULL, 'done', 'high', 'server', NULL, 'Q-009', '2026-02-09 15:21:44', '2026-02-11 23:10:24', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-359', 'task', 'T-43', 'Resolve Q-018: shadowcasting algorithm selection', 'Benchmark symmetric (Albert Ford) vs recursive shadowcasting at 150x150 scale. Output: decision in decisions/perception.md or questions.md.', 'done', 'critical', 'server', NULL, 'Q-018', '2026-02-11 21:21:10', '2026-02-11 23:11:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-110', 'story', 'T-43', 'Shadowcasting algorithm - server', 'Implement LOS calculation per z-level. Raycasting or shadowcasting. Wall occlusion. Vision range.', 'done', 'critical', 'server', NULL, NULL, '2026-02-10 23:19:52', '2026-02-11 23:13:42', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-111', 'story', 'T-43', 'Vision cone implementation', 'Forward/peripheral/behind sectors. Directional LOS quality. Range reduction for peripheral vision.', 'done', 'critical', 'server', NULL, NULL, '2026-02-10 23:19:52', '2026-02-11 23:15:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-112', 'story', 'T-43', 'Observer visibility query', 'Given observer entity, return visible entities and tiles. Respects information boundaries. Feeds ObserverSnapshot.', 'done', 'critical', 'server', NULL, NULL, '2026-02-10 23:19:52', '2026-02-11 23:19:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-356', 'story', 'T-38', 'Fog data through bridge', 'Integration: server sends visibility-filtered ObserverSnapshot, client consumes fog data. Both sides must agree on the expanded snapshot schema.', 'done', 'critical', 'joint', NULL, NULL, '2026-02-11 21:20:32', '2026-02-11 23:35:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-113', 'story', 'T-43', 'Fog rendering - client', 'Render fog overlay in Godot. Reveal explored tiles, hide unexplored. Fog returns on departure (time-based decay).', 'done', 'critical', 'client', NULL, NULL, '2026-02-10 23:19:52', '2026-02-11 23:37:04', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-361', 'story', 'T-351', 'Implement KnowledgeGraph component + types (D-041)', 'Full KnowledgeGraph component with BTreeMap and BTreeMap. Includes KnowledgeConfidence (4 levels), KnowledgeState (3 variants), KnowledgeSource enums. All types per D-041 synthesis Part 3. Sprint 2 uses DirectObservation and Background sources only. Estimate: 1 day.', 'done', 'critical', NULL, 'server', NULL, '2026-02-11 22:14:28', '2026-02-11 23:48:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-362', 'story', 'T-351', 'StableEntityId component + EntityRegistry resource', 'StableEntityId component and EntityRegistry resource for bidirectional StableId <-> Entity mapping. Assigns stable IDs at spawn, survives save/load. Partially resolves Q-019. Estimate: 1 day.', 'done', 'critical', NULL, 'server', NULL, '2026-02-11 22:14:29', '2026-02-11 23:48:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-363', 'story', 'T-351', 'KnowledgeEventQueue + processing system', 'Event-driven knowledge updates. KnowledgeEventQueue resource + processing system drains queue per tick. Decouples perception from knowledge writes. Estimate: 0.5 day.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 22:14:30', '2026-02-11 23:48:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-364', 'story', 'T-351', 'Direct observation knowledge flow', 'Perception system calls observe_entity() when entity in LOS, observe_entity_leaving_los() when exits. Sets Direct confidence, downgrades to KnowsDetails on departure. Estimate: 0.5 day.', 'done', 'critical', NULL, 'server', NULL, '2026-02-11 22:14:31', '2026-02-11 23:48:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-365', 'story', 'T-351', 'Basic knowledge decay system', 'Knowledge decay pass once per game-minute (every 10 ticks per D-031). Configurable via DecayThresholds resource. Downgrades confidence based on tick age. Does not generate Stale state yet (Sprint 3). Estimate: 0.5 day.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 22:14:32', '2026-02-11 23:48:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-367', 'task', 'T-351', 'Knowledge graph unit test suite', 'Unit tests for CRUD operations, decay mechanics, confidence ordering, serialization roundtrip, relationship state transitions. Estimate: 1 day.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 22:14:34', '2026-02-11 23:48:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-130', 'story', 'T-47', 'Entity sprite management', 'Character sprites, NPC sprites. Animation states (idle, walk, interact). Sprite facing direction.', 'done', 'critical', 'client', NULL, NULL, '2026-02-10 23:21:12', '2026-02-12 00:16:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-360', 'task', 'T-38', 'Resolve Q-019: entity ID stability', 'Define how entity_id (u64) maps to bevy Entity across ticks. Affects client entity lifecycle and sprite management.', 'done', 'high', 'joint', NULL, 'Q-019', '2026-02-11 21:21:22', '2026-02-12 00:16:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-366', 'task', 'T-351', 'Observer snapshot knowledge integration', 'Observer visibility query (#112) reads KnowledgeGraph to: 1) overlay relationship color on visible entities, 2) include remembered (not visible) entities in snapshot. Implements interface from D-041 Part 5. Estimate: 1 day.', 'done', 'critical', NULL, 'joint', NULL, '2026-02-11 22:14:33', '2026-02-12 00:28:37', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-373', 'task', 'T-369', 'Add smuggler-perspective FactId progression text', 'Add smuggler-path text for all FactIds where smuggler starts at KnowsDetails or has different knowledge path than detective.', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 15:13:01', '2026-02-12 15:14:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-378', 'task', 'T-369', 'Create environmental text examples file', 'Create wiki/authoring/environmental-text-examples.md. 4 text types: bar menu, safety notice, news ticker cycle, corridor graffiti. Krenn-voiced with cultural notes + monologue pairings (smuggler + detective). Needed for wow moment #1 (Arrival).', 'done', 'medium', NULL, 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 15:14:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-379', 'story', 'T-369', 'NPC Authoring Style Guide', 'Combined document: tier templates (Paula), authoring rules (Mellanie conventions, Gestalt constraints, Ozzie anchor line), regional culture (Miri), content pipeline (Tyre). Reframed as generator specification -- this IS the NPC generator input format. Most complex ticket; many blockers.', 'done', 'critical', 'paula', 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 15:14:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-383', 'story', 'T-369', 'NPC-format briefs for both PCs — Concept A v0.1', 'When you play the smuggler, the detective exists as an NPC (and vice versa). NPC-mode behavior scripts (5-7 routine entries each), reverse dual-lens notes, observation monologue for PC seeing other-PC-as-NPC (3-5 lines per character). ~20-30 authored items total.', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 15:14:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-387', 'task', 'T-369', 'Create global/enums/ YAML files from D-035', 'Populate enums: situations (13), topics (9), moods (8), triggers (9), access-tiers (5), activities (new -- from Gestalt routine format + Miri cultural patterns).', 'done', 'medium', NULL, 'server', NULL, '2026-02-12 15:13:02', '2026-02-12 15:14:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-388', 'task', 'T-369', 'Create global/knowledge/entity-attributes.yaml', 'Machine-readable entity attribute definitions. 16 canonical keys after A7 update (14 original, 4 new, 2 renamed). All observer->target.', 'done', 'medium', 'hoshe', 'server', NULL, '2026-02-12 15:13:02', '2026-02-12 15:14:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-389', 'task', 'T-369', 'Create pools.yaml for v0.1 seed-time selection', 'Sova single-candidate pools: friend_smuggler (kael-davan), friend_detective (sera-venn), bar_regulars, compromised_inspector, primary_contraband. Architecture supports N candidates; v0.1 has 1 each.', 'done', 'medium', 'hoshe', 'server', NULL, '2026-02-12 15:13:02', '2026-02-12 15:14:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-390', 'task', 'T-369', 'Create template YAML files with role slot definitions', '3 social sites: logistics-hub.yaml, bar.yaml, smuggling-ring.yaml. Each declares named role slots with count ranges, required flags, pool references, triangle constraints.', 'done', 'medium', 'hoshe', 'server', NULL, '2026-02-12 15:13:02', '2026-02-12 15:14:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-391', 'task', 'T-369', 'Create triangle YAML files for 5 v0.1 triangles', '5 triangles: hub-power (T1, active fork), worried-knowledge (T2, active fork), bar-tensions (T3, passive), worried-partner (T4, active fork), informant-question (T5, passive). Self-contained forks -- no cross-triangle cascade (A-17).', 'done', 'medium', 'hoshe', 'server', NULL, '2026-02-12 15:13:02', '2026-02-12 15:14:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-394', 'story', 'T-369', 'Seed configuration schema design', 'Schema for what the randomizer produces at game-start: FRIEND selections, social site population, compromised NPC, contraband type, entanglement overrides. v0.1 has single-candidate pools but architecture must support N. Saved with game state. Location: runtime/ (not content/). Constrained by D-029 ratio (30/50/20).', 'done', 'medium', 'tyre', 'server', NULL, '2026-02-12 15:13:02', '2026-02-12 15:14:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-395', 'task', 'T-369', 'News ticker headline pool', '~20 dual-lens headlines for Meridian feed at Leras bar. Mix: freight/commodity data, Assembly politics, local infrastructure, sports, Commission advisories. Each headline works as dual-lens monologue trigger.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 15:14:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-396', 'task', 'T-369', 'Apply Round 2 NPC pattern/motivation mapping', 'Apply the Round 2 finalized NPC pattern/motivation mapping (Gestalt-Paula synthesis) to wiki and content files. 17 NPCs x (pattern + motivation). Includes Harek structural role formalization (Paula Gap 7).', 'done', 'high', 'copy', 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 15:14:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-398', 'story', 'T-369', 'Wiki → YAML content conversion (Sova NPCs)', 'Convert 17 NPC wiki profiles to engine-readable YAML in content/districts/sova-transit/npcs/. Includes routine YAML layer (Paula Gap 3), triangle fork decision points (Gap 4), location smuggler detail (Gap 6). Must match schemas from C3. Tyre estimates 2-3 full days.', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 15:14:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-399', 'story', 'T-369', 'Monologue content pool — minimum viable (~200 lines)', '~100 lines per character. Categories: arrival observations, NPC routine commentary, environmental flavor, contradiction hints, idle reflections, tutorial/orientation. Follows Mellanie authoring order (FRIEND packs first, then fill to ~200).', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 15:13:03', '2026-02-12 15:14:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-401', 'story', 'T-369', 'PC-as-NPC content authoring', 'Author the actual PC-as-NPC lines: 5-7 routine entries per character, 3-5 observation monologue lines, reverse dual-lens notes. ~25 authored items (Mellanie budget). Blocked by FRIEND packs -- must know who the characters ARE before writing how they appear as NPCs.', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 15:13:03', '2026-02-12 15:14:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-403', 'task', 'T-369', 'YAML → RON converter tool', 'Build-time converter: reads content YAML, emits RON. Lives in tooling/. Runs as make target (make content-ron). Not on critical path -- engine consumes YAML in v0.1; RON is future-proofing.', 'done', 'medium', 'tyre', 'server', NULL, '2026-02-12 15:13:03', '2026-02-12 15:14:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-407', 'task', 'T-369', 'Line previewer CLI', 'CLI tool to preview monologue/dialogue line selection for a given game state. Lives in tooling/. Helps content authors test prerequisite logic without running the full game.', 'done', 'medium', 'tyre', 'server', NULL, '2026-02-12 15:13:03', '2026-02-12 15:14:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-408', 'story', 'T-369', 'YAML content loader Phase 2 — real content loading', 'Content loader Phase 2: load real content from YAML files populated by content conversion (NEW-3) and C4-C8 YAML tickets. Extends Phase 1 skeleton with actual district content, NPC profiles, dialogue/monologue pools, triangle definitions. Hot-reload support for development iteration.', 'done', 'high', 'dudley', 'server', NULL, '2026-02-12 15:13:03', '2026-02-12 15:14:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-357', 'story', 'T-38', 'Sprint 2 proof: fog of perception', 'Acceptance: (1) player moves, (2) camera follows, (3) tiles render from snapshot, (4) entities appear/disappear via LOS, (5) fog outside vision cone, (6) walls hide, (7) corners reveal.', 'done', 'critical', 'joint', NULL, NULL, '2026-02-11 21:20:44', '2026-02-12 16:14:39', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-372', 'task', 'T-369', 'Rename Hael → Naia Tamm across all wiki files', 'Phonetic collision fix (Kael/Hael). Find-and-replace across ~16 files (Paula full cascade). Triangle 4 becomes Naia-Kael-Sera. Update all relationship references, triangle diagrams, cross-references.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-12 15:13:01', '2026-02-12 16:35:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-371', 'task', 'T-369', 'Apply canonical full names to all NPC wiki pages', 'Apply Miri''s 12 full names to NPC wiki pages. Update Core Identity blocks, environmental text references (manifests, shift rosters, Commission kiosk). Names: Voss->Arvo Voss, Devra->Devra Talsen, Resha->Resha Neven, Harek->Harek Valde, Renn->Renn Harsk, Pell->Pell Torssen, Drin->Drin Rosta, Sess->Sess Kolvur, Olin->Olin Tavren, Sabel->Sabel Hersk, Tav->Tav Merik.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-12 15:13:01', '2026-02-12 16:37:40', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-375', 'task', 'T-369', 'Standardize location shortcodes in monologue-guide.md', 'Fix hub_m_ -> terminal_m_ inconsistency. Canonical shortcodes: terminal, bar, corridor. Add shortcode reference table. Add situation overlap rules and mood exclusivity rules.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 16:38:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-374', 'task', 'T-369', 'Update entity-attributes.md — smuggler role-perspective keys', 'Add 4 new role-perspective keys: risk_assessment, loyalty_assessment, position_integrity, moral_weight. Rename secret_held -> leverage_held (broader scope: secrets, debts, promises, obligations). Rename secret_confidence -> leverage_confidence. Update trust_level description to absorb trust_read scope. All keys are observer->target. Total after update: 16 canonical keys.', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 15:13:01', '2026-02-12 16:44:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-376', 'task', 'T-369', 'Stub NPC profile for Nils Davan (off-stage)', 'Minimal off-stage profile: Core Identity, relationship to Kael (siblings), role in ring (upstream pressure), known attributes by other NPCs. Referenced in 5+ NPC profiles but has no wiki page.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 16:44:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-384', 'story', 'T-369', 'Content directory structure design doc', 'Document converged structure: _meta/ + _schema/ (infrastructure, underscore prefix), global/ + districts/ (game content). Canonical_id format ({system}.{station}.{district}.{type}.{slug}). Mod-compatible directory conventions (no overlay implementation). District as atomic pack unit. Informs all content implementation.', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 16:44:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-261', 'story', 'T-59', 'Dual Lens Authoring Guide', 'BLOCKING DEPENDENCY — must exist before any content authoring begins. Content design document defining how the same world plays differently through smuggler vs detective perspective. Contents: (1) Core identity + emotional starting state per character, (2) The Dual-Lens Rule with tag implications, (3) Access tier mapping per NPC role + shift paths per character per social site, (4) Divergence escalation curve, (5) Authoring checklist (5 questions per line), (6) THE FRIEND specification section, (7) Voice signature section — speech patterns. ~12-15 pages. Owner: Paula. Source: all 6 workshop agents. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-11 00:03:37', '2026-02-12 16:54:03', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-380', 'story', 'T-369', 'THE MIRROR pattern spec', 'Define honest-character NPC pattern. No contradiction arc, no secret, no tell. Tier 1 emotional depth. v0.1 acceptance criteria: Pattern definition with mechanical rules, content requirements (50-70 lines, 10-axis profile), tell system rules (MIRROR has none), Naia Tamm as reference implementation. Output becomes generator template.', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 16:54:03', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-400', 'task', 'T-369', 'v0.1 wow moment content checklist', 'Map D-039 6 wow moments to specific content deliverables + implementation tickets. Track completion. Acceptance: every moment has identified content + code backing it.', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 15:13:03', '2026-02-12 16:54:03', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-402', 'task', 'T-369', 'v0.1 interaction verb spec + verbs[] terminology', 'Document the 7 interaction types (A-04: Move, Look, Monologue, Examine Object, Examine NPC, Talk, Overhear). Define triggers, UI needs, server events per type. v0.1 surfaces single context-sensitive action; architecture supports N verbs via verbs[]. Includes wiki + decisions rename to verbs[] terminology where appropriate. Soft dependency for NEW-9 (InteractionOptions).', 'done', 'medium', NULL, 'copy', NULL, '2026-02-12 15:13:03', '2026-02-12 16:54:03', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-377', 'story', 'T-369', 'Fix Triangle 1 (Hub Power) — Volume Escalation decision', 'Add smuggler decision fork: side with Nils (louder signal), side with Voss (internal tension), or split the route (new exposure surface). Each option cascades within T1 only -- self-contained, no cross-triangle cascade (A-17). Includes Nils partial presence via lattice message (~5-8 lines).', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 17:06:11', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-381', 'story', 'T-369', 'PC-as-NPC unified spec', 'Unified spec: starting knowledge graph, starting relationship map, reverse knowledge (bidirectional -- Gestalt critical insight), orientation monologue (Ozzie first 60 seconds), agency boundaries, authored relationship stubs (Gore requirement), tell inversion. 9-step conversion checklist for content authors. v0.1 scope: 2 PC briefs (smuggler, detective).', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 17:06:11', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-397', 'task', 'T-369', 'Drin Tier 2 profile expansion', 'Drin confirmed promoted to Tier 2 (A-01 consensus). Expand wiki profile to full Tier 2 depth: all 10 profile axes, smuggler lens section, triangle membership formalized for T2 and T5.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 17:06:11', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-382', 'story', 'T-369', 'Smuggler voice card + moral arc spec', 'Two deliverables: (1) Smuggler voice card -- paired examples with detective showing dual-lens register differences. Thinks in people vs data, first names vs surnames, fragments vs complete sentences, Krenn substrate vocabulary. (2) Smuggler moral arc -- 4 phases (Comfort, Doubt, Reckoning, Compromise), smuggler-specific FactIds, monologue triggers. Subsumes #310 (Character voice speech patterns).', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 15:13:02', '2026-02-12 17:12:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-385', 'task', 'T-369', 'Create content/ directory skeleton', 'Create directory tree with empty YAML stubs. _meta/, _schema/, global/ (factions, technology, contraband, knowledge, enums, regions), districts/sova-transit/ (district.yaml, npcs/, locations/, templates/, triangles/, lines/).', 'done', 'high', NULL, 'server', NULL, '2026-02-12 15:13:02', '2026-02-12 22:33:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-386', 'story', 'T-369', 'Content schema definitions (YAML Schema files)', 'Create _schema/ with validation schemas: npc.schema.yaml (tier-conditional rules), location.schema.yaml, faction.schema.yaml, template.schema.yaml, fact.schema.yaml, dialogue.schema.yaml, monologue.schema.yaml, district.schema.yaml, pool.schema.yaml.', 'done', 'high', NULL, 'server', NULL, '2026-02-12 15:13:02', '2026-02-12 22:33:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-392', 'story', 'T-369', 'Implement make validate-content CLI', 'Structural + tier-conditional content validation. Same crate as C3 schemas. Reads _schema/ definitions, validates all YAML in content/. v0.1: structural validation (required fields, type checks, enum matching) + tier-conditional rules. v0.2: cross-reference validation (FactId existence, NPC slug resolution).', 'done', 'high', NULL, 'server', NULL, '2026-02-12 15:13:02', '2026-02-12 22:33:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-404', 'story', 'T-369', 'Proximity detection + multi-verb InteractionOptions (verbs[])', 'Proximity detection system + server-side InteractionOptions component modeling N available actions per entity via verbs[]. Without proximity, InteractionOptions has no trigger. v0.1 client picks first/best verb; v0.2 client shows menu. Must not be throwaway. Includes ObserverSnapshot v2 -> v3 protocol extension for interaction data.', 'done', 'high', NULL, 'server', NULL, '2026-02-12 15:13:03', '2026-02-12 22:33:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-406', 'story', 'T-369', 'Pause system — server tick rate scaling', 'Tick rate supports 3 states: full speed (normal play), 50% speed (UI overlay open -- knowledge panel, dialogue), 0% (spacebar pause). Server receives pause/speed commands from client via IPC.', 'done', 'medium', NULL, 'server', NULL, '2026-02-12 15:13:03', '2026-02-12 22:33:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-301', 'story', 'T-33', 'Wiki taxonomy and structure — full future-ready schema', 'Full future-ready wiki taxonomy. Directory structure: star-systems/, characters/, factions/, technology/, cultural-groups/, contraband/, institutions/, species/, lore/, concepts/. Templates per category with YAML frontmatter metadata. Hierarchical spatial (system>station>district>location) with cross-references by ID. Scale-tested from 1 star system to 500+. First entries: Krenn System, Station Sova, Sova Transit District. Governance: Miri owns structure, anyone can create entries following templates. Status field: proposed>draft>canonical. Non-negotiable per project lead. Owners: Miri + Qatux. Proposed by: Mellanie, Paula, Miri. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', NULL, NULL, NULL, '2026-02-11 19:27:33', '2026-02-12 23:01:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-319', 'story', 'T-33', 'Krenn System wiki entry — first star system', 'First concrete star system wiki entry. Krenn System: G3V star, mid-Reach, ~180yr settlement, ~2.4M population, freight logistics economy. Establishes template for all future system entries with YAML frontmatter metadata. Owner: Miri. Proposed by: Paula, Miri. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', NULL, NULL, NULL, '2026-02-11 19:29:48', '2026-02-12 23:01:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-310', 'story', 'T-57', 'Character voice speech patterns — smuggler + detective', 'Speech-level character detail beyond personality traits. Per character: sentence length patterns, contraction usage, internal monologue style, nervous behavior verbal markers, frustration register, vocabulary level. The micro-decisions that determine whether 500 lines sound like the same person. Blocks voice kits. Owners: Paula + Mellanie. Proposed by: Mellanie, Paula. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, NULL, NULL, '2026-02-11 19:28:38', '2026-02-13 00:35:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-297', 'story', 'T-59', 'THE FRIEND: Smuggler NPC — Kael Davan full profile + content pack', 'Production-level NPC for smuggler playthrough. Kael Davan — dock worker, smuggler closest colleague, ring member. Full 10-axis profile, all relationship phases (comfort > first crack > observation > confrontation > new equilibrium). Full voice kit (15-20 lines), greeting pool (8-10), trust-gated dialogue (15-20), routine dialogue (10-12), contradiction dialogue (8-10), monologue reactions per PC (10-15 each), tell descriptions (5-8 per PC), post-discovery dialogue (5-8). Total ~75-100 authored lines. Contradiction: Kael meeting unknown person in restricted corridor — trying to exit ring to protect partner Hael. Tests entire content pipeline end-to-end. D-027 criterion #3. Owners: Paula (profile) + Mellanie (content). Proposed by: Mellanie, Paula, Gestalt, Ozzie. Workshop: content-gap-analysis v0.1 R2.', 'done', 'critical', NULL, NULL, NULL, '2026-02-11 19:27:29', '2026-02-13 00:35:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-298', 'story', 'T-59', 'THE FRIEND: Detective NPC — Sera Venn full profile + content pack', 'Production-level NPC for detective playthrough. Sera Venn — Commission field tech, bar regular, detective pre-existing contact. Full 10-axis profile, all relationship phases (trust > background data > pattern recognition > the question > contaminated trust). Full voice kit, greeting pool, trust-gated dialogue, routine, contradiction arc, monologue reactions, tells. Total ~75-100 authored lines. Contradiction: Sera always leaves when Torek arrives — she knows about smuggling via friend Hael but protects Hael by not reporting. Tests dual-lens on investigation chain. D-027 criterion #3. Owners: Paula (profile) + Mellanie (content). Proposed by: Mellanie, Paula, Gestalt, Ozzie. Workshop: content-gap-analysis v0.1 R2.', 'done', 'critical', 'paula', NULL, NULL, '2026-02-11 19:27:30', '2026-02-13 00:35:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-405', 'story', 'T-369', 'Interaction prompt — client extensible prompt system', 'Client-side interaction prompt designed for extensibility. v0.1: single context-sensitive E prompt. Architecture supports v0.2 multi-verb menu. Prompt system reads InteractionOptions from server state. Separate from #240 (Player interaction system and dispatcher) -- different team, different definition of done.', 'done', 'high', 'Stig', 'client', NULL, '2026-02-12 15:13:03', '2026-02-13 00:35:07', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-410', 'task', NULL, 'Integration test: tile type data in live server mode', 'Server ObserverSnapshot.visible_tiles sends {x, y, z, visibility} but no tile type (floor/wall/door). Client TileRenderer.update_tiles() requires a type field. Test mode fakes a separate tiles array with types, masking the gap. Add an integration test that connects a real client game loop to a live server and verifies tile type data is present and renderable. Should fail until #412 is resolved.', 'done', 'high', NULL, 'client', NULL, '2026-02-13 00:43:11', '2026-02-13 00:43:11', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-411', 'task', NULL, 'Integration test: input roundtrip through live server', 'No test validates the full input path: keypress → InputMapper → SimBridge.send_input → TCP wire → server deserialize → movement system → new ObserverSnapshot → client render. Unit tests prove each side works in isolation but miss the integration seam. Add a test that starts a real server, connects via TCP (not test mode), sends movement inputs, and verifies the player entity position changes in the returned snapshot. Should cover: basic movement, interaction with target, and verify no silent deserialization failures.', 'done', 'high', 'Stig', 'client', NULL, '2026-02-13 00:43:12', '2026-02-13 00:43:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-412', 'bug', NULL, 'Server ObserverSnapshot missing tile type data for client rendering', 'ObserverSnapshot.visible_tiles contains {x, y, z, visibility} but no tile type field (floor/wall/door/object). The client TileRenderer needs tile types to render walls, floors, and doors. In test mode this was masked by SimBridge generating a fake tiles array with type data. In live mode (make game), no walls or floors render — only entity boxes visible. Server needs to include tile geometry type in the snapshot, either by adding a type field to VisibleTile or by sending a separate tile geometry array. Blocks #410.', 'done', 'high', NULL, 'server', NULL, '2026-02-13 00:43:12', '2026-02-13 00:43:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-409', 'task', 'T-369', 'UI microcopy', '~50 strings: interaction prompt labels, knowledge panel labels, relationship state descriptors, HUD labels, tutorial text. YAML format at content/campaigns/main/_meta/ui-strings.yaml, loaded via content loader (D-042). Blocked by Stig UI element specs from Sprint 3.', 'done', 'medium', 'Stig', 'client', 'D-042', '2026-02-12 15:13:03', '2026-02-13 16:40:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-393', 'task', 'T-369', 'Pre-commit FactId typo check', 'Grep-based pre-commit check validating FactId references in YAML content files against canonical facts.yaml. Cheap v0.1 bridge until full cross-reference validation lands in C9 v0.2.', 'done', 'medium', 'Justine', 'ci', NULL, '2026-02-12 15:13:02', '2026-02-13 17:10:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-413', 'task', NULL, 'Add Interactable component to NPC spawn', NULL, 'done', 'critical', NULL, 'server', NULL, '2026-02-13 17:44:15', '2026-02-13 17:44:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-414', 'story', NULL, 'Implement monologue pipeline end-to-end', NULL, 'done', 'critical', NULL, 'joint', NULL, '2026-02-13 17:44:15', '2026-02-13 17:44:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-415', 'task', NULL, 'Wire PlayerAction::Interact with target/verb data', NULL, 'done', 'high', NULL, 'server', NULL, '2026-02-13 17:44:15', '2026-02-13 17:44:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-416', 'epic', NULL, 'Workshop: Control & Interaction Scheme', NULL, 'backlog', 'critical', NULL, NULL, 'D-053', '2026-02-13 21:05:22', '2026-02-13 21:05:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-333', 'story', 'T-47', 'Fog rendering visual spec — 4 states', 'Four-state fog rendering: visible (full detail), fog-edge (partial, sound indicators), hidden (no information), remembered (desaturated ghost, static snapshot, NPCs vanished — information decay). Owner: Araminta. Proposed by: Araminta. Workshop: content-gap-analysis v0.1 R2.', 'cancelled', 'medium', NULL, NULL, NULL, '2026-02-11 19:30:04', '2026-02-13 21:06:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-445', 'task', 'T-416', 'Resolve OQ-24: inventory capacity — 3 slots or 4 (lead call needed)', NULL, 'done', 'medium', NULL, 'server', NULL, '2026-02-13 21:07:01', '2026-02-13 21:11:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-448', 'task', 'T-416', 'Implant auto-pause (SP) — PauseSimulation on insert open/close', NULL, 'cancelled', 'medium', NULL, 'server', 'D-058', '2026-02-13 21:09:38', '2026-02-13 21:12:07', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-444', 'task', 'T-416', 'Resolve OQ-01: tile size in world units', NULL, 'done', 'high', NULL, 'server', NULL, '2026-02-13 21:06:59', '2026-02-13 21:12:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-441', 'task', 'T-416', 'Define 3 smuggler item specs — manifest copy, access token, comm log', NULL, 'done', 'high', NULL, 'copy', 'D-065', '2026-02-13 21:06:07', '2026-02-14 08:32:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-417', 'story', 'T-416', 'Stance system — Sprint/Walk/Careful/Crouch with tick-based movement', NULL, 'done', 'critical', NULL, 'server', 'D-053', '2026-02-13 21:05:26', '2026-02-14 14:57:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-418', 'task', 'T-416', 'MovementProfile component per archetype', NULL, 'done', 'high', NULL, 'server', 'D-053', '2026-02-13 21:05:27', '2026-02-14 14:57:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-419', 'task', 'T-416', 'Sprint interaction buffer suppression', NULL, 'done', 'high', NULL, 'server', 'D-055', '2026-02-13 21:05:28', '2026-02-14 14:57:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-420', 'story', 'T-416', 'Same-tile occupancy — TilePresence with posture layers', NULL, 'done', 'critical', NULL, 'server', 'D-054', '2026-02-13 21:05:29', '2026-02-14 14:57:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-421', 'task', 'T-416', 'ObjectType component + verb sets per type', NULL, 'done', 'high', NULL, 'server', 'D-057', '2026-02-13 21:05:30', '2026-02-14 14:57:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-422', 'story', 'T-416', 'Two-phase verb computation — KG-gated Phase 2 observer filter', NULL, 'done', 'critical', NULL, 'server', 'D-057', '2026-02-13 21:05:31', '2026-02-14 14:57:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-424', 'story', 'T-416', 'Smuggler inventory — CarriedBy component, Take/Place verbs, info boundary', 'Inventory using CarriedBy component pattern. Items are world entities with CarriedBy(StableId) referencing the carrier. Query: all items WHERE CarriedBy == player. Two verbs: Take, Place. Carried items are PRIVATE behind info boundary. LEAD CALL (OQ-24 resolved): 3x3 grid inventory, 9 slots, ALL characters (not per-archetype capacity). Mapped to 1-9 number keys. Wire format: player_inventory field on ObserverSnapshot. D-065. Est: 2d.', 'done', 'critical', NULL, 'server', 'D-065', '2026-02-13 21:05:36', '2026-02-14 14:57:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-428', 'task', 'T-416', 'Sprint anomaly monologue — double-take survival', NULL, 'done', 'medium', NULL, 'server', 'D-055', '2026-02-13 21:05:41', '2026-02-14 14:57:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-449', 'task', 'T-416', 'ObserverSnapshot v6 — add player_stance, player_inventory wire fields', NULL, 'done', 'critical', NULL, 'server', NULL, '2026-02-13 21:09:39', '2026-02-14 14:57:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-429', 'story', 'T-416', 'Cursor state machine — 4 states, Araminta spec, 150ms transitions', NULL, 'done', 'critical', NULL, 'client', 'D-056', '2026-02-13 21:05:46', '2026-02-15 22:41:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-430', 'story', 'T-416', 'Fog shader rebuild — 5-layer, CanvasGroup Layer 5, animated noise', 'REBUILD from scratch. Replace current TileMapLayer-based fog_renderer.gd with CanvasGroup + fragment shader. 5 layers: clear (soft gradient 3-4 tiles), light fog (desaturated 40-50%%, Perlin noise 8-10s), deep fog (near-monochrome, zone temperature tint), unexplored+maps (wireframe #333340), unexplored (solid #12141a). Animated noise texture, smooth boundary interpolation, vision cone shape integration. Supersedes #113/#131 fog code — remove old TileMapLayer implementation. Performance: <1ms/frame. D-059. Est: 3-4d.', 'done', 'critical', NULL, 'client', 'D-059', '2026-02-13 21:05:47', '2026-02-15 22:41:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-432', 'story', 'T-416', 'Entity interaction vertical list — insert-styled, z-layer 6', NULL, 'done', 'critical', NULL, 'client', 'D-057', '2026-02-13 21:05:50', '2026-02-15 22:41:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-433', 'story', 'T-416', 'World radial menu — 2 spokes v0.1 (Observe + Insert)', 'Right-click world radial menu. v0.1: 2 spokes — Observe (eye icon) and Insert (phone icon). Drag-release for power users, click-click for newcomers. Insert-styled: geometric lines, thin spokes with icons, nearly transparent. Renders on z-layer 6. Acceptance criterion: when Insert spoke activates in SP, client sends PlayerAction::Pause; on close sends Unpause (~10 lines). D-058. Est: 1d.', 'done', 'high', NULL, 'client', 'D-058', '2026-02-13 21:05:51', '2026-02-15 22:41:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-438', 'task', 'T-416', 'Inventory UI — 3x3 grid, 1-9 hotkeys', 'UPDATED per lead call (OQ-24): 3x3 grid inventory UI replacing pocket-icon design. All characters get 9 slots with 1-9 number key direct access. No empty slots displayed (icons appear when items carried). Bottom-right positioning. D-065. Est: 1d (increased from 0.5d — grid layout more complex than pocket icons).', 'done', 'high', NULL, 'client', 'D-065', '2026-02-13 21:06:00', '2026-02-15 22:41:03', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-439', 'task', 'T-416', 'Stance toggle UI — keybind + HUD indicator', NULL, 'done', 'high', NULL, 'client', 'D-053', '2026-02-13 21:06:01', '2026-02-15 22:41:03', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-446', 'task', 'T-416', 'Resolve OQ-25: stance name — Careful or Sneak (lead call needed)', NULL, 'done', 'low', NULL, 'server', NULL, '2026-02-13 21:07:02', '2026-02-15 22:42:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-434', 'story', 'T-416', 'Dialogue box — max 20% height, max-width, NPC speech + options + monologue', NULL, 'done', 'high', 'Stig', 'client', 'D-061', '2026-02-13 21:05:52', '2026-02-15 23:01:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-443', 'task', 'T-416', 'Archetype evidence presentation spec — detective case file vs smuggler notebook', NULL, 'done', 'low', NULL, 'copy', 'D-065', '2026-02-13 21:06:09', '2026-02-15 23:07:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-423', 'story', 'T-416', 'Cognitive delay system for fog recognition', NULL, 'done', 'high', NULL, 'server', 'D-060', '2026-02-13 21:05:35', '2026-02-15 23:37:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-308', 'story', 'T-55', 'Line pool format specification — formal document', 'Standalone spec document formalizing the converged YAML format from workshop. Not buried in workshop output. Covers: file structure (content/templates/{site}/dialogue.yaml), all tag enums with descriptions, example entries, authoring workflow. Reference document for all content authors. Owner: Gestalt. Proposed by: Mellanie, Gestalt. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, NULL, NULL, '2026-02-11 19:28:36', '2026-02-15 23:37:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-326', 'story', 'T-55', 'YAML content loader — hot-reload for previewer', 'Rust system parsing content YAML files into indexed queryable line pools at startup. Must support hot-reload for previewer/authoring workflow. Shares code with line previewer (#193) and dialogue selection pipeline (#305). Owner: Dudley. Proposed by: Gestalt. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', NULL, NULL, NULL, '2026-02-11 19:29:55', '2026-02-15 23:37:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-426', 'task', 'T-416', 'ListeningFocus — eavesdrop positioning via stationary_ticks', NULL, 'done', 'medium', NULL, 'server', 'D-053', '2026-02-13 21:05:39', '2026-02-15 23:37:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-442', 'task', 'T-416', 'InteractionMemory KG schema design', NULL, 'done', 'medium', NULL, 'server', 'D-064', '2026-02-13 21:06:08', '2026-02-15 23:37:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-431', 'story', 'T-416', 'Fog entity visualization — sound pings, recognized/unrecognized, cognitive delay anim', NULL, 'done', 'high', NULL, 'client', 'D-059', '2026-02-13 21:05:48', '2026-02-16 00:24:34', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-435', 'task', 'T-416', 'Dialogue response selection — max 3 visible, invisible locks', NULL, 'done', 'high', NULL, 'client', 'D-062', '2026-02-13 21:05:56', '2026-02-16 00:24:34', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-436', 'task', 'T-416', 'Confrontation text styling — italic voice, monologue beat', NULL, 'done', 'medium', NULL, 'client', 'D-063', '2026-02-13 21:05:57', '2026-02-16 00:24:34', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-437', 'task', 'T-416', 'Walk-away mechanic — WASD detect during dialogue, 300ms fade', NULL, 'done', 'medium', NULL, 'client', 'D-064', '2026-02-13 21:05:59', '2026-02-16 00:24:34', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-255', 'story', 'T-46', 'Client audio manager', 'Basic audio playback system for the Godot client. Spatial audio positioning for close-range sounds. Bridge between server-side sound events and client audio output. Blocks #124 (sound event system) and #125 (close-range audio). Source: Tyre R1 H-12.', 'done', 'high', 'tyre', 'client', NULL, '2026-02-11 00:03:14', '2026-02-16 22:23:39', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-470', 'task', 'T-455', 'Boundary value tests: GDScript encode-only (41 values)', 'Test all 41 MessagePack boundary values in GDScript: verify header byte + payload for each. 25 positive boundaries (0 to 2^63-1) + 16 negative boundaries (-1 to -2^63). Location: client/tests/test_msgpack_boundaries.gd. Also encode-decode roundtrip. Prevents Bug #4 class (format boundary encoding errors). See hoshe-round3.md Section 4 for full value matrix. Effort: 1d.', 'done', 'high', 'hoshe', 'client', NULL, '2026-02-17 12:58:13', '2026-02-17 12:58:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-476', 'task', 'T-455', 'Fog byte value constants (VIS_HIDDEN/PERIPHERAL/FORWARD, EXP_UNEXPLORED/EXPLORED/VISIBLE)', 'Define 6 named constants for fog byte values in client code. Eliminates magic numbers, provides stable assertion targets for fog tests. See stig-round3.md and workshop-outcomes.md. Effort: 0.25d.', 'done', 'high', 'hoshe', 'client', NULL, '2026-02-17 12:58:13', '2026-02-17 12:58:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-477', 'task', 'T-455', 'Client P0 tests: monologue not lost on overwrite (Bug #5), camera static during pause (Bug #2)', '2 critical client regression tests. (1) Monologue text preserved when snapshot buffer drops one-shots (Bug #5). (2) Camera remains centered during pause state (Bug #2). Open question R2-OQ-11: client test headless stability (resolve during impl). See stig-round3.md. Effort: 0.5d.', 'done', 'high', 'hoshe', 'client', NULL, '2026-02-17 12:58:13', '2026-02-17 12:58:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-478', 'task', 'T-455', 'Client P1 tests: fog shader state (4), entity lifecycle, pending recognition blob', '7 client tests. 4 fog shader tests: correct layer values for each visibility state. Entity lifecycle: entity added/removed correctly. Pending recognition blob: unrecognized entity renders as blob during cognitive delay. See stig-round3.md. Effort: 1d.', 'done', 'high', NULL, 'client', NULL, '2026-02-17 12:58:13', '2026-02-17 12:58:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-459', 'task', 'T-455', 'Server --test-mode and --port 0 flags', 'Add --test-mode flag: prints LISTENING:{port} to stdout after bind, all tracing to stderr, --port 0 for OS-assigned port (uses existing accept_on(listener)), --seed 42 default, exits after first client disconnect, setup_proof_room() extracted for both modes. Unblocks Layer 3 tests, test client binary, Gauntlet headless testing. See workshop-outcomes.md Section 2 and dudley-round3.md for full spec. Effort: 1d.', 'done', 'critical', 'tyre', 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:22:23', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-461', 'task', 'T-455', 'Pause guard test: movement_discarded_while_paused', 'Test that movement input is rejected while game is paused. Prevents Bug #3 recurrence (player moves while paused). See hoshe-round3.md for test spec. Effort: 0.25d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:29:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-462', 'task', 'T-455', 'Pause guard test: unpause_accepted_while_paused', 'Test that unpause command is accepted while paused (the only allowed action). Prevents Bug #3 class (pause state corruption). See hoshe-round3.md. Effort: 0.25d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:29:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-463', 'task', 'T-455', 'Pause guard test: pause_unpause_roundtrip_with_movement', 'Full cycle: pause -> attempt move (rejected) -> unpause -> move (accepted). Prevents Bug #3 class (full cycle regression). See hoshe-round3.md. Effort: 0.25d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:29:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-467', 'task', 'T-455', 'Per-fix determinism unit tests (Fix A equidistant NPCs, Fix D same-tile movers)', 'Targeted unit tests for each determinism fix. Fix A: equidistant NPCs produce stable ordering. Fix D: same-tile movers resolve deterministically. See hoshe-round3.md. Effort: 0.5d.', 'done', 'high', 'tyre', 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:29:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-468', 'task', 'T-455', 'Remaining pause guard tests (stance_toggle, interact, batch_discard, set_tick_rate)', 'Edge case pause guard tests: stance_toggle rejected while paused, interact rejected, batch_discard (all inputs in batch rejected), SetTickRate(Half) rejected while paused (4-line fix in input.rs, see workshop-outcomes.md Section 2). Open question R2-OQ-01: resolve during implementation. Effort: 0.5d.', 'done', 'high', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:29:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-469', 'task', 'T-455', 'EntityRegistry lifecycle tests (stale mapping, register-after-unregister, unregister-unknown)', '3 tests for entity registry edge cases. Stale mapping detection, register-after-unregister correctness, unregister-unknown entity handling. Open question R2-OQ-02: entity respawn + bevy generation counter safety (safe per Dudley). See hoshe-round3.md. Effort: 0.5d.', 'done', 'high', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:29:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-471', 'task', 'T-455', 'Boundary value tests: Rust encode-only + roundtrip', 'Test all 41 BV values as i64 in Rust: to_vec -> from_slice -> assert_eq. Location: server/tests/serialization.rs. Prevents Rust-side encoding regressions. See hoshe-round3.md Section 4. Effort: 0.5d.', 'done', 'high', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:29:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-479', 'task', 'T-455', 'malformed_input_in_batch_rejects_entire_batch test', 'Documents batch-failure behavior: when one input in a batch is malformed, the entire batch is rejected. Resolves open question UQ-01. See hoshe-round3.md. Effort: 0.25d.', 'done', 'high', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:29:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-466', 'task', 'T-455', 'Determinism regression test: gauntlet_deterministic_replay', 'Master determinism regression guard. Run same input sequence twice, compare snapshots byte-for-byte. Catches any non-determinism regression. Depends on all 3 determinism fixes. See hoshe-round3.md. Effort: 1d.', 'done', 'high', 'tyre', 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:29:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-450', 'task', NULL, 'Wire RecognitionTrigger::Urgent to anomaly detection', NULL, 'done', 'medium', NULL, 'server', 'D-060', '2026-02-15 23:28:05', '2026-02-17 15:33:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-452', 'task', NULL, 'Add ContentSlug component for entity slug resolution', NULL, 'done', 'medium', NULL, 'server', 'D-041', '2026-02-15 23:58:51', '2026-02-17 15:33:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-456', 'task', 'T-455', 'Determinism Fix A: visible_ids HashSet -> BTreeSet + sort visible_tiles', 'Replace HashSet with BTreeSet for visible_positions/ids in query.rs and observer/mod.rs. Sort visible_tiles by (x,y). ~15 lines. Prevents Bug #1 class (state divergence) and non-deterministic sprint anomaly detection. After fix, run `make fixtures` and commit updated fixture files (two client tests reference visible_tiles[0] by index). See workshop-outcomes.md Section 2 for full spec. Effort: 0.5d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:33:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-457', 'task', 'T-455', 'Determinism Fix B: Sort visible entities in snapshot by entity_id', 'Sort entities by entity_id in observer/mod.rs snapshot construction. 2 lines. Prevents non-deterministic golden file comparison. See workshop-outcomes.md Section 2 for full spec. Effort: 0.25d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:33:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-458', 'task', 'T-455', 'Determinism Fix D: Sort movers by Entity bits in validate_movement', 'Sort movers by Entity::to_bits() in movement.rs for deterministic collision resolution. ~5 lines. Prevents non-deterministic movement tie-breaking. See workshop-outcomes.md Section 2 for full spec. Effort: 0.25d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:33:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-472', 'task', 'T-455', 'gen_fixtures.rs boundary extension (14 raw + 5 snapshot fixtures)', 'Extend gen_fixtures.rs to generate 14 raw integer boundary fixtures and 5 snapshot fixtures at boundary tick values. These are Rust-generated fixtures consumed by GDScript decoder tests. See hoshe-round3.md Section 4. Effort: 0.5d.', 'done', 'high', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:34:11', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-473', 'task', 'T-455', 'Encoding asymmetry tests: Rust decoder accepts GDScript-style signed encodings', '4 test cases: Rust rmp_serde decodes int_16(256), int_16(32767), int_32(65536), int_32(2^31-1) into u64 fields. Validates the encoding overlap zone (GDScript uses signed for 256-32767, Rust uses unsigned). Dudley traced rmp-serde 1.3.1: safe. Location: server/tests/serialization.rs. See hoshe-round3.md Section 4 ''Direction 2''. Effort: 0.5d.', 'done', 'high', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-17 15:36:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-305', 'story', 'T-55', 'Dialogue selection pipeline — 4-layer filtering engine', 'Core runtime system: 4-layer filtering engine for dialogue line selection. Layer 1 (access) = hard filter by access tier. Layer 2 (situation) = context filter from engine-tracked interaction state. Layer 3 (trust) = hard filter by trust progression level. Layer 4 (mood+topic) = weighted selection from eligible pool. Consumes YAML line pools (#168). Must handle access tier as list, trust as progressive enum. Includes line variety tracking to prevent repeats. Owner: Dudley. Proposed by: Gestalt. Workshop: content-gap-analysis v0.1 R2.', 'done', 'critical', NULL, 'server', NULL, '2026-02-11 19:27:38', '2026-02-17 16:38:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-427', 'task', 'T-416', 'Walk-away KG recording — confrontation incompleteness', NULL, 'done', 'medium', NULL, 'server', 'D-064', '2026-02-13 21:05:40', '2026-02-17 16:38:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-451', 'task', NULL, 'Monologue fires DURING cognitive delay window (D-060)', NULL, 'done', 'medium', NULL, 'server', 'D-060', '2026-02-15 23:28:05', '2026-02-17 16:38:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-440', 'story', 'T-416', '6 interaction audio assets — cursor hover, weapon mode, fog recognition, implant, dialogue, confrontation dip', NULL, 'done', 'medium', 'inigo', 'audio', 'D-059', '2026-02-13 21:06:05', '2026-02-18 00:26:48', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-480', 'task', 'T-455', 'Test client binary scaffolding + CLI (tooling/test-client/)', 'Separate workspace crate at tooling/test-client/. Imports bridge types from server crate (ObserverSnapshot, PlayerInput, read_framed, write_framed). CLI: --connect, --replay, --text, --json, --quiet, --golden, --ticks. Exit codes: 0=success, 1=golden mismatch, 2=connection error. Lead override: NOT server/src/bin/ — separate crate in tooling/. See workshop-outcomes.md Section 5 and tyre-round3.md. Effort: 0.5d.', 'done', 'high', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 00:41:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-481', 'task', 'T-455', 'Text renderer library (server/src/bridge/text_renderer.rs)', 'format_snapshot_text(&ObserverSnapshot) -> String. Pub-exported from server crate for tooling/test-client/ consumption. Entity labels as kind:entity_id, sorted by distance, room name from room_at() constants. ~100 lines Rust. Unblocks human tester workflow and WRONG button. See tyre-round3.md for full implementation. Effort: 0.5-1d.', 'done', 'high', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 00:41:19', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-474', 'task', 'T-455', 'Encoding asymmetry tests: GDScript decoder accepts Rust-style unsigned encodings', '4 test cases: GDScript Messagepack.decode handles uint_16(256), uint_16(32767), uint_32(65536), uint_32(2^31-1). Validates cross-encoder compatibility. Location: client/tests/test_msgpack_boundaries.gd. See hoshe-round3.md Section 4 ''Direction 1''. Effort: 0.5d.', 'done', 'high', NULL, 'client', NULL, '2026-02-17 12:58:13', '2026-02-18 00:42:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-460', 'task', 'T-455', 'make pre-pr target', 'Implement `make pre-pr` chain: lint -> build -> test -> content validation -> fixture staleness. Also branch-specific variants: pre-pr-server, pre-pr-client, pre-pr-content. Total runtime <3min. Fixture staleness is BLOCKER (exit 1 on stale). See hoshe-round3.md Section 5 for definitive Makefile spec. Effort: 0.5d.', 'done', 'critical', NULL, 'ci', NULL, '2026-02-17 12:58:13', '2026-02-18 01:02:27', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-464', 'task', 'T-455', 'Content cross-reference validation (9 checks)', 'Extend tooling/validate-content with cross-reference validation pass. 9 checks: canonical_id uniqueness, relationship target resolution, location slug resolution, dialogue location resolution, fact_id resolution (absorbs check-fact-ids), triangle membership, npc_count accuracy (warning), dialogue line_id uniqueness, bidirectional relationship (warning). Phase 1 (Sprint 8): checks #1-#6. Phase 2 (Sprint 8): checks #4,#5,#8. Phase 3 (Sprint 9): #7,#9. See hoshe-round3.md Section 2 for ContentIndex skeleton and all 9 check specs. Effort: 1.5d.', 'done', 'critical', NULL, 'ci', NULL, '2026-02-17 12:58:13', '2026-02-18 01:02:28', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-465', 'task', 'T-455', 'Fixture staleness check in make pre-pr', 'Add fixture staleness detection to pre-pr chain. Regenerates fixtures via gen_fixtures, checks git diff on client/tests/fixtures/. Exit 1 on stale (BLOCKER — stale fixtures = false positive client tests per Tyre''s argument). See hoshe-round3.md Section 5. Effort: 0.25d.', 'done', 'critical', NULL, 'ci', NULL, '2026-02-17 12:58:13', '2026-02-18 01:02:28', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-516', 'bug', NULL, 'Fix MessagePack int_64 encoder dead code branch', NULL, 'done', 'medium', 'stig', 'client', NULL, '2026-02-17 16:32:40', '2026-02-18 01:19:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-492', 'task', 'T-455', 'Client P2 tests: remaining camera (5), entity alpha/color (4), UI (7)', '16 client tests. Camera: smoothing, zoom, viewport. Entity: alpha/color for visibility states. UI: monologue display, interaction panel, inventory HUD, dialogue overlay, pause indicator, recognition progress, minimap. Target: Sprint 9. See stig-round3.md. Effort: 2d.', 'done', 'high', 'stig', 'client', NULL, '2026-02-17 12:58:13', '2026-02-18 01:19:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-493', 'task', 'T-455', 'Client P3 tests: z-layer ordering (4), entity lerp (3), Tyre additions (5)', '12 client tests. Z-layer: correct render order for floors/walls/entities/UI. Entity lerp: smooth interpolation targets. Tyre additions: recognition transition timing. Target: Sprint 9. See stig-round3.md. Effort: 1.5d.', 'done', 'high', 'stig', 'client', NULL, '2026-02-17 12:58:13', '2026-02-18 01:19:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-494', 'task', 'T-455', 'Client anti-tedium tests: bug report capture, progress hidden when not gauntlet', 'Client regression tests for anti-tedium features: F12 bug report captures correctly, gauntlet progress UI hidden in non-gauntlet mode. Target: Sprint 9. See stig-round3.md. Effort: 0.5d.', 'done', 'high', NULL, 'client', NULL, '2026-02-17 12:58:13', '2026-02-18 01:19:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-475', 'task', 'T-455', 'make fixtures-client target (GDScript-generated fixtures for Rust)', 'New Makefile target: runs GDScript test that generates .msgpack files at server/tests/fixtures/gdscript/. Rust test verifies decode. Reverse-direction protocol validation (GDScript encoder -> Rust decoder). See hoshe-round3.md Section 4 ''Direction 4''. Effort: 0.5d.', 'done', 'high', NULL, 'ci', NULL, '2026-02-17 12:58:13', '2026-02-18 01:23:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-482', 'task', 'T-455', 'Layer 3 subprocess test: server_subprocess_sends_snapshot_on_connect', 'Integration test at server/tests/layer3.rs. Spawns server with --test-mode --port 0, parses LISTENING:{port} from stdout, connects via TCP, sends input, reads snapshot, asserts version/tick/entities. ServerGuard drop pattern for cleanup. Catches: binary startup panic, subprocess I/O blocking (Bug #1), port binding, protocol version. Target: Sprint 9. See hoshe-round3.md Section 3 for full test code. Effort: 1d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 01:26:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-484', 'task', 'T-455', 'Test client golden file comparison (JSON diff)', 'JSON diff with sorted keys, pretty-printed. Recursive diff_json_values() comparison. Output on mismatch shows field-level diffs. Exit code 1 on mismatch. Location: tooling/test-client/. Target: Sprint 9. See tyre-round3.md. Effort: 0.5d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 01:26:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-485', 'task', 'T-455', 'Golden file test suite: gauntlet_tick_10_matches_golden', 'Run deterministic replay for 10 ticks, compare output snapshot against committed golden file. Catches any code change that alters snapshot output. Target: Sprint 9. See hoshe-round3.md. Effort: 0.5d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 01:26:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-487', 'story', 'T-455', 'Gauntlet first 3 rooms (Inventory Warehouse, Occlusion Corridor, Pause Chamber)', 'Implement first 3 Gauntlet rooms as hybrid YAML + Rust inject. Inventory Warehouse (30x28, 11 entities, D-065 inventory), Occlusion Corridor (42x22, 4 entities, D-035 LOS), Pause Chamber (16x16, 1 entity, D-031 pause). Plus Central Hub (24x24, 4 signs). StableId ranges per gestalt-round3.md. Additive-only constraint: existing rooms/entities never reordered. Target: Sprint 9. See workshop-outcomes.md Section 4. Effort: 2-3d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 01:26:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-488', 'task', 'T-455', 'Gauntlet room constants module (server/src/test_world/constants.rs)', 'GauntletRoom struct, GauntletEntity struct, 8 room constants, ROOMS array, room_at() lookup function. ~100 lines Rust. Provides stable coordinate references for all tests. Target: Sprint 9. See gestalt-round3.md. Effort: 0.5d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 01:26:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-489', 'task', 'T-455', 'Content runtime validation: boot + tick 10 + snapshot', 'Test that content passes runtime validation: server boots, ticks 10 times, produces valid snapshot. Catches content that passes schema validation but panics at runtime. Target: Sprint 9. Effort: 0.5d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 01:26:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-490', 'story', 'T-455', 'Room reset trigger mechanism', 'RoomResetTrigger component, RoomSnapshots resource (tick-0 state per room), execute_room_reset system. Resets: entity positions, entity KG, player KG (room refs only), fog (room tiles), inventory items from room, dialogue state. Does NOT reset other rooms, player position, session timer, global SimRng. 10-tick debounce. Test-mode only. Target: Sprint 9. See workshop-outcomes.md Section 8. Effort: 1d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 01:26:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-453', 'story', NULL, 'Revisit Sprint 7 UI audio assets — trim to target durations and iterate', NULL, 'done', 'medium', 'inigo', 'audio', NULL, '2026-02-16 00:21:46', '2026-02-18 10:07:47', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-486', 'task', 'T-455', 'make golden-diff + make golden-update targets', 'Developer workflow targets for golden file management. golden-diff shows changes, golden-update regenerates and commits. Target: Sprint 9. Effort: 0.25d.', 'done', 'critical', NULL, 'ci', NULL, '2026-02-17 12:58:13', '2026-02-18 10:07:47', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-497', 'task', 'T-455', 'Checklist YAML schema + make checklist generation', 'Per-room checklist at content/gauntlet/rooms/{room_id}/checklist.yaml. Cross-room at content/gauntlet/cross_room_checks.yaml. 7 condition types: player_near, player_facing, entity+expected, expected_sector, perception_mode, fog counts, inventory_count, dialogue_active, monologue_contains. make checklist generates docs/qa/gauntlet-checklist.md. Target: Sprint 9. See stig-round3.md. Effort: 0.5d.', 'done', 'high', NULL, 'ci', NULL, '2026-02-17 12:58:13', '2026-02-18 10:07:47', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-495', 'story', 'T-455', 'WRONG button (F12) MVP: snapshot + text render + description', 'Client-side Godot implementation. F12 -> pause -> one-line prompt -> save files -> unpause. Captures: ObserverSnapshot (JSON), text render output, tick/room/seed, tester description. Output: tests/bug-reports/gauntlet-t{tick}-{timestamp}/. bug_report.gd autoload ~80 lines. Target: Sprint 9. See ozzie-round3.md and stig-round3.md. Effort: 1.5d.', 'done', 'high', NULL, 'client', NULL, '2026-02-17 12:58:13', '2026-02-18 10:14:14', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-496', 'task', 'T-455', 'Room timer + personal bests', 'Display TIMER: 00:47 (PB: 00:38). Timer starts on room entry, resets on room reset. Stats persisted to tests/gauntlet-stats.json. Session summary on disconnect. Target: Sprint 9. See ozzie-round3.md. Effort: 0.5d.', 'done', 'high', NULL, 'client', NULL, '2026-02-17 12:58:13', '2026-02-18 10:14:14', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-499', 'task', 'T-455', 'Performance baseline tooling (make perf-baseline)', 'Establish performance baselines: tick timing, memory usage, entity count scaling. make perf-baseline runs benchmark suite, outputs to tests/perf/. Enables performance regression detection. Target: Sprint 9. See justine-round3.md. Effort: 1d.', 'done', 'high', 'justine', 'ci', NULL, '2026-02-17 12:58:13', '2026-02-18 11:42:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-515', 'task', 'T-455', 'Bidirectional relationship consistency warning (Check 9 in content validation)', 'Phase 3 of content validation: warning when NPC A has relationship to NPC B but no reciprocal relationship exists. Advisory, non-blocking. Backlog. See hoshe-round3.md Section 2. Effort: 0.25d.', 'done', 'low', 'justine', 'ci', NULL, '2026-02-17 12:58:13', '2026-02-18 11:42:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-491', 'task', 'T-455', 'Hub teleport action (PlayerAction::TeleportToHub)', 'Server-side: move player to hub_spawn, clear dialogue/monologue/interaction buffer. Does NOT affect room state, inventory, game time, knowledge graph. Gauntlet-only (reject in non-Gauntlet maps). Target: Sprint 9. See workshop-outcomes.md Section 8. Effort: 0.5d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 11:45:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-520', 'task', 'T-416', 'Confrontation world response — server-side trigger (Tier 2 anim, monologue spike, topic narrowing)', 'D-063 specifies world responds when confrontation is delivered: (1) NPC shifts to Tier 2 animation (D-047 ambiguous animation tier), (2) entity D-033 relationship color may fade (relationship state change), (3) monologue frequency spikes during exchange, (4) available topics narrow post-confrontation. Client text styling (#436) is done. This ticket covers the server-side event that triggers these world changes: emit a ConfrontationDelivered event from the dialogue system, which perception systems consume to update NPC AnimationState and the KG relationship record. NPC routine change is downstream of the relationship shift.', 'done', 'medium', NULL, 'server', 'D-063', '2026-02-18 10:45:21', '2026-02-18 11:45:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-483', 'task', 'T-455', 'Test client replay loading + tick-scheduled sending', 'Test client loads JSONL replay file (one JSON array per tick), sends PlayerInput at correct tick timing. Unblocks scripted Gauntlet testing. Location: tooling/test-client/. Target: Sprint 9. Effort: 0.5d.', 'done', 'critical', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 11:45:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-500', 'task', 'T-455', 'Content scaling test (baseline + extra NPC comparative)', 'Test content additions don''t break existing functionality. Baseline run + extra NPC pack comparative. Target: Sprint 9. Effort: 1d.', 'done', 'high', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 11:45:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-514', 'task', 'T-455', 'blocked_entities debug field on ObserverSnapshot', 'Add blocked_entities field showing LOS-blocked entities for debugging in test client. Feasible per R2-OQ-05: ~300 tile lookups/tick. Backlog. Feasibility confirmed. Effort: 0.5d.', 'done', 'medium', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 11:45:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-519', 'task', 'T-416', 'Walk-away NPC reaction — server-side Phase 2 (animation shift, routine change)', 'D-064 three-phase walk-away consequences. Phase 1 (client fade, #437) and Phase 3 (KG recording, #427) are done. Phase 2 is missing: when the player walks away from dialogue, the server must: (1) trigger NPC animation shift (to Tier 2 ambiguous animation per D-047), (2) optionally trigger an NPC call-after line (short audio/text), (3) flag the NPC routine as potentially changed (downstream storyteller hook). Blocked by: #427 (KG incompleteness flag exists, can be the trigger). Blocks Phase 2 NPC behavior and second-approach dialogue differences.', 'done', 'medium', NULL, 'server', 'D-064', '2026-02-18 10:45:18', '2026-02-18 11:45:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-327', 'story', 'T-46', 'Audio asset set — 8 minimum viable files via Stable Audio Open', '8 OGG Vorbis files via Stable Audio Open: (1) amb_station_base 60-90s station hum/span gate vibration, (2) amb_workplace_layer 45-60s cargo machinery, (3) amb_bar_layer 45-60s conversation murmur, (4) amb_corridor_layer 45-60s echoing footsteps/ventilation, (5) sfx_footstep_metal 0.3-0.5s walk, (6) sfx_footstep_metal_run 0.2-0.3s run, (7) sfx_monologue_chime 0.5-1.0s crystalline insight tone, (8) sfx_monologue_chime_urgent 0.5-1.0s sharper variant. Monologue chime is NON-NEGOTIABLE per Ozzie. Owners: TBD. Proposed by: Mellanie, Ozzie, Gestalt. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, NULL, NULL, '2026-02-11 19:29:55', '2026-02-18 11:54:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-498', 'story', 'T-455', 'Gauntlet next 3-4 rooms (Interaction Gallery, Fog Theater, Crowd Plaza, Dialogue Room)', 'Implement rooms 1,4,6,7: Fog Theater (44x32, 4 entities, D-059), Interaction Gallery (24x20, 5 entities, D-057), Dialogue Room (28x20, 4 entities, D-041), Crowd Plaza (32x32, 15 entities, density stress). Target: Sprint 9. See workshop-outcomes.md Section 4. Effort: 2-3d.', 'done', 'high', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-18 11:56:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-502', 'task', 'T-455', 'Room reset client UX (reset plate tile, interaction verb, amber flash)', 'Client-side: amber reset_plate tile rendering, ''Reset Room'' interaction verb, 0.15s amber flash + monologue ''Systems recalibrated.'' on reset. Target: Sprint 9. See workshop-outcomes.md Section 8. Effort: 0.5d.', 'done', 'high', NULL, 'client', NULL, '2026-02-17 12:58:13', '2026-02-18 17:36:17', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-503', 'task', 'T-455', 'Auto-checklist progress tracking (client-side snapshot evaluation)', 'Client evaluates ObserverSnapshot against checklist conditions, auto-tracks verification items. Full tracking in test-client-only (lightweight overlay in Godot per R2-OQ-06). Target: Sprint 9. See stig-round3.md. Effort: 1d.', 'done', 'high', NULL, 'client', NULL, '2026-02-17 12:58:13', '2026-02-18 17:36:17', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-517', 'task', NULL, 'Introduce Michroma as game font', 'Install and integrate the Michroma font (https://fonts.google.com/specimen/Michroma) as the primary game font for The Settled Reach. + +Acceptance criteria: +- Download Michroma font files from Google Fonts +- Add font files to the Godot client asset directory (client/assets/fonts/) +- Configure Michroma as the default theme font in Godot +- Update any existing label/text nodes to use the new font resource +- Verify rendering at key UI sizes (HUD, menus, dialogue) + +Implementation notes — "Implant" styling: +- Wide-screen letter spacing: Increase tracking (letter-spacing) by ~5-10% to give the font a clinical, high-end neural overlay OS feel. Michroma looks best with room to breathe. +- Alpha pulse: Subtle opacity animation pulsing between 85-100% alpha to make the UI feel alive — connected to the character heartbeat or power supply. +- Color grading: Avoid pure white (#FFFFFF). Use a slight cyan-white (#E0F7FA) or pale amber (#FFF8E1) to mimic light projected through a lens or onto a retina. + +NOTE: Alpha pulse and color grading are first-implementation specs — subject to revision in a future design workshop.', 'done', 'high', NULL, 'client', NULL, '2026-02-18 09:03:24', '2026-02-18 17:36:17', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-518', 'task', 'T-416', 'Client: wire insert open/close to PauseSimulation command', 'The server pause system (50%/0% tick rate) exists in #406. D-058 (D-03 resolved) confirms auto-pause in SP when the implant UI is open. Ticket #448 was cancelled before client-side wiring was done. Implement: when the Insert spoke of the world radial menu (#433) is selected and the implant overlay opens, client sends PauseSimulation (50% tick rate). On close, client sends Unpause. Server-side pause infrastructure is complete (#406). References: D-058, #406, #433.', 'done', 'medium', NULL, 'client', 'D-058', '2026-02-18 10:44:51', '2026-02-18 17:36:17', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-526', 'story', NULL, 'Client: mouse-relative facing and movement (D-054)', 'D-054 specifies: Mouse facing is a client-side float; the server receives the facing octant only. Currently WASD uses fixed cardinal directions (W=North, D=East, etc.) and facing comes from the server based on last movement direction. Scope: (1) Track mouse position relative to player sprite, compute continuous facing angle. (2) Derive 8-direction octant from mouse angle, send to server as player facing. (3) Remap WASD to be relative to mouse facing — W moves toward mouse, S away, A/D strafe. (4) Update entity_renderer facing indicator to use client-side mouse angle. (5) Update InputMapper to produce relative movement actions instead of absolute cardinal ones. Files: input_mapper.gd, game_state.gd, entity_renderer.gd, sim_bridge.gd', 'done', 'high', NULL, 'client', 'D-054', '2026-02-18 10:50:35', '2026-02-18 17:36:17', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-501', 'task', 'T-455', 'Gauntlet dev teleport — Home key resets to hub spawn (test-only)', 'Gauntlet-only: Home key sends TeleportToHub, instant camera snap + 0.3s fade-to-black-and-back, clears dialogue/monologue buffers. Gated behind gauntlet_mode flag — NOT available in production gameplay. Production fast-travel is diegetic (see Q-012). Effort: 0.5d.', 'done', 'high', NULL, 'client', NULL, '2026-02-17 12:58:13', '2026-02-19 08:10:46', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-521', 'task', 'T-416', 'Confrontation D-033 color shift — client-side entity tint on confrontation delivered', 'D-063 specifies entity D-033 color may fade after confrontation is delivered. This is a client rendering concern: the ObserverSnapshot will carry updated relationship state (from #520 server-side trigger); the client must apply the D-033 color palette change to the entity sprite/overlay. The cursor entity-hover state also uses D-033 color (D-056) so both cursor tint and entity outline tint must update. Blocked by: #520 (server-side ConfrontationDelivered event that changes relationship state in snapshot).', 'done', 'medium', NULL, 'client', 'D-063', '2026-02-18 10:45:21', '2026-02-19 08:10:46', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-513', 'task', 'T-455', 'Content scaling stress test (100 ticks, max-NPC pack, tick budget)', 'Performance stress test: 100 ticks with maximum entity count, verify tick budget holds. Backlog. Effort: 1d.', 'done', 'medium', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-19 08:55:19', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-425', 'task', 'T-416', 'Contraband detection — NPC scan checks carried items + KG', NULL, 'done', 'medium', NULL, 'server', 'D-065', '2026-02-13 21:05:38', '2026-02-19 11:38:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-504', 'story', 'T-455', 'Gauntlet rooms: Sprint Gauntlet, Eavesdrop Alcove, Confrontation Stage', '3 additional Gauntlet rooms focused on interaction combination coverage. Backlog. See workshop-outcomes.md Section 4. Effort: 3d.', 'done', 'medium', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-19 11:38:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-506', 'task', 'T-455', 'Cross-room transition test scenarios (T1-T8 from Gestalt)', '8 cross-room transition tests: Sprint Exit, Inventory Interact, Pause Anywhere, etc. Tests system combination bugs at room boundaries. Backlog. See gestalt-round3.md. Effort: 2d.', 'done', 'medium', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-19 11:38:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-507', 'story', 'T-455', 'WRONG button full captures (input history ring buffer, snapshot history, replay seed)', 'Full bug reproduction: 60-tick ring buffer, input history, replay seed, room metadata. Backlog. See ozzie-round3.md. Effort: 1.5d.', 'done', 'medium', NULL, 'client', NULL, '2026-02-17 12:58:13', '2026-02-19 11:38:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-522', 'task', 'T-416', 'Resolve OQ-07: no-insert interaction behavior (diegetic test)', 'D-056 and D-057 both reference a diegetic test: labels (interaction prompts) should disappear if the insert is off, and render on z-layer 6 (insert overlay). OQ-07 asks: does a character WITHOUT an insert get NO interaction prompts? Or does the cursor still change shape? Decision needed: (a) cursor reverts to default shape only (no tooltip/verb labels), or (b) cursor does not change at all, or (c) prompts are available via non-insert fallback. Resolve and implement in the entity interaction vertical list (#432) and cursor state machine (#429).', 'done', 'low', NULL, 'client', 'D-056', '2026-02-18 10:45:24', '2026-02-19 11:38:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-524', 'task', 'T-416', 'Resolve OQ-18: dialogue access tiers vs D-041 confidence hierarchy (same or layered)', 'D-028 defines 4 dialogue access layers (surface/real/secret/unprompted). D-041 defines 4 KG confidence tiers (Suspects/KnowsOf/KnowsDetails/Direct). OQ-18 asks: are Nigels dialogue access tiers (per character archetype) the same system as D-041 confidence hierarchy, or a layered system on top? The dialogue selection pipeline (#305) filters by confidence tier already. Decision needed: (a) same system - archetype access tiers map directly to KG confidence tiers, or (b) layered - archetype adds a second gating dimension (e.g., detective can always access surface regardless of KG confidence, smuggler needs KnowsOf minimum). Resolve and document, then update #305 if filtering logic changes.', 'done', 'medium', NULL, 'server', 'D-041', '2026-02-18 10:45:27', '2026-02-19 11:38:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-309', 'story', 'T-55', 'Knowledge state vocabulary for v0.1', 'List of knowledge flags for monologue prerequisites (e.g. knows:smuggling_operation, met:kael_davan, suspects:manifest_discrepancy). Hierarchy: suspects < knows_of < knows_details. Blocks monologue authoring — Mellanie cannot write lines with prerequisites referencing invented strings. Owners: Gestalt + Dudley. Proposed by: Mellanie, Gestalt. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'copy', NULL, '2026-02-11 19:28:37', '2026-02-19 12:00:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-93', 'story', 'T-40', 'Tier marker components', 'ActiveSim, BackgroundSim, StateSaved components. Tag-based tier identification.', 'done', 'critical', NULL, 'server', NULL, '2026-02-10 23:19:08', '2026-02-19 12:33:04', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-124', 'story', 'T-46', 'Sound event system - server', 'Sound event system: SoundEventEmitter emits typed events (Footstep, Voice, Machinery, Alert, Ambient) with position, intensity, range_category (Close/Medium/Long). Client AudioAssetRegistry maps types to files; missing assets get visual indicator + monologue trigger. AmbientManager for location loops with crossfade. v0.1: 8 audio files. Scales from 0 to hundreds without structural changes. Source: Gestalt+Ozzie content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:20:58', '2026-02-19 12:33:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-125', 'story', 'T-46', 'Close-range stereo audio - client', 'Play 2D positional audio for events within LOS or near player. Maps to screen space for fixed camera.', 'done', 'high', NULL, 'client', NULL, '2026-02-10 23:20:58', '2026-02-19 13:53:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-126', 'story', 'T-46', 'Medium-range visual indicators', 'Fog-edge directional indicators. Arrow/icon at map edge. Triggers monologue description.', 'done', 'high', NULL, 'client', NULL, '2026-02-10 23:20:58', '2026-02-19 13:53:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-345', 'task', 'T-47', 'Fix entity_renderer.gd field name bug (id vs entity_id)', 'Line 19 of entity_renderer.gd checks entity_data.has("id") but Protocol returns entity_id. This causes all entities to be silently dropped. Change check to entity_data.has("entity_id").\n\nEffort: XS\nCodebase: client\nSource: Architecture Review Audit 2026-02-11 (critical bug)\nSprint: 1', 'done', 'medium', NULL, 'client', NULL, '2026-02-11 20:27:17', '2026-02-19 13:53:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-447', 'task', 'T-416', 'Resolve OQ-29: dialogue max-width pixel value', NULL, 'done', 'low', NULL, 'client', NULL, '2026-02-13 21:07:03', '2026-02-19 13:53:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-252', 'story', 'T-47', 'Placeholder art specification', 'Define tile size, sprite dimensions, color palette, animation frame requirements for placeholder art. Unblocks #133 (placeholder art pipeline). Source: Tyre R1 H-13.', 'done', 'high', NULL, 'visual', NULL, '2026-02-11 00:02:37', '2026-02-19 13:54:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-303', 'story', 'T-47', 'v0.1 Visual Grammar Document', 'Root dependency for all visual work. One-page document codifying: (1) Color palette — 3 zone palettes (logistics hub cool, bar warm, corridors neutral) with hex values, (2) Entity sizing/proportions, (3) Label conventions, (4) UI layer hierarchy, (5) Fog rendering spec (visible/fog-edge/hidden/remembered), (6) Character-specific player entity colors (detective cool, smuggler warm). Zero image files — everything procedural. Zero dependencies — can start immediately. Supersedes #252 (placeholder art spec). Owner: Araminta. Proposed by: Araminta, Ozzie. Workshop: content-gap-analysis v0.1 R2.', 'done', 'critical', NULL, 'visual', NULL, '2026-02-11 19:27:35', '2026-02-19 13:54:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-311', 'story', 'T-58', 'Spatial layout: Logistics Hub (The Terminal)', 'Tile-level floor plan with sightline analysis for Sova Logistics Hub (The Terminal). Zones: scanner bays, main corridor (chokepoint), manifest processing, break room, supervisor office (window), restricted storage (smuggling ops). Serves Triangle 1 (Hub Power) and Triangle 2 (Worried Knowledge). Public/semi-private/private areas mapped to access tiers. Owner: Araminta. Proposed by: Paula, Araminta. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'visual', NULL, '2026-02-11 19:28:39', '2026-02-19 13:54:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-312', 'story', 'T-58', 'Spatial layout: Bar (The Last Shift)', 'Tile-level floor plan for The Last Shift bar. Irregular layout from converted maintenance staging area. Key elements: long bar counter (high visibility), corner booth (key observation position seeing bar + card table + entrance + back room), scattered tables, news ticker display, back room (alley exit). Serves Triangle 3 (Bar Tensions) and Triangle 4 (Worried Partner). Owner: Araminta. Proposed by: Paula, Araminta. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'visual', NULL, '2026-02-11 19:28:40', '2026-02-19 13:54:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-313', 'story', 'T-58', 'Spatial layout: Smuggling spaces and transition corridors', 'Smuggling spaces are NOT a separate building. Ring operates in: restricted storage (hub), maintenance corridors, dead-drop locations. Includes transition corridors between hub and bar district (40m chokepoint). Design principle: ring is invisible — meeting points have mundane purposes, function only apparent if you know what to look for. Same physical space, different player understanding. Owner: Araminta. Proposed by: Paula, Araminta. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'visual', NULL, '2026-02-11 19:28:41', '2026-02-19 13:54:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-94', 'story', 'T-40', 'Active tier simulation', 'Full behavior systems run at 10-20 ticks/sec for Active NPCs. Movement, perception, decision-making.', 'done', 'critical', NULL, 'server', NULL, '2026-02-10 23:19:08', '2026-02-19 14:40:50', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-99', 'story', 'T-40', 'Tier transition logic', 'Promote StateSaved → Background → Active on player approach. Demote Active → Background → StateSaved on departure. ~2-5ms reactivation budget.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:19:08', '2026-02-19 14:40:50', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-138', 'story', 'T-351', 'Information tag schema', 'Define ObserverAccess tags. Public, OwnerOnly, FactionOnly, RelationshipGated, etc. Component metadata.', 'done', 'critical', NULL, 'server', NULL, '2026-02-10 23:21:35', '2026-02-19 14:40:50', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-139', 'story', 'T-351', 'Component-level access control', 'Tag ECS components with observer access rules. Query filters respect tags.', 'done', 'critical', NULL, 'server', NULL, '2026-02-10 23:21:35', '2026-02-19 14:40:50', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-193', 'story', 'T-59', 'Line previewer CLI - Tyre', 'CRITICAL AUTHORING TOOL. Rust CLI sharing code with dialogue pipeline. MVP: (1) Load YAML, (2) Set filter context via CLI, (3) Show matching lines, (4) Show selected line, (5) Explain mode, (6) Sequence mode for walk-throughs, (7) Coverage report, (8) Batch validation. Build AS the first dialogue pipeline implementation. Source: Gestalt+Mellanie+Ozzie content-gap-analysis v0.1 R2.', 'done', 'critical', NULL, 'server', NULL, '2026-02-10 23:25:57', '2026-02-19 14:40:50', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-343', 'task', 'T-61', 'Ban HashMap in simulation crate via clippy', 'Add clippy::disallowed_types lint for std::collections::HashMap in simulation code. Use BTreeMap or IndexMap for deterministic iteration order. Critical for deterministic simulation.\n\nEffort: XS\nCodebase: server\nSource: Architecture Review Audit 2026-02-11\nSprint: 1', 'done', 'critical', NULL, 'ci', NULL, '2026-02-11 20:27:04', '2026-02-19 14:40:50', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-344', 'task', 'T-61', 'Set up tracing crate infrastructure', 'Set up tracing crate for server instrumentation. Configure structured logging for:\n- Tick duration\n- Per-system timing\n- Bridge I/O metrics\n- Entity tier transitions\n\nOutput to stdout in development, file in production.\n\nEffort: S\nCodebase: server\nSource: Architecture Review Audit 2026-02-11\nSprint: 1', 'done', 'high', NULL, 'ci', NULL, '2026-02-11 20:27:09', '2026-02-19 14:40:50', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-346', 'task', 'T-64', 'System dependency graph debug command', 'Write print_system_graph debug command that dumps bevy_ecs schedule ordering and component access patterns. Run in CI and diff across commits to catch unintended system reordering.\n\nEffort: S\nCodebase: server\nSource: Architecture Review Audit 2026-02-11\nSprint: 2+', 'done', 'medium', NULL, 'ci', NULL, '2026-02-11 20:27:25', '2026-02-19 14:40:50', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-527', 'story', NULL, 'Add rng_seed field to ObserverSnapshot for deterministic replay', 'The WRONG button (#507) ring buffer captures inputs.jsonl and seed.txt for replay, but seed.txt currently writes ''unavailable'' because the server does not include rng_seed in ObserverSnapshot. Add rng_seed: u64 to ObserverSnapshot with serde default for backward compat. Client already parses this field. Enables deterministic replay from bug reports.', 'done', 'medium', NULL, 'ci', NULL, '2026-02-19 11:40:17', '2026-02-19 14:40:50', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-368', 'task', 'T-351', 'Knowledge vocabulary for v0.1 content (#309)', 'Content authoring vocabulary document from D-041 Appendix A. Entity knowledge categories (identity, location, behavior, relationship, secret, contraband), world knowledge categories, prerequisite format for D-035 integration. Unblocks content team ticket #309. Estimate: 0.5 day.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-11 22:14:35', '2026-02-19 14:43:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-262', 'story', 'T-59', 'Environmental text content', 'Signs, terminals, documents, and readable objects in social sites. Provides world-building texture and investigation clues. Both characters can read them but interpret differently. Source: Gestalt R2 M-3.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-11 00:03:49', '2026-02-19 15:11:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-307', 'story', 'T-59', 'Flat NPC memorable trait pass — 3 flat NPCs', '3 flat NPCs (Pael/maintenance tech, Ren/drifter, Tev/lookout) each need: one memorable trait, one seems-important-but-isnt line, visible routine. Without this, the 30/50/20 investigation noise floor collapses — flat NPCs must be indistinguishable from signal at first glance. Owners: Paula (traits) + Mellanie (lines). Proposed by: Ozzie. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'copy', NULL, '2026-02-11 19:28:35', '2026-02-19 15:11:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-331', 'story', 'T-51', 'Diegetic insert flavor text — per character', 'Character-specific insert labels and notification strings. Smuggler: Msg from Kael, Drop point updated. Detective: Case file update: Subject Davan, Commission advisory. POI labels, status text different per character. Owners: Mellanie + Araminta. Proposed by: Ozzie. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-11 19:30:03', '2026-02-19 15:11:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-189', 'story', 'T-59', 'Cultural generation guide - Miri', 'BLOCKING DEPENDENCY. Cultural voice variation guide. Sova Transit District in Krenn System is the FIRST CONCRETE INSTANCE — Miri Round 1 output IS the v0.1 slice. Includes naming conventions, economic texture, institutional presence. Needs formalization into standalone document. Workshop: content-gap-analysis v0.1 R2.', 'done', 'critical', 'miri', 'copy', NULL, '2026-02-10 23:25:57', '2026-02-19 15:16:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-302', 'story', 'T-59', 'Sova Texture Appendix — slang glossary, idioms, sensory details', '1-page appendix to Sova setting brief. Covers: (1) Slang glossary 15-20 terms — do workers say shift or rotation, credits or local term, container or pod, (2) Informal decoration — graffiti, stickers, locker personalization, (3) The local complaint — ventilation in Sector 3, (4) Meridian self-censorship rules — what cant be said on public channels, (5) Food/drink specifics, (6) Additional sensory details. Blocks Mellanie environmental text and monologue authoring. Owner: Miri. Proposed by: Mellanie, Miri. Workshop: content-gap-analysis v0.1 R2.', 'done', 'critical', 'miri', 'copy', NULL, '2026-02-11 19:27:34', '2026-02-19 15:16:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-320', 'story', 'T-33', 'Sova Station Profile — station beyond Transit District', 'Station beyond the Transit District. Type, population (~12,000), districts, governance. NPCs reference wider station — dialogue needs to know whats off-district. Owner: Miri. Proposed by: Miri. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', 'miri', 'copy', NULL, '2026-02-11 19:29:48', '2026-02-19 15:16:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-321', 'story', 'T-33', 'Contraband specification — lattice components + supply chain', 'Primary: unlicensed lattice components (aftermarket neural mods bypassing Commission regulation). Secondary: Severance counter-surveillance tech, off-manifest biologicals. Includes medical-grade neural replacements (humanitarian dimension). Supply chain: aftermarket manufacturers > freight networks > local distributors > end users. The ring is smuggling ACCESS not weapons — moral ambiguity core. Owner: Miri. Proposed by: Miri. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', 'miri', 'copy', NULL, '2026-02-11 19:29:48', '2026-02-19 15:16:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-336', 'story', 'T-33', 'Span Gate Transit Schedule', 'How often the gate cycles, peak times, maintenance windows. The freight rhythm is the districts heartbeat — NPC routines depend on it, ring operational timing depends on it. Owner: Miri. Proposed by: Miri. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', 'miri', 'copy', NULL, '2026-02-11 19:30:04', '2026-02-19 15:16:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-306', 'story', 'T-59', 'News ticker / Meridian feed content — 20-30 lines', '20-30 ticker lines for Sova Transit District. 3 types: Concord Assembly proceedings, freight market prices, Commission notices. Setting-consistent per Miri. Cheapest wow-per-word in the project. Dual-lens: same ticker triggers different monologue reactions. Owners: Mellanie + Miri. Proposed by: Mellanie, Paula, Ozzie. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-11 19:28:34', '2026-02-19 15:19:48', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-335', 'story', 'T-33', 'Meridian Coverage Map for Sova Transit', 'Where coverage is strong, where it degrades, dead spots the ring exploits. Affects detective investigation capability, smuggler operational planning, NPC behavior (off-Meridian communication in dead spots). Owner: Miri. Proposed by: Miri. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', 'miri', 'copy', NULL, '2026-02-11 19:30:04', '2026-02-19 15:22:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-259', 'story', 'T-59', 'First 5 minutes experience design', 'Define each character opening: where they wake up, first diegetic objective, opening monologue lines, who they meet. Not a cutscene — systemic opening using existing systems. The hook that determines whether the player keeps playing. Opening hooks should draw from seed-selected pool of 3-4 per character. Source: Gestalt R2, Ozzie R1+R2 H-9, Nigel R2.', 'done', 'high', NULL, 'copy', NULL, '2026-02-11 00:03:37', '2026-02-19 15:26:43', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-329', 'story', 'T-59', 'Mirror moment design document — 10-15 paired observations', '10-15 scripted dual-perspective observation triggers. Same event, different character monologue creating dramatic irony on replay. 7 core mirrors designed: The Friends Routine, The Empty Corridor, The Worried Partner, The Spending, Sera Leaving, The Hum, The Commission Kiosk. Plus 3-5 organic mirrors discovered during content review. Owners: Paula + Mellanie. Proposed by: Mellanie, Paula. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-11 19:30:03', '2026-02-19 15:26:43', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-332', 'story', 'T-59', 'Contradiction arc design document — reusable FRIEND pattern', 'Reusable pattern document from THE FRIEND implementation. Defines: 3+ relationship phases with distinct monologue registers, observable contradiction discoverable through observation not dialogue, sympathetic motivation, no clean resolution, dual-lens resonance, triangle integration, 3+ tell progressions, pre/post-discovery dialogue pools. Owner: Paula. Proposed by: Paula. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-11 19:30:03', '2026-02-19 15:26:43', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-179', 'story', 'T-57', 'Character definition schema', 'Define character structure: background, starting knowledge, relationships, access permissions, skills. Smuggler vs Detective specs. NEEDS DESIGN DISCUSSION.', 'done', 'critical', NULL, 'copy', NULL, '2026-02-10 23:24:52', '2026-02-19 15:26:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-180', 'story', 'T-57', 'Smuggler character build', 'Logistics worker. Insider access to workplace and smuggling ring. Social camouflage. Criminal templates as daily life. NEEDS DESIGN DISCUSSION.', 'done', 'critical', NULL, 'copy', NULL, '2026-02-10 23:24:52', '2026-02-19 15:26:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-181', 'story', 'T-57', 'Detective character build', 'Institutional investigator. Authority access. Analytical skills. Smuggling ring as investigation target. NEEDS DESIGN DISCUSSION.', 'done', 'critical', NULL, 'copy', NULL, '2026-02-10 23:24:52', '2026-02-19 15:26:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-182', 'story', 'T-57', 'Divergent starting knowledge', 'Smuggler knows criminals, workplace gossip. Detective knows institutional info, case files. Inverted information sets.', 'done', 'critical', NULL, 'copy', NULL, '2026-02-10 23:24:52', '2026-02-19 15:26:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-183', 'story', 'T-57', 'Divergent relationships', 'Smuggler: friends with criminals, neutral to law. Detective: backed by institution, adversarial to criminals. Same NPCs, different trust.', 'done', 'critical', NULL, 'copy', NULL, '2026-02-10 23:24:52', '2026-02-19 15:26:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-322', 'story', 'T-57', 'Detective institutional chain of command', 'Who assigned the investigation, stated mandate, political pressures. Was the previous Commission liaison rotation routine or arranged? Affects detective narrative arc — who they report to and what constraints they operate under. Owner: Miri + Paula. Proposed by: Miri, Paula. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'copy', NULL, '2026-02-11 19:29:48', '2026-02-19 15:26:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-260', 'story', 'T-59', 'Opening hook content per character', 'Authored content for character-specific opening moments. Smuggler: contact messages, obligation pull. Detective: case file, investigation pull. Seed-aware pool of 3-4 opening situations per character for replay variation. Source: Gestalt R2, Ozzie R2, Nigel R2.', 'done', 'high', NULL, 'copy', NULL, '2026-02-11 00:03:37', '2026-02-19 15:28:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-534', 'story', 'T-47', 'Monologue display system visual spec', 'Visual spec for monologue display per #315 (existing backlog ticket). Typography, positioning, fade animation, stacking rules (max 3 visible), priority system. Character-differentiated color (smuggler warmer, detective cooler). This ticket is #315 — assigning to visual team and sprint 13.', 'cancelled', 'high', NULL, 'visual', NULL, '2026-02-19 15:32:41', '2026-02-19 15:32:45', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-190', 'story', 'T-59', 'Workplace content pack - Mellanie', 'Role voice kits for cargo workers, supervisors. Situation scripts (shift change, cargo issues, break conversations). Monologue hooks. Trait transformation guide. ~165-210 lines.', 'done', 'critical', NULL, 'copy', NULL, '2026-02-10 23:25:57', '2026-02-19 15:43:27', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-191', 'story', 'T-59', 'Bar content pack - Mellanie', 'Role voice kits for bartender, regulars. Social dialogue (40% more lines than investigation). Gossip pools. Flirting, tension, comfort. ~210-280 lines.', 'done', 'critical', NULL, 'copy', NULL, '2026-02-10 23:25:57', '2026-02-19 15:43:27', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-192', 'story', 'T-59', 'Smuggling ring content pack - Mellanie', 'Role voice kits for criminals. Trust-gated disclosure. Coded language, paranoia, loyalty tests. Investigation target dialogue. ~165-210 lines.', 'done', 'critical', NULL, 'copy', NULL, '2026-02-10 23:25:57', '2026-02-19 15:43:27', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-194', 'story', 'T-59', 'Generation pass expansion', 'LLM-assisted generation: authored lines as style anchors, 4x expansion. Human writes 10, generates 40. Background filler.', 'done', 'high', NULL, 'copy', NULL, '2026-02-10 23:25:57', '2026-02-19 15:43:27', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-315', 'story', 'T-47', 'Monologue display system visual spec', 'Typography, positioning, fade animation, stacking rules (max 3 visible), priority system (observation > atmosphere > tutorial). Character-differentiated color (smuggler warmer, detective cooler). Max ~80 chars per line. Gives Mellanie display constraints. Owner: Araminta. Proposed by: Araminta, Paula. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'visual', NULL, '2026-02-11 19:29:48', '2026-02-19 16:07:32', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-532', 'task', 'T-46', 'NPC conversation murmur asset — event-driven World SFX bus wiring', 'Per D-072: NPC proximity murmur is a separate event-driven asset played on the World SFX bus. Single universal murmur asset (not zone-specific). Zone ambient determines conspicuousness: bar ambient buries it, corridor ambient exposes it. Inigo to produce the murmur asset via Stable Audio Open. Client wiring (event-driven playback) is a separate client ticket blocked by this one.', 'done', 'medium', NULL, 'audio', 'D-072', '2026-02-19 15:32:31', '2026-02-19 16:11:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-505', 'story', 'T-455', 'Gauntlet rooms: Sound Lab, Decay Observatory, Shift Change', '3 Gauntlet rooms requiring sound system and knowledge decay implementation. Audio + decay + stress coverage. Backlog. Depends on sound system and knowledge decay systems. Effort: 3d.', 'done', 'medium', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-19 17:37:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-523', 'task', 'T-416', 'Resolve OQ-09: zone temperature memory — server-tracked or client-only', 'D-059 specifies deep fog (previously explored) carries a ~10% zone temperature tint (bar=warm dark, hub=cool dark, corridor=neutral dark). OQ-09 asks whether this is server-tracked (server sends zone temperature per tile in ObserverSnapshot) or client-only (client remembers last-visited zone and applies tint locally). Architectural decision affects the ObserverSnapshot protocol and whether zone temperature is diegetically accurate or a client heuristic. Decide and implement. If server-tracked: add zone_temperature field to snapshot. If client-only: implement in fog shader layer 3 using local visited-zone memory.', 'done', 'low', NULL, 'server', 'D-059', '2026-02-18 10:45:25', '2026-02-19 17:37:37', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-528', 'story', 'T-46', 'AudioManager full implementation — 5-bus setup, directory registry, volume sliders', 'Implement the full AudioManager GDScript autoload singleton per D-068. 5 buses: Music, Ambient, World SFX, Player Actions, UI Sounds. Directory-scan registry: scan res://audio/ on startup, map filenames to AudioStream resources. No hardcoded asset list. No-op fallback if assets missing. 5 player-facing volume slider bindings for settings UI. Confirm bus routing: NPC conversation murmur -> World SFX, monologue chimes -> UI Sounds. Replaces the Sprint 7 stub with production-ready implementation.', 'done', 'high', NULL, 'client', 'D-068', '2026-02-19 15:32:09', '2026-02-19 17:46:07', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-529', 'story', 'T-46', 'Zone crossfade implementation — 1.5-2s tween on zone_id change', 'Implement zone audio crossfades per D-073. AudioManager receives zone_id from ObserverSnapshot tile data. On zone_id change: start 1.5-2s tween crossfading from current ambient layer to new zone ambient layer. Hard boundary trigger at tile entry. Interruptible. Zones for v0.1: hub/workplace, bar, smuggling corridor. Blocked by AudioManager full implementation.', 'done', 'high', NULL, 'client', 'D-073', '2026-02-19 15:32:15', '2026-02-19 17:46:07', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-530', 'story', 'T-46', 'Audio dip profiles — dialogue, confrontation, ListeningFocus boost', 'Implement 3 audio dip profiles per D-069. Dialogue dip: Ambient -6 to -8dB, 300ms ease-in, 500ms ease-out. Confrontation dip: Ambient -10 to -12dB + low-pass filter 20kHz->800Hz, World SFX -4 to -6dB graduated, 500ms ease-in, 1000ms ease-out with filter sweep. ListeningFocus boost: World SFX +2 to +3dB when player stationary 30+ ticks (D-071). All values proportional to player slider settings, not absolute. Dips interruptible on walk-away or stance change. No UI indicator (D-070: felt not computed).', 'done', 'high', NULL, 'client', 'D-069', '2026-02-19 15:32:20', '2026-02-19 17:46:07', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-531', 'story', 'T-46', 'Recognition chime — fires at cognitive delay onset (D-067)', 'Wire the recognition chime per D-067. Chime fires at ONSET of cognitive delay (D-060), not at completion. Duration 300-400ms, overlapping with start of 0.6s delay. Full sequence: (1) entity detected in fog -> (2) chime plays -> (3) cognitive delay begins -> (4) monologue text appears during delay -> (5) blob transitions to D-033 color + silhouette -> (6) recognition complete. Chime asset: monologue chime from D-038 assets 7-8, routed to UI Sounds bus. Client detects RecognitionTrigger in ObserverSnapshot and triggers the chime + delay sequence.', 'done', 'high', NULL, 'client', 'D-067', '2026-02-19 15:32:27', '2026-02-19 17:46:08', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-533', 'task', 'T-46', 'Wire NPC conversation murmur to World SFX bus — event-driven playback', 'Client-side wiring for NPC conversation murmur per D-072. AudioManager plays murmur asset on World SFX bus when SimBridge receives conversation events from ObserverSnapshot. Single universal asset (produced by audio team, #532). Zone ambient provides natural conspicuousness: bar = buried, corridor = exposed. No zone-specific variants needed. Blocked by #532 (murmur asset).', 'done', 'medium', NULL, 'client', 'D-072', '2026-02-19 15:32:37', '2026-02-19 17:46:08', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-251', 'story', 'T-47', 'Tell visual/behavioral expression', 'Define how NPC behavioral tells manifest in the top-down renderer. Movement hesitation before entering rooms, route changes, grouping behavior, interaction changes. The visible starting point for the observation chain — without visual tells, the observation mechanic has no entry point. Source: Paula R1+R2 H-7, Ozzie R2.', 'done', 'high', NULL, 'visual', NULL, '2026-02-11 00:02:37', '2026-02-20 17:49:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-304', 'story', 'T-47', 'Entity Color System Spec — relationship-to-player mapping', 'Formal spec for approved color model: relationship states map to colors (unknown=teal #4a9ebb, known/friendly=green #6bc9a6, person-of-interest=amber #e8c547, hostile=red #d45d5d, static objects=grey #8b8ba0). Transition animations (0.5s fade). Edge cases (relationship change mid-observation). Key principle: red means danger TO YOUR CHARACTER, not abstract danger. Same NPC different color per character = asymmetric information rendered visually. Owner: Araminta. Proposed by: Araminta. Workshop: content-gap-analysis v0.1 R2.', 'done', 'critical', NULL, 'visual', NULL, '2026-02-11 19:27:37', '2026-02-20 17:49:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-316', 'story', 'T-47', 'Text display hierarchy spec — 4 content pipelines', 'How dialogue, monologue, observation, overheard conversation, and environmental text each render distinctly. Four pipelines, four visual treatments. Dialogue: max ~100 chars in panel. Environmental: 8-40 char labels, up to 200 for terminals. News ticker: single scrolling line, ~60 char window. Owner: Araminta. Proposed by: Araminta. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'visual', NULL, '2026-02-11 19:29:48', '2026-02-20 17:49:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-317', 'story', 'T-46', 'Sound indicator visual design — fog-edge pulse', 'Fog-edge pulse indicators for the three-range sound model (D-018). Complementary to audio, not replacement. Color-coded: neutral #c8d0e0, voices #e8c547, danger #d45d5d. Shows sound direction — audio communicates something there, visuals communicate where. Owner: Araminta. Proposed by: Araminta. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'visual', NULL, '2026-02-11 19:29:48', '2026-02-20 17:49:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-318', 'story', 'T-47', 'THE FRIEND visual treatment spec', 'How THE FRIEND NPC looks different from other NPCs — through EARNED visual detail, not special marking. Phase 1: identical to other friendly NPCs (green rectangle), attachment built through monologue frequency and spatial proximity. Phase 2: color shift green to amber on contradiction discovery (0.5s fade) — should be FIRST relationship color change in session. Phase 3 (future): unique sprite, behavioral animations, memory echo. Owner: Araminta. Proposed by: Araminta. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'visual', NULL, '2026-02-11 19:29:48', '2026-02-20 17:49:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-334', 'story', 'T-47', 'Environmental text visual standards', 'How signage, terminals, news tickers render in-world. Bilingual treatment per Miri (Concordat Standard + Krenn vernacular). Character limits per format. Owner: Araminta. Proposed by: Araminta. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', NULL, 'visual', NULL, '2026-02-11 19:30:04', '2026-02-20 17:49:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-120', 'story', 'T-45', 'Monologue line pool system', 'Categorized line pools: perception, atmosphere, tutorial, observation. Tag-based line selection.', 'done', 'high', NULL, 'copy', NULL, '2026-02-10 23:20:40', '2026-02-20 17:58:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-121', 'story', 'T-45', 'Character voice variation', 'Personality-driven line selection. Background-dependent phrasing (Guardian vs Senator vs Worker). Mood influence.', 'done', 'high', NULL, 'copy', NULL, '2026-02-10 23:20:40', '2026-02-20 17:58:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-168', 'story', 'T-55', 'Tagged line pool structure', 'CONVERGED in workshop. YAML format with 6 structural tags (id, text, role, access, trust, situation) + 3 selection tags (topic, mood, freeform) + 2 authoring-only (dual_lens, notes). Monologue adds: character (hard partition), trigger (9 types), prerequisite. Access=list(public,insider,authority,peer,hostile). Trust=surface/real/secret. 13 situations, 9 topics, 8 moods. Location/type are directory/file-level. Source: Gestalt+Mellanie+Paula content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'copy', NULL, '2026-02-10 23:24:25', '2026-02-20 17:58:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-253', 'story', 'T-45', 'Monologue content architecture', 'Define monologue line pool structure, category tags, and authoring requirements. Identity-driven interpretation: monologue queries character interpretive frame (cares about, fears, responsible for), not just knowledge state. Includes tone progression tracking based on cumulative discoveries. Source: Gestalt R2 H-10, Paula R1 monologue tone progression, Gore R2 interpretive framing.', 'done', 'high', NULL, 'copy', NULL, '2026-02-11 00:02:40', '2026-02-20 17:58:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-328', 'story', 'T-55', 'Access tier shift design document', 'How access tiers change during gameplay. Per social site: 2-3 most likely tier transitions per character with triggers. E.g. Smuggler at hub: insider>hostile when cover blown. Detective at bar: public>insider after 3-4 visits. Content packs need lines for both starting AND shifted states. Owners: Paula + Gestalt. Proposed by: Paula, Gestalt. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'copy', NULL, '2026-02-11 19:29:55', '2026-02-20 17:58:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-536', 'story', 'T-55', 'NPC-to-NPC overheard dialogue line pool', 'Write the line pool for NPC-to-NPC conversations that the player can overhear, per D-078. Lines must work both at full clarity and under partial occlusion (dropped words should not destroy meaning — prefer short declarative sentences, front-load key information). Requirements: (1) Minimum 40 exchange pairs covering social/work/gossip registers. (2) Each exchange is tagged with: speaker role, topic, relationship_type (colleague, friend, hostile, romantic), and knowledge payload (what the player could infer if they heard it clearly). (3) Lines must be self-contained per-turn — no exchanges that only make sense with both halves audible. (4) Avoid pronouns as sentence-openers (occlusion drops first word; pronoun loss breaks reference). Source: D-078.', 'done', 'high', NULL, 'copy', NULL, '2026-02-19 18:34:05', '2026-02-20 17:58:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-101', 'story', 'T-41', 'Routine execution system', 'Schedule-driven NPC movement. Location transitions at scheduled times. Activity state management.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:19:21', '2026-02-20 18:31:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-103', 'story', 'T-41', 'Relationship dynamics', 'Relationship values change over time. Interaction effects, decay, reinforcement. Trust modification.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:19:21', '2026-02-20 18:31:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-122', 'story', 'T-45', 'Monologue display - client', 'Text display area in HUD. Timed display, queue management. Readable but non-intrusive.', 'done', 'high', NULL, 'client', NULL, '2026-02-10 23:20:40', '2026-02-20 18:31:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-247', 'story', 'T-41', 'NPC-to-NPC conversation system', 'NPCs engage in conversations with each other that the player can observe and overhear. Generates sound events for the sound propagation model. Observable social interactions feed the observation pipeline. Source: Gestalt R2 H-4.\n\nD-078 scope addition: Emit conversation events to the client with full metadata. Each ConversationEvent on ObserverSnapshot must carry: occluded_line: String (the NPC dialogue line with dropped words replaced by "..."), speaker_id: EntityId, target_id: EntityId, speaker_name: String, target_name: String. The server computes per-word occlusion before emission — the client receives pre-occluded text and renders it as-is.\n\nPer-word occlusion algorithm (server-side, D-078 amendment): iterate the dialogue line word by word. For each word, perform an independent Bernoulli trial using a seedable RNG (seeded per tick for deterministic replay, D-010). The per-word drop probability is derived from three inputs at the moment of emission: (a) tile distance from player to the speaking NPC — linear decay from 0.0 drop probability at 0 tiles to 1.0 at the Voice sound range boundary; (b) ambient noise level at the player position (already tracked in ObserverSnapshot.ambient_noise) — adds up to 0.3 to drop probability; (c) whether the player entity has ListeningFocus stance active — subtracts 0.2 from drop probability (clamped to [0.0, 1.0]). Words that fail the trial are replaced with "..." in occluded_line. The client receives only occluded_line and renders it verbatim — no stochastic logic on the client.\n\nWhen a conversation ends (NPC departs zone or duration expires), emit a conversation_end event with the same pair IDs so the client can dismiss the panel. Trigger witness_interaction on the player observation pipeline whenever the player receives any conversation event (regardless of occlusion level).\n\nNo dialogue content needed in this ticket — content is sourced from the NPC-to-NPC line pool (#536, copy team, Sprint 14).\n\nDelivery: NpcConversation state component, run_npc_conversations system, Voice SoundEvent emission, ConversationEvent struct with occluded_line on ObserverSnapshot, conversation_end event, per-word occlusion function with seedable RNG, tests: npc_conversation_emits_voice_event_when_in_range, npc_conversation_terminates_when_apart, occlusion_drops_words_with_distance, occlusion_suppressed_by_listening_focus, occlusion_deterministic_with_same_seed. Blocks #535 (client).', 'done', 'high', NULL, 'server', NULL, '2026-02-11 00:02:28', '2026-02-20 18:31:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-323', 'story', 'T-39', 'NPC mood state machine', 'NPCs need mood component that changes based on simulation events (triangle pressure, time of day, recent interactions). Mood drives Layer 4 dialogue selection + tell system. 8 moods for v0.1: neutral, happy, tired, annoyed, nervous, defensive, friendly, cautious. Owner: Dudley. Proposed by: Gestalt. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 19:29:48', '2026-02-20 18:31:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-324', 'story', 'T-39', 'Trust progression system', 'Engine tracks trust level per player-NPC pair. Progression: surface > real > secret. Advances based on interaction quality and frequency. Must be observable (player senses trust improving). Feeds Layer 3 dialogue filtering. Owner: Dudley. Proposed by: Gestalt. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 19:29:55', '2026-02-20 18:31:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-325', 'story', 'T-39', 'Interaction tracking component', 'Per-NPC-pair counter: interaction_count, last_interaction_time, notable_events log. Drives Layer 2 situation activation (first_meeting requires count==0, repeated_visit requires count>=3). Owner: Dudley. Proposed by: Gestalt. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 19:29:55', '2026-02-20 18:31:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-508', 'task', 'T-455', 'Map-agnostic invariant tests (36 invariants from Gestalt)', '36 invariants across 4 categories: structural (8), perception (5), population (8), simulation (8). Must hold for ANY valid map. Backlog. Depends on dynamic map system. See workshop-outcomes.md Appendix D. Effort: 3d.', 'done', 'medium', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-20 18:31:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-511', 'task', 'T-455', 'F3 debug overlay (deferred — WRONG button covers same data)', 'Real-time debug overlay. Deferred indefinitely per Stig recommendation — WRONG button captures same data on demand without per-frame performance cost. Backlog. Effort: 1.5d.', 'done', 'medium', NULL, 'client', NULL, '2026-02-17 12:58:13', '2026-02-20 18:43:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-535', 'story', 'T-55', 'Passive dialogue panel — overheard NPC conversation display', 'Render overheard NPC-to-NPC conversations in the dialogue panel in passive (read-only) mode. Consumes ConversationEvent from ObserverSnapshot (added by server #247). Requirements per D-078 (amended — occlusion is server-authoritative):\n\n(1) Speaker attribution: Display header as "Speaker → Target" (e.g. "Kael → Mira") using speaker_name and target_name from the event. Use the same attribution label slot as player conversation NPC-name display — no new layout region needed.\n\n(2) Pre-occluded text renderer: Render occluded_line as-is. The server has already performed per-word Bernoulli drops and replaced dropped words with "...". The client performs no stochastic logic — no clarity_score, no randf(), no per-word processing. Display the received string directly in the passive panel.\n\n(3) Read-only mode: The dialogue box must suppress response options and player input when displaying a passive conversation. No response list, no input capture. Player can still move freely.\n\n(4) Dismissal: On conversation_end event (or if player moves far enough that no ConversationEvent arrives for the NPC pair), dismiss via the standard 300ms fade (same Tween as walk-away fade, #437 done).\n\n(5) Monologue isolation: Monologue display (#122, z-layer 6) is unaffected. Do not route conversation text through the monologue display. The server triggers witness_interaction which may produce a monologue — that arrives separately via current_monologue and is rendered by #122 normally.\n\nBlocked by #247 — ConversationEvent struct must exist on ObserverSnapshot before this can be wired. Start with a stub event type and placeholder renderer if #247 is not yet landed.\n\nDelivery: passive mode in client/scripts/ui/dialogue_box.gd (or a new passive_dialogue.gd sibling), verbatim occluded_line render, speaker attribution header, conversation_end dismissal. Tests via Hoshe gdUnit4 harness: attribution renders correctly, occluded_line with "..." tokens renders verbatim, panel does not show response options in passive mode, dismisses on conversation_end.', 'done', 'high', NULL, 'client', NULL, '2026-02-19 18:33:58', '2026-02-20 19:11:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-299', 'story', 'T-59', 'Opening hook content — smuggler first 5 minutes', 'First 10-15 tightly sequenced monologue lines for smuggler. Diegetic tutorial: teaches movement, fog, sound, NPC interaction, insert. Sets character voice. Establishes motivation. Opening sequence: station hum playing, NPCs already moving, first named NPC encounter (Kael), first news ticker glance, first environmental text read. The most important content in the game — blocks all playtest feedback. Owner: Mellanie. Proposed by: Mellanie, Paula, Ozzie. Workshop: content-gap-analysis v0.1 R2.', 'done', 'critical', NULL, 'copy', NULL, '2026-02-11 19:27:31', '2026-02-21 13:04:30', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-169', 'story', 'T-55', 'Layer 1: Access tier filtering', 'Insider/outsider/authority/peer filters. Every line tagged. Basic conversation gating.', 'done', 'high', NULL, NULL, NULL, '2026-02-10 23:24:25', '2026-02-21 13:04:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-300', 'story', 'T-59', 'Opening hook content — detective first 5 minutes', 'First 10-15 tightly sequenced monologue lines for detective. Different emotional register and tutorial pathway from smuggler. Detective arrives into established rhythm (mid-morning). First NPC contact mediated by institutional insert. Sets analytical voice, institutional backing, outsider perspective. Blocks all playtest feedback. Owner: Mellanie. Proposed by: Mellanie, Paula, Ozzie. Workshop: content-gap-analysis v0.1 R2.', 'done', 'critical', NULL, 'copy', NULL, '2026-02-11 19:27:32', '2026-02-21 13:04:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-170', 'story', 'T-55', 'Layer 2: Relationship history', 'Interaction log per NPC pair. Modifies greeting, topic selection. First meeting vs established vs tense.', 'done', 'high', NULL, NULL, NULL, '2026-02-10 23:24:25', '2026-02-21 13:04:32', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-71', 'story', 'T-36', 'Tilemap rendering system', 'TileMap node setup, tile atlas management, multi-layer support for floors/walls/objects.', 'done', 'critical', NULL, 'client', NULL, '2026-02-10 23:18:12', '2026-02-21 13:08:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-72', 'story', 'T-36', 'Entity sprite system', 'Sprite rendering for dynamic entities (characters, NPCs). Position sync from snapshot data.', 'done', 'critical', NULL, 'client', NULL, '2026-02-10 23:18:12', '2026-02-21 13:08:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-73', 'story', 'T-36', 'Input capture system', 'Keyboard/mouse input → semantic actions (MoveNorth, Interact, etc). Input buffer for network send.', 'done', 'critical', NULL, 'client', NULL, '2026-02-10 23:18:12', '2026-02-21 13:08:50', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-74', 'story', 'T-36', 'Basic UI framework', 'HUD structure, text display areas for monologue, placeholder for insert/minimap.', 'done', 'high', NULL, 'client', NULL, '2026-02-10 23:18:12', '2026-02-21 13:08:50', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-117', 'story', 'T-44', 'Smooth camera movement', 'Interpolation for character movement. No jarring snaps. Configurable smoothing.', 'done', 'high', NULL, 'client', NULL, '2026-02-10 23:20:20', '2026-02-21 13:08:51', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-90', 'story', 'T-39', 'Personality & tell system', 'PersonalityTraits (2-3 traits). TellSystem with 5 categories: nervous, angry, friendly, guarded, routine deviation. v0.1 renderer is MONOLOGUE TEXT not visual animation. Tell state derived from NPC axis values (Secret+Tolerance=nervous, low Contentment=frustrated). Source: Gestalt+Araminta+Ozzie content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:18:49', '2026-02-23 14:43:15', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-92', 'story', 'T-39', 'NPC generation pipeline', 'Procedural NPC generator. Takes template role, produces fully-populated NPC entity. Constraint validation.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:18:49', '2026-02-23 14:43:15', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-105', 'story', 'T-41', 'Tolerance threshold triggers', 'Monitor for threshold violations. Trigger reactions when tolerance exceeded. Behavioral state changes.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:19:21', '2026-02-23 14:43:15', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-119', 'story', 'T-45', 'Monologue event generation - server', 'Trigger monologue on perception events, environment changes, NPC proximity. Context tagging (location, situation, character state).', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:20:40', '2026-02-23 14:43:15', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-241', 'story', 'T-234', 'Follow mechanic', 'Player designates target NPC to follow. System tracks distance and LOS. NPC suspicion increases if player is too close too long (feeds NPC vision #115). Observation events fire at higher frequency while following. Success: target reaches destination. Failure: target enters fog, or detects player. Source: Gestalt R2 H-1. Required by D-027 criterion 4.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 00:01:51', '2026-02-23 14:43:15', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-243', 'story', 'T-234', 'Routine deviation detection', 'Server-side system: compare NPC current position/action vs known routine pattern. Emit RoutineDeviation trigger events when NPCs break their established daily patterns. Core detective mechanic. Feeds into observation event generator. Also covers absence detection (expected NPC not observed at known location). Source: Ozzie R1+R2, Paula R1 absence detection, Gestalt R2.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 00:01:55', '2026-02-23 14:43:15', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-340', 'task', 'T-40', 'Define SpatialIndex trait with naive Vec implementation', 'Create SpatialIndex trait with methods: entities_in_range(position, radius), entities_at(position), update(entity_id, position). Implement naive Vec-based backend for Sprint 1. Grid/quadtree optimization deferred to Sprint 2.\n\nEffort: XS\nCodebase: server\nSource: Architecture Review Audit 2026-02-11\nSprint: 1', 'done', 'critical', NULL, 'server', NULL, '2026-02-11 20:26:47', '2026-02-23 14:43:15', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-538', 'task', NULL, 'Arch: Move dialogue systems from BridgePlugin to NpcPlugin', 'BridgePlugin registers process_talk_interaction, process_walk_away, process_confrontation_response — game logic that depends on NPC-layer resources (TrustEventQueue, KnowledgeGraph). Should be in NpcPlugin. BridgePlugin should own wire protocol only. Found during Sprint 15 QA: game_loop test needed manual TrustEventQueue init.', 'done', 'medium', NULL, 'server', NULL, '2026-02-21 11:32:38', '2026-02-23 18:51:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-171', 'story', 'T-55', 'Layer 3: Trust-gated gossip', 'Three disclosure tiers per role: surface/real/secret. Trust threshold determines tier access. Progressive revelation.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:24:25', '2026-02-23 18:51:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-338', 'story', 'T-55', 'Line variety tracker — prevent repeat dialogue', 'Prevents same line firing repeatedly. Tracks recently-used line IDs per NPC per session. Selects from eligible pool excluding recent history. Critical for 30-minute sessions where player enters same location 4-5 times. Owner: Dudley. Proposed by: Gestalt. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', NULL, 'server', NULL, '2026-02-11 19:30:04', '2026-02-23 18:51:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-539', 'task', 'T-55', 'Server: implement DialogueResponse verb handler', 'The client sends DialogueResponse interact when the player picks a dialogue option, but no server system processes it. Currently only Talk verb is handled (process_talk_interaction in dialogue.rs). Need: a system that receives DialogueResponse with response_id, looks up the NPC''s dialogue tree, and generates a follow-up line + new options (or ends the conversation). Without this, dialogue options 1-2 (non-confrontation) do nothing and option 3 (confrontation) only triggers a client-side monologue beat.', 'done', 'medium', NULL, 'server', NULL, '2026-02-21 12:11:02', '2026-02-23 18:51:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-541', 'story', 'T-47', '3D sprite render pipeline setup', 'Establish the offline 3D sprite render pipeline: Camera3D configuration, lighting rig, export process for entity/object/wall sprites. Prerequisite for all camera-angle and sprite re-render work (see #540, D-019). Pipeline must produce 64x64 tile-grid-aligned sprites at configurable camera angles.', 'done', 'medium', NULL, 'visual', NULL, '2026-02-21 12:36:34', '2026-02-23 19:28:08', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-540', 'story', 'T-47', 'Adjust sprite camera to D-019 angle (~15-20° from vertical)', 'Integrate rendered sprites from #541 into the Godot client. The 3D render pipeline already produces sprites at D-019 angle (-72.5° from horizontal). Remaining work: + +1. Load PNG sprites from client/assets/sprites/ (npc_generic_*_64.png, wall_structural_*_64.png) +2. Replace programmatic draw_rect placeholders in entity_renderer.gd with Sprite2D using the rendered PNGs +3. Switch entity y-sort anchor from center to bottom-anchor (ENTITY_OFFSET_Y comment already notes this migration) +4. Verify 24x32 footprint within 64x64 tile matches D-044 visual hierarchy +5. Test z-sorting with real sprites (y-based sort must still work correctly) + +Ref: decisions/perception.md D-019, D-043, D-044.', 'done', 'medium', NULL, 'client', NULL, '2026-02-21 12:36:26', '2026-02-23 20:02:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-543', 'story', NULL, 'Optimize zone_id extraction from O(N) tile scan to O(1) dictionary lookup', 'game_state.gd apply_snapshot() currently does a linear scan across visible_tiles on every snapshot to extract zone_id for the player''s current tile position. At v0.1 bounded map sizes (~150x150, D-012) this is acceptable, but will degrade when the chunk system lands and visible_tiles grows with view radius. + +Fix: when visible_tiles is parsed into visible_positions in the same apply_snapshot() call, populate a _tile_by_coord Dictionary at the same time and use O(1) lookup for zone_id. Net-zero-complexity change since the loop is already there. + +Flagged by Tyre in PR #54 review (T3). Pre-existing code, not introduced by Sprint 15.', 'done', 'medium', NULL, 'client', NULL, '2026-02-21 13:30:38', '2026-02-23 20:02:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-542', 'story', NULL, 'Migrate line IDs from location-scoped to NPC-scoped namespace', 'D-035 Sprint 15 Amendment: Line ID prefix changes from {location_slug} to {npc-slug}. + +Current: the-terminal_d_039 (shared across all NPCs at The Terminal — collisions already occurring) +New: kael-davan_d_001, sera-venn_d_001, dock-worker_d_001 (each NPC independent) + +Work items: +1. Update schema description fields in dialogue-pool.schema.json, monologue-pool.schema.json, dialogue-line.schema.json (regex pattern already accepts the new format) +2. Rename all existing line IDs in ~20 dialogue YAML files under content/.../dialogue/ +3. Rename all existing line IDs in monologue pool YAML files under content/.../monologue/ +4. Update any server code that parses or references specific line IDs +5. Update content authoring docs and voice guides that reference the old convention +6. Verify no golden test snapshots reference old IDs + +This is a mechanical rename — no content changes. Each NPC file gets its own sequence starting at _001. The 999-line ceiling per NPC is generous vs 999 per location. + +Rationale: Location-scoped IDs require cross-file coordination and already caused a collision (the-terminal_d_039) with only 15 hand-authored NPCs. Will not scale to procedurally generated populations (D-029: hundreds of NPCs).', 'done', 'medium', NULL, 'copy', NULL, '2026-02-21 13:25:38', '2026-02-23 20:57:37', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-314', 'story', 'T-51', 'Insert/HUD wireframe and spec — dual character variants', 'The lattice overlay design with dual-character variants. Smuggler: social contacts as dots (relationship color), casual labels (The Last Shift, Kaels usual spot). Detective: POI as amber diamonds, evidence squares, institutional labels (Licensed establishment District 7, POI: K. Davan). One parameterized system with lattice_profile parameter — Stig builds one framework not two. Owner: Araminta. Proposed by: Araminta. Workshop: content-gap-analysis v0.1 R2.', 'done', 'high', NULL, 'visual', NULL, '2026-02-11 19:28:42', '2026-02-24 10:26:29', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-263', 'story', 'T-51', 'Time display on insert HUD', 'Show current game time on the diegetic insert display. Player needs to know the time for routine-based investigation. Source: Tyre R1 M-7.', 'done', 'medium', NULL, 'client', NULL, '2026-02-11 00:04:28', '2026-02-24 10:45:56', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-537', 'task', NULL, 'UX: E-Talk overlay feels pointless during proximity', 'Playtester feedback (gauntlet-t2414): the E-Talk interaction overlay does not communicate enough value. When adjacent to an NPC, the overlay appears but does not convey what talking will accomplish. Consider: showing preview of conversation topic, visual hint of NPC mood, or suppressing overlay when already in range.', 'done', 'low', NULL, 'client', NULL, '2026-02-21 11:32:37', '2026-02-24 10:45:57', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-330', 'story', 'T-59', 'Diegetic tutorial monologue lines — per character', '8-10 monologue lines per character that teach mechanics diegetically: movement, fog, sound, NPC interaction, insert usage. Fires on first-time events. Part of opening experience but distinct from opening hook (which sets voice/motivation). Owners: Mellanie. Proposed by: Paula, Gestalt. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-11 19:30:03', '2026-02-24 11:15:14', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-552', 'task', NULL, 'Author contradiction monologue lines — Sera/Kael FRIEND arc', 'Author source-named contradiction monologue lines for the Sera/Kael FRIEND arc per D-083 and Paula Round 2 Mellanie spec. Cognitive-dissonance-not-accusation tone. Lines must name the source entity (e.g. ''Sera said Kael was at the dock. I just saw him in B-7.''). Both detective and smuggler variants needed. Can be authored against spec in parallel with #550 mechanical implementation.', 'done', 'high', NULL, 'copy', NULL, '2026-02-24 01:07:49', '2026-02-24 11:15:14', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-148', 'story', 'T-51', 'POI data model', 'PointOfInterest component. Name, location, category, discovery source, visibility rules.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:22:17', '2026-02-24 11:58:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-149', 'story', 'T-51', 'POI discovery system', 'Learn POIs via: character background, NPC tips, research, physical discovery. Discovery events.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:22:17', '2026-02-24 11:58:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-173', 'story', 'T-55', 'Trait modifier system', 'Trait modifier system for unprompted disclosure — two-stage filter spec (D-081).\n\nStage 1 — candidate pool filter (WHAT):\n- Cautious: remove candidates with confidence < KnowsDetails; remove ToldBy-source facts (will not pass on rumors)\n- Gossipy: include Suspects-confidence candidates (normally excluded)\n- Loyal: remove facts linked to entities with trust_level >= Real in NPC Relationships\n- Talkative: override witness inhibition gate; include candidates at all confidence levels\nTraits map to filter predicates via content-authorable YAML config (not hard-coded enum dispatch).\n\nStage 2 — line pool scoring (HOW):\n- Trait tags in IndexedDialogueLine.tags matched by Layer 4 line selection\n- Tag examples: cautious_delivery, gossip_delivery, professional_delivery\n- Same candidate fact can have multiple authored line variants with different trait delivery tags\n\ndisclosure_eligible / disclosure_blocked field:\n- disclosure_blocked: bool on FactKnowledge (default false)\n- Set true for Major secrets with survival stakes (e.g. Kael ring membership)\n- Never enters candidate pool regardless of trust tier or trait\n\nImplemented as part of Ticket #551 (~40 lines for trait filter predicates + YAML schema).\nDecision refs: D-081.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:24:25', '2026-02-24 11:58:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-545', 'task', 'T-351', 'KnowledgeGrant schema + ContentEntityRegistry', 'Replace KnowledgeGrant struct in server/src/content/types.rs with untagged enum supporting Fact { fact_id, confidence } and Entity { entity_ref, attributes, confidence } variants. Add disclosure_blocked: bool field to FactKnowledge. Create server/src/knowledge/content_registry.rs implementing ContentEntityRegistry resource (BTreeMap). Wire NPC spawn sites to call content_registry.register(content_id, sid). Content index validation: parse confidence strings, validate entity_refs resolve in registry. D-079.\n\nEst: ~120 lines. Blocks all downstream knowledge work (Tickets B-G).', 'done', 'critical', NULL, 'server', NULL, '2026-02-23 23:24:45', '2026-02-24 11:58:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-546', 'task', 'T-351', 'KnowledgeGranted event + process_knowledge_events handler', 'Add KnowledgeEventType::KnowledgeGranted variant in server/src/knowledge/events.rs with ProcessedKnowledgeGrant enum (Fact and Entity subtypes). Add match arm handler. Add TryFrom<&str> for KnowledgeConfidence in server/src/knowledge/types.rs. Wire knowledge_grant field in process_talk_interaction (server/src/simulation/dialogue.rs) after line selection. Runtime NPC KG guardrail: if granting NPC KG does not contain the fact, drop grant with tracing::warn!. Implements D-079 grant mechanism.\n\nEst: ~150 lines. Depends on #545 (Ticket A schema). Blocks: Ticket D (#548), Ticket F (#549), Ticket G (#550), and ticket #141.', 'done', 'high', NULL, 'server', NULL, '2026-02-23 23:24:52', '2026-02-24 11:58:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-547', 'task', 'T-351', 'ContradictionClaim struct + detection in observe_entity', 'Add ContradictionClaim struct and CONTRADICTION_WINDOW_TICKS: u64 = 600 constant in server/src/knowledge/types.rs. Add contradicted_claim: Option to EntityKnowledge with #[serde(skip_serializing_if = "Option::is_none")] and #[serde(default)] (backward-compatible, zero migration required). Implement pre-overwrite contradiction check in observe_entity() in server/src/knowledge/graph.rs: if existing entry has ToldBy source, positions differ, and |current_tick - told_tick| < CONTRADICTION_WINDOW_TICKS, set entry.state = Contradicted, populate contradicted_claim, push ContradictionDetected event. Both ToldBy and DirectObservation entries receive Contradicted state (epistemic neutrality — engine does not determine which is wrong). Add ContradictionDetected event variant in server/src/knowledge/events.rs. Tests: location contradiction, time window boundary, no false positive for non-ToldBy sources. Implements D-083. Closes Q-026.\n\nEst: ~120 lines + ~40 lines tests. Depends on #545 (Ticket A). Blocks: Ticket F (#549).', 'done', 'high', NULL, 'server', NULL, '2026-02-23 23:25:01', '2026-02-24 11:58:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-548', 'task', 'T-351', 'NPC-to-NPC knowledge transfer system (transfer_npc_knowledge)', 'Create server/src/simulation/npc_knowledge_transfer.rs implementing transfer_npc_knowledge Bevy system. System ordering: after(run_npc_conversations). Dual-mutable KG access via kg_query.get_many_mut([entity_a, entity_b]). Transfer fires once per conversation at conversation start. Rate: rng.random_range(1..=3) facts drawn from eligible entries sorted by last_updated_tick descending. Trust-tier eligibility: None/trust<0 = no transfer; Surface 0-3 = Active facts at KnowsOf+ only; Real 3-7 = facts at any confidence + entity observations; Secret 7-10 = all Active entries. Confidence cap: min(source_confidence, KnowledgeConfidence::KnowsOf). Facts with disclosure_blocked: true never transferred. Source: KnowledgeSource::ToldBy { source_id: speaker_sid, tick: time.tick }. Player overheard grant: within VOICE_RANGE_TILES (8), player gains entity-level KG entries at Suspects confidence with KnowledgeSource::Heard { tick, range: Medium }. Implements D-080. Closes Q-024.\n\nEst: ~160 lines. Depends on #545 (Ticket A) + #546 (Ticket B). Blocks: Ticket F (#549, ToldBy entries needed for contradiction), Ticket G (#550, NPC KGs need meaningful content).', 'done', 'high', NULL, 'server', NULL, '2026-02-23 23:25:13', '2026-02-24 11:58:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-549', 'task', 'T-351', 'tell_state.rs KG awareness — MVP information boundary (#142)', 'In server/src/npc/tell_state.rs, add Option<&KnowledgeGraph> to derive_tell_state query. Replace Friendly-tell relationships.entries direct read with kg.relationship_with(&entity_sid) for OTHER-entity relationship state. Self-axis components (Secret, Contentment, Tolerance, Mood) remain as ground-truth reads — information boundary applies to external knowledge only. None KG falls through to current axis-based behavior — existing tests continue passing. Scoped to Active NPCs with KnowledgeGraph component (With). Fallback on missing KG entry: fall through to ground truth with tracing::debug! structured logging. Implements D-082 MVP (ticket #142 Sprint 17 deliverable, step 1 of 2).\n\nEst: ~35 lines. No dependencies, no blockers. Standalone improvement.', 'done', 'high', NULL, 'server', NULL, '2026-02-23 23:25:21', '2026-02-24 11:58:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-551', 'task', 'T-351', 'DisclosureCandidates + unprompted disclosure', 'Create server/src/npc/disclosure.rs: DisclosureCandidates component {candidates: Vec, computed_tick: u64}; DisclosureCooldown component {per_fact_history: BTreeSet, npc_cooldown_until: u64}; derive_disclosure_candidates system (recomputes every 30 ticks, Active NPCs only — filter by Active state, confidence >= KnowsOf trait-adjusted, not in per_fact_history, disclosure_blocked != true, trust rough-gate); process_unprompted_disclosure system with trigger gates (trust >= Surface; mood != Hostile; contentment >= -10; candidates not empty; per-NPC 300-tick cooldown clear; global 1/10-tick rate limit, StableId-ordered for determinism; witness inhibition — no non-trusted NPCs within 5 tiles OR Secret trust OR Talkative trait; location privacy — disclosure_context vs zone type); global rate limit resource. Trait Stage 1 filter predicates: Cautious (requires KnowsDetails+, removes ToldBy-source facts); Gossipy (includes Suspects candidates); Loyal (suppresses entity-linked facts where entity trust >= Real); Talkative (overrides witness inhibition, all confidence levels). Candidate list capped at 10, sorted by confidence desc then last_updated_tick desc. In server/src/simulation/dialogue.rs, Layer 4 reads DisclosureCandidates for NPC-initiated line selection. System ordering: derive_disclosure_candidates.after(process_knowledge_events), process_unprompted_disclosure.after(derive_disclosure_candidates). Implements D-081, D-082 step 2, tickets #172 + #173.\n\nEst: ~220 lines. Depends on #546 (B) + #548 (D) for meaningful NPC KG content.', 'done', 'high', NULL, 'server', 'D-081', '2026-02-23 23:25:47', '2026-02-24 11:58:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-232', 'task', 'T-75', 'Create protocol versioning scheme', 'Version field in messages. Compatibility checking. Migration strategy.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:27:49', '2026-02-24 12:03:16', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-550', 'task', 'T-351', 'Contradiction monologue + event chain completion', 'In server/src/simulation/monologue.rs, add EntityRegistry + Query<&NpcName> to system signature; add resolve_name helper; add match arm for ContradictionDetected. In server/src/knowledge/events.rs, ContradictionDetected processing: call relationship shift for ToldBy source entity (-> PersonOfInterest); pre-resolve source_display_name and subject_display_name via EntityRegistry + NpcName into event struct (monologue system is a pure string consumer). Content (separate Mellanie ticket): generic fallback template line + hand-authored FRIEND-specific lines for Sera/Kael contradiction phases. Integration test: full THE FRIEND arc sequence — Tick T1 grant creates ToldBy EntityKnowledge -> Tick T2 observation triggers ContradictionClaim -> monologue fires with correct names -> Sera/Kael shift to PersonOfInterest -> AnomalyMarker set. Downstream consumers (anomaly.rs, D-033 pipeline) already built and tested. Implements D-083 event chain.\n\nEst: ~90 lines. Depends on #545 (A), #546 (B), #547 (C), #548 (D). No downstream blockers.', 'done', 'high', NULL, 'server', 'D-083', '2026-02-23 23:25:34', '2026-02-24 12:03:17', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-141', 'story', 'T-351', 'Knowledge-based information gating', 'POI discovery wiring via KnowledgeGranted event (D-079). When player enters a POI trigger zone, push KnowledgeGranted { fact_id: FactId("poi.*"), confidence, source: DirectObservation { tick } } to KnowledgeEventQueue. filter_by_access -> KnowledgeGated("poi.dock_7_restricted") already gates content on this fact (graph.rs:299-302). No new access control code; no new types; no new systems beyond the shared KnowledgeGranted event. Primarily content authoring for POI definitions.\n\nWorkshop scope note (2026-02-24): grant mechanism is KnowledgeEventType::KnowledgeGranted unified event type — no separate event type for POI discovery. Implementation: ~20 lines on top of #546 infrastructure.\n\nDepends on: #546 (KnowledgeGranted event + handler).\nDecision refs: D-079.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:21:35', '2026-02-24 12:03:28', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-142', 'story', 'T-351', 'NPC information boundaries', 'NPC information boundaries — MVP scope (D-082). Sprint 17 deliverables:\n\n1. tell_state.rs KG awareness (#549): derive_tell_state adds Option<&KnowledgeGraph>; uses KG for OTHER-entity relationship reads; falls back to axis components for self-state and when KG absent. ~35 lines.\n\n2. DisclosureCandidates component + derive_disclosure_candidates system (see #551): Active NPCs derive candidate pool from own KG every 30 ticks. ~part of 220-line Ticket G.\n\n3. process_unprompted_disclosure system stub (#551): trigger gates operational; content-authored lines sparse for Sprint 17.\n\nExplicitly OUT OF Sprint 17 scope:\n- Conversation partner KG-awareness check (Sprint 18)\n- Routine KG awareness (v0.2+)\n- Pathfinding KG integration (not planned — unresolvable failure mode)\n\nNPCs check only their own KG (not player KG) — diegetically correct per D-082, creates dramatic irony when NPC says things player already knows.\n\nDepends on: #549 (tell_state), #546 (B), #548 (D) for full delivery.\nDecision refs: D-082.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:21:35', '2026-02-24 12:03:29', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-172', 'story', 'T-55', 'Layer 4: Unprompted disclosure', 'Unprompted disclosure — full mechanical specification (D-081).\n\nNew components (server/src/npc/disclosure.rs):\n- DisclosureCandidates { candidates: Vec, computed_tick: u64 }\n- DisclosureCooldown { per_fact_history: BTreeSet, npc_cooldown_until: u64 }\n\nderive_disclosure_candidates system: runs every tick for Active NPCs; recomputes when time.tick - computed_tick > 30. Filters NPC own KG: Active state; confidence >= KnowsOf (trait-adjusted); not in per_fact_history; disclosure_blocked \!= true; trust rough-gate. Candidate list capped at 10; sorted by confidence desc, last_updated_tick desc.\n\nprocess_unprompted_disclosure system: trigger gates (ALL must pass): trust >= Surface; mood \!= Hostile; contentment >= -10; candidates not empty; per-NPC 300-tick cooldown clear; global 1/10-tick rate limit (StableId-ordered for determinism per D-010); witness inhibition (no non-trusted NPCs within 5 tiles OR Secret trust OR Talkative trait override); location privacy (disclosure_context tag vs current zone type).\n\nTrait Stage 1 (candidate pool filter): Cautious = requires KnowsDetails+, removes ToldBy-source facts; Gossipy = includes Suspects candidates; Loyal = suppresses entity-linked facts where entity trust >= Real; Talkative = overrides witness inhibition. Implemented via Ticket #551.\n\nNPCs check only their own KG — creates dramatic irony (NPC praises Kael after player found discrepancies).\nDecision refs: D-081.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:24:25', '2026-02-24 12:03:29', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-151', 'story', 'T-51', 'Minimap rendering - client', 'Small map overlay. Show nearby POIs as dots. Distant POIs as border arrows with direction.', 'done', 'high', NULL, 'client', NULL, '2026-02-10 23:22:17', '2026-02-25 08:48:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-174', 'story', 'T-55', 'Dialogue UI - client', 'Superseded by #434 (Dialogue box, D-061) from Control & Interaction workshop. Workshop spec: max 20% screen height, max-width (not percentage), NPC speech top, player options below, left-aligned, NO portraits, monologue floats above on z-layer 7, walk-away via WASD with 300ms fade. Original description retained for reference: Conversation interface. Topic selection, response display, NPC portrait/name. Relationship indicator.', 'done', 'high', NULL, 'client', NULL, '2026-02-10 23:24:25', '2026-02-25 08:48:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-264', 'story', 'T-51', 'Knowledge/journal display', 'Client UI for reviewing accumulated information inventory (#89). Shows provenance via CauseChain: how and when information was learned. Source: Tyre R1 M-4.', 'done', 'medium', NULL, 'client', NULL, '2026-02-11 00:04:28', '2026-02-25 08:48:03', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-158', 'story', 'T-53', 'Tier 1 drama module schema', 'Define drama module structure: entry conditions, NPC requirements, event sequences, outcomes. Pool format.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-10 23:23:54', '2026-02-25 08:55:09', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-544', 'task', NULL, 'Design: collision-resistant line IDs for auto-generated NPCs', 'Current line ID scheme uses NPC slug as prefix (kael-davan_d_001). Hand-authored NPCs have unique slugs, but auto-generated populations (D-029: hundreds of NPCs) will produce collisions. Need a collision-resistant ID scheme that stays human-readable for authored content. Options: short UUID suffix, entity UUID prefix, slug registry, or composite key. Cross-refs: D-035, D-029, D-024.', 'done', 'medium', NULL, 'copy', NULL, '2026-02-23 20:56:23', '2026-02-25 08:55:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-91', 'story', 'T-39', 'Skill system & combat flag', 'SkillSet component with named skills. Combat-trained flag triggers CombatCapability component addition.', 'done', 'medium', NULL, 'server', NULL, '2026-02-10 23:18:49', '2026-02-25 09:09:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-95', 'story', 'T-40', 'Background tier state machines', 'Four state machines: schedule, mood, relationships, job. Tick at 1/game-minute for Background NPCs.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:19:08', '2026-02-25 09:09:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-115', 'story', 'T-43', 'NPC vision system', 'NPCs use same LOS system. NPC memory of player location. Inference (saw you enter building).', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:19:52', '2026-02-25 09:09:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-242', 'story', 'T-234', 'Examine mechanic', 'Player uses interact on entity/object at close range. Returns detail information filtered through character knowledge (#138-142). Generates detailed ObservationEvent with low uncertainty. Character-specific: smuggler and detective see different details on same object. Source: Gestalt R2 H-2.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 00:01:54', '2026-02-25 09:09:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-244', 'story', 'T-234', 'NPC player-awareness behavior', 'NPCs react when they detect the player observing or following them. Feeds into suspicion mechanics for the follow verb. Uses NPC vision system (#115) to detect player proximity and attention. Source: Gestalt R2 H-5.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 00:01:55', '2026-02-25 09:09:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-248', 'story', 'T-41', 'Character goal/pressure framework', 'Define systemic pressures per character: smuggler faces relationship maintenance + exposure pressure; detective faces institutional + moral pressure. Pressures modulate monologue tone and observation salience. Not scripted arcs — emergent from system interaction. Source: Gestalt R2 H-8, Paula R2 character arcs.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 00:02:28', '2026-02-25 09:09:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-249', 'story', 'T-41', 'Player-action social propagation', 'Player actions toward one NPC ripple through relationship graph. First-order strong/immediate, second-order weaker/delayed, third-order ambient. Topology varies per seed, so same action produces different cascades. Anti-metagaming property. Source: Paula R1+R2, Nigel R2.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 00:02:28', '2026-02-25 09:09:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-256', 'story', 'T-235', 'Save state data model', 'Define serialization format for full game state. Shares architecture with #96 (state serialization system). Covers entity state, relationship graph, knowledge inventories, game clock position. Source: Tyre R1 H-14.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 00:03:27', '2026-02-25 09:09:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-337', 'story', 'T-39', 'Tell state derivation system', 'System that reads NPC axis values and outputs observable tell states consumed by monologue trigger system. Secret + low Tolerance = nervous. Low Contentment = frustrated. Connects NPC internal state to player-observable behavior. Owner: Dudley. Proposed by: Gestalt. Workshop: content-gap-analysis v0.1 R2.', 'done', 'medium', NULL, 'server', NULL, '2026-02-11 19:30:04', '2026-02-25 09:09:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-96', 'story', 'T-40', 'State serialization system', 'Serialize/deserialize NPC state to frozen structs (~1-2KB each). Save to file or memory.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:19:08', '2026-02-25 11:45:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-555', 'task', 'T-75', 'Protocol version handshake: server', 'Server side of protocol handshake split from #339. Server sends protocol_version in the initial IPC message (already present as PROTOCOL_VERSION const in bridge/types.rs = 14). Ensure the first message sent after subprocess spawn includes this field so the client can validate. Fail fast with a clear error log if handshake is not completed within N ticks. Source: Architecture Review Audit 2026-02-11, split from #339.', 'done', 'critical', NULL, 'server', NULL, '2026-02-25 10:21:32', '2026-02-25 11:45:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-97', 'story', 'T-40', 'Timestamp-based eviction', 'LastInteraction timestamp on all NPCs. LRU priority queue. Evict to lower tier when sim-space pressure.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:19:08', '2026-02-25 11:45:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-98', 'story', 'T-40', 'Scope tag system', 'Scope tags: neighborhood, active-quest, colleague, known-contact. Tagged NPCs stay in Active tier.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:19:08', '2026-02-25 11:45:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-200', 'story', 'T-61', 'Test module organization', 'External test modules. Separate from production code. Minimal coupling. Clear test entry points.', 'done', 'high', 'hoshe', 'server', NULL, '2026-02-10 23:26:24', '2026-02-25 11:45:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-272', 'story', 'T-63', 'Information boundary negative test suite', 'Verify that information DOES NOT leak. Entity X CANNOT see component Y. Highest-value integration test in the project — proves the core asymmetric information claim. Source: Hoshe R1, Tyre R2 T-1.', 'done', 'high', 'hoshe', 'server', NULL, '2026-02-11 00:05:00', '2026-02-25 11:45:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-553', 'story', 'T-235', 'Save/load: server ECS extraction', 'Server side of save/load split from #257. Extract ECS world state into SaveStateV1 (data model done in #256). Serialize to MessagePack and write to file. Inject SaveStateV1 back into ECS on load — rebuild entities from NpcSaveState, restore KnowledgeGraph, RelationshipGraph, SimulationTime, and RNG seed. Per-game save directory path received from client via IPC (client owns D-085 directory structure). MessagePack via rmp_serde (D-020). Source: Team Leader Sprint 19, split from #257.', 'done', 'high', NULL, 'server', NULL, '2026-02-25 10:20:45', '2026-02-25 11:45:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-205', 'story', 'T-62', 'GDScript test framework setup', 'GUT (Godot Unit Test) or similar. Test scene organization. Automated test runner.', 'done', 'high', 'oscar', 'client', NULL, '2026-02-10 23:26:33', '2026-02-25 12:07:29', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-206', 'story', 'T-62', 'Scene testing utilities', 'Load test scenes, manipulate nodes, assert on state. Scene validation.', 'done', 'high', 'oscar', 'client', NULL, '2026-02-10 23:26:33', '2026-02-25 12:07:29', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-258', 'story', 'T-235', 'Game session management', 'Start/save/resume flow for play sessions. New Game creates per-game save directory (D-085). Loading screen shows game directories sorted by last-modified with most recent save per game. Resume loads most recent save. Quit prompts save-before-exit. Source: Tyre R1 M-6, Team Leader Sprint 19.', 'done', 'medium', NULL, 'client', NULL, '2026-02-11 00:03:27', '2026-02-25 12:07:30', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-348', 'story', 'T-62', 'Debug visualization overlay', 'Godot debug overlay (dev tool only) showing:\n- Pathfinding waypoints\n- Line-of-sight rays\n- Vision cones\n- Information state tags\n- Tick timing graph\n\nToggle with F3 key.\n\nEffort: M\nCodebase: client\nSource: Architecture Review Audit 2026-02-11\nSprint: 2+', 'done', 'medium', NULL, 'client', NULL, '2026-02-11 20:27:36', '2026-02-25 12:07:30', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-270', 'story', 'T-61', 'Test runner bash scripts', 'Create test/run-rust, run-godot, run-ipc-fixtures, run-ipc-protocol, run-ipc-integration, run-all. Each script: exit code 0/non-zero, structured JSON stdout, accepts filter arguments, no interactive input. Whitelistable for Claude Code agents. Source: Tyre R1+R2.', 'done', 'high', NULL, 'ci', NULL, '2026-02-11 00:04:56', '2026-02-25 12:10:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-271', 'story', 'T-61', 'IPC serialization fixture files', 'Layer 1 test data: pre-generated ObserverSnapshot, PlayerInput, and malformed .msgpack files. Cross-language verification: Rust writes fixtures, GDScript reads and verifies. Source: Hoshe R1, Tyre R2.', 'done', 'high', NULL, 'ci', NULL, '2026-02-11 00:04:56', '2026-02-25 12:10:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-342', 'task', 'T-63', 'IPC round-trip timing benchmark', 'Sprint 1 exit criterion. Measure complete round-trip latency:\n- rmp_serde::to_vec (server)\n- pipe write (server)\n- GDScript read + decode (client)\n- scene update (client)\n\nFlag if total latency exceeds 5ms. Report p50/p95/p99.\n\nEffort: S\nCodebase: server + client\nSource: Architecture Review Audit 2026-02-11\nSprint: 1', 'done', 'critical', NULL, 'ci', NULL, '2026-02-11 20:26:58', '2026-02-25 12:10:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-556', 'task', 'T-75', 'Protocol version handshake: client', 'Client side of protocol handshake split from #339. Client reads protocol_version from the first IPC message after server process starts. Compares against Protocol.PROTOCOL_VERSION (currently 14). If mismatch: show error message and shut down gracefully. Implements the version validation stub that already exists in protocol.gd decode_snapshot(). Source: Architecture Review Audit 2026-02-11, split from #339.', 'done', 'critical', NULL, 'ci', NULL, '2026-02-25 10:21:42', '2026-02-25 12:10:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-554', 'story', 'T-235', 'Save/load: client UI', 'Client side of save/load split from #257. F5 = quicksave, F6 = quickload mapped in InputMapper. Loading screen lists game directories (user://saves/) sorted by last-modified, shows most recent save per game per D-085. Send SavePath IPC message to server with the target file path. Receive SaveComplete/LoadComplete responses. MessagePack format (D-020). Display loading screen during load. Source: Team Leader Sprint 19, split from #257.', 'done', 'high', NULL, 'client', NULL, '2026-02-25 10:21:12', '2026-02-25 15:54:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-153', 'story', 'T-52', 'Station district layout design', 'Map design: workplace hub, bar location, smuggling ring hideout. Gate corridor cluster. Spatial relationships. NEEDS DESIGN. NEEDS DESIGN DISCUSSION.', 'done', 'critical', NULL, 'planning', NULL, '2026-02-10 23:22:44', '2026-02-25 20:08:57', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-106', 'story', 'T-42', 'Triangle definition schema', 'Define triangle structure: 3 NPCs, conflicting interests, relationship constraints. Template specification format.', 'done', 'high', 'server', NULL, NULL, '2026-02-10 23:19:37', '2026-02-25 21:35:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-107', 'story', 'T-42', 'Intra-template triangle generation', 'Generate 2+ triangles within single social site. Role-based conflict patterns. Constraint satisfaction.', 'done', 'high', 'server', NULL, NULL, '2026-02-10 23:19:37', '2026-02-25 21:35:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-163', 'story', 'T-54', 'Role definition schema', 'Define template roles: required traits, skills, relationships, routines. Role constraint system.', 'done', 'high', 'server', NULL, NULL, '2026-02-10 23:24:06', '2026-02-25 21:35:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-164', 'story', 'T-54', 'Spatial requirement specification', '15-40 tile space definitions. Sightline maps, privacy zones, traffic patterns. Authored or generated.', 'done', 'high', 'server', NULL, NULL, '2026-02-10 23:24:06', '2026-02-25 21:35:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-165', 'story', 'T-54', 'Single-ownership model', 'NPCs owned by one template. Reference links to other templates carry relationship metadata. Lifecycle coordination.', 'done', 'high', 'server', NULL, NULL, '2026-02-10 23:24:06', '2026-02-25 21:35:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-250', 'story', 'T-42', 'Triangle escalation system', 'Periodic state updates push triangle tensions toward breaking points. Observable events when triangles enter crisis. Consequences when triangles resolve. Different tolerance thresholds per seed = different escalation timing = different 30-min arcs. Source: Gestalt R2 H-3, Paula R1 triangle escalation, Ozzie R1 triangle escalation events.', 'done', 'high', 'server', NULL, NULL, '2026-02-11 00:02:32', '2026-02-25 21:35:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-557', 'story', NULL, 'Refactor: game_state.gd derived state in apply_snapshot()', 'Code review finding: apply_snapshot() computes stationary_ticks and derives current_zone_id from tile iteration. These are behavior-driving computations, not pure state storage per D-020. Move to server-side snapshot fields or extract to a client-side derived state helper.', 'done', 'low', NULL, 'client', NULL, '2026-02-25 11:23:02', '2026-02-25 21:42:33', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-558', 'story', NULL, 'Refactor: dialogue_box.gd direct GameState mutation and AudioManager coupling', 'Code review finding: dialogue_box.gd sets GameState.dialogue_active from a UI component (3 call sites) and calls AudioManager.apply_dip() directly. Should use signals and let a coordinator manage state. Audio transitions should be signal-driven.', 'done', 'low', NULL, 'client', NULL, '2026-02-25 11:23:03', '2026-02-25 21:42:33', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-559', 'story', NULL, 'Refactor: main.gd god coordinator — extract SnapshotEventRouter', 'Code review finding: main.gd (517 lines) dispatches to 15+ child nodes. The consume methods all follow the same pattern. Extract into a SnapshotEventRouter object.', 'done', 'low', NULL, 'client', NULL, '2026-02-25 11:23:04', '2026-02-25 21:42:34', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-560', 'story', NULL, 'Refactor: unify duplicate YAML parsers', 'Code review finding: checklist_evaluator.gd contains its own YAML parser that partially duplicates ui_strings.gd._parse_yaml(). Unify into a shared utility.', 'done', 'low', 'stig', 'client', NULL, '2026-02-25 11:23:05', '2026-02-25 21:42:34', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-562', 'story', 'T-50', 'Generator architecture workshop — district/block/chunk pipeline', 'Workshop brief: docs/workshops/generator-architecture/workshop-brief.md. Design workshop to establish the top-down generator pipeline architecture. Cities Skylines model: geography → infrastructure → amenities → population → zoning → block fill → chunk fill. Covers: chunk/block/district spatial hierarchy (reference #153 D-record), sub-chunk quarter system for building variety, multi-block structures (stations, government buildings, parks, stadiums), district skeleton as generator output (Q-036), v0.1/generator boundary (Q-037). Output: D-record defining generator architecture primitives + implementation tickets. Participants: Gestalt, Tyre, Miri, Araminta, Nigel.', 'done', 'medium', NULL, 'planning', NULL, '2026-02-25 17:35:23', '2026-02-27 09:19:42', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-257', 'story', 'T-235', 'Save/load game flow', 'Client-side save/load integration. Save-to-file and load-from-file UI flow. Implements loading screen (wireframe TBD). F5/F6 mapped to quicksave/quickload. Per-game save directory structure per D-085. Quick-and-dirty MessagePack format for v0.1 (long-term format tracked in Q-029). Source: Tyre R1 M-5, Team Leader Sprint 19.\n\nSPLIT (Sprint 19): Split into #553 (server ECS extraction, team: server) and #554 (client UI, team: client). Do not assign this ticket to any sprint.', 'done', 'medium', NULL, 'client', NULL, '2026-02-11 00:03:27', '2026-02-27 10:07:14', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-561', 'story', NULL, 'Housekeeping: move debug_overlay.gd to ui/ directory', 'Code review finding: debug_overlay.gd lives at scripts/ui/ while all 17 other UI components are in ui/. Move for consistency or document the distinction.', 'done', 'low', NULL, 'client', NULL, '2026-02-25 11:23:06', '2026-02-27 10:07:15', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-85', 'story', 'T-38', 'Error handling & recovery', 'Handle simulation crashes, protocol errors, desync detection. Graceful degradation.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:18:35', '2026-02-27 16:47:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-159', 'story', 'T-53', 'Tier 2 template definition format', 'Social site template specification: roles, spaces, triangles, dialogue pools, routines. YAML or structured markdown.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:23:54', '2026-02-27 16:47:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-161', 'story', 'T-53', 'Template instantiation engine', 'Take template definition, generate NPCs, assign relationships, place in world. Instance lifecycle management.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:23:54', '2026-02-27 16:59:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-166', 'story', 'T-54', 'Template-to-instance mapping', 'Instantiate template: spawn NPCs in roles, generate triangles, place in functional cluster space. Validation.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:24:06', '2026-02-27 16:59:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-108', 'story', 'T-42', 'Cross-template triangle generation', 'Generate 1+ triangle spanning multiple social sites. Reference link creation. Shared NPC coordination.', 'done', 'medium', NULL, 'server', NULL, '2026-02-10 23:19:37', '2026-02-27 18:28:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-109', 'story', 'T-42', 'Triangle validation', 'Verify conflict viability, relationship coherence, interest divergence. Quality checks.', 'done', 'medium', NULL, 'server', NULL, '2026-02-10 23:19:37', '2026-02-27 18:28:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-246', 'story', 'T-234', 'Basic environmental interaction', 'Doors (open/close), examinable objects, usable terminals. Environmental entities with Interactable components routed through the interaction dispatcher. Source: Gestalt R2 M-2.', 'done', 'medium', NULL, 'server', NULL, '2026-02-11 00:02:14', '2026-02-27 18:28:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-274', 'task', NULL, 'Move connector scripts from db/connectors/ to tooling/db/', 'Move sqlite_connector.py, qdrant_connector.py, config.json, and all wrapper scripts (sqlite-query, sqlite-exec, sqlite-init, sqlite-seed, qdrant-search, qdrant-index, qdrant-health, qdrant-count) from db/connectors/ to tooling/db/. Update all references in CLAUDE.md, docs/DEVOPS.md, agent briefings, skill files, and any scripts that reference the old paths.', 'done', 'medium', NULL, 'ci', NULL, '2026-02-11 00:36:38', '2026-02-27 18:28:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-564', 'story', 'T-30', 'Fog shader too opaque — tune alpha for semi-transparent layers per D-059', 'The fog shader (client/shaders/fog.gdshader) renders Layer 2 (peripheral) and Layer 3 (deep fog) at alpha values that feel too opaque in practice. Per D-059, Layer 2 should be desaturated 40-50% and Layer 3 should show zone temperature tint through the fog. Tune alpha constants so fog reads as limited visibility, not a dark wall. Verify D-066 gradient edge (6-8 sim tiles = 3-4 visual tiles) is preserved. Acceptance: Fog Theater gauntlet room — entities behind peripheral fog dimmed but identifiable, deep fog shows zone tint, vision cone edge is soft.', 'done', 'high', NULL, 'visual', 'D-059,D-011,D-066', '2026-02-26 18:22:23', '2026-02-27 20:52:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-185', 'story', 'T-58', 'Social venue template - bar', 'Template definition: bartender, regulars, transients. Social hub, gossip nexus. Overlap with workplace and smuggling NPCs. 4-6 NPCs.', 'done', 'critical', NULL, NULL, NULL, '2026-02-10 23:25:13', '2026-02-28 11:21:19', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-186', 'story', 'T-58', 'Smuggling ring template', 'Template definition: organizer, couriers, lookout, fence. Hidden operations, trust network. Embedded in workplace. 5-7 NPCs.', 'done', 'critical', NULL, NULL, NULL, '2026-02-10 23:25:13', '2026-02-28 11:21:19', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-187', 'story', 'T-58', 'Shared NPC coordination', 'NPCs with roles in multiple templates. Bartender knows smugglers. Worker is courier. 20-30 total NPCs across 3 templates.', 'done', 'high', NULL, NULL, NULL, '2026-02-10 23:25:13', '2026-02-28 11:21:19', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-566', 'task', NULL, 'Document MobileChunk Idle state as stationary installation primitive', 'D-111: Add documentation to D-108 MobileChunk specification noting that the Idle movement state is the canonical primitive for player-owned stationary installations (space stations, orbital platforms, parked vessels as bases). No code change — documentation of design intent to prevent future over-engineering. Update relevant briefings.', 'done', 'low', NULL, 'planning', 'D-111', '2026-02-27 10:05:43', '2026-02-28 11:32:03', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-162', 'story', 'T-53', 'Storyteller module activation', 'Sprint 23 implementation scope. The StorytellerPlugin (server/src/storyteller/mod.rs) reads ContaminationActive (from ticket #254) to gate all activation logic. This is the post-contamination pacing layer: D-023 stipulates the storyteller activates Tier 1 modules based on player proximity and engagement, not timers. + +**Why this is interesting:** The player never sees engagement scores. They just notice that after spending real time with Kael — watching him, talking to him, having monologue moments — things start happening around Kael. Organic play shapes which mystery thread escalates. Same contamination trigger, different activation per playthrough. + +Implementation steps: +1. Gate check: read ContaminationActive component; no activation runs until contamination is active. Poll on a 10-tick cadence — no activation bus needed, just a system that no-ops until the gate opens. + +2. Proximity query: collect all Active-tier NPCs within the player character''s last-N-tick movement path. Parameter name: ENGAGEMENT_WINDOW_TICKS (suggested starting value: 3000 = ~5 real minutes at 10 tps). Query the movement history buffer (#571) for NPC co-presence events within that window. + +3. Engagement scoring: compute a score per NPC from three inputs with suggested weights: + - conversation_count * 2.0 (direct interaction; cappable — consider capping at 5 conversations to prevent dialogue-spam gaming) + - observation_time_ticks * 0.005 (sustained attention; 200 ticks ≈ 20 real seconds ≈ 1 point) + - monologue_triggers * 8.0 (richest signal — the character''s internal voice noticed something; weight heavily) + Formula: score = min(conversation_count, 5) * 2.0 + observation_time_ticks * 0.005 + monologue_triggers * 8.0 + Source data: EngagementRecord component (#570) per entity. + +4. Unentangled-NPC routing: if the highest-scoring NPC is from the mundane 50% (D-029), use D-025 reference links to find a connected active triangle and route activation through that NPC. The storyteller does not waste player investment — it weaponizes it. Fallback: if no reference links exist, use the highest-scoring Active-tier NPC. + +5. Module selection: among active TriangleState forks, activate the fork containing the highest-scoring NPC (or routed NPC from step 4). SelectionStrategy enum: HighestScore (v0.1 default), WeightedRandom (future). Tie-breaking: SimRng (seeded, per D-010/D-030 determinism). Edge cases: + - No NPC has any engagement score: fall back to proximity-only (nearest Active-tier NPC). + - No active TriangleState forks: log warning, hold, retry on next 10-tick check. + +6. Activation event: emit TriangleActivated { triangle_id } for downstream consumers: + - Tell system (D-024 NPC axis 9): escalate tell behavior frequency + - Routine scheduler: activated triangle NPCs may deviate from routine + - Monologue system (D-016): unlock situation-tagged lines for triangle_activated context + - FRIEND arc phase manager (D-034): if activated triangle contains THE FRIEND, advance to next relationship phase + - Activation produces subtle behavioral shifts, not announcements. The player discovers through observation. See Q-052 for the full parallel hint delivery channel model. + +7. Lifecycle: see #572 for multi-activation, cooldown, and resolution rules. + +System interaction chain: + ContaminationActive (#254) → gates → StorytellerPlugin.activation_pass() every 10 ticks + → reads EngagementRecord (#570) signals → scores NPCs + → routes through unentangled NPCs if needed (D-025 reference links) + → selects TriangleState fork → emits TriangleActivated { triangle_id } + → consumed by: tell system, routine scheduler, monologue pool, FRIEND arc manager + → hint delivery via parallel diegetic channels (Q-052) + +Prerequisites: +- #254 (contamination pacing layer, Sprint 22 server) — hard blocker +- #570 (EngagementRecord component) — data layer for step 3 +- #571 (MovementHistoryBuffer) — data layer for step 2 +- #572 (lifecycle rules) — multi-activation/cooldown spec for step 7 +- Q-052 (hint delivery channels) — post-activation player nudging + +D-023: storyteller activates Tier 1 modules based on player proximity and engagement, not timers.', 'done', 'high', NULL, 'server', 'D-023', '2026-02-10 23:23:54', '2026-02-28 12:00:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-565', 'task', NULL, 'Fix signed z-level addressing: base_z u8 → i8', 'D-110: Change base_z from u8 to i8 in MultiBlockReservation, FloorZone.z_level, and all structs that reference a z-level position (not a count). z_levels counts remain u8. Propagate through ~20 structs. Add documentation comment on DistrictSkeleton clarifying the distinction: base_z (i8, lowest floor, can be negative) vs z_levels (u8, count, always positive). Mechanically trivial type change — cascades through struct definitions but no logic changes.', 'done', 'high', NULL, 'server', 'D-110', '2026-02-27 10:05:42', '2026-02-28 12:56:03', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-563', 'story', NULL, 'Fog shader too opaque — tune alpha for semi-transparent layers per D-059', '## Problem +The fog shader (client/shaders/fog.gdshader) renders fog layers nearly opaque, obscuring the underlying world. Deep fog (layer 3) uses alpha 0.78-0.90 and light fog (layer 2) uses alpha 0.25-0.55. D-059 specifies: +- Light fog (peripheral): Desaturated 40-50%, brightness -30% — implies world visible through a colour/brightness filter, not hidden behind opaque overlay +- Deep fog (explored): Near-monochrome with ~10% zone temperature tint — world should be visible but heavily desaturated, not masked + +Current behaviour makes fog feel like a wall rather than a perceptual filter. This hurts test gameplay because players cannot see previously explored areas at all. + +## Acceptance Criteria +- Light fog (layer 2): world content visible through desaturation + dimming, not alpha blending to near-opaque +- Deep fog (layer 3): world content visible but near-monochrome, zone tint applied as colour shift not opaque overlay +- Unexplored (layer 5): remains fully opaque (correct as-is) +- Fog still breathes with Perlin noise animation per D-059 + +## Files +- client/shaders/fog.gdshader — primary change +- client/scripts/rendering/fog_shader.gd — may need uniform additions +- docs/architecture/fog-shader-spec.md — update if approach changes + +## Design References +- D-059: Fog — shader-based, five layers, knowledge-graph-driven +- D-011: Fog of perception is non-negotiable +- D-066: Dual-scale grid (sim tile to visual tile mapping)', 'done', 'high', NULL, 'visual', 'D-059, D-011, D-066', '2026-02-26 18:21:13', '2026-02-28 13:12:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-175', 'story', 'T-56', 'Entanglement ratio configuration', '30/50/20 flat/mundane/intrigue split. Variable per seed. Configuration system.', 'done', 'high', NULL, 'client', NULL, '2026-02-10 23:24:37', '2026-02-28 13:25:32', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-178', 'story', 'T-56', 'Seed-based variation', 'Per-world-seed entanglement parameters. Prevent player calibration across playthroughs.', 'done', 'high', NULL, 'client', NULL, '2026-02-10 23:24:37', '2026-02-28 13:25:32', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-569', 'bug', NULL, 'Fix fog system: blocky edges and zero visibility in explored areas', '## Problem + +The fog/vision cone system has been iteratively modified and is now in a regressed state. Two persistent visual issues: + +1. Blocky stair-stepped edges at the vision cone boundary — the transition from clear vision to fog shows hard tile-sized steps instead of a smooth gradient +2. Zero visibility in explored fog — tiles the player has previously seen appear as near-black instead of showing the underlying art with a light fog overlay. The player should always be able to see furniture, walls, NPCs etc that they have already discovered, just dimmed. + +## Desired behavior (spec) + +Three visual states, with smooth transitions between them: + +### 1. Forward cone (120 deg arc, clear vision) +- Tiles currently in the player line of sight within the 120 deg forward cone +- Nearly transparent — world art fully visible +- Soft gradient edge at the cone boundary (6-8 tile fade, NOT tile-stepped) + +### 2. Explored fog (light overlay) +- Tiles the player has previously seen but are not currently in the forward cone +- Light fog overlay (~25-30% opacity) — ALL underlying art, sprites, furniture, NPCs remain visible +- Just indicates not currently looking — NOT deep fog, NOT obscured +- Subtle animated noise for atmosphere (breathing, 8-10s cycle) +- Exploration memory is permanent: once seen, always shown in this state (never reverts to unexplored) + +### 3. Unexplored (solid black) +- Tiles never seen — no information, solid near-black (#12141a) +- Smooth transition at the boundary with explored tiles + +### Key constraints +- Explored tiles MUST preserve art and information — the fog is a translucent overlay, not an opaque mask +- No hard pixel boundaries between states — all transitions must be smooth gradients +- Exploration texture bounds must only grow, never shrink (tiles behind the player stay in the texture) +- Exploration data must survive texture resizes (copy old data into new buffer) + +## Current state (failed initial QA) + +Changes were made to server vision_cone.rs (simplified to Forward-only, removed Peripheral sector), fog.gdshader (simplified to 3-layer continuous blend), and fog_state.gd (grow-only bounds, exploration preservation). Server tests pass (1048+). But visual QA shows the two issues above persist — the shader math for the smooth gradient and the explored-tile overlay alpha are not producing the intended result. These changes are uncommitted on main. + +## Files involved +- server/src/perception/vision_cone.rs — cone classification (simplified, tests pass) +- client/shaders/fog.gdshader — fog shader (needs work on gradient + alpha) +- client/scripts/autoloads/fog_state.gd — fog texture state (grow-only bounds in place) +- decisions/perception.md D-015, D-059 — design spec + +## Acceptance criteria +- Forward cone edge has a smooth 6-8 tile gradient (no visible tile stepping) +- Explored tiles outside the cone show underlying art at ~25-30% fog overlay +- Explored tiles never revert to unexplored black +- Unexplored tiles are solid near-black +- Transitions between all three states are smooth (no hard edges) +- Server tests remain green', 'done', 'high', NULL, 'client', 'D-059', '2026-02-27 22:48:58', '2026-02-28 13:25:32', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-176', 'story', 'T-56', 'NPC pool generation', 'Generate NPC population according to ratio. Flat (routine+greeting), mundane triangles, intrigue-entangled.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:24:37', '2026-02-28 15:30:47', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-509', 'task', 'T-455', 'Fuzzy tests for dynamic/procedural maps', 'Randomized testing of procedurally generated maps against invariants. Backlog. Depends on dynamic map system. Effort: 1d.', 'done', 'medium', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-28 15:31:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-512', 'story', 'T-455', 'Zone Gate room implementation', 'Gauntlet room for testing zone transitions. Backlog. Depends on multi-map system. Effort: 1d.', 'done', 'medium', NULL, 'server', NULL, '2026-02-17 12:58:13', '2026-02-28 15:31:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-188', 'story', 'T-58', 'Triangle instantiation', '2+ triangles per template. 1 cross-template triangle. Conflicting interests, relationship tensions. Authored constraints.', 'done', 'high', NULL, 'server', NULL, '2026-02-10 23:25:13', '2026-02-28 15:31:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-254', 'story', 'T-53', 'Contamination activation mechanic', 'Simplified v0.1 storyteller: even a timer-based trigger gives the 30-min session shape. Activates escalation events to prevent flat daily-life experience. Bridges gap until full storyteller (Q-010). Source: Gestalt R2 H-11, Ozzie R2 promotion of #162.', 'done', 'high', NULL, 'server', NULL, '2026-02-11 00:02:44', '2026-02-28 15:31:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-568', 'task', NULL, 'remove db/connectors symlink (Sprint 22)', 'Remove the db/connectors → tooling/db/ backwards-compat symlink added in #274. Before removal: (1) update whatsinagame/ templates that still use db/connectors/ as canonical path — note these are kit templates and need their own path config, (2) grep all worktree branches for remaining db/connectors/ references and update them. The symlink was marked ''remove after Sprint 22'' in PR #274.', 'done', 'medium', NULL, 'ci', NULL, '2026-02-27 16:50:24', '2026-02-28 22:16:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-567', 'task', NULL, 'Add modifications: Vec stub on chunk and MobileChunk entities', 'DLC scope stub (D-111/D-112): Add a modifications: Vec field (initially empty Vec) to both static chunk entities and MobileChunk entities. This is the entry point for the future player construction system. The stub must exist early so player-modified spaces round-trip through save/load. Define the Modification enum/struct with at minimum: position, modification_type, timestamp. Implementation of actual construction mechanics is DLC scope — this ticket covers only the data model stub.', 'done', 'medium', NULL, 'server', 'D-112', '2026-02-27 10:05:45', '2026-02-28 22:57:19', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); diff --git a/.pql/changelog/tickets/2026-03.sql b/.pql/changelog/tickets/2026-03.sql new file mode 100644 index 000000000..13646415d --- /dev/null +++ b/.pql/changelog/tickets/2026-03.sql @@ -0,0 +1,515 @@ +INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-184', 'story', 'T-58', 'Workplace template - logistics hub', 'Template definition: cargo handlers, supervisors, shift workers. Work routines, break room, cargo bay. 6-8 NPCs.', 'done', 'critical', NULL, NULL, NULL, '2026-02-10 23:25:13', '2026-03-03 16:12:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-339', 'task', 'T-75', 'Protocol version handshake implementation', 'Add version negotiation to IPC handshake. Server sends protocol_version in initial message, client validates compatibility. Fail fast on mismatch with clear error message.\n\nEffort: XS\nCodebase: server + client\nSource: Architecture Review Audit 2026-02-11\nSprint: 1\n\nSPLIT (Sprint 19): Split into #555 (server, team: server) and #556 (client, team: ci). Do not assign this ticket to any sprint.', 'done', 'critical', NULL, NULL, NULL, '2026-02-11 20:26:40', '2026-03-03 16:12:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-143', 'story', 'T-50', 'Chunk data structure', 'Define chunk size (16x16 or 32x32 tiles). Chunk storage, indexing, coordinate mapping.', 'done', 'high', NULL, NULL, NULL, '2026-02-10 23:22:01', '2026-03-03 16:12:37', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-144', 'story', 'T-50', 'Chunk generation system', 'Procedural chunk generation from templates. Bounded map = only generate chunks within boundary.', 'done', 'high', NULL, NULL, NULL, '2026-02-10 23:22:01', '2026-03-03 16:12:37', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-145', 'story', 'T-50', 'Chunk loading/unloading', 'Load chunks around player. Unload distant chunks. Memory management. Performance budget.', 'done', 'high', NULL, NULL, NULL, '2026-02-10 23:22:01', '2026-03-03 16:12:37', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-154', 'story', 'T-52', 'Functional cluster spatial specs', '15-40 tile connected spaces per social site. Internal sightlines. Public/private zones. 2-3 z-levels per cluster.', 'done', 'high', NULL, NULL, NULL, '2026-02-10 23:22:44', '2026-03-03 16:12:39', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-155', 'story', 'T-52', 'Hand-crafted location authoring', 'Build key locations in Godot tilemap editor. Workplace, bar, smuggling hideout. Embed in procedural district.', 'done', 'high', NULL, NULL, NULL, '2026-02-10 23:22:44', '2026-03-03 16:12:39', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-157', 'story', 'T-52', 'Gate corridor template', 'Gate infrastructure as social chokepoint. Customs, cargo, coffee vendor, commuter traffic. Observation-rich.', 'done', 'high', NULL, NULL, NULL, '2026-02-10 23:22:44', '2026-03-03 16:12:39', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-577', 'story', NULL, 'Location YAML tile format and content loader integration', 'Define the tile data format for hand-authored location YAML files and implement the server-side loader that populates WalkabilityMap from ContentStore on production startup. + +Two deliverables: + +1. TILE FORMAT — Add a tiles section to the Location type in server/src/content/types.rs. Format: array of string rows where each character is a tile code (F=floor, W=wall, V=void, R=restricted). Example: tiles: [''FFFFF'', ''FWWWF'', ''FFFFF'']. Agree the exact format with Araminta before she begins authoring — this is a hard blocker for the visual tile tickets. Document the format in a brief comment block in types.rs. + +2. LOADER — Implement load_location_tiles(location: &Location, origin: TilePosition, map: &mut WalkabilityMap) in server/src/content/loader.rs or a new server/src/content/tile_loader.rs. Each row in tiles[] maps to a y-offset from origin; each character maps to an x-offset. W tiles set walkable=false + kind=Wall; F tiles set walkable=true + kind=Floor; V and R tiles set walkable=false with their respective kinds. + +3. STARTUP WIRING — Connect ContentStore -> WalkabilityMap in the production startup path (server/src/main.rs). After NPCs and triangles are spawned from ContentStore, call load_location_tiles for each Location that has tile data. The Gauntlet startup path (test_world/) must remain unchanged. + +Blocked by: #576 (tile-type layer on WalkabilityMap). +Blocks: visual tile authoring tickets (Araminta cannot author YAML until format is agreed and documented).', 'done', 'high', NULL, 'server', NULL, '2026-03-03 16:09:18', '2026-03-03 16:14:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-578', 'task', NULL, 'Chunk loading/unloading: streaming around player position', 'Implement chunk streaming: load chunks near the player, unload distant chunks, manage memory budget. + +For v0.1 the district is hand-authored and bounded (256x256 visual tiles per D-094 = 8x8 chunks of 32 tiles each). For production v0.3+ the district is procedurally generated and potentially unbounded. This ticket builds the streaming infrastructure that works for both. + +Scope: +1. Add a ChunkLoadRadius resource (configurable, default: load chunks within N chunks of player position). +2. Implement a chunk streaming system that runs every N ticks: query player TilePosition -> compute ChunkCoord -> load/unload chunks around that position in WalkabilityMap. +3. For v0.1: pre-load the entire hand-authored district at startup (all chunks fit in memory for a 256x256 map). The streaming system exists but the radius covers the full map. This means no streaming stutter for v0.1 while the architecture is ready for v0.3 borderless generation. +4. Track loaded/unloaded state per chunk (ZLevelLoadState::Loaded / Skeleton / Ungenerated already defined in server/src/simulation/generator.rs — use these). +5. Add a test: spawn player, walk to edge of loaded region, verify adjacent chunks are loaded and distant chunks are unloaded. + +Integration points: +- WalkabilityMap: server/src/simulation/movement.rs (ChunkCoord, ChunkData already internal) +- Generator types: server/src/simulation/generator.rs (ZLevelLoadState) +- Player position: TilePosition component, PlayerCharacter marker + +Blocked by: #576 (tile-type layer). Coordinate with #577 (tile loader) on startup sequencing.', 'done', 'high', NULL, 'server', NULL, '2026-03-03 16:09:31', '2026-03-03 16:14:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-579', 'task', NULL, 'Storyteller activation pass — implement activation_pass() system', 'Implement the full storyteller module activation logic as specified in ticket #162. The contamination layer (#254) is done and gates this system. This ticket implements steps 1-6 of the activation spec. + +Implementation steps (from #162 design): + +1. GATE CHECK — Read ContaminationActive resource. If false, early-return. Poll on 10-tick cadence — no activation bus needed. + +2. PROXIMITY QUERY — Query MovementHistoryBuffer (#571) for Active-tier NPCs within the player''s last ENGAGEMENT_WINDOW_TICKS (3000 ticks = ~5 real minutes at 10 tps) of movement. Co-presence = NPC was within LOS range during any tick in the window. + +3. ENGAGEMENT SCORING — For each co-present NPC, read EngagementRecord (#570): + score = min(conversation_count, 5) * 2.0 + observation_time_ticks * 0.005 + monologue_triggers * 8.0 + +4. UNENTANGLED-NPC ROUTING — If the highest-scoring NPC is from the mundane 50% (D-029), use D-025 reference links to find a connected Active-tier triangle and route activation through that NPC. Fallback: if no reference links exist, use the highest-scoring Active-tier NPC. + +5. MODULE SELECTION — Among active TriangleState forks, activate the fork containing the highest-scoring NPC (or routed NPC from step 4). SelectionStrategy: HighestScore (v0.1 default). Tie-breaking: SimRng (seeded, D-010). Edge cases: no engagement scores -> fall back to proximity-only (nearest Active-tier NPC). No active forks -> log warning, hold, retry on next 10-tick check. + +6. ACTIVATION EVENT — Emit TriangleActivated { triangle_id } for downstream consumers. This event is defined and emitted here; consumers (tell system, routine scheduler, monologue, FRIEND arc) are wired up in Sprint 24. + +Location: add activation_pass() system to server/src/storyteller/mod.rs. Register in StorytellerPlugin.build(). + +Prerequisites: +- #570 (EngagementRecord component) +- #571 (MovementHistoryBuffer resource) +- #572 (storyteller lifecycle rules — must be specced before implementation)', 'done', 'high', NULL, 'server', NULL, '2026-03-03 16:09:49', '2026-03-03 16:14:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-570', 'task', NULL, 'EngagementRecord component — track per-NPC engagement metrics for storyteller', 'The storyteller activation system (#162) needs per-NPC engagement data that does not currently exist in the KnowledgeGraph (D-041). Create an EngagementRecord component (or extend KnowledgeGraph) with three fields: cumulative observation_time_ticks, conversation_count, and monologue_trigger_count — all per observed entity. The perception system, dialogue system, and monologue system must write to this record. Sprint 23 prerequisite for #162.', 'done', 'high', NULL, 'server', NULL, '2026-02-28 11:52:26', '2026-03-03 16:32:40', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-576', 'task', NULL, 'Chunk data structure: tile-type layer and ChunkStore resource', 'Extend the existing WalkabilityMap (server/src/simulation/movement.rs) to carry tile type data alongside walkability booleans. For v0.1 the map is hand-authored, not procedurally generated, but the data model must be reusable architecture. + +Concrete scope: + +1. Define a TileKind enum in movement.rs (or a new server/src/simulation/chunk.rs): Floor | Wall | Void | Restricted. Mirrors the existing TileKind in bridge/types.rs (VisibleTile) but lives server-side as the authoritative source. + +2. Extend ChunkData (currently a Vec walkability grid) to store both walkability and tile kind per tile. Use a single Vec or parallel vecs — whichever is cleaner internally. The WalkabilityMap public API (set_walkable, is_walkable) must remain backward-compatible. + +3. Add set_tile_kind(pos, kind) and tile_kind(pos) -> TileKind API to WalkabilityMap. + +4. All existing tests must pass. Add new tests for tile kind round-trip. + +CHUNK_SIZE = 32 (D-094). WalkabilityMap lives in server/src/simulation/movement.rs. ChunkCoord / ChunkData are private; the public API is the extension surface.', 'done', 'high', NULL, 'server', NULL, '2026-03-03 16:09:10', '2026-03-03 16:32:40', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-571', 'task', NULL, 'MovementHistoryBuffer resource — player path history for storyteller proximity query', 'The storyteller proximity query (#162 step 2) needs the player character''s recent movement path to identify co-present NPCs. Define and implement a MovementHistoryBuffer resource that records the player''s tile positions over the last N ticks (suggested: ENGAGEMENT_WINDOW_TICKS = 3000). The storyteller queries this buffer to find Active-tier NPCs who were within proximity during the window. Sprint 23 prerequisite for #162.', 'done', 'high', NULL, 'server', NULL, '2026-02-28 11:52:30', '2026-03-03 16:32:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-572', 'task', NULL, 'Storyteller lifecycle rules — multi-activation, cooldown, resolution for v0.1', 'The storyteller activation spec (#162) defines how a triangle activates but not the lifecycle after activation. Specify for v0.1: (1) Can multiple triangles be active simultaneously? (2) What happens when an activated triangle resolves (player completes investigation or consequences fire)? (3) Is there a cooldown between activations? (4) For the 30-minute vertical slice, probably only one activation per session — state this explicitly so the implementer does not over-engineer. Sprint 23 prerequisite for #162.', 'done', 'medium', NULL, 'server', NULL, '2026-02-28 11:52:32', '2026-03-03 16:32:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-580', 'task', NULL, 'Debug console server: command handler and state manipulation API', 'Implement the server-side debug console command handler. Receives DebugCommand variants via IPC (new PlayerAction variant), executes state manipulation, returns DebugResponse via ObserverSnapshot or a new debug channel. + +PROTOCOL CHANGES: +Add to PlayerAction enum in server/src/bridge/types.rs: + DebugCommand(DebugCommandKind) + +Add DebugCommandKind enum: + AdvanceTicks(u64) -- fast-forward simulation by N ticks + SkipToContamination -- advance to CONTAMINATION_DELAY_TICKS + TeleportToPosition { x: i32, y: i32, z: i32 } -- move player + TeleportToLocation(String) -- move player to named location (e.g. ''the-terminal'') + ForceContaminationActivate -- bypass timer, fire ContaminationActive immediately + ForceTriangleActivation(String) -- activate named triangle by id + InspectNpc(u64) -- dump NPC state: routine, knowledge graph, relationships + ListTriangles -- return all TriangleState entities + ListPopulation -- return all Active-tier NPCs with tier and position + GetContaminationStatus -- return ContaminationActive status and tick + +Add DebugResponse to ObserverSnapshot (or a new optional field): debug_response: Option + +EXECUTION: +Add system handle_debug_commands in server/src/bridge/ or server/src/storyteller/. Only executes if a DebugEnabled resource is set (server accepts a --debug flag at startup, or the client sends a DebugEnable command). In v0.1 this is on by default. + +SECURITY MODEL: Debug commands are accepted only when DebugEnabled resource is true. The resource is set at startup and cannot be toggled mid-session via IPC (prevents accidental debug access in production builds — though v0.1 enables it by default). + +Integration points: +- bridge/types.rs: PlayerAction, ObserverSnapshot +- storyteller/mod.rs: ContaminationActive, ContaminationEventQueue +- content/template.rs: TriangleState +- simulation/tier.rs: ActiveSim, ActiveTier +- knowledge/: StableId, EntityRegistry', 'done', 'medium', NULL, 'server', NULL, '2026-03-03 16:10:11', '2026-03-03 16:32:42', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-584', 'bug', NULL, 'Walls at LOS boundary: server — extend visible_tiles with 1-tile wall margin', 'Wall tiles at the edge of the LOS cone are never included in visible_tiles because the server only sends currently visible tiles. The client has no content to render at the boundary, so the fog overlay composites over empty space, making walls look like fog. + +FIX: +In the observer snapshot generation (server/src/perception/observer/mod.rs or query.rs), after computing the standard visible_tiles set, add a secondary pass: for each tile on the LOS boundary, check 1 tile beyond in each direction. If that tile is not walkable (wall or void) in WalkabilityMap, include it in visible_tiles with VisibilitySector::Boundary (or a new sector variant). + +This gives the client wall tile data at the boundary so fog composites over real content rather than empty space. + +SCOPE: +- Only extend the server-side snapshot to include boundary wall tiles +- Use a new VisibilitySector variant if needed (e.g. BoundaryWall), or reuse LosObstructed (#514 added this field) +- Limit to 1-tile margin — do not include walls 2+ tiles beyond LOS +- Wall margin tiles must not be included in the exploration/memory data (they are ''seen now'' not ''explored'') + +Integration: client ticket #575b (client half) consumes this data. + +Files: +- server/src/perception/observer/mod.rs (snapshot generation) +- server/src/bridge/types.rs (VisibilitySector enum — may need new variant)', 'done', 'medium', NULL, 'server', NULL, '2026-03-03 16:11:11', '2026-03-03 16:32:42', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-581', 'task', NULL, 'Debug console client: tilde console UI, settings toggle, command dispatch', 'Implement the in-game debug console. Permanent feature, enabled by default until v1.0, toggleable via Settings menu. + +UI: +- Tilde (~) key toggles the console open/closed (KEY_QUOTELEFT in Godot) +- Console is a semi-transparent panel anchored to bottom of screen (~40% screen height) +- Input line at bottom, output log above (last 50 lines, scrollable) +- Console pauses normal keyboard input routing while open (no movement commands leak through) + +SETTINGS INTEGRATION: +- Add ''Debug Console'' toggle to client/ui/settings_dialog.gd (existing settings panel) +- Persisted in user://settings.cfg alongside audio volumes +- Default: enabled. Toggle disables the tilde key entirely. + +COMMAND DISPATCH: +Parse input line as: [args...] +Commands map to DebugCommandKind variants sent via Protocol.encode_player_input(''debug_command'', {...}): + ticks -> AdvanceTicks(n) + contaminate -> SkipToContamination + tp [z] -> TeleportToPosition + tp -> TeleportToLocation + activate -> ForceContaminationActivate + triangle -> ForceTriangleActivation + npc -> InspectNpc + triangles -> ListTriangles + pop -> ListPopulation + status -> GetContaminationStatus + help -> print command list locally (no server round-trip) + +RESPONSE DISPLAY: +Read debug_response from ObserverSnapshot (new field added by server ticket #580). Format and append to output log. JSON-format complex payloads (NPC state, triangle list). + +PROTOCOL: +Extend protocol.gd encode_player_input to handle ''debug_command'' action_name -> serialize DebugCommandKind as action_data. Read debug_response from snapshot decode. + +Files: +- New: client/ui/debug_console.gd + debug_console.tscn +- Modify: client/ui/settings_dialog.gd (add toggle) +- Modify: client/scripts/protocol/protocol.gd (encode debug_command, decode debug_response) +- Modify: client/scripts/main.gd (wire tilde key, instantiate console) + +Blocked by: #580 (server debug command handler — need the protocol contract before client can dispatch)', 'done', 'medium', NULL, 'client', NULL, '2026-03-03 16:10:27', '2026-03-04 19:33:39', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-585', 'bug', NULL, 'Walls at LOS boundary: client — render margin tiles correctly through fog', 'Client half of the LOS boundary wall fix. Consumes the server-side boundary wall tiles added by #584. + +FIX: +In client/scripts/rendering/tile_renderer.gd, the update_tiles() method processes VisibleTile entries from the snapshot. Currently all visible tiles are rendered to the TileMapLayer with the same logic regardless of VisibilitySector. + +Add handling for the new BoundaryWall sector (or equivalent) from #584: +- BoundaryWall tiles are rendered to the tile map (so fog has content to composite over) +- BoundaryWall tiles do NOT update the exploration/memory state (they are not ''explored'') +- BoundaryWall tiles use the same tile rendering as normal wall tiles visually + +This ensures the fog shader composites over actual wall content at the LOS boundary rather than over empty viewport. + +Files: +- client/scripts/rendering/tile_renderer.gd (update_tiles method) +- client/scripts/autoloads/fog_state.gd (ensure boundary tiles don''t affect fog exploration data) + +Blocked by: #584 (server must send boundary wall tiles before client can render them)', 'done', 'medium', NULL, 'client', NULL, '2026-03-03 16:11:20', '2026-03-04 19:33:40', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-582', 'task', NULL, 'Author tile map: The Terminal (logistics hub)', 'Translate the Sprint 12 floor plan (#311) for The Terminal (Sova Logistics Hub) into tile coordinate data in content/campaigns/main/systems/krenn/stations/sova/districts/transit/locations/the-terminal.yaml. + +Source material: +- #311: Spatial layout: Logistics Hub (The Terminal) — tile-level floor plan with sightline analysis +- D-093: Sova Transit District — Terminal dimensions: 44x28 visual tiles +- Zones: scanner bays, main corridor (chokepoint), manifest processing, break room, supervisor office (window), restricted storage (smuggling ops) +- Access tiers: public (main corridor), credentialed (work floor), restricted (storage) +- Zone palette surface hex: #7a8490 / fog tint: #0d1520 + +TILE FORMAT: +Use the format defined by server ticket #577 (Location YAML tile format). Wait for Dudley to confirm the format before authoring. The format will be: tiles[] array of string rows, one character per tile (F=floor, W=wall, V=void, R=restricted). Origin tile (0,0) = top-left corner. + +OUTPUT: +Complete the stub at content/campaigns/main/systems/krenn/stations/sova/districts/transit/locations/the-terminal.yaml with: +- canonical_id, display_name, description (already partially present) +- tile_bounds: { x_min, y_min, x_max, y_max, z } +- tiles: [...] (the 44x28 grid) +- sightlines: { open: false, notes: ''supervisor office window faces main corridor'' } + +Blocked by: #577 (tile format agreed and documented)', 'done', 'high', NULL, 'visual', NULL, '2026-03-03 16:10:41', '2026-03-04 22:24:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-583', 'task', NULL, 'Author tile maps: The Last Shift, maintenance corridors, and gate corridor', 'Translate three Sprint 12 floor plans into tile coordinate data for the Sova Transit District. One YAML file per location. + +SOURCE MATERIAL: +- #312: Spatial layout: Bar (The Last Shift) — 28x22 visual tiles + 6m east extension +- #313: Spatial layout: Smuggling spaces and transition corridors — maintenance corridors, restricted storage, dead-drop locations +- D-093: Gate Cluster spec — 40x32 visual tiles, 7 zones: + aperture chamber 8x4 (restricted) + freight staging 24x8 (private) + passenger arrival 12x8 (semi-public) + freight customs 20x10 (semi-private, 3-5 lanes at 2vt/lane) + pedestrian customs 12x10 (semi-public, 3 lanes at 1vt) + gate concourse 40x8 (public) + observation gallery z=2 32x10 (Commission-only) +- D-093 corridor widths: maintenance 2vt, internal 3-4vt, secondary public 4vt, transition 6vt, gate concourse 8vt + +TILE FORMAT: +Same format as #582 (The Terminal). Wait for #577 format confirmation before authoring. + +LOCATIONS TO AUTHOR: +1. the-last-shift.yaml — bar layout: long bar counter, corner booth, scattered tables, news ticker, back room (alley exit). Zone palette: #6b4018 / fog #200c04 +2. maintenance-corridors.yaml — ring operation spaces: restricted storage + maintenance hatch + transition corridor (40m between hub and bar district). Zone palette: #4e5054 / fog #101214 +3. New file: locations/gate-corridor.yaml — gate cluster zones at z=0 (all zones except observation gallery) and z=2 (gallery). Cross-z rail = transparent low wall. + +Update district.yaml to add ''gate-corridor'' to the locations list. + +Blocked by: #577 (tile format), parallel with #582 (can author in parallel once format is agreed)', 'done', 'high', NULL, 'visual', NULL, '2026-03-03 16:10:57', '2026-03-04 22:24:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-573', 'bug', NULL, 'Dialogue speaker colors are position-based instead of speaker-bound', 'All speakers on the left side share the same color and all speakers on the right side share the same color. Colors should be bound to speaker identity, so each speaker has a consistent unique color regardless of their position in the conversation.', 'done', 'medium', NULL, 'client', NULL, '2026-03-03 07:50:12', '2026-03-04 22:26:14', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-574', 'bug', NULL, 'Pre-existing test failures in test_entity_renderer (test_rendering.gd)', 'Multiple entity renderer tests fail on clean HEAD (main@5aea6e2). Affected tests: test_entity_renderer_positions_centered, test_entity_renderer_player_color_differs_from_npc, test_entity_renderer_player_uses_d033_color, test_entity_renderer_npc_uses_unknown_teal, test_entity_renderer_object_uses_grey, test_entity_renderer_facing_indicator_rotation_accuracy, test_regression_345_entity_position_set_from_entity_id_entity. Likely entity_renderer.gd changed without updating tests.', 'done', 'low', NULL, 'client', NULL, '2026-03-03 07:50:15', '2026-03-04 22:26:17', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-38', 'epic', 'T-28', 'Client-Server Integration', 'Connect Rust simulation to Godot client via subprocess/IPC. End-to-end tick loop, input processing, state synchronization.', 'done', 'critical', NULL, NULL, 'D-020', '2026-02-10 23:15:13', '2026-03-04 22:32:11', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-369', 'epic', NULL, 'v0.1 Content Scoping Workshop Outputs', 'Parent epic for all v0.1 Content Scoping Workshop tickets. Covers: wiki content fixes, style guides/specs, content directory/schema, design specs, workshop-derived tickets, and lead decision tickets. Supersedes original Wiki Review Workshop scope.', 'done', 'high', NULL, 'copy', NULL, '2026-02-12 10:12:50', '2026-03-04 22:32:11', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-455', 'epic', NULL, 'QA Strategy & Test Infrastructure', 'QA and test infrastructure from the Test Architecture Workshop (2026-02-17). 59 items across Sprint 8 P0/P1, Sprint 9, and backlog. See docs/workshops/test-architecture/workshop-outcomes.md for full spec.', 'done', 'critical', NULL, 'ci', NULL, '2026-02-17 12:58:13', '2026-03-04 22:32:11', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-575', 'bug', NULL, 'Walls at LOS boundary absorbed into fog instead of rendering as content', 'Wall tiles at the edge of the LOS cone blend into the fog overlay instead of rendering as distinct wall content. The server only sends currently visible tiles — walls just outside the cone boundary are never included in visible_tiles, so the client has no content to render there. The fog composites over empty space, making walls look like part of the fog. + +Bug report: gauntlet-t1093-2026-03-03_14-30-38 +Tick: 1093 | Position: (26.5, 20.5) | Facing: North +Tester notes: the walls themselves need to be sent as visible tiles by the server. It looks weird to have them be part of the fog + +Context: The client-side tile accumulation fix (removing TileMapLayer.clear per frame) helps for previously-seen walls, but walls that were NEVER in the LOS cone still have no tile data. The server may need to include a margin of wall tiles beyond the LOS boundary so the fog has content to composite over. + +Potential approaches: +- Server: include wall tiles 1-2 tiles beyond the LOS cone in visible_tiles +- Server: send a separate nearby_walls array for tiles adjacent to visible positions +- Client: infer wall positions from the gap between visible floor tiles and the explored boundary', 'done', 'medium', NULL, 'server,client', NULL, '2026-03-03 15:33:22', '2026-03-04 22:32:11', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-596', 'story', NULL, 'Opening monologue — content: already complete (smuggler #299, detective #300)', NULL, 'done', 'high', NULL, 'copy', 'D-039', '2026-03-04 22:32:41', '2026-03-04 22:33:57', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-587', 'story', NULL, 'Character archetype selection — server: accept archetype in StartSession, spawn correct PC', NULL, 'done', 'high', NULL, 'server', 'D-027', '2026-03-04 22:32:15', '2026-03-05 10:05:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-589', 'story', NULL, 'Triangle activation consumer — server: emit behavioral tell escalation on TriangleActivated', NULL, 'done', 'high', NULL, 'server', 'D-024', '2026-03-04 22:32:20', '2026-03-05 10:05:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-591', 'story', NULL, 'News ticker — server: load ticker YAML, emit current headline in snapshot', NULL, 'done', 'medium', NULL, 'server', 'D-039', '2026-03-04 22:32:26', '2026-03-05 10:05:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-593', 'story', NULL, 'v0.1 playthrough proof: full session from main menu through storyteller activation', NULL, 'done', 'critical', NULL, 'server', NULL, '2026-03-04 22:32:33', '2026-03-05 10:05:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-594', 'task', 'T-586', 'Tile data model design — produce D-record for extensible tile properties', NULL, 'done', 'medium', NULL, 'server', NULL, '2026-03-04 22:32:35', '2026-03-05 10:05:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-595', 'story', NULL, 'Opening monologue trigger — server: emit opening monologue lines at session start based on archetype', NULL, 'done', 'high', NULL, 'server', 'D-039', '2026-03-04 22:32:39', '2026-03-05 10:05:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-597', 'story', NULL, 'Triangle activation — copy: author 3–5 proximity monologue lines for TriangleActivated (per archetype)', NULL, 'done', 'high', NULL, 'copy', 'D-039', '2026-03-04 22:34:02', '2026-03-05 10:06:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-598', 'epic', NULL, 'Insert document reader — onboarding dossiers', 'Player-facing document reader for the insert UI. First use case: onboarding dossiers on first load — Commission assignment brief (detective) and network warning note (smuggler). Diegetic documents that set up asymmetric information. Three stories: (1) client document reader UI rendering markdown, (2) server+client document data model in YAML, (3) authored content for both archetypes. Documents are persistent/re-readable from insert, markdown format, variable fields injected at runtime. See Q-055 for design details. Refs: D-065, D-090, D-091, D-034, D-036, D-087, D-012. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. Onboarding dossiers for detective/smuggler archetypes are defunct — the game is pivoting to a generator-first life sim with tycoon bookmark. Insert system survives but will be re-scoped for v0.2.', 'cancelled', 'high', NULL, NULL, 'D-065,Q-055', '2026-03-05 10:24:14', '2026-03-05 10:24:14', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-599', 'story', 'T-598', 'Document reader UI component — markdown rendering in insert panel', 'Build an insert UI panel that renders markdown documents. Requirements: (1) Parse markdown subset — headers, bold, italic, horizontal rules, field labels. (2) Full-screen overlay mode for first-load display, dismissed by keypress. (3) Persistent access from insert — player can re-open and re-read documents at any time. (4) Support variable field injection (case ref, date, PC name) via template markers in the markdown source. (5) Scrollable for longer documents. Design should feel like a diegetic data-pad display, not a browser. Refs: D-065 insert UI. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. Onboarding dossiers for detective/smuggler archetypes are defunct — the game is pivoting to a generator-first life sim with tycoon bookmark. Insert system survives but will be re-scoped for v0.2.', 'cancelled', 'high', NULL, 'client', 'D-065,Q-055', '2026-03-05 10:24:20', '2026-03-05 10:24:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-600', 'story', 'T-598', 'Document data model — YAML content, server loading, wire format', 'Design and implement the document data model. Requirements: (1) YAML content files for documents with markdown body, metadata (id, title, archetype, trigger condition, variable field definitions). (2) Server loads document YAML at startup via ContentStore. (3) Documents emitted in ObserverSnapshot — initially the onboarding document for the player''s archetype. (4) Client receives, stores, and surfaces documents to the insert reader UI. (5) Trigger system: onboarding docs fire on first snapshot (tick 0 or session start). Future documents may trigger on events/locations. Wire format: document id + markdown body + injected variables in ObserverSnapshot. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. Onboarding dossiers for detective/smuggler archetypes are defunct — the game is pivoting to a generator-first life sim with tycoon bookmark. Insert system survives but will be re-scoped for v0.2.', 'cancelled', 'high', NULL, 'server', 'Q-055', '2026-03-05 10:24:26', '2026-03-05 10:24:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-601', 'story', 'T-598', 'Onboarding dossier content — detective brief and smuggler warning', 'Author the two onboarding documents per the design consensus: + +DETECTIVE DOSSIER (150–200 words): Commission Field Operations assignment brief. Institutional voice — labelled fields, case ref, formal passive. Establishes: cargo irregularities at Sova Transit, standard observation authority, reporting to office not person. Omits: suspect names, ring existence, threat assessment. Format: header block (case ref, date, classification), Background, Scope, Objective, Reporting sections. The Commission is not worried — that''s the tell. + +SMUGGLER WARNING (60–80 words): Anonymous dead drop from network coordinator. Terse operational voice, no headers, unsigned or coded sign-off. Establishes: Commission investigator incoming, maintain normal schedule, stay quiet. Omits: detective identity, intel source, reassurance. The brevity IS the voice. + +BOTH OMIT all triangle NPC names (Kael, Sera, Torek). Triangle is discovered through observation. + +Voice refs: D-090 registers. Detective dossier = Commission voice (not PC). Smuggler note = network contact voice (not PC). Contrast with PC monologue is intentional. See existing monologue pools for PC voice reference. Refs: D-034, D-036, D-087, D-091. + +[CANCELLED 2026-03-05] Superseded by Where''s the Fun? Workshop decisions. Onboarding dossiers for detective/smuggler archetypes are defunct — the game is pivoting to a generator-first life sim with tycoon bookmark. Insert system survives but will be re-scoped for v0.2.', 'cancelled', 'high', NULL, 'copy', 'D-090,D-091,D-087', '2026-03-05 10:24:32', '2026-03-05 10:24:32', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-602', 'story', NULL, 'Design discussion: insert data feeds — documenting feature systems and plumbing patterns', 'Broad design discussion to map out ALL the data feed systems the insert will eventually surface, identify common patterns, and design foundational plumbing that serves them all. This is bigger than the onboarding dossier — it is the insert as an information platform. + +Participants: Tyre (architecture), Dudley (server), Stig (UI), Gestalt (systems design), Miri (worldbuilding — what feeds exist in-setting), Ozzie (player experience — what feels good to check) + +The insert (D-065) is the player''s primary information device. It needs to surface a wide variety of data feeds that exist naturally in the setting. Map these out FIRST, then identify patterns, then design plumbing. + +## Known and candidate feed types + +**Documents/dossiers** — static or semi-static authored content. Assignment briefs, personal notes, found documents, intercepted communications. Markdown body, variable injection, triggered delivery. + +**Messaging/comms** — NPC-to-player and overheard messages. Meridian messages, dead drops, intercepted transmissions. Threaded? Timed delivery? Read/unread state? + +**News/ticker feeds** — station news, sector bulletins, propaganda. Already have TickerPool (#591) for the bar — how does this generalize to the insert? Weather/atmospheric feeds for planets (adds environmental flavor). + +**Time systems** — local station time, central Settled Reach time, planetary day-night cycles (varying rotation periods). How does the insert display multiple time references? Which are always visible vs on-demand? + +**Maps** — district layouts, marked locations, fog-of-war on map data. Progressive reveal as player explores. + +**Logs/journal** — auto-generated from observations? Player-annotated? Investigation notes the detective accumulates vs cargo manifests the smuggler tracks? + +**Faction/relationship status** — trust levels, known affiliations, reputation. How much is visible to the player vs hidden (D-012 information boundary)? + +**Inventory/cargo** — physical items, data chips, contraband manifests. + +## Questions to resolve + +1. What feed types exist in the Settled Reach setting? (Miri: what does a station worker/visitor actually have on their insert?) +2. Which feeds are universal vs archetype-specific? (Detective gets case files; smuggler gets network dead drops. Both get news and time.) +3. What are the common patterns across feeds? (Delivery trigger, persistence, read state, update frequency, rendering format) +4. Server-side: single generic "insert_feeds" collection in ObserverSnapshot vs typed fields? Delta updates vs full state? +5. Client-side: plugin/renderer architecture — how does the insert UI dispatch feed types to renderers without hardcoding each one? +6. Persistence: session-persistent vs save-persistent vs ephemeral. Which feeds accumulate, which rotate, which expire? +7. Information boundary (D-012): feeds are perception-filtered. The insert only shows what the PC has access to. How does this interact with the observer snapshot? +8. Priority/notification: which feeds notify the player (new message!), which are passive (time ticks), which are urgent (warning)? + +## Output + +D-record (or major amendment to D-065) documenting: +- Catalog of insert feed types with properties +- Common envelope/interface pattern +- Server→client data flow architecture +- Rendering dispatch pattern +- Persistence and lifecycle model + +This is a design discussion, not implementation. Produce decisions and patterns that #600 and future insert work implement against. + +## Refs +D-065 (insert UI), D-012 (information boundary), D-010 (determinism), Q-055', 'backlog', 'high', NULL, NULL, 'D-065,Q-055', '2026-03-05 10:28:30', '2026-03-05 10:28:30', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-588', 'story', NULL, 'Character archetype selection — client: character select screen before session start', NULL, 'done', 'high', NULL, 'client', 'D-027', '2026-03-04 22:32:17', '2026-03-05 15:44:42', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-590', 'story', NULL, 'Triangle activation consumer — client: react to triangle_crisis_events in snapshot (monologue chime + urgent overlay)', NULL, 'done', 'high', NULL, 'client', 'D-039', '2026-03-04 22:32:23', '2026-03-05 15:44:43', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-592', 'story', NULL, 'News ticker — client: scrolling ticker HUD element in The Last Shift zone', NULL, 'done', 'medium', NULL, 'client', 'D-039', '2026-03-04 22:32:30', '2026-03-05 15:44:43', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-603', 'initiative', NULL, 'v0.2 Life-Sim Pivot', 'Generator-first life sim pivot following the Where''s the Fun? workshop (2026-03-05). 24 decisions locked: all NPCs generated, tycoon bookmark, culture-implicit-in-location, broad life verbs, dual-scale consequence model. Detective/smuggler framing retired. Critical path: Sprint 25 generator spike. See docs/workshops/wheres-the-fun/workshop-outcomes.md.', 'backlog', 'critical', NULL, NULL, NULL, '2026-03-05 23:11:31', '2026-03-05 23:11:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-604', 'epic', 'T-603', 'Generator Proof-of-Life', 'Sprint 25 spike: generator must produce usable output before anything else matters. Prove auto-generated locations at scale with legible characters. Template assembly (not procedural geography) for v0.2. See workshop decisions #1, #7, #22, #23. Estimated 7 sprints to proof-of-life playtest (generated location + legible characters + tycoon bookmark from creation to Day 3) — Tyre estimate.', 'backlog', 'critical', NULL, NULL, NULL, '2026-03-05 23:11:39', '2026-03-05 23:11:39', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-605', 'epic', 'T-603', 'Tycoon Bookmark', 'Tycoon is the v0.2 bookmark: small business owner, existing in the Krenn System. Zero investigation content. Tycoon = aspiration not starting state. Workshop decisions #4, #19, #20. Broad economic verb vocabulary serving all careers. Auto-generated apartment reflecting wealth + cultural context. CK3-style bookmark selection flow.', 'backlog', 'high', NULL, NULL, NULL, '2026-03-05 23:11:42', '2026-03-05 23:11:42', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-606', 'epic', 'T-603', 'Character Creation', 'CK3-style character creation: skills + bookmark selection. Full cosmetic customisation (hair, clothing, colours — workshop decision #11). Culture implicit in starting location (decision #16). No family/culture/religion sliders in creation — those are deferred. Decision #2.', 'backlog', 'high', NULL, NULL, NULL, '2026-03-05 23:11:48', '2026-03-05 23:11:48', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-607', 'epic', 'T-603', 'NPC Legibility', 'The proof-of-life gate: generated NPCs must have sufficient personality surface area for emotional attachment. Without legible NPCs nothing else works — all 9 workshop agents converged on this. Decisions #7, #8, #17. Traits + observable behaviour as personality surface. Relationships via Sims interaction + Rimworld adversity. AI-assisted content templating via culture vectors.', 'cancelled', 'critical', NULL, NULL, NULL, '2026-03-05 23:11:52', '2026-03-05 23:11:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-608', 'epic', 'T-603', 'World Feel', 'The world is quietly responsive, not indifferent. Gradient of caring by social proximity — world doesn''t care globally but notices locally. Dual-scale consequence model: Rimworld sharp events (crises, reversals) + DF slow accumulation (reputation, debt, relationship erosion). Setting delivery via both visual and insert layers in parallel. Workshop decisions #10, #12, #13, #21.', 'backlog', 'high', NULL, NULL, NULL, '2026-03-05 23:11:59', '2026-03-05 23:11:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-615', 'story', 'T-605', 'Tycoon small business owner starting state', 'Define the tycoon Day 1 state: small business owner in the Krenn System, NOT a wealthy tycoon. Tycoon = aspiration, not starting state (decision #20). Starting assets, relationships, knowledge, economic position. Auto-generated apartment reflects this. Feeds into character creation and generator.', 'backlog', 'high', NULL, 'planning', NULL, '2026-03-05 23:12:34', '2026-03-05 23:12:34', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-616', 'story', 'T-605', 'Broad economic verb vocabulary design', 'Design the tycoon-era verb map. Decision #19: broad life-verb vocabulary, not tycoon-specific. Verbs serve all potential careers. Economic verbs as a superset. Works: hire, negotiate, inspect, invest, source, sell, manage. Social verbs remain. No investigation verbs in v0.2.', 'backlog', 'high', NULL, 'planning', NULL, '2026-03-05 23:12:41', '2026-03-05 23:12:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-617', 'story', 'T-605', 'Auto-generated apartment', 'SPLIT — see #681 (server: apartment generator logic) and #682 (client: visual rendering + first-moment sequence). Original: Player starting apartment is auto-generated to reflect economic position and cultural context. Decision D-136 (First Settled Reach moment: apartment + insert activation). Decision D-126 (Groundhog Day alarm clock homage).', 'backlog', 'high', NULL, 'server', NULL, '2026-03-05 23:12:44', '2026-03-05 23:12:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-619', 'story', 'T-606', 'Full character customisation', 'Cosmetic customisation: hair, clothing, colours. Decision #11. Separate from skills/bookmark — aesthetic only. Question open: do creation choices trace into the generated apartment? (Q-WTF-040).', 'backlog', 'high', NULL, 'client', NULL, '2026-03-05 23:12:52', '2026-03-05 23:12:52', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-621', 'story', 'T-607', 'NPC personality surface area', 'Define and implement the observable personality surface for generated NPCs: traits + visible behaviour patterns. Decision #17. Must be sufficient for emotional attachment without authored backstory. This is the proof-of-life test question: can the player read NPC relationships from generator output? Personality surface = primary gate for the generator spike.', 'cancelled', 'critical', NULL, 'server', NULL, '2026-03-05 23:13:06', '2026-03-05 23:13:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-622', 'story', 'T-607', 'Relationship formation system', 'NPC-to-NPC and NPC-to-player relationships form through: Sims-style direct interaction + Rimworld-style shared adversity. Decision #17. Relationships must be readable from the outside. Codify for systems. Decision #18: prove relationships readable before layering narrative depth.', 'backlog', 'high', NULL, 'server', NULL, '2026-03-05 23:13:08', '2026-03-05 23:13:08', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-623', 'story', 'T-607', 'AI content templating pipeline', 'Generative AI pipeline for NPC content templating. Decision #8. Culture vectors (from Krenn culture profile) as prompt constraints. Tone, accents, speech patterns culturally driven — job modifies, culture primary (decision #6). Question open: Claude API, local ollama, or manual for v0.2? (Q-WTF-033). Decision #9: in-game ollama deferred but door open.\n\n[Superseded by #638 LLM Voice Pipeline epic — workshop decisions resolved Q-WTF-033 in favour of local llama-cpp-rs. 2026-03-07]', 'cancelled', 'high', NULL, NULL, NULL, '2026-03-05 23:13:16', '2026-03-05 23:13:16', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-624', 'story', 'T-608', 'Quietly responsive world', 'The world notices locally but doesn''t care globally. Gradient of caring based on social proximity. Decision #10. Primary social contacts develop responsiveness over time. Indifferent world is wrong — quietly responsive world is right. Implementation: proximity-weighted NPC attention and reaction systems.', 'backlog', 'high', NULL, 'server', NULL, '2026-03-05 23:13:22', '2026-03-05 23:13:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-625', 'story', 'T-608', 'Dual-scale consequence model', 'Two consequence scales operating simultaneously. Decision #21. Rimworld-style: sharp events, crises, dramatic reversals (fast). DF-style: slow accumulation — reputation erosion, debt, relationship drift (slow). Both at different scales, not either/or. Failure mode is clear (decision #21 resolves risk register item).', 'backlog', 'high', NULL, 'server', NULL, '2026-03-05 23:13:25', '2026-03-05 23:13:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-626', 'story', 'T-608', 'Setting delivery — both layers', 'Setting delivered via two parallel channels: visual (what you see in the world) + insert (diegetic information device). Decision #12. These are not sequential — both activate simultaneously. Decision #13: First Settled Reach moment = apartment + insert activation. The insert is the primary diegetic information tool. Open question: what should the player feel looking at the span gate from their apartment? (Q-WTF-041).', 'backlog', 'high', NULL, 'planning', NULL, '2026-03-05 23:13:37', '2026-03-05 23:13:37', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-586', 'epic', NULL, 'Design extensible tile data model to replace single-char encoding', 'The current tile format uses single characters (F/W/V/R) in string arrays. This cannot represent tile-level properties like: door access lists, container contents, damage/hit points, visual properties (paint, material, wear), furniture/interactables, terrain variants, sound properties, trigger zones. This ticket is a DESIGN task. Deliverables: 1) Survey what tile-level data the game needs across all systems. 2) Design an extensible tile data model (consider tile palette/registry, per-tile property bags, layer systems, ECS-style tile components). 3) Write a D-record with the chosen design. 4) Estimate migration effort for existing location YAMLs. The design must handle authoring (human-writable YAML), loading (server parser), runtime (ECS queries), and future procedural generation.', 'done', 'medium', NULL, 'server', NULL, '2026-03-04 21:29:27', '2026-03-06 18:48:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-613', 'story', 'T-604', 'NPC generation pipeline', 'Wire template generator output into NPC entity creation. Input: DistrictSkeleton with NpcBlueprints from #612. Output: spawned ECS entities using the existing npc/generate.rs pipeline, extended to accept cultural markers from the blueprint. + +For the sprint proof this does NOT spawn into a running bevy world — it extends the generator-spike binary to also print per-NPC detail lines. The ECS wiring is the stretch goal; the mandatory deliverable is the text output proving NPC generation from blueprints works. + +The pipeline: NpcBlueprint.to_role_definition() feeds the existing 10-axis generator. Cultural markers from the blueprint bias trait selection (a rural Krenn NPC should not generate cosmopolitan traits). Relationship pre-seeds from the blueprint are injected into the relationship component. + +Sprint proof output per NPC (printed to stdout for both the rural and industrial runs): +- Name, age, role/occupation +- 2-4 personality traits (from trait enum, human-readable) +- 1-2 observable behaviors (what a bystander notices) +- Cultural speech markers (register, filler words) +- Relationships: "[name] knows [other_name] as [relationship_type] ([valence])" + +D-129 gate: can you READ the relationships from the text dump? Not infer — read. The pass condition is a human scanning the output and saying "yes, I can see who knows whom and how they feel about it." + +Two-zone comparison test (extends #612 proof): +- Rural NPCs should skew toward agricultural/trade roles, lower density, tighter social networks (more relationships per capita) +- Industrial NPCs should skew toward logistics/manufacturing roles, higher density, looser networks +- Both sets should share Krenn cultural markers (naming, speech patterns) + +Acceptance criteria: +- [ ] generator-spike binary prints per-NPC detail for both --zone rural and --zone industrial +- [ ] NPC names follow Krenn phoneme/naming conventions from culture profile +- [ ] Trait sets differ between NPCs (not all NPCs get the same 3 traits) +- [ ] Relationships are explicit in output: "A knows B as colleague (positive)" +- [ ] Rural and industrial NPC populations differ in role distribution and social network density +- [ ] Cultural markers (speech register, filler words) appear in output and match Krenn profile +- [ ] No per-NPC authoring — every NPC is fully derived from zone_type + culture + seed', 'cancelled', 'critical', NULL, 'server', NULL, '2026-03-05 23:12:25', '2026-03-06 19:41:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-611', 'story', 'T-604', 'NpcBlueprint struct design', 'Define ZoneSpec, CultureProfile, and NpcBlueprint as Rust structs with serde_yaml deserialization. Write example YAML showing the expected format. This IS the schema contract — copy team fills YAML to match these structs. Use a spike-specific SpikeOutput struct, NOT DistrictSkeleton. Phase 0 deliverable: structs + example YAML shared with copy team.', 'done', 'critical', NULL, 'server', NULL, '2026-03-05 23:12:17', '2026-03-07 07:48:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-612', 'story', 'T-604', 'Template assembly generator', 'Generator binary: takes --zone --seed , loads zone spec + culture YAML from disk, produces NPCs via NpcBlueprint, prints text output. Must work with hardcoded test data before real YAML arrives (Phase 1). Sprint proof: run twice (rural + industrial), read side by side, can you tell which is which. Includes the NPC generation pipeline and stdout formatting (absorbs #613).', 'done', 'critical', NULL, 'server', NULL, '2026-03-05 23:12:19', '2026-03-07 07:48:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-609', 'story', 'T-604', 'Zone identity spec', 'Zone identity taxonomy as YAML the generator deserializes. Schema defined by #611 Rust structs. Minimum two zone types (rural, industrial) with real content. Remaining types can be stubs. The taxonomy must make the generator produce visibly different output per zone type.', 'done', 'critical', 'mellanie', 'copy', NULL, '2026-03-05 23:12:07', '2026-03-07 08:59:42', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-610', 'story', 'T-604', 'Krenn culture profile', 'Krenn system-wide culture profile as YAML the generator deserializes. Schema defined by #611 Rust structs. Must provide enough cultural signal that generated NPCs feel Krenn. Sprint scope: name lists (not phoneme generation), speech markers, economic values, social norms. Phoneme-based name generation is out of scope.', 'done', 'critical', 'mellanie', 'copy', NULL, '2026-03-05 23:12:10', '2026-03-07 08:59:43', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-628', 'task', NULL, 'Fix name pool first-pick bias (Dav in all runs)', 'Fisher-Yates shuffle in generator_spike.rs build_name_pool() produces the same first name across different seeds. ''Dav'' appears as NPC 1 in all three test runs (rural/42, industrial/42, rural/99). Investigate seed initialization — the shuffle should produce different orderings for different seeds. This is a bug, not a feature request. Players will metagame recognized names across playthroughs.', 'done', 'high', NULL, 'server', NULL, '2026-03-07 09:35:45', '2026-03-07 10:14:51', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-629', 'task', NULL, 'Behavior dedup within a zone run', 'Generator spike assigns the same behavior string to multiple NPCs in one run. At 11 NPCs (industrial/42): Sera and Vrek both ''presses an ear to a vibrating duct and listens'', Torek and Rask both ''pulls a worker aside for a quiet word near the far wall''. Apply without-replacement selection to behaviors within a single zone generation, same pattern as the name pool Fisher-Yates. If pool exhausts, allow repeats but log a warning.', 'done', 'high', NULL, 'server', NULL, '2026-03-07 09:35:49', '2026-03-07 10:14:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-631', 'task', NULL, 'Relationship-to-behavior pipeline', 'Generator spike assigns relationships (rival, friend, subordinate, colleague with sentiment) but they are invisible in behavior output. Five reviewers independently flagged this. Relationships should modify behavior selection: rivals don''t acknowledge each other, friends gravitate, subordinates defer. Minimum viable: when NPC A has a relationship with NPC B and both are in the same social site, A''s behavior line should reflect the relationship. E.g. ''talks past Rask without making eye contact'' for a rival. This is the bridge between ''populated'' and ''inhabited''.', 'done', 'medium', NULL, 'server', NULL, '2026-03-07 09:36:06', '2026-03-07 10:14:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-632', 'task', NULL, 'Want/State layer — internal motive biases behavior selection', 'Five reviewers independently identified this as the gap between ''populated'' and ''inhabited''. Every NPC gets a current Want/State (e.g. bored, alert, suspicious, avoiding someone, looking for information) that biases behavior selection and introduces micro-tells. Not a UI element — an internal driver that leaks through observable action. The player sees the behavior, not the Want. The mystery is the gap between them. This is where perception mode gets something to read, and where the asymmetric information mechanic engages. Gestalt''s framing: ''the system generates legible characters but not interesting situations — Want is the lever that converts generated cast into generated situation.'' Ozzie''s framing: ''every NPC is correctly in their lane — what if one isn''t? That crack is the whole game.'' Depends on #629 (behavior dedup) and #630 (expanded behavior pools) being in place so Want has material to express through.', 'done', 'high', NULL, 'server', NULL, '2026-03-07 09:36:51', '2026-03-07 10:14:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-644', 'story', 'T-638', 'Content: Universal negative injectors (NI-1 through NI-5)', 'Spike 2 finding: universal negative injectors (NI-1 through NI-5) were removed from the RULES const. Worldbuilding constraints belong in per-culture voice_persona blocks, not universal rules. Each culture defines its own technology vocabulary, rank conventions, humor register, Earth references. NI-1/NI-5 are culture-gated not universal. This ticket is superseded by #653 (culture persona authoring).', 'done', 'medium', NULL, 'copy', NULL, '2026-03-07 11:56:00', '2026-03-07 11:56:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-639', 'story', 'T-638', 'Spike 1: Build llama-cpp-rs inference CLI', 'Build a standalone Rust CLI tool wrapping llama-cpp-rs. Accepts a prompt via stdin or CLI arg, returns generated text. Loads Gemma 2B (Q4_K_M) and Phi-3 (Q4_K_M) — both models tested against the same prompts in Spike 1. No game integration, no queue, no cache. Goal: prove the plumbing works and enable the manual prompt quality session. Reference: docs/workshops/llm-voice-pipeline/round-3-inputs.md (Spike 1 strategy).', 'done', 'high', NULL, 'server', NULL, '2026-03-07 11:55:31', '2026-03-07 18:18:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-640', 'story', 'T-638', 'Spike 1: Manual prompt quality session', 'Jeroen + Mellanie + Paula manually craft and test prompts using the Spike 1 CLI tool (ticket #639). Test culture injectors, behavior seeds, dialogue seeds. Run Gemma 2B and Phi-3 head-to-head on the same prompts. Answer: does this even play? Outputs: winning model recommendation, refined injector templates, go/no-go for Spike 2. No game integration — purely inference tool + manual experimentation. Reference: docs/workshops/llm-voice-pipeline/round-3-inputs.md.', 'done', 'high', NULL, 'copy', NULL, '2026-03-07 11:55:37', '2026-03-07 18:18:04', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-641', 'story', 'T-638', 'Spike 2: Pre-voicing pipeline integration', 'Wire the validated llama-cpp-rs runner (Spike 1) into the full pre-voicing pipeline. Scope: background queue, cache-as-determinism (generate once per seed, cache result), thread pool isolation (inference vs world generation), baked content generation (pre-voice at build time for hub zones), fallback to base text. Uses whichever model won Spike 1 (Gemma 2B or Phi-3). Full architecture as designed in workshop — both observable behaviors AND dialogue re-voiced. Tells excluded from LLM output but present as read-only context inputs. Reference: docs/workshops/llm-voice-pipeline/round-3-inputs.md.', 'done', 'high', NULL, 'server', NULL, '2026-03-07 11:55:43', '2026-03-07 18:18:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-642', 'task', 'T-638', 'Data model: Add tell_behaviors field to NpcBlueprint', 'Add a separate tell_behaviors: Vec field to NpcBlueprint alongside observable_behaviors. Tells are passthrough — the pipeline checks the field tag and routes all tell_behaviors content as base text, never sending it to the LLM. Additionally, tell presence is used as a read-only input to the re-voicing prompt for surrounding behaviors and dialogue (e.g. an NPC with avoidance_tell gets dialogue phrased in an avoiding way). The tell itself is never LLM output. See D-record from LLM Voice Pipeline Workshop.', 'done', 'high', NULL, 'server', NULL, '2026-03-07 11:55:50', '2026-03-07 18:18:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-643', 'story', 'T-638', 'Content: Krenn culture injector clauses', 'Author Krenn culture injector clauses for use in LLM re-voicing prompts. 10-20 clauses per culture tier. Sourced from Krenn culture RON speech fields (ticket #610 base). Covers tone, speech patterns, idioms, cultural philosophy. Must include explicit NOT-lists (negative injectors) specific to Krenn to prevent lore contamination. Output: structured clause set ready for pipeline consumption. Required input for Spike 1 manual prompt session (ticket #640).', 'done', 'high', NULL, 'copy', NULL, '2026-03-07 11:55:56', '2026-03-07 18:18:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-654', 'story', 'T-638', 'Voice pipeline: GPU acceleration (ROCm/Vulkan)', 'sr-voice has cargo features for rocm/vulkan/cuda/metal but builds CPU-only (~13 t/s). Enable after code stable. GPU would reach 50+ t/s. LIBCLANG_PATH already in Makefile.', 'backlog', 'low', NULL, 'server', NULL, '2026-03-07 18:19:29', '2026-03-07 18:19:29', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-638', 'epic', NULL, 'LLM Voice Pipeline', 'Runtime LLM re-voicing of NPC observable behaviors and dialogue using llama-cpp-rs (Gemma 2B / Phi-3 bundled). Decided in LLM Voice Pipeline Workshop (2026-03-07). Two-spike strategy: Spike 1 proves plumbing and quality; Spike 2 wires into pre-voicing pipeline. Tells pass through untouched (base text only) but inform LLM context as read-only inputs. Model bundled with install (~1.5GB). Amends D-123 and supersedes D-124. See docs/workshops/llm-voice-pipeline/.', 'done', 'high', NULL, 'server', NULL, '2026-03-07 11:55:26', '2026-03-07 18:19:40', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-630', 'task', NULL, 'Expand behavior pools — trader, foreman, off-shift register', 'Review feedback: trader has 6 behaviors (3 are functional, not observable), foreman has 5 (4 are surveillance). At 11 NPCs per zone, collisions are math. Add: (1) more trader behaviors that are stage directions not internal notes, (2) foreman behaviors showing the person beneath the role (covering for someone, absorbing a problem), (3) off-shift behaviors for dock_worker and technician roles so break room social site has material to draw from. Paula flagged this as medium priority.', 'done', 'medium', NULL, 'copy', NULL, '2026-03-07 09:36:02', '2026-03-07 18:22:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-648', 'task', NULL, 'Update all agent briefings to reflect v0.2 pivot', 'The Where''s the Fun workshop (2026-03-05) pivoted: generator-first, tycoon bookmark, no detective/smuggler. Multiple agents still reference old design. Update docs/briefings/*.md and .claude/agents/*.md. Nigel specifically flagged during Spike 1 voice testing.', 'cancelled', 'medium', NULL, 'main', NULL, '2026-03-07 14:43:16', '2026-03-07 18:37:45', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-650', 'story', 'T-638', 'ContentType::Factual — LLM bypass for fact-bearing lines', 'Lines with numbers, causal chains, denials bypass LLM. New ContentType alongside Dialogue/Behavior. Spike 2 showed 2B corrupts numbers and inverts meaning. Separate truth layer (simulation) from register layer (LLM).', 'done', 'high', NULL, 'server', NULL, '2026-03-07 18:19:12', '2026-03-13 08:38:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-652', 'story', 'T-638', 'Voice pipeline: observer integration', 'Wire voice cache into perception/observer. Look up voiced text before emitting behavior/dialogue to client. Tell behaviors always passthrough. Fall back to base text on cache miss. Final integration step for voiced content.', 'done', 'high', NULL, 'server', NULL, '2026-03-07 18:19:23', '2026-03-13 08:38:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-627', 'story', NULL, 'SQLite settings storage', 'Use SQLite for persistent settings storage. SQLite is compiled into the server binary via rusqlite with bundled feature — zero runtime dependency, no installer, no DLL. + +Architecture: settings live on the SERVER side in a SQLite database with per-player settings tables. The client is a dumb terminal — it sends ChangeSettings commands to the server over the existing IPC protocol, same as any other player action. The server reads/writes the SQLite file. The client never touches the database directly. + +This keeps the client thin (Godot rendering + input only) and settings consistent with the multiplayer-ready baseline (D-010). Per-player tables mean multiple players on the same server get isolated settings. + +Scope: keybindings, audio volume, display preferences, accessibility options. Replaces Godot ConfigFile approach. SQLite gives structured queries for free if settings grow beyond flat key-value (per-game overrides, profile-specific keybindings, accessibility presets).', 'done', 'high', NULL, 'server', NULL, '2026-03-07 08:06:58', '2026-03-13 08:38:21', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-651', 'story', 'T-638', 'Friendly and RoutineDeviation tells — iterate post-ship', 'Spike 2 showed these two tells produce output indistinguishable from neutral on Gemma 2B. 3/5 tells work (Nervous, Guarded, Angry). May be 2B capacity ceiling. Options: stronger examples, non-speech channels only, or revisit at 7B.', 'done', 'low', NULL, 'server', NULL, '2026-03-07 18:19:20', '2026-03-13 08:38:21', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-633', 'task', NULL, 'Composable behavior engine — assemble NPC behaviors from culture + role + context primitives', 'Current behavior pools are hand-authored per culture×zone×role combination. This doesn''t scale. The generator should compose observable behaviors from smaller pieces: role actions (generic physical stage directions), culture modifiers (Krenn-specific flavoring, speech patterns), and context tags (on-shift, off-duty, social site type). Server implements the composition engine that assembles these at generation time. See Q-057. Dependency: copy team delivers the decomposed content format (separate ticket).', 'done', 'high', NULL, 'server', NULL, '2026-03-07 09:54:51', '2026-03-13 08:38:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-655', 'task', NULL, 'Remove v0.1 content loading system', 'Delete the v0.1 hand-authored content pipeline, superseded by the v0.2 generator-first approach (D-122, D-128). Scope: server/src/content/ module (loader.rs, types.rs, line_pool.rs, hot_reload.rs, spawn.rs, template.rs, instantiation.rs, mod.rs), tooling/content-converter/, tooling/validate-content, content-ron/ compiled output, content/_meta/ style guides, related design docs (content-directory-structure.md, monologue-content-architecture.md, opening-hook-content.md, v0.1-wow-moments-checklist.md), and server/tests/content_*.rs test files. Preserve content/global/ (enums, knowledge, culture profiles) — those are still live. Preserve any types from content/types.rs that are re-exported to other modules.', 'done', 'medium', NULL, 'server', NULL, '2026-03-07 18:31:00', '2026-03-13 08:38:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-660', 'story', NULL, 'Server: extract platform abstraction module when second consumer appears', 'Trigger ticket: when any server module beyond voice/hardware.rs needs OS-dependent info (CPU, memory, battery, GPU), extract shared platform queries into server/src/platform.rs. Currently all OS detection lives in server/src/voice/hardware.rs (sysinfo crate, on_battery(), VRAM probes, available_parallelism). Single consumer, no duplication — no action needed until a second consumer appears. Trigger conditions: (1) a second system needs CPU/memory info independently of voice pipeline, (2) battery detection needed outside voice scaling (e.g. tick rate throttling), (3) server exposes system info over IPC (multiplayer diagnostics). Extraction is ~30 minutes: pull on_battery(), probe_current_free(), sysinfo calls into platform.rs, leave voice-specific scaling logic in hardware.rs.', 'backlog', 'low', NULL, 'server', NULL, '2026-03-13 09:49:07', '2026-03-13 09:49:07', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-661', 'task', NULL, 'Restructure: move behavior primitives to zone-type template files --sprint 26', 'Move existing behavior_primitives from per-location zone specs (krenn-rural-zone.ron, krenn-industrial-zone.ron) into global zone-type template files (content/global/zone-types/rural_agricultural.ron, industrial_freight.ron). Strip primitives and typical_behaviors from location specs. Add zone_type field to location specs. Scrub Krenn-specific language from primitives (they must be culture-neutral). Per D-141 zone-type template architecture.', 'done', 'high', 'done', 'copy', NULL, '2026-03-13 10:30:29', '2026-03-13 10:43:42', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-646', 'story', 'T-638', 'UX: AI-Enhanced Dialogue toggle + hardware detection', 'Implement layered hardware detection and player-facing controls for the LLM Voice Pipeline. Three detection layers: (1) CPU/RAM check — can the model even load? (2) time-per-token benchmark on first enable — is inference fast enough to be useful? (3) recommendation threshold — suggest disabling if below bar, but player can always override. Always-available ''AI-Enhanced Dialogue'' toggle in settings. No hard minimum spec floor — if they pass the RAM check, let them run it. Bundled model (no download step). Blocked on Spike 2 pipeline existing.', 'done', 'medium', NULL, 'client', NULL, '2026-03-07 11:56:15', '2026-03-13 10:45:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-659', 'story', NULL, 'PlatformInfo: client-side OS abstraction autoload', 'Create a PlatformInfo autoload (client/scripts/autoloads/platform_info.gd) that centralizes all OS-dependent queries. Individual systems consume PlatformInfo — they never call OS.* directly. + +Scope: +- PowerProfile enum (FULL, BATTERY, POWER_SAVER) with power_profile_changed signal +- 30-second power state poll timer (skipped on desktops without battery) +- Memory queries (refresh on demand) +- Platform identity (OS name, has_battery) +- Platform-dependent file paths (user_data_dir, config_dir, install_dir, executable_path, benchmark_cache_path, cache_dir, model_dir) +- Full interface scope per Q-059 (Tyre researching best practices — resolution, GPU, CPU, DPI, locale, etc.) + +Migration: +- Refactor HardwareDetector to consume PlatformInfo instead of calling OS directly +- Delete AiDialogueDetector (duplicate of HardwareDetector) +- Wire power_profile_changed into HardwareDetector for battery auto-suspend (D-138 Layer 3) + +Architecture: D-141. Client-side only — never relies on server for hardware info (multiplayer readiness).', 'done', 'high', NULL, 'client', 'D-141', '2026-03-13 09:40:49', '2026-03-13 10:45:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-634', 'task', NULL, 'Author decomposed behavior content — role action templates, culture modifiers, context tags', 'Define and author the content format for composable behaviors (Q-057). Deliver: (1) role action templates — generic observable stage directions per role, no culture specificity, (2) culture modifier sets — Krenn-specific flavoring that overlays role actions (speech style, mannerisms, social norms), (3) context tags — on-shift, off-duty, break-room, social that the generator uses to filter/weight behaviors. Output format TBD with server team (RON or similar). Blocked by server ticket #633 for composition engine schema.', 'done', 'high', NULL, 'copy', NULL, '2026-03-07 09:55:04', '2026-03-13 11:24:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-645', 'story', 'T-638', 'Content: Base text elevation pass', 'Review and elevate existing NPC base text across zone RON content (~50 lines/role). Base text serves as both the LLM seed and the fallback when pre-voicing is unavailable or disabled — it must be strong on its own. Pass should improve clarity, cultural neutrality (so culture injectors have clean material to work from), and completeness. Priority: Sova Transit District hub NPCs (baked content tier). Reference: resolved input C-5 and C-9 from workshop round 2.', 'done', 'medium', NULL, 'copy', NULL, '2026-03-07 11:56:06', '2026-03-13 11:24:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-647', 'task', NULL, 'Docs: Amend D-123, supersede D-124, file workshop D-records', 'File D-records from the LLM Voice Pipeline Workshop (2026-03-07). (1) Amend D-123 to cover both baked (build-time, human-reviewed) and pre-voiced (runtime background) modes — Paula''s distinction must be explicit. AI pipeline is both an authoring tool and a runtime enhancement. (2) Supersede D-124 (in-game live AI deferred) — the workshop resolved this with the two-spike strategy. (3) File new D-records covering: model selection (Gemma 2B primary, Phi-3 fallback; no Chinese-origin models), bundled distribution (~1.5GB), hardware detection policy (no hard floor), tell treatment (passthrough + context influence), spike strategy. Source: docs/workshops/llm-voice-pipeline/round-3-inputs.md and workshop-outcomes.md when available.', 'done', 'medium', NULL, 'copy', NULL, '2026-03-07 11:56:25', '2026-03-13 11:24:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-653', 'story', 'T-638', 'Voice pipeline: culture persona authoring for non-Krenn cultures', 'Each culture needs voice_persona, voice_examples, occasional_injections. Worldbuilding constraints (tech terms, rank conventions) belong in culture persona not universal rules. Krenn done and test-validated. Remaining cultures per content roadmap.', 'done', 'medium', NULL, 'copy', NULL, '2026-03-07 18:19:26', '2026-03-13 11:24:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-656', 'task', NULL, 'Remove handwritten Krenn dialogue and monologue content', 'Delete v0.1 hand-authored Krenn dialogue trees, NPC profiles, and monologue files from content/campaigns/. Superseded by generated NPCs (D-122) and voice pipeline (D-138). Scope: content/campaigns/main/systems/krenn/ (23 NPC YAML profiles, dialogue/ trees, monologue/ files for detective and smuggler, insert/detective.yaml), content-ron/campaigns/ compiled versions. Note: content/global/culture-krenn.ron and culture-krenn.example.ron are LIVE — do not delete.', 'done', 'medium', NULL, 'copy', NULL, '2026-03-07 18:31:07', '2026-03-13 11:25:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-657', 'task', NULL, 'Remove detective mission system', 'Delete v0.1 detective/investigation system, dropped in v0.2 pivot (D-122). Scope: content/global/knowledge/investigation.yaml (case facts), content/global/factions/lattice-commission.yaml (detective employer faction), docs/design/ detective specs (character-build-detective.md, detective-chain-of-command.md, archetype-evidence-presentation.md, divergent-starting-knowledge.md, insert-hud-wireframe-v01.md detective sections), docs/workshops/v01-content-scoping/ and content-gap-analysis_v0_1/ workshop outputs, pc-detective.yaml and pc-smuggler.yaml NPC files. Review client/tests/test_insert_off_behavior.gd and server test_world invariants for detective references.', 'done', 'medium', NULL, 'copy', NULL, '2026-03-07 18:31:10', '2026-03-13 11:25:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-658', 'task', NULL, 'Update agent profiles and briefings for v0.2', 'Audit and update .claude/agents/ profiles (20 files) and docs/briefings/ (18 files) to reflect v0.2 pivot. Many briefings still reference v0.1 detective/smuggler gameplay, hand-authored content pipeline, and pre-workshop design assumptions. Update to reflect: generator-first approach (D-122), all NPCs generated (no named NPCs), voice pipeline (D-138), tycoon bookmark deferred, no detective/smuggler roles. Remove stale context that could mislead agents.', 'done', 'medium', '', 'planning', NULL, '2026-03-07 18:31:14', '2026-03-13 11:27:57', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-666', 'task', NULL, 'Mid-sprint ticket creation protocol for team agents', 'When team agents discover new work during a sprint (like #661 zone-type templates in Sprint 26), they should message the lead immediately for retroactive ticket creation rather than just doing the work uncaptured. Document this in the sprint-start skill agent spawn prompt and/or team-patterns.md.', 'backlog', 'low', NULL, 'meta', NULL, '2026-03-13 11:37:34', '2026-03-13 11:37:34', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-667', 'task', NULL, 'Remove dead content-ron build artifact and converter tool', 'content-ron/ is a gitignored generated directory that nothing consumes at runtime. tooling/content-converter/ generates it. Both are v0.1 artifacts superseded by the v0.2 RON-first generator pipeline. Remove the converter crate, clean up any Makefile targets that reference content-ron or content-converter.', 'done', 'medium', NULL, 'maintenance', NULL, '2026-03-13 12:33:46', '2026-03-13 14:01:21', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-668', 'task', NULL, 'Remove v0.1 YAML schema and meta directories', 'JSON Schema validation of YAML content is replaced by Rust struct deserialization (validate_ron). These directories served the v0.1 YAML pipeline which has been deleted (server/src/content/ removed). Clean up any references to these schemas.', 'done', 'medium', NULL, 'maintenance', NULL, '2026-03-13 12:33:58', '2026-03-13 14:01:21', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-670', 'task', NULL, 'Move NPC pattern docs from docs/design/ to wiki/', 'docs/design/npc-patterns/ contains lore/authoring reference material (mirror moments, contradiction arcs, threshold patterns). These belong in wiki/ alongside other canonical worldbuilding content, not in project documentation. Move to wiki/npc-patterns/ or wiki/authoring/npc-patterns/.', 'done', 'medium', NULL, 'maintenance', NULL, '2026-03-13 12:34:27', '2026-03-13 14:01:21', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-671', 'task', NULL, 'Move authoring guides from docs/design/ to wiki/authoring/', 'Authoring guides (base-text, dual-lens, cultural generation, monologue voice guides) are about the game world''s voice and content standards. They belong in wiki/authoring/ alongside existing authoring docs. Move from docs/design/ and update any cross-references.', 'done', 'medium', NULL, 'maintenance', NULL, '2026-03-13 12:48:38', '2026-03-13 14:01:21', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-673', 'task', NULL, 'Add standardized frontmatter to docs/ and wiki/ files', 'Adopt a consistent frontmatter format across all documentation, similar to what skills use. Minimum fields: name, description (one-line, used for relevance filtering), type (architecture/design/lore/authoring/briefing/sprint/workshop), status (active/archived/draft). This enables context-aware document loading -- agents can filter by metadata instead of loading everything. Design the schema first, then apply incrementally (wiki/ first as it''s smaller, then docs/).', 'done', 'medium', NULL, 'maintenance', NULL, '2026-03-13 12:49:15', '2026-03-13 23:02:07', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-675', 'story', 'T-51', 'Gate network travel planner — interactive route-finding overlay on the star map insert, showing hop paths between systems with transit time estimates and corridor information', NULL, 'backlog', 'medium', NULL, 'client', NULL, '2026-03-15 10:20:07', '2026-03-15 10:20:07', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-681', 'story', 'T-605', 'Apartment generator logic (server)', 'Server implementation: apartment generator takes economic position (from #615 tycoon starting state) + cultural context (from #679 location-to-culture resolution) + aesthetic taste trait. Produces apartment tile layout, furniture placement, and item set. Decision D-136 (First Settled Reach moment: apartment + insert activation). Decision D-137 (generator: structural and cosmetic variety). Blocked by: #615 (tycoon starting state), #679 (culture resolution).', 'backlog', 'high', NULL, 'server', NULL, '2026-03-17 07:06:30', '2026-03-17 07:06:30', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-682', 'story', 'T-605', 'Apartment visual rendering + first-moment sequence (client)', 'Client implementation: renders apartment generator output. Implements alarm clock homage on Day 1 wake (D-126 Groundhog Day homage). Implements insert activation beat — first moment the player activates their insert in the apartment (D-136). Blocked by: #681 (apartment generator must produce layout/items before client can render).', 'backlog', 'high', NULL, 'client', NULL, '2026-03-17 07:06:36', '2026-03-17 07:06:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-683', 'epic', NULL, 'Character Visuals System', 'Epic covering all character visual systems for Sprint 28: body types, face types, hair, expressions, scars/tattoos, injuries, clothing/apparel/accessories, 8-direction rotation, color mesh recolorability, sprite layer compositor, and character creation UI. Architectural foundation: D-134 (full character customization at tile scale), D-146 (tile-scale heavy zoom preview).\n\nScope will be refined during the Sprint 28 planning workshop. Workload is fluid until the workshop concludes.', 'done', 'high', NULL, 'visual', NULL, '2026-03-17 08:19:55', '2026-03-17 08:19:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-676', 'task', NULL, 'Assign team and sprint for v0.2 story tickets (#614-#626)', 'The v0.2 story tickets from the Where''s the Fun? workshop (#614-#626, plus #620-#622) are teamless in the backlog. Before they can enter a sprint they need: (1) team assignment — each ticket must be assigned to exactly one team (server, client, copy, or planning). Split cross-team work into separate tickets with explicit blockers. (2) Review open questions that block implementation: Q-WTF-039 (character creation portrait vs tile preview), Q-WTF-040 (do creation choices trace into the generated apartment). (3) Confirm whether any of these tickets should be split further before implementation begins. Tickets in scope: #614 (bookmark definition system), #615 (tycoon small business owner starting state), #616 (broad economic verb vocabulary design), #617 (auto-generated apartment), #618 (CK3-style character creation screen), #619 (full character customisation), #620 (culture-implicit-in-location system), #621 (NPC personality surface area), #622 (relationship formation system), #624 (quietly responsive world), #625 (dual-scale consequence model), #626 (setting delivery — both layers). Output: each ticket has a team and any required child tickets are created with blockers.', 'done', 'high', NULL, 'planning', NULL, '2026-03-16 21:43:12', '2026-03-17 08:30:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-663', 'task', NULL, 'Server: add ZoneTypeTemplate and LocationSpec structs for D-142 zone-type architecture', 'Content team has shipped zone-type template files (content/global/zone-types/) and restructured location specs per D-142. Server needs: (1) ZoneTypeTemplate struct in blueprint.rs — roles without weight, behavior_primitives only, no typical_behaviors. (2) LocationSpec struct (or update ZoneSpec) — role_weights instead of full roles, zone_type string reference, abandoned flag, poi_overlay field. (3) Register zone_type schema in validate-ron so tooling/validate-ron accepts the new format. (4) Loader change: resolve (zone_type, role) → primitive pool from global template file, not from location spec.', 'done', 'high', NULL, 'server', NULL, '2026-03-13 10:47:54', '2026-03-17 11:18:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-669', 'task', NULL, 'Move content/ directory under server/', 'Game content (RON files, campaign data) is consumed exclusively by the server. Move content/ to server/content/ so it lives with its consumer. Update all path references in server Rust code (generator_spike, validate_ron, tests), Makefile targets, and any tooling scripts. The client''s own data files (client/data/) are separate and stay put.', 'done', 'medium', NULL, 'server', NULL, '2026-03-13 12:34:12', '2026-03-17 11:18:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-635', 'task', NULL, 'Clippy cleanup and CI enforcement', 'Gemini project review found 66 clippy warnings with --deny warnings. Two actions: (1) one-time cleanup — run cargo clippy --fix for automatable fixes, manual refactor for complex type signatures and too_many_arguments. (2) Add cargo clippy -- --deny warnings as a blocking check in the PR review workflow or pre-commit hook. This is the single biggest process gap given our review standards elsewhere.', 'done', 'high', NULL, 'server', NULL, '2026-03-07 10:58:10', '2026-03-17 11:18:03', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-637', 'task', NULL, 'Add cargo audit to CI/review pipeline', 'Gemini''s project review used cargo audit to surface the bincode RUSTSEC finding. We should run this regularly. Options: (1) add to pre-PR review checks (make pre-pr), (2) run on Cargo.toml/Cargo.lock changes in CI, (3) scheduled periodic scan. Recommend option 2 — trigger on dependency changes so new vulnerabilities are caught at introduction, not months later. Also add cargo-audit to the Makefile targets so it can be run manually.', 'done', 'medium', NULL, 'server', NULL, '2026-03-07 10:58:17', '2026-03-17 11:18:04', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-672', 'task', NULL, 'Audit and flag v0.1 YAML content on server/copy branches', 'The server and copy branches contain ~67 YAML files (NPC profiles, dialogue, monologue pools) that haven''t merged to main. Per D-122 (all NPCs generated) and D-138, this content is superseded by the generator approach. Audit these files: flag what''s still useful as generator input (convert to RON), and mark the rest as deprecated. Don''t delete without team review.', 'done', 'medium', NULL, 'server', NULL, '2026-03-13 12:49:07', '2026-03-17 11:18:04', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-696', 'task', NULL, 'Formal D-record for overheard conversation RON format', 'The overheard conversation pool format (role-pair-parameterized, knowledge_payload, relationship_context) was introduced in #664 with a content note in decisions/content.md but no formal D-record. Claim and write a D-NNN entry before the format proliferates to all 29 zone types.', 'cancelled', 'low', NULL, 'copy', NULL, '2026-03-17 11:19:09', '2026-03-17 11:19:09', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-697', 'task', NULL, 'Design transit_corridor zone type for between-zone passage spaces', 'No zone type exists for transit corridors, walkways, and passage spaces between zones where eavesdropping gameplay naturally occurs. These are high-value spaces for overheard conversation mechanics. Needs zone character definition, roles, and behavior primitives.', 'cancelled', 'low', NULL, 'copy', NULL, '2026-03-17 11:19:12', '2026-03-17 11:19:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-662', 'epic', NULL, 'Author zone-type behavior templates (29 remaining types)', 'Author behavior primitive pools for the 29 zone types not yet covered (rural_agricultural and industrial_freight exist). Each zone type needs ~4 roles x ~15 primitives. Primitives must be culture-neutral, standalone-readable, tagged with context and modifier_hint. Per D-141 zone-type template architecture. 31 total zone types for v1.0.', 'done', 'high', NULL, 'copy', NULL, '2026-03-13 10:30:36', '2026-03-17 11:28:30', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-664', 'task', NULL, 'Replace overheard.yaml with generator-compatible conversation system', 'content/npc-conversations/overheard.yaml contains 48 hand-authored conversation entries referencing deleted named NPCs (Kael, Sera, Torek, etc.). All entries are v0.1 detective-arc content. Needs disposition: either delete entirely (generator replaces overheard conversations) or redesign as role-generic templates compatible with the zone-type template architecture (D-142). Cross-references removed but content still references named characters that no longer exist.', 'done', 'medium', NULL, 'copy', NULL, '2026-03-13 10:57:46', '2026-03-17 11:28:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-665', 'task', NULL, 'Extend validate-ron to cross-culture name pool collision checking', 'Currently name collisions across culture profiles (Vael, Osse, Krenn) are caught only in PR review. Extend tooling/validate-ron to check for given_name and family_name overlaps across all culture-*.ron files. Sprint 26 review caught 6 overlaps manually.', 'done', 'low', NULL, 'copy', NULL, '2026-03-13 11:37:33', '2026-03-17 11:28:31', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-686', 'story', 'T-683', 'Body type sprites', '2 body types, each with 8-direction rotation sprites and color mesh regions marked for recolorability. These are the base layer all other character sprites composite on top of.\n\nDeliverables:\n- 2 distinct body type sprite sheets (8 directions each)\n- Color mesh region maps per body type\n- Naming and file conventions per workshop spec\n\nBlocked by: #684 (Character visuals planning workshop) — body proportions, color mesh spec, and target size confirmed by workshop.\n\nScope will be refined during the Sprint 28 planning workshop. Workload is fluid until the workshop concludes.', 'cancelled', 'high', NULL, 'visual', NULL, '2026-03-17 08:20:41', '2026-03-17 17:48:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-687', 'story', 'T-683', 'Face type sprites', '2 face types, each with 8-direction rotation sprites and color mesh regions (skin tone recolorability at minimum).\n\nDeliverables:\n- 2 distinct face type sprite sheets (8 directions each)\n- Color mesh region maps per face type\n- Alignment spec for compositing over body sprites\n\nBlocked by: #684 (Character visuals planning workshop) — face spec, color mesh regions, and alignment approach confirmed by workshop.\n\nScope will be refined during the Sprint 28 planning workshop. Workload is fluid until the workshop concludes.', 'cancelled', 'high', NULL, 'visual', NULL, '2026-03-17 08:20:44', '2026-03-17 17:48:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-688', 'story', 'T-683', 'Hair type sprites', '2 hair styles, each with 8-direction rotation sprites and color mesh regions for hair color recolorability.\n\nDeliverables:\n- 2 distinct hair style sprite sheets (8 directions each)\n- Color mesh region maps per hair style\n- Alignment and layering rules (sits above face, may occlude ears/forehead)\n\nBlocked by: #684 (Character visuals planning workshop) — hair spec, occlusion rules, and color mesh approach confirmed by workshop.\n\nScope will be refined during the Sprint 28 planning workshop. Workload is fluid until the workshop concludes.', 'cancelled', 'high', NULL, 'visual', NULL, '2026-03-17 08:20:47', '2026-03-17 17:48:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-689', 'story', 'T-683', 'Facial expression sprites', 'Expression state sprites for all expression types defined by the planning workshop. 8-direction rotation per expression.\n\nDeliverables:\n- Sprite sheets for each expression state (count TBD by workshop) across 8 directions\n- Expression state naming conventions\n- Compositing approach (replaces or modifies face layer)\n\nBlocked by: #684 (Character visuals planning workshop) — expression state list and count confirmed by workshop.\n\nScope will be refined during the Sprint 28 planning workshop. Workload is fluid until the workshop concludes.', 'cancelled', 'high', NULL, 'visual', NULL, '2026-03-17 08:20:49', '2026-03-17 17:48:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-690', 'story', 'T-683', 'Scar and tattoo overlay sprites', '2 scar options and 2 tattoo options as overlay sprites with placement system. These are additive overlays composited above the skin layer.\n\nDeliverables:\n- 2 scar overlay sprites with placement anchors\n- 2 tattoo overlay sprites with placement anchors\n- Placement system spec (body region mapping, z-order within overlay stack)\n- Interaction with color mesh (tattoos may have their own recolorable region)\n\nBlocked by: #684 (Character visuals planning workshop) — placement system approach and overlay rules confirmed by workshop.\n\nScope will be refined during the Sprint 28 planning workshop. Workload is fluid until the workshop concludes.', 'cancelled', 'high', NULL, 'visual', NULL, '2026-03-17 08:20:52', '2026-03-17 17:48:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-691', 'story', 'T-683', 'Visible injuries overlay sprites', 'Damage state sprites and healing progression visuals as overlay sprites. Represents the visible state of combat injury on the character.\n\nDeliverables:\n- Damage state overlay sprites (states defined by workshop)\n- Healing progression visuals showing recovery stages\n- Layering rules relative to clothing and scar overlays\n\nBlocked by: #684 (Character visuals planning workshop) — damage state count, healing progression steps, and layering rules confirmed by workshop.\n\nScope will be refined during the Sprint 28 planning workshop. Workload is fluid until the workshop concludes.', 'cancelled', 'high', NULL, 'visual', NULL, '2026-03-17 08:20:54', '2026-03-17 17:48:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-692', 'story', 'T-683', 'Clothing, apparel and accessory layer sprites', '2 clothing sets and 2 accessories with full layer ordering, occlusion rules, 8-direction rotation, and color mesh regions. Clothing is the outermost visible layer and must occlude appropriately.\n\nDeliverables:\n- 2 clothing set sprite sheets (8 directions each)\n- 2 accessory sprite sheets (8 directions each)\n- Layer order spec (clothing above body/injuries, accessories above clothing)\n- Occlusion rules (which body parts are hidden per garment)\n- Color mesh regions per clothing item and accessory\n\nBlocked by: #684 (Character visuals planning workshop) — clothing system spec, occlusion rules, and layer ordering confirmed by workshop.\n\nScope will be refined during the Sprint 28 planning workshop. Workload is fluid until the workshop concludes.', 'cancelled', 'high', NULL, 'visual', NULL, '2026-03-17 08:20:57', '2026-03-17 17:48:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-701', 'task', 'T-683', 'LOD crowd rendering research — performance-driven strategy for 400+ characters', 'Research and prototype LOD strategy for 400+ simultaneous characters on screen (crowd scenes, protests, battles).\n\nCurrent budget: 80 NPCs at full detail. This ticket defines the path to 400+.\n\nKey constraints from workshop:\n- LOD degradation is performance-driven, NOT distance/count threshold\n- Degradation is proactive (triggers on PROJECTED viewport character count, not measured frame drop — reactive causes hitching)\n- Progressive from player outward: furthest degrade first (full mesh -> simplified mesh -> billboard)\n- When paused: restore full detail on all characters\n- At billboard tier: body size tier and dominant clothing color must remain visually distinct\n- Outline baked into impostor sprite at billboard tier\n\nDeliverable: technical spec + prototype result. Does not produce shippable code.\n\nNot in Sprint 28 — backlog for when crowd-scale systems begin.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-17 17:48:12', '2026-03-17 17:48:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-698', 'story', 'T-683', 'Standalone 3D character editor', 'Standalone Godot tool for authoring and previewing 3D character appearances. Primary Sprint 28 deliverable.\n\nSpec: docs/design/character-visuals-spec.md (written by Qatux this sprint)\n\nRequirements:\n- Real-time 3D viewport at 30 degree camera tilt / 45 degree map rotation\n- 4 cardinal direction buttons (N/E/S/W), South-facing default\n- Body type selector (2-3 types, switching must validate all combinations)\n- Clothing/hair/face customization panels with per-item color pickers\n- Inverted hull outline at #1e1e24\n- Dark/neutral backdrop (no apartment preview)\n- No free rotation — cardinal buttons only\n- Player and NPC use identical models (no protagonist distinction)\n\nBlocked by: wireframe (#685), body type meshes (#699)', 'cancelled', 'high', NULL, 'client', NULL, '2026-03-17 17:48:05', '2026-03-17 17:48:48', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-699', 'story', 'T-683', '3D body type placeholder meshes (2-3 types)', '2-3 distinct 3D body types as Godot-compatible meshes. Placeholder quality acceptable for Sprint 28 — visual fidelity is not the goal, switching validation and proportion read at 30 degree isometric is.\n\nRequirements:\n- 2-3 body type meshes (e.g. lean / average / broad)\n- Readable as distinct body shapes at ~40px screen height\n- Compatible with clothing overlay / compositor system (#700)\n- Rig must support 4 visual facing directions (N/E/S/W)\n- Proportions validated in the standalone editor at 30 degree camera\n\nBlocks: #698 (editor), #700 (compositor)', 'cancelled', 'high', NULL, 'visual', NULL, '2026-03-17 17:48:05', '2026-03-17 17:48:48', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-700', 'story', 'T-683', '3D character appearance compositor', 'Godot shader/material system for real-time character appearance assembly. Runtime compositor for 3D characters.\n\nSpec: docs/design/compositor-api-spec.md (written by Qatux this sprint)\n\nRequirements:\n- Per-item clothing color (not uniform team color — each item has its own color parameter)\n- Inverted hull outline at #1e1e24, uniform for all characters\n- Billboard impostor tier: outline baked in, body size tier and dominant clothing color preserved\n- LOD integration: compositor outputs baked impostors at billboard tier\n- Wear level as continuous shader parameter (flavor, not primary sprint focus)\n- No player/NPC distinction in compositor logic\n\nBlocked by: #699 (body type meshes)\nBlocks: #698 (editor depends on compositor for preview)', 'cancelled', 'high', NULL, 'client', NULL, '2026-03-17 17:48:05', '2026-03-17 17:48:48', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-684', 'story', 'T-683', 'Character visuals planning workshop', 'Planning workshop for Sprint 28 character visuals. Scope revised during workshop: approach is real-time 3D models in Godot, not 2D sprites.\n\nDeliverables (workshop outputs):\n- docs/design/character-visuals-spec.md\n- docs/design/compositor-api-spec.md\n- docs/workshops/character-visuals/workshop-outcomes.md\n- D-records filed for: camera angle (supersedes D-019), 3D rendering approach, outline spec, direction count, LOD strategy, uniform player/NPC visuals\n\nKey decisions locked:\n- Camera: 30 degree tilt / 45 degree map rotation (diamond grid)\n- Rendering: real-time 3D models, not sprites\n- Directions: 8 server-side (perception), 4 visual facings (N/E/S/W) with smooth rotation interpolation\n- Outlines: inverted hull, #1e1e24, uniform for all characters\n- LOD: performance-driven, proactive (projected viewport count), not reactive\n- Editor: standalone Godot tool, 4 cardinal direction buttons, South-facing default, dark/neutral backdrop\n- Player/NPC: no visual distinction\n\nBlocks downstream implementation tickets.', 'done', 'high', NULL, 'planning', NULL, '2026-03-17 08:20:05', '2026-03-17 18:28:03', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-702', 'story', 'T-683', 'Port spike shaders and import settings to production client', 'Copy the proven shader and import configuration from the spikes into the production client tree. No functional changes — this is a verified copy.\n\nSource files:\n- spikes/quaternius-aesthetic/shaders/toon.gdshader\n- spikes/quaternius-aesthetic/shaders/toon_masked.gdshader\n- spikes/quaternius-aesthetic/shaders/outline.gdshader\n\nDestination: client/assets/characters/shaders/\n\nAlso copy skin tone textures: spikes/quaternius-aesthetic/assets/T_Skin_*.png -> client/assets/characters/skin_tones/ (renamed to match convention: pale_cool.png, pale_warm.png, etc.)\n\nproject.godot update: ensure gltf/embedded_image_handling=3 is set under [gltf]. This was the critical finding from the 3dpipeline spike — values 0-2 fail or degrade textures.\n\nAcceptance: shaders present at client/assets/characters/shaders/, skin tones at client/assets/characters/skin_tones/, project.godot setting verified.', 'done', 'high', NULL, 'client', NULL, '2026-03-19 21:20:16', '2026-03-20 08:05:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-703', 'story', 'T-683', 'Define CharacterVisualDescriptor (GDScript + Rust)', 'Define the server-to-client data contract for character visual state. This struct must be agreed and stable before compositor code is written.\n\nSpec (from docs/architecture/character-asset-organization.md Section 6):\n\nCharacterVisualDescriptor:\n body_type: BodyType # enum: ThinM, ThinF, AverageM, AverageF, MuscularM, MuscularF, TeenM, TeenF, HeavyM, HeavyF, Child\n head_id: String # template ID ("head_042") -- resolves to heads/templates/\n hair_id: String # hair style key ("bob", "ponytail", "bald")\n hair_tint: Color\n facial_hair_id: String # empty string = none\n facial_hair_tint: Color\n eyebrow_id: String\n eyebrow_tint: Color\n skin_tone: int # index 0-8 into 9-tone palette\n clothing_slots: Dictionary # slot -> item_id\n clothing_tints: Dictionary # item_id -> Array[Color]\n accessory_slots: Dictionary # slot -> item_id\n accessory_tints: Dictionary # item_id -> Color\n\nDeliverables:\n- GDScript class at client/scripts/rendering/character_visual_descriptor.gd\n- Rust struct in server at server/src/bridge/types.rs (or equivalent bridge layer)\n- IPC serialization: MessagePack field mapping between Rust struct and GDScript class\n- BodyType enum defined in both GDScript and Rust with matching variant names\n\nDecisions: D-159 (11 body types), D-160 (21 segments), D-161 (head separate)\n\nAcceptance: Both sides compile. A hardcoded test descriptor can be constructed in GDScript and matched to a Rust struct without panics.', 'done', 'high', NULL, 'client', NULL, '2026-03-19 21:20:28', '2026-03-20 08:05:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-704', 'story', 'T-683', 'Build character visual compositor', 'Implement the runtime character assembler (CharacterVisual.gd) that takes a CharacterVisualDescriptor and produces a visible 3D character in the scene tree.\n\nThe compositor is a runtime assembler. It selects pre-authored meshes and attaches them. It does NOT scale, deform, or generate anything at runtime.\n\nLocation: client/scripts/rendering/character_visual.gd\n\nSlot architecture:\n- Body: loads seg_*.glb files from bodies/{body_type}/ by convention path\n- Head: loads heads/templates/{head_id}.glb via BoneAttachment3D to Head bone\n- Hair: loads hair/{hair_id}.glb via BoneAttachment3D to Head bone\n- Facial hair: loads facial_hair/{facial_hair_id}.glb via BoneAttachment3D\n- Eyebrows: loads eyebrows/{eyebrow_id}.glb via BoneAttachment3D\n- Clothing: reads clothing/{item_id}/coverage.json, hides covered segments, loads clothing/{item_id}/{body_type}.glb\n- Accessories: loads accessories/{accessory_id}.glb via BoneAttachment3D to slot bone\n\nTorso variant handling: coverage.json torso_variant field selects seg_torso.glb (full) or seg_torso_upper.glb (upper only). Full-coverage garments hide seg_torso entirely.\n\nSkin tone: applies tint_color to body segment materials using skin_tones/{skin_tone_name}.png\n\nTest against: Quaternius starter assets (4 OnlyHead templates + Source tier hairstyles) and placeholder segment meshes from visual team.\n\nPath convention: all paths derived programmatically from descriptor — no lookup tables. The directory structure IS the lookup table.\n\nDecisions: D-159, D-160, D-161, D-162, D-163, D-164\nRef: docs/architecture/character-asset-organization.md Section 6', 'done', 'high', NULL, 'client', NULL, '2026-03-19 21:20:39', '2026-03-20 08:05:07', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-706', 'story', 'T-683', 'Skeleton and animation library import', 'Extract the shared 65-bone armature and import the Universal Animation Libraries (UAL1 + UAL2) into the production client.\n\nSkeleton:\n- Source: extract armature from a Quaternius Source .blend (Regular_Male_FullBody.blend or equivalent)\n- Output: client/assets/characters/skeleton/armature.glb\n- Requirements: 65-bone hierarchy, no mesh geometry, no animation data, Y-up -Z forward, 1 unit = 1 meter\n\nAnimation libraries:\n- UAL1 (core): client/assets/characters/animations/ual_standard.glb — idle, walk, run, and core animations\n- UAL2 (extended): client/assets/characters/animations/ual_extended.glb — extended animations + female mannequin\n- Requirements: same skeleton hierarchy as armature.glb, bone names match post-January 2026 naming update\n\nValidation: instantiate armature.glb in a test scene, apply AnimationPlayer from ual_standard.glb, confirm idle and walk animations play without joint collapse.\n\nNote: the January 2026 bone naming update in the Quaternius Universal Animation Library changed several bone names. Verify compatibility before committing.\n\nDecision: D-164 (fork Quaternius skeleton, replace body meshes)', 'done', 'high', NULL, 'client', NULL, '2026-03-19 21:21:00', '2026-03-20 08:05:07', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-694', 'story', 'T-683', 'Character creation screen', 'Full character creation UI using the game UI kit and widget system — not a debug/test wrapper. This is the production character creation screen that players use at game start. + +Built on the 3D CharacterVisual compositor (#693). Uses the same UI kit, widgets, and interaction patterns as the rest of the game UI. + +Features: +- Body type selector (11 types) +- Head template browser (curated library) +- Hair, facial hair, eyebrow pickers with preview +- Skin tone selector (9-tone palette) +- Clothing and accessory slots +- Color customization per recolorable region +- Live 3D preview with camera orbit (frontal default per D-158, full rotation per D-155) +- Keyboard navigation (tab/arrow/enter/esc) +- Randomize button +- Standalone scene entry point (can be launched independently for artist review) +- Feeds CharacterVisualDescriptor into new game flow on confirm + +Decisions: D-134 (full customization), D-146 (tile-scale heavy zoom preview), D-155 (editor rotation), D-158 (frontal camera default) +Blocked by: #693 (compositor)', 'backlog', 'high', NULL, 'client', NULL, '2026-03-17 08:21:47', '2026-03-22 14:11:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-713', 'story', 'T-683', '3D character compositor (CharacterVisual.gd)', 'Port the spike CharacterVisual.gd to production. Loads body segments onto shared armature, attaches head/hair/facial_hair/eyebrows via BoneAttachment3D, applies skin tone tinting, handles clothing segment coverage. Replaces cancelled #693 (2D sprite compositor). Input: CharacterVisualDescriptor. Output: assembled 3D character node. Ref: spikes/quaternius-aesthetic/scripts/spike/character_visual.gd, docs/architecture/character-asset-organization.md Section 6.', 'cancelled', 'high', NULL, 'client', NULL, '2026-03-22 14:09:54', '2026-03-22 14:11:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-714', 'story', 'T-683', 'Standalone character viewer / creation screen', 'Standalone Godot scene wrapping the 3D CharacterVisual compositor with UI controls for previewing and creating characters. Features: body type selector, head template picker, hair/facial hair/eyebrow pickers, skin tone selector, camera orbit (frontal default per D-158, with rotation per D-155), zoom. Runs as its own scene (F6 or main menu entry) for quick artist review and gameplay character creation. Replaces cancelled #694 (2D character creation screen).', 'cancelled', 'high', NULL, 'client', NULL, '2026-03-22 14:09:57', '2026-03-22 14:11:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-707', 'story', 'T-683', 'Body type meshes from Source .blends (all 11 types, 21 segments each)', 'Author all 11 body type meshes from Quaternius Source .blend files, segmented into 18 GLB files per body type.\n\nBody type breakdown (from docs/architecture/character-asset-organization.md):\n- average_m: Regular_Male_FullBody.blend — fork + segment\n- average_f: Regular_Female_FullBody.blend — fork + segment\n- muscular_m: Superhero_Male_FullBody.blend — segment as-is\n- muscular_f: Superhero_Female_FullBody.blend — segment as-is\n- teen_m: Teen_Male_FullBody.blend — segment as-is or minor tweaks\n- teen_f: Teen_Female_FullBody.blend — segment as-is or minor tweaks\n- thin_m: Regular_Male as base — fork + slim down + segment\n- thin_f: Regular_Female as base — fork + slim down + segment\n- heavy_m: Regular_Male as base — fork + widen + segment\n- heavy_f: Regular_Female as base — fork + widen + segment\n- child: Teen as base — fork to gender-neutral + scale down + segment\n\n21 segments per body type (17 base + 2 swappable torso + 2 face detail):\nseg_head, seg_neck, seg_torso, seg_torso_upper, seg_arm_upper_l, seg_arm_upper_r,\nseg_arm_lower_l, seg_arm_lower_r, seg_hand_l, seg_hand_r, seg_leg_upper_l,\nseg_leg_upper_r, seg_leg_lower_l, seg_leg_lower_r, seg_foot_l, seg_foot_r,\nseg_eyes, seg_eyebrows\n\nOutput: client/assets/characters/bodies/{body_type}/seg_{segment}.glb\n\nRequirements:\n- 1-ring vertex overlap at all segment boundaries (eliminates seams during animation)\n- Foot segments extend past ankle bone (1-ring overlap with lower leg segment)\n- No animation data embedded in segment GLBs\n- Shared skeleton hierarchy (same bone names as armature.glb)\n- All meshes start fresh from Source .blends — no spike mesh output carries over\n\nDecisions: D-159 (11 body types), D-160 (21 segments per body type), D-164 (Source .blends as starting point)', 'done', 'high', NULL, 'visual', NULL, '2026-03-19 21:21:13', '2026-03-22 14:26:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-708', 'story', 'T-683', 'Hairstyle import from Source tier', 'Process the Source tier ''Rigged to Head Bone'' hairstyle .blends for production use. ~18 hairstyles are nearly production-ready.\n\nSource files: docs/assets/downloads/Universal Base Characters[Source]/ (hair .blends)\n\nHairstyle list from Source tier:\nFemale: Bob, Buns, BuzzedFemale, Long, LongDreads, Ponytail_2 (+ Teen variants)\nMale: Balding, Beard, Buzzed, Dreads, Mohawk, Moustache, MuttonChops, Ponytail, SimpleParted, SlickBack (+ Teen variants)\nEyebrows: Female, Regular, Teen, Thick\n\nNaming convention (Quaternius name -> file key):\n- Bob -> bob, Buns -> buns, Long -> long, Ponytail -> ponytail\n- SimpleParted -> simple_parted, SlickBack -> slick_back\n- BuzzedFemale -> buzzed_female, LongDreads -> long_dreads\n- Beard -> beard, Moustache -> moustache, MuttonChops -> mutton_chops\n\nOutput per hairstyle: {key}.glb + {key}_mask.png\n- Hair: client/assets/characters/hair/{key}.glb + {key}_mask.png\n- Facial hair (beard, moustache, mutton_chops): client/assets/characters/facial_hair/{key}.glb + {key}_mask.png\n- Eyebrows: client/assets/characters/eyebrows/eyebrows_{key}.glb\n\nRequirements:\n- BoneAttachment3D-compatible: attached to Head bone, single-bone follow\n- Mask PNG: greyscale, white = tintable region (for hair_tint shader uniform)\n- No body-type-specific variants needed — hair attaches to Head bone, body type irrelevant\n\nInclude bald.glb in hair/ as explicit ''no hair'' slot placeholder.\n\nDecision: D-164 (Source tier as foundation)', 'done', 'high', NULL, 'visual', NULL, '2026-03-19 22:03:36', '2026-03-22 14:26:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-709', 'story', 'T-683', 'Head template library — process OnlyHead .blends', 'Process the 4 Quaternius OnlyHead .blends as the starter set for the curated head template library.\n\nSource files (Quaternius Source tier):\n- Regular_Female_OnlyHead.blend -> head_001.glb\n- Regular_Male_OnlyHead.blend -> head_002.glb\n- Teen_Female_OnlyHead.blend -> head_003.glb\n- Teen_Male_OnlyHead.blend -> head_004.glb\n\nOutput: client/assets/characters/heads/templates/\n head_001.glb + head_001_mask.png\n head_002.glb + head_002_mask.png\n head_003.glb + head_003_mask.png\n head_004.glb + head_004_mask.png\n\nNumeric ID format: head_NNN (zero-padded 3 digits). These are catalogue entries, not descriptive names — heads are unique per character.\n\nRequirements:\n- BoneAttachment3D-compatible: attaches to Head bone, no skinning required\n- Correct scale relative to body at gameplay zoom (verified against armature.glb)\n- Mask PNG: greyscale, white = tintable skin tone region\n- Skin tone matching: head skin tone must be matchable to body skin tone via toon shader tinting\n\nNote: Trellis-generated heads expand this library over time via the offline pipeline (see D-163). This ticket is only the 4 Quaternius starter heads.\n\nDecisions: D-161 (head always separate), D-163 (Trellis offline pipeline for expansion)', 'done', 'high', NULL, 'visual', NULL, '2026-03-19 22:03:48', '2026-03-22 14:26:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-715', 'story', 'T-683', 'Scar overlay system — per-segment scar meshes or textures', 'Visual overlay system for scars on character bodies. Scars are per-segment (leveraging the 18-segment body architecture for placement). Each scar is a visual modification to a specific body segment — either a decal/texture overlay or a small mesh overlay attached to the segment. Requirements: scars placed per body segment, multiple scars per character, persist across clothing changes (visible on exposed segments), hidden under clothing via coverage system, recolorable via toon shader for skin tone matching. Depends on compositor (#704) and body segments (#707) — both done. Architecture uses per-segment addressability from D-160.', 'backlog', 'medium', NULL, 'visual', NULL, '2026-03-22 14:30:36', '2026-03-22 14:30:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-716', 'story', 'T-683', 'Tattoo overlay system — per-segment tattoo textures', 'Visual overlay system for tattoos on character bodies. Tattoos are per-segment texture overlays with their own recolor masks for ink color variation. Requirements: tattoos placed per body segment, multiple tattoos per character, persist across clothing changes (visible on exposed segments), hidden under clothing via coverage system, recolorable via multi-region mask for multi-color tattoos. May share implementation approach with scar system (#715). Architecture uses per-segment addressability from D-160.', 'backlog', 'medium', NULL, 'visual', NULL, '2026-03-22 14:30:42', '2026-03-22 14:30:42', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-717', 'story', 'T-683', 'Visible injury overlay system — per-segment injury visualization', 'Visual overlay system for injuries on character bodies. Injuries are per-segment visual states showing damage (bruises, cuts, burns) and healing progression. Requirements: injuries placed per body segment, severity/type affects visual appearance, healing progression over time changes the overlay, hidden under clothing via coverage system, interacts with amputation system (injury on a removed limb is moot). Depends on compositor (#704) and body segments (#707) — both done. Architecture uses per-segment addressability from D-160 and limb removal capability.', 'backlog', 'medium', NULL, 'visual', NULL, '2026-03-22 14:30:49', '2026-03-22 14:30:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-685', 'story', 'T-683', 'Character creation screen wireframe', 'UI wireframe for the character creation screen, updated for slot-based architecture per the Sprint 28 planning workshop outcome and asset organization proposal.\n\nContext: character creation uses a slot system (body type, head, hair, facial hair, eyebrows, clothing slots, accessory slots). The wireframe must reflect this architecture and the 11 body type selector.\n\nDecisions: D-159 (11 body types), D-160 (21 segments per body type), D-162 (clothing pre-baked per body type), D-163 (Trellis head template library), D-164 (Source tier as starting point)\n\nDeliverables:\n- Wireframe for character creation screen covering all slot panels\n- Body type selector (11 options: thin_m/f, average_m/f, muscular_m/f, teen_m/f, heavy_m/f, child)\n- Head template picker (scrollable grid, starts with 4 Quaternius OnlyHead starters)\n- Hair slot, facial hair slot, eyebrow slot panels\n- Clothing slot panels (torso, legs, feet, hands) — category filter (coveralls, jacket, shirt, pants, boots, gloves)\n- Accessory slot panels (hat, goggles, mask, backpack, belt, held_l, held_r)\n- Skin tone selector (9 tones)\n- Camera angle toggle (editor frontal -5deg, gameplay dramatic -30deg per D-158)\n\nTool: Frame0 or equivalent wireframing tool\nOutput: wireframe PNG(s) committed to docs/design/character-creation-wireframe/', 'done', 'high', NULL, 'planning', NULL, '2026-03-17 08:20:27', '2026-03-22 15:27:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-721', 'story', NULL, 'Accessory slot filtering — _get_accessory_ids_for_slot() ignores slot param', '_get_accessory_ids_for_slot(slot) accepts a slot parameter but returns all accessories unfiltered. Every accessory slot shows the full catalogue. Should filter by slot-appropriate prefix (hat_*, goggles_*, etc.) matching the clothing tab''s approach. Currently invisible with placeholder assets but will be wrong when real accessories are added.', 'backlog', 'low', 'client', NULL, NULL, '2026-03-22 16:33:07', '2026-03-22 16:33:09', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-710', 'story', 'T-683', 'Surface Deform batch pipeline (Blender tooling)', 'Build the Blender batch pipeline that takes one reference clothing mesh (authored on average_m) and produces 11 fitted variants via Surface Deform.\n\nOutput location: tooling/blender/surface_deform_batch.py (not in client tree)\n\nScript interface:\n- Input: path to reference GLB (authored on average_m)\n- Input: path to the 11 body type meshes (Surface Deform targets)\n- Output: directory to write fitted variants\n\nOutput per clothing item:\n /\n thin_m.glb, thin_f.glb\n average_m.glb (copy of reference)\n average_f.glb, muscular_m.glb, muscular_f.glb\n teen_m.glb, teen_f.glb\n heavy_m.glb, heavy_f.glb\n child.glb\n\nRequirements:\n- Headless-capable (Blender --background mode)\n- average_m.glb variant is a direct copy of reference, not a new fit\n- Surface Deform bind must work in headless context (MEDIUM reliability per spike — document any workarounds needed)\n- UV layout preserved through deform (mask sidecar applies identically to all variants)\n\nValidation: run against one test clothing item across all 11 body types. Verify visual quality at gameplay zoom especially at extreme types (heavy_m, heavy_f, child). This answers the open question from the quaternius-aesthetic spike VERDICT.\n\nRef: spikes/quaternius-aesthetic/VERDICT.md (Surface Deform PARTIALLY VALIDATED)\nRef: docs/architecture/character-asset-organization.md Section 5', 'done', 'high', NULL, 'visual', NULL, '2026-03-19 22:04:00', '2026-03-22 16:39:46', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-711', 'story', 'T-683', 'Initial clothing set — reference meshes and batch fit', 'Author the initial v0.2 clothing set as reference meshes on average_m, then run the Surface Deform batch pipeline to produce all 11 body-type variants.\n\nMinimum v0.2 clothing catalogue (to be confirmed with project lead — scope decision per open question in VERDICT.md):\n- coveralls_basic (full-body work suit)\n- jacket_utility (upper body outerwear)\n- pants_cargo (lower body)\n- shirt_henley (upper body inner)\n- boots_work (foot slot)\n\nPer item, author on average_m:\n- reference.glb — the authored mesh\n- reference_mask.png — recolor mask (greyscale, white = tintable, black = preserve)\n- coverage.json — segment hides array + torso_variant\n\nThen run tooling/blender/surface_deform_batch.py to produce 11 variants.\n\nFinal output per item in client/assets/characters/clothing/{item_id}/:\n reference.glb, reference_mask.png, coverage.json\n thin_m.glb, thin_f.glb, average_m.glb, average_f.glb\n muscular_m.glb, muscular_f.glb, teen_m.glb, teen_f.glb\n heavy_m.glb, heavy_f.glb, child.glb\n\ncoverage.json format:\n { "hides": ["torso", "arm_upper_l", ...], "torso_variant": "full" }\n\nAcceptance: compositor can load all variants and apply coverage correctly on all 11 body types.\n\nDecision: D-162 (clothing pre-baked per body type via Surface Deform)', 'done', 'high', NULL, 'visual', NULL, '2026-03-19 22:04:11', '2026-03-22 16:39:47', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-705', 'story', 'T-683', 'Character editor Godot tool implementation', 'Standalone Godot tool (EditorPlugin or standalone scene) that uses the compositor to preview and edit character appearances. Built from the wireframe (#685).\n\nFeatures:\n- Body type selector: 11 options (ThinM, ThinF, AverageM, AverageF, MuscularM, MuscularF, TeenM, TeenF, HeavyM, HeavyF, Child)\n- Head template picker: scrollable grid of available head GLBs in heads/templates/\n- Slot panels: hair, facial hair, eyebrows (each showing available options)\n- Clothing slot panels by category (coveralls, jacket, shirt, pants, boots, gloves, vest, dress, uniform)\n- Accessory slot panels (hat, goggles, mask, backpack, belt, held_l, held_r)\n- Skin tone selector: 9 swatches\n- Tint color pickers per slot (hair_tint, facial_hair_tint, clothing tints, accessory tints)\n- Camera angle toggle: three presets per D-148/D-158 — frontal (-5°, editor default), dramatic/low-angle (-30°, gameplay default), top-down (0°, overhead)\n- Live preview via compositor — all selections drive a live CharacterVisualDescriptor\n\nAcceptance: can select all slots and see changes reflected live in the 3D viewport.\n\nDecisions: D-158 (camera angles), D-159 (11 body types)', 'done', 'high', NULL, 'client', NULL, '2026-03-19 21:20:50', '2026-03-22 16:56:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-725', 'task', NULL, 'Adopt auto-sizing label pattern for dynamic text', 'Evaluate GodotFontAutoSizeLabels (https://github.com/LuisEscorza/GodotFontAutoSizeLabels) for handling text that must fit a fixed container. We will hit this with: NPC name labels, item names in grids, clothing/hair button labels, dialogue boxes, any server-generated text rendered in fixed UI elements. Adopt the pattern early (either this plugin or our own implementation) before overflow bugs accumulate.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 17:42:32', '2026-03-23 17:42:32', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-727', 'task', NULL, 'Install Godot Icons Fonts addon for UI development', 'Godot Icons Fonts (https://github.com/rakugoteam/Godot-Icons-Fonts) — searchable icon font library (FontAwesome, Material Icons, etc.) directly in the Godot editor. MIT. Saves time hunting for individual icon assets during UI development. Install from asset library. Use for: HUD icons, status indicators, navigation symbols, button icons, inventory categories.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 18:19:22', '2026-03-23 18:19:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-728', 'task', NULL, 'Add resolution parameter to screenshot test config', 'Extend the character creator screenshot test config JSON with a resolution field. The system sets viewport size before capturing, enabling automated visual regression across common resolutions (1080p, 1440p, 4K, ultrawide, Steam Deck 800p). Batch script iterates the manifest body types × resolutions for full coverage. No plugin needed — just OS.window_size or viewport size override. Inspired by Project Resolution plugin (https://github.com/Danim3D/Godot-4-Plugin-Project-Resolution) but built into our existing test infrastructure.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:27:51', '2026-03-23 18:27:51', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-729', 'task', NULL, 'First-launch install wizard for distribution', 'Evaluate Godot4xInstallWizard (https://github.com/untamedlabs/Godot4xInstallWizard) for first-launch experience: EULA acceptance, initial settings (resolution, audio, controls), install path selection. Needed when packaging for Steam or standalone distribution. Low priority until release preparation begins.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 18:31:35', '2026-03-23 18:31:35', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-730', 'task', NULL, 'License and attribution screen in settings menu', 'Add a licenses/credits screen accessible from the main menu settings. Must display all third-party licenses: Quaternius (CC0), Godot engine, any adopted plugins (MIT), font licenses, audio assets. Pattern reference: godot-licensing (https://github.com/nathanfranke/godot-licensing) — auto-collects license info. We don''t need the plugin but need the pattern: scan for LICENSE files, Godot''s built-in Engine.get_license_info(), and our own attribution list. Legal requirement for distribution.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:33:04', '2026-03-23 18:33:04', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-731', 'task', NULL, 'Konami code easter egg', 'Up up down down left right left right B A. Because reasons. https://github.com/aravikusu/konamicode — reference implementation. Trigger: unlock debug panel in release builds, or something fun.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 18:38:37', '2026-03-23 18:38:37', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-732', 'task', NULL, 'Minimap rendering from server exploration data', 'The minimap needs to render from server-sent exploration and visibility data. No existing Godot minimap plugin fits because our information boundary is server-authoritative. Architecture: server sends explored tile states (unexplored/explored/visible) as part of ObserverSnapshot. Client renders a top-down 2D minimap from this data — fog for unexplored, dim for explored-not-visible, lit for currently visible. Player position centered. Needs a dedicated data stream or section in the snapshot for minimap tile states. Reference: the existing 2D fog_state.gd has the rendering patterns (texture from tile data), but the 3D minimap may use a separate overhead Camera3D in a SubViewport instead.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:48:16', '2026-03-23 18:48:16', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-733', 'task', NULL, 'Nested tooltip system for information layering', 'Implement nested/recursive tooltips for the information-dense UI. Reference: Nested-Tooltips (https://github.com/duzychri/Nested-Tooltips). Pattern: hover over text → tooltip appears → hover over a keyword in the tooltip → nested tooltip explains that keyword. Use cases: NPC names (→ disposition, role), items (→ stats → stat modifier explanations), zone names (→ zone type, danger level), factions (→ relationship, territory). This is core to the asymmetric information design — tooltips reveal what your character KNOWS, with depth proportional to familiarity. Study the plugin for the recursive hover detection pattern, implement with our diegetic UI aesthetic.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:49:04', '2026-03-23 18:49:04', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-734', 'task', NULL, '3D speech bubbles for NPC dialogue in world', '3D speech bubbles floating above NPC heads for overheard dialogue, conversation snippets, and NPC chatter. Reference: speechbubble3d (https://github.com/tamort/speechbubble3d). The server sends dialogue events in ObserverSnapshot — the client renders them as 3D world-space bubbles above the speaking NPC. Information boundary applies: only NPCs within hearing range get bubbles, content reflects what the player character can hear. Different bubble styles: direct conversation (solid), overheard (faded/partial), internal monologue (thought bubble, player character only). Must face camera (billboard) and scale appropriately at gameplay zoom.', 'cancelled', 'medium', NULL, 'client', NULL, '2026-03-23 18:51:14', '2026-03-23 18:51:14', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-735', 'epic', NULL, 'Settings and input system — keybinds, save browser, cursors, controller', 'Unified design and implementation pass for player-facing settings and input: (a) Key binding remapper with save/load. (b) Save browser with thumbnails and metadata. (c) Context-sensitive cursors (examine, talk, use, attack, walk). (d) Controller/gamepad support with radial menus. Design all four together in Frame0 for visual consistency, then implement as a cohesive system. These share UI patterns (settings panels, modal dialogs, input feedback) and should not be built independently.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:53:39', '2026-03-23 18:53:39', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-736', 'task', NULL, 'Install Poly Haven downloader addon', 'Godot Poly Haven Downloader (https://github.com/P3ntest/godot-polyhaven-downloader) — browse and download CC0 models, textures, and HDRIs from Poly Haven directly in the Godot editor. Removes friction from asset sourcing. Install when environment art work begins.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 19:08:40', '2026-03-23 19:08:40', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-737', 'task', NULL, 'Selection glow effect for interactable objects', 'Soft glow border on hovered/selected objects and characters. Reference: GlowBorderEffect (https://github.com/Magodra/GlowBorderEffect). Distinct from our inverted hull outline (permanent character silhouette) — this is a context-sensitive highlight: hover over an NPC to see a soft glow indicating they''re interactable, selected items glow in inventory, quest-relevant objects pulse. Could be a simple shader (stencil + blur) or adopt the plugin. Evaluate when interaction system is built.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 19:28:45', '2026-03-23 19:28:45', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-738', 'epic', 'T-746', 'Body catalog completion — 258 remaining systems', 'Author body catalogs for all remaining star systems using the /atlas author-system pipeline. 43 systems done (hops 0-3 + Schuilhoek), 258 remaining across 5 corridor tracks. Each system: wiki analysis, astrophysical skeleton, Miri naming, Paula+Ozzie review, integrity check, commit. Parallelizable by corridor.', 'done', 'high', NULL, 'copy', NULL, '2026-03-25 13:22:02', '2026-03-25 13:22:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-745', 'initiative', NULL, 'Development Cascade — 6-phase first-things-first build order', 'The Settled Reach builds core system to core system in strict cascade order. Each phase completes before the next begins. No scoping negotiations, no v0.2 target. Established 2026-03-24 during world generation workshop. See CLAUDE.md for the full cascade table.', 'backlog', 'critical', NULL, NULL, NULL, '2026-03-25 13:28:54', '2026-03-25 13:28:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-749', 'epic', 'T-745', 'Phase 5: Player control & in-world rendering — character, walls/stairs/doors, lighting on generated tiles', 'Deliverable: Player viewport with final-version assets (boring repeating but correct). 2-floor test map streamed from server to validate dynamic mapping protocols. Character model rendering + basic walls, stairs, doors (fully materialized models). Lighting and visual polish pass. Depends on Phases 1-3 (world data exists to stream).', 'backlog', 'high', NULL, NULL, NULL, '2026-03-25 13:29:48', '2026-03-25 13:29:48', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-750', 'epic', 'T-745', 'Phase 4: World generation (tile/chunk/block) — deterministic multilayer seed-to-tile cascade + per-layer Atlas maps + asset pipeline', 'Deliverable: Walkable generated world + asset creation catalog with production status. Automated tile/chunk/block generation (NPC layer ignored). Parallel asset pipeline: rural walls, barns, station walls, auto doors, cars, lamp posts, TVs, billboards etc. Depends on Phases 1-4 (world structure + rendering pipeline exist).', 'backlog', 'high', NULL, NULL, NULL, '2026-03-25 13:30:00', '2026-03-25 13:30:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-751', 'epic', 'T-745', 'Phase 6: Detail coloring — room-level content, cultural architecture', 'ONLY starts when the world is walkable and the question is ''what is here''. Room-level detail, furniture, signage, cultural architectural expression, environmental storytelling props. NO NPC layer — life comes after the cascade. Depends on Phase 5 (walkable world exists).', 'backlog', 'medium', NULL, NULL, NULL, '2026-03-25 13:30:11', '2026-03-25 13:30:11', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-739', 'story', 'T-738', 'Track A: North Reach body catalogs (43 systems)', 'Author body catalogs for 43 north_reach systems (hops 4-12). Commonwealth naming register. Process in hop order using /atlas author-system pipeline.', 'done', 'high', NULL, 'copy', NULL, '2026-03-25 13:22:18', '2026-03-25 20:28:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-740', 'story', 'T-738', 'Track B: South Reach body catalogs (47 systems)', 'Author body catalogs for 47 south_reach systems (hops 4-10). Iberian/Latin American naming register. Process in hop order using /atlas author-system pipeline.', 'done', 'high', NULL, 'copy', NULL, '2026-03-25 13:22:29', '2026-03-26 09:27:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-741', 'story', 'T-738', 'Track C: East Reach body catalogs (47 systems)', 'Author body catalogs for 47 east_reach systems (hops 4-10). East Asian naming register (Chinese/Japanese/Korean). Process in hop order using /atlas author-system pipeline.', 'done', 'high', NULL, 'copy', NULL, '2026-03-25 13:22:39', '2026-03-29 15:42:00', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); diff --git a/.pql/changelog/tickets/2026-04.sql b/.pql/changelog/tickets/2026-04.sql new file mode 100644 index 000000000..48eddcbd1 --- /dev/null +++ b/.pql/changelog/tickets/2026-04.sql @@ -0,0 +1,699 @@ +INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-742', 'story', 'T-738', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-743', 'story', 'T-738', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-757', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-758', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-769', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-770', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-759', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-764', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-767', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-754', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-755', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-756', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-760', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-761', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-765', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-768', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-771', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-753', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-763', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-674', 'story', 'T-51', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-712', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-744', 'task', 'T-738', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-752', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-762', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-718', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-719', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-720', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-772', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-693', 'story', 'T-683', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-766', 'task', 'T-746', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-773', 'task', 'T-746', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-774', 'task', 'T-746', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-775', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-780', 'story', 'T-746', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-776', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-777', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-782', 'story', 'T-746', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-783', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-791', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-796', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-801', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-788', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-792', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-786', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-778', 'story', 'T-746', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-779', 'story', 'T-746', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-795', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-787', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-781', 'story', 'T-746', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-784', 'task', 'T-746', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-790', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-793', 'story', 'T-746', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-797', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-798', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-819', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-794', 'story', 'T-746', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-804', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-817', 'story', 'T-746', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-815', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-802', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-818', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-816', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-820', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-803', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-799', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-812', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-800', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-805', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-806', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-807', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-808', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-809', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-813', 'task', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-785', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-824', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-825', 'story', 'T-747', '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 '' — fires InjectEconEvent. ''econ param '' — fires SetEconParam. ''econ inspect '' — 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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-695', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-814', 'task', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-810', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-821', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-822', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-823', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-811', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-748', 'epic', 'T-745', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-841', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-843', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-837', 'story', 'T-748', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-840', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-830', 'task', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-831', 'task', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-826', 'task', 'T-821', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-827', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-839', 'task', 'T-748', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-832', 'story', 'T-748', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-845', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-846', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-834', 'story', 'T-748', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-835', 'story', 'T-748', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-836', 'story', 'T-748', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-850', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-851', 'task', 'T-748', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-833', 'story', 'T-748', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-838', 'story', 'T-748', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-9', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-852', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-828', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-614', 'story', 'T-605', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-679', 'story', 'T-606', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-829', 'story', 'T-747', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-842', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-636', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-726', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-849', 'task', 'T-838', '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//bodies//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 `. 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 = ''''" +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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-722', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-844', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-724', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-848', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-19', 'story', NULL, 'v0.1 prototype scope', NULL, 'backlog', 'medium', NULL, NULL, 'Q-002', '2026-02-09 15:21:44', '2026-04-19 17:08:51', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-864', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-868', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-618', 'story', 'T-606', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-680', 'story', 'T-606', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-723', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-880', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-881', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-859', 'task', 'T-855', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-857', 'task', 'T-855', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-855', 'story', 'T-854', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-856', 'task', 'T-855', '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-" 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-` 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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-854', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-858', 'task', 'T-855', '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 `) 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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-883', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-789', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-847', '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 --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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-860', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-862', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-863', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-874', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-877', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-878', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-853', 'task', 'T-838', '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: "-" 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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-866', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-869', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-870', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-872', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-873', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-875', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-889', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-890', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-891', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-894', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-895', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-896', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-861', 'task', 'T-828', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-865', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-876', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-893', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-897', '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, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); diff --git a/.pql/changelog/tickets/2026-05.sql b/.pql/changelog/tickets/2026-05.sql new file mode 100644 index 000000000..c6d21d66c --- /dev/null +++ b/.pql/changelog/tickets/2026-05.sql @@ -0,0 +1,519 @@ +INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-928', 'bug', 'T-871', 'test_dialogue_sprint20: 5 failures — AudioManager.get_active_dip or other API drift', '5 failing test cases in test_dialogue_sprint20.gd. The suite tests D-020 signal decoupling for dialogue_box. Likely failure: test_show_dialogue_does_not_call_audio_manager_directly compares AudioManager.get_active_dip() before/after show_dialogue — if AudioManager.get_active_dip() behavior changed or is not returning clean state, this would fail. Investigate by running the suite in isolation and reading specific assertion failures from the log. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:11:54', '2026-05-02 08:11:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-929', 'bug', 'T-871', 'test_input_roundtrip: 3 failures — server binary missing or LocalBridge API change', '3 failing test cases in test_input_roundtrip.gd. All tests check _connect_to_server() which skips if server binary not found — but 3 still fail, suggesting either: (1) server binary is present but something in LocalBridge.send_message, poll, or Protocol.encode_player_inputs changed, or (2) test environment returns false from _connect_to_server but then asserts fail. Investigate by running with --filter test_input_roundtrip and checking the log for exact assertion sites. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:11:59', '2026-05-02 08:11:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-934', 'bug', 'T-871', 'test_implant_app_lifecycle: 1 failure — ImplantApp or HudGroups state API', '1 failing test case in test_implant_app_lifecycle.gd. Suite tests ImplantApp._internal_app_changed, nav stack, preserves_state, and HudGroups state. after_test resets HudGroups._active_app, _active_mode, _groups — if these private fields were renamed or removed, after_test would fail and bleed state. Or a specific on_open/on_close hook fires differently. Run --filter test_implant_app_lifecycle and check specific assertion. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:32', '2026-05-02 08:12:32', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-935', 'bug', 'T-871', 'test_game_state_sprint20: 1 failure — SnapshotHandler or stationary_ticks path', '1 failing test case in test_game_state_sprint20.gd. before_each resets SnapshotHandler._prev_player_position. If this static var was renamed or moved, the before_each hook would error. Alternatively a stationary_ticks path changed in SnapshotHandler. Verify SnapshotHandler still has static var _prev_player_position at that exact name. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:38', '2026-05-02 08:12:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-936', 'bug', 'T-871', 'test_fog_shader: 1 failure — stale VIS_PERIPHERAL or peripheral sector assertion', '1 failing test case in test_fog_shader.gd. The most likely failure is test_fog_state_forward_vs_peripheral: it asserts Forward > Peripheral visibility values, but Sprint 22 (#569) removed peripheral sector. Now all visible tiles write VIS_FORWARD regardless. The test checks the texture is non-null (not the actual byte values), so it should pass... unless the failure is in test_fog_state_exploration_persists which has a weak assertion. Run --filter test_fog_shader to identify the specific failure. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:45', '2026-05-02 08:12:45', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-937', 'bug', 'T-871', 'test_e2e_connection: 1 failure — server binary path or TCP connection state', '1 failing test case in test_e2e_connection.gd. test_send_input_receive_snapshot skips if server binary not found. If it fails, either: (1) server binary exists but connection fails (port collision, timing), or (2) LocalBridge.reset() method was removed (the test calls _bridge.reset() but this may not exist on LocalBridge). Verify LocalBridge has a reset() method. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:51', '2026-05-02 08:12:51', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-938', 'bug', 'T-871', 'test_audio_sprint13: 1 failure — AudioManager.clear_dip or API drift', '1 failing test case in test_audio_sprint13.gd. before_test calls AudioManager.clear_dip(), stop_all_loops(), set_volume() for all buses. If any of these methods were renamed or a bus constant changed, setup would fail and cascade. Or a specific dip timing assertion is stale. Run --filter test_audio_sprint13 and read the specific failure. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:56', '2026-05-02 08:12:56', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-939', 'bug', 'T-871', 'test_ai_dialogue_sprint26: 1 failure — HardwareDetector autoload missing or settings_dialog API', '1 failing test case in test_ai_dialogue_sprint26.gd. The HardwareDetector tests skip if autoload not found. The GameState field tests (ai_enhanced_dialogue_enabled) look correct. The failing test is likely in the settings_dialog section: SETTINGS_DIALOG_SCENE preloaded at class level — if settings_dialog.tscn doesn''t exist or a method was renamed, class-level preload would fail. Check res://ui/settings_dialog.tscn exists and the relevant methods. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:13:02', '2026-05-02 08:13:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-940', 'bug', 'T-871', 'test_dialogue_sprint20 — 5 cases fail (signal decoupling suite)', '5 tests in test_dialogue_sprint20.gd fail since sprint-36. Tests verify D-020 dialogue_box.gd signal decoupling (#558). Code analysis shows signals are correctly implemented but failures persist. Requires actual Godot test run to identify root cause. Opened 2026-05-02 during #871 triage. Tests: test_show_dialogue_emits_dialogue_state_changed_true, test_show_dialogue_does_not_mutate_game_state_directly, test_hide_dialogue_emits_dialogue_state_changed_false, test_show_dialogue_emits_audio_dip_requested_dialogue, test_show_dialogue_does_not_call_audio_manager_directly.', 'cancelled', 'medium', NULL, 'client', NULL, '2026-05-02 08:20:14', '2026-05-02 08:20:14', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-941', 'bug', 'T-871', 'test_input_roundtrip — 3 live-server cases fail', '3 tests in test_input_roundtrip.gd fail. Tests require the Rust server binary at server/target/debug/settled-reach-server. When binary is present, round-trip input tests (movement, interact, move_then_interact) fail — likely a protocol mismatch or timing issue. Opened 2026-05-02 during #871 triage. Skipped gracefully when binary absent.', 'cancelled', 'low', NULL, 'client', NULL, '2026-05-02 08:20:19', '2026-05-02 08:20:19', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-942', 'bug', 'T-871', 'test_implant_app_lifecycle — 1 case fails (unknown)', '1 test in test_implant_app_lifecycle.gd fails since sprint-36. Suite tests ImplantApp hook ordering, preserves_state, register_screen. Cannot identify the specific failing test from code analysis alone — requires actual Godot test run. Opened 2026-05-02 during #871 triage.', 'cancelled', 'low', NULL, 'client', NULL, '2026-05-02 08:20:22', '2026-05-02 08:20:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-943', 'bug', 'T-871', 'test_game_state_sprint20 — 1 case fails (stationary_ticks/zone_id)', '1 test in test_game_state_sprint20.gd fails. Suite tests D-020 server-authoritative stationary_ticks and zone_id. Logic appears correct from code analysis against snapshot_handler.gd — requires actual Godot test run to identify which of the 9 test cases fails. Opened 2026-05-02 during #871 triage.', 'cancelled', 'low', NULL, 'client', NULL, '2026-05-02 08:20:28', '2026-05-02 08:20:28', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-944', 'bug', 'T-871', 'test_fog_shader — 1 case fails (FogState boundary/timing)', '1 test in test_fog_shader.gd fails. FogState is registered as autoload so all tests run (not skipped). Cannot identify the specific failing test from code analysis. Candidates: test_boundary_wall_fog_vis_forward (uses update_from_state on live FogState), performance timing tests. Requires actual Godot test run. Opened 2026-05-02 during #871 triage.', 'cancelled', 'low', NULL, 'client', NULL, '2026-05-02 08:20:32', '2026-05-02 08:20:32', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-945', 'bug', 'T-871', 'test_e2e_connection — 1 case fails (live server required)', '1 test in test_e2e_connection.gd (test_send_input_receive_snapshot) fails when server binary is present. Requires server/target/debug/settled-reach-server. Skips gracefully when binary absent. Likely protocol or connection timing issue. Opened 2026-05-02 during #871 triage.', 'cancelled', 'low', NULL, 'client', NULL, '2026-05-02 08:20:37', '2026-05-02 08:20:37', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-946', 'bug', 'T-871', 'test_audio_sprint13 — 1 case fails (AudioManager/zone)', '1 test in test_audio_sprint13.gd fails. Suite tests D-073 zone crossfade, D-068 volume persistence, D-069 dip timing. All code paths verified correct against AudioManager implementation. Requires actual Godot test run to identify which specific test case fails. Opened 2026-05-02 during #871 triage.', 'cancelled', 'low', NULL, 'client', NULL, '2026-05-02 08:20:42', '2026-05-02 08:20:42', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-947', 'bug', 'T-871', 'test_ai_dialogue_sprint26 — 1 case fails (HardwareDetector/settings)', '1 test in test_ai_dialogue_sprint26.gd fails. Suite has 67 tests — HardwareDetector-dependent tests skip gracefully when autoload absent, but HardwareDetector IS registered as an autoload so most run. Cannot identify specific failing case without actual test run. Opened 2026-05-02 during #871 triage.', 'cancelled', 'low', NULL, 'client', NULL, '2026-05-02 08:20:46', '2026-05-02 08:20:46', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-930', 'bug', 'T-871', 'test_examine_display_sprint18: 2 failures — ExamineDisplay scene or API mismatch', '2 failing test cases in test_examine_display_sprint18.gd. Scene path res://ui/examine_display.tscn exists. Failures are likely in the ExamineDisplay-specific tests (not the GameState snapshot tests which look straightforward). Check whether ExamineDisplay API changed: _show(result), _dismiss(), _is_showing(), auto_dismiss timer wiring. Sprint 38 triage #871.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:04', '2026-05-02 08:22:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-931', 'bug', 'T-871', 'test_client_p1: 2 failures — FogEntities or EntityRenderer API change', '2 failing test cases in test_client_p1.gd. Suite tests fog byte encoding (#3-#6) and entity lifecycle (#7-#9). The fog tests look correct against current FogState API. Entity tests may be failing if EntityRenderer or FogEntities constructor/script changed. Run --filter test_client_p1 and check specific failed assertions. Sprint 38 triage #871.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:09', '2026-05-02 08:22:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-932', 'bug', 'T-871', 'test_time_display_sprint17: 1 failure — test_hud_time_row_updates_after_process', '1 failing test case in test_time_display_sprint17.gd. Likely test_hud_time_row_updates_after_process: calls instance._process(0.016) then asserts hud.get_time_text() returns ''12:00 . Afternoon . D1''. If main.gd _process no longer calls HUD update_from_state or if HUD.get_time_text format changed, this would fail. Check main.gd _process for HUD update wiring. Sprint 38 triage #871.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:20', '2026-05-02 08:22:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-933', 'bug', 'T-871', 'test_monologue_display: 1 failure — MonologueDisplay private API mismatch', '1 failing test case in test_monologue_display.gd. Suite reads private state (_visible, _queue, _next_fade_in_msec) from monologue_display.tscn instance. If any of these internal var names changed or the scene path moved, the test fails. Check client/ui/monologue_display.gd for current private var names. Sprint 38 triage #871.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:26', '2026-05-02 08:22:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-887', 'story', NULL, 'Add decisions-orphan-tickets CLI — surface tickets with invalid decision_ref', 'Follow-up from PR #136 review (T8): tickets.decision_ref is free-text without a foreign key. A typo''d D-ID, or a decision that gets renumbered/deleted, will silently leave tickets pointing at nothing — they won''t show up under the referenced decision in ''make decisions-coverage'' or ''tooling/db/decision show ''. + +Deliverable: a new CLI subcommand (e.g. ''tooling/db/decision orphan-tickets'') that lists tickets whose decision_ref is set but does not match any row in the decisions table. Optionally add a ''make decisions-orphan-tickets'' Makefile target. + +Schema unchanged — pure SELECT. Avoids the fragility of a two-way foreign key across markdown-sourced decisions and DB-sourced tickets.', 'done', 'low', NULL, 'ci', NULL, '2026-04-22 06:22:41', '2026-05-02 16:37:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-888', 'task', NULL, 'Switch meta.schema_version to monotonic semver for savegame migration lineage', 'Follow-up from PR #136 review (T9): the current meta.schema_version field stores a SHA-1 of server/data/systems-schema.sql at generation time. Two SHAs cannot be ordered — you cannot tell from the hash alone which schema version is newer. + +When the savegame system is built (Phase 5+) and needs migration lineage (forward-migrating an old save to a current systems.db), SHA hashing is the wrong primitive. Switch to an explicit monotonic version number (semver or integer) bumped manually whenever the schema changes in a backwards-incompatible way. The SHA can still be stored alongside for tamper detection. + +This is a Phase 5+ item — do NOT change now. Ticket exists to capture the design debt so it isn''t rediscovered during savegame work. + +Blocked by: Phase 5 (world generation + walkable world) reaching savegame design.', 'done', 'low', NULL, 'ci', NULL, '2026-04-22 06:22:51', '2026-05-02 16:37:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-884', 'task', NULL, 'Copy-team review: wiki/corporations authored by server team in #860', '**Follow-up to sprint 37 server #860.** Server-team agent Dudley authored/modified 21 wiki/corporations/*.md files to resolve the economy-db coverage gate. Per CLAUDE.md team scope rules, wiki/ is copy-team territory — this ticket asks copy team to review the cross-team writes for voice, style, lore consistency, and factual accuracy. + +**Files to review:** + +*Modified (tag additions for economy coverage):* +- baektu-mining-alliance.md, bergkraft-antriebswerke.md, bifrost-marmor.md +- gate-corporation.md, hanyang-precision.md, jeju-lattice.md +- nordmark-skog.md, norrland-woodcraft.md, salud-alliance.md +- shetland-wool.md, societe-chimique.md, stalownia-kowalski.md +- svanevann-waters.md, thrds.md, tongyeong-drive.md + +*New (~36-line corp pages):* +- arbour-aggregates.md +- earth-standard-group.md +- rush-mining.md +- scapa-flow-industries.md +- sede-chemical-works.md +- threshold-fuel-syndicate.md + +**Scope of review:** +- Voice/style consistency with existing wiki corp pages +- Lore consistency (system references, corridor geography, D-record citations) +- Tag values match existing commodity vocabulary +- Frontmatter schema compliance + +**Rationale for accepting cross-team write:** Lead decision 2026-04-21 — sprint 37 is a maintenance sweep, Dudley''s writes were pragmatically needed to unblock the coverage gate, and the content is plausibly written. Quality review happens here, not at merge time. + +**If issues are found:** File fixes as direct copy-team tickets; do not revert the server PR. + +**Context:** server PR sprint-37/server, ticket #860 (original), wiki/authoring/tier1-module-authoring.md (schema reference).', 'done', 'medium', NULL, 'copy', NULL, '2026-04-21 15:34:55', '2026-05-02 16:46:06', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-915', 'task', NULL, 'Implement CityGenerationContext struct (D-200)', 'Rust struct populated from systems.db at game startup. Fields: city_id, political_archetype, prosperity_baseline, surrounding_biome, road_entry_directions, footprint_radius_km, founding_orientation, world_tier. See D-200, workshop-outcomes.md.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:39:18', '2026-05-02 20:51:30', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-898', 'story', NULL, 'Free camera viewer — decouple camera from player, WASD pan + scroll zoom, implant/atlas/map access', 'Bare-minimum debug viewer to inspect generated tile output without a player character. This is throwaway/iterative — the rendering system will evolve with the generation pipeline. Do not over-engineer. + +Deliverables: +1. Decouple Camera2D from GameState.player_position — add a debug toggle key (e.g. F4) +2. WASD / arrow key pan in free camera mode (no server input sent) +3. Scroll wheel zoom +4. Implant UI accessible in free camera mode — atlas (implant/map/atlas) and star chart (implant/map) openable as normal + +Explicitly NOT in scope: +- Visual polish +- Fog or LOS adjustments +- Any rendering changes — use whatever TileRenderer produces today +- Save/restore of camera position + +Key files: client/scripts/main.gd (camera lerp in _process), client/scripts/autoloads/hud_groups.gd', 'done', 'high', NULL, 'client', NULL, '2026-04-24 10:56:54', '2026-05-03 09:23:43', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-882', 'task', NULL, 'Strip archetype-driven client code (follow-up to #878 server)', '**Follow-up to server #878.** Per lead direction 2026-04-21: the CharacterArchetype trace is Phase 6 filler, not production. Server #878 strips the full server-side trace. This ticket mirrors it on the client. + +**Keep (production, per lead):** +- Character creation UI flow +- Insert screens / diegetic neural overlays + +**Strip (uncleaned filler):** +- `client/scripts/autoloads/game_state.gd` — `character_archetype: String` field (line 100), `lattice_profile` derivation from archetype (line 47) +- `client/scripts/autoloads/session_manager.gd` — `save_character_archetype()`, `_read_archetype_file()`, character.txt save/load (lines 58, 172-192) +- `client/scripts/protocol/protocol.gd` — character_archetype field on StartupMessage encoding +- `client/scripts/autoloads/sim_bridge.gd` — archetype wire-up +- `client/tests/test_signal_sprint24.gd` — audit; delete or narrow if archetype-dependent +- Any monologue color-palette code keyed off archetype (search for lattice_augmented / lattice_baseline) + +**Blocked by:** server #878 (removes `character_archetype` field from StartupMessage — protocol break rides #874''s PROTOCOL_VERSION wave). + +**Verification:** client launches, character creation UI loads, insert screens render, game session starts without archetype state in the codebase. Grep `character_archetype`, `lattice_profile`, `smuggler`, `detective` in client/ — only character-creation UI references remain. + +**Context:** see `docs/architecture/sprint-37-878-audit.md` (Tyre''s full audit of the archetype trace) and the revised #878 scope in the server task description.', 'done', 'medium', NULL, 'client', NULL, '2026-04-21 15:05:27', '2026-05-03 09:23:44', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-867', 'bug', NULL, 'dialogue_box confrontation_monologue signal does not fire in headless test mode', 'test_d063_confrontation_signal_fires_on_confrontation_option in test_dialogue_sprint18.gd: signal_fired remains false after _on_option_pressed(0) on a confrontation option. _start_confrontation_beat calls create_tween() before emitting confrontation_monologue; likely the tween creation or tween_property call on ''panel'' aborts execution before the emit in headless mode. Investigate whether panel is null or tween creation fails headless. Test spec: D-063.', 'done', 'medium', NULL, 'client', NULL, '2026-04-20 16:09:48', '2026-05-03 09:23:45', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-879', 'task', NULL, 'Revive fog state behavioral tests (exploration persistence, grow-only bounds)', 'test_fog_sprint22.gd was deleted in Sprint 37 (#870 parse-error cleanup). It contained unique behavioral tests for FogState: EXP_EXPLORED persistence after leaving LOS, grow-only bounds invariant, texture-resize copy, BoundaryWall handling (#585). test_fog_shader.gd covers shader file content only — the FogState data management tests are not covered elsewhere. Rewrite against current FogState API when time allows. Spec: D-059, D-066, #569.', 'done', 'medium', NULL, 'client', NULL, '2026-04-21 15:01:10', '2026-05-03 09:23:45', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-871', 'bug', NULL, 'Pre-existing test failures across 13 suites (sprint-36/37 triage umbrella)', 'Umbrella for pre-existing client test failures that pre-date sprint 36 work and are unrelated to ongoing sprint features. Each needs investigation: stale assertion, real regression from a prior sprint, or flaky. Recommend splitting into per-suite subtasks once a sprint has bandwidth. + +## Current state (2026-04-22, after sprint-37 PR #135 review-fix pass) + +**23 failing test cases across 13 suites, 60 assertion-level failures** (each test case can report multiple failed assertions): + +| Suite | Failing test cases | +|---|---| +| test_dialogue_sprint20.gd | 5 | +| test_rendering.gd | 3 | +| test_input_roundtrip.gd | 3 | +| test_examine_display_sprint18.gd | 2 | +| test_client_p1.gd | 2 | +| test_time_display_sprint17.gd | 1 | +| test_monologue_display.gd | 1 | +| test_implant_app_lifecycle.gd | 1 | +| test_game_state_sprint20.gd | 1 | +| test_fog_shader.gd | 1 | +| test_e2e_connection.gd | 1 | +| test_audio_sprint13.gd | 1 | +| test_ai_dialogue_sprint26.gd | 1 | + +**Delta vs sprint-36 baseline:** Sprint-36 triage recorded 22-33 failing test cases (two counts given in the original ticket — title said 22, enumeration summed to 33). Current 23 is consistent with those numbers within drift. Some suites improved: + +- test_bug_report_ring_buffer (was 2, now 0) — resolved by sprint-37 #869 fix +- test_game_state (was 1, now 0) — resolved, root cause unidentified; no longer in output +- test_rendering (was 5, now 3) +- test_input_roundtrip (was 6, now 3) +- test_examine_display_sprint18 (was 3, now 2) +- test_client_p1 (was 3, now 2) +- test_e2e_connection (was 2, now 1) + +No suite regressed upward. No new suites surfaced failures. The 60 assertion-level count (vs the 22-33 test-case count) is a different counting mode reported by the gdUnit4 JSON summary — the same 23 test cases can raise multiple assertion failures each. + +**Umbrella scope also covers** the coverage gaps from sprint-37 #870 deletions that are not tracked by named revive tickets: test_entanglement_sprint22 (no live client behavior — Entanglement is a server-side seed concept per #178), test_sprint30 (no unique live coverage), test_session_manager_sprint19 (SessionManager API contracts — ID format, uniqueness, resume_game — none directly asserted in the new merge-path tests; tracked here rather than filing a dedicated ticket). + +Failure log archived to /tmp/sr-test-full.log on dev branch sprint-36/client (timestamp 2026-04-21).', 'done', 'medium', NULL, 'client', NULL, '2026-04-21 07:29:34', '2026-05-03 09:23:46', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-948', 'task', NULL, 'D-210 SubBiomeVariant implementation', 'D-210 defines SubBiomeVariant for fine-grained biome classification within SettingType::Wilderness districts. Currently deferred — SettingType::Wilderness carries a plain String biome field. Implement SubBiomeVariant enum and wire it into the atlas skeleton generator when the biome taxonomy is finalized.', 'backlog', 'low', NULL, 'server', NULL, '2026-05-03 10:30:14', '2026-05-03 10:30:14', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-885', 'bug', NULL, 'Multiple baseline tests panic with Bevy Resource-does-not-exist on main', 'Discovered: 2026-04-21 during sprint 37 server work verification. Confirmed present on clean main (commit f0465e40), NOT a sprint regression. + +**6 failing tests share the same Bevy runtime panic pattern:** +- t3_pause_mid_corridor_discards_movement_and_resumes (cross_room_transitions.rs) +- player_moves_north_through_full_pipeline +- proof_room_tick_10_matches_golden +- entity_collision_blocks_movement +- movement_validated_within_app +- world_boots_and_ticks + +**Symptom (same across all 6):** +thread panicked: Encountered an error in system ''Enable the debug feature to see the name'': Parameter ''Enable the debug feature to see the name'' failed validation: Resource does not exist + +**Likely root cause:** A Resource was removed from the app init somewhere without updating the test harness (or the test harness was never updated when a system was added). The Bevy debug feature is OFF so system names are hidden. + +**Investigation steps:** +1. Enable Bevy debug feature (feature = [''debug''] on bevy_ecs dep) OR set BEVY_BACKTRACE=full — get the actual panicking system name and missing Resource. +2. Most likely one Resource missing in test harness setup fixes all 6 (they share symptom). +3. Fix: either insert the resource in the test fixture, or wrap the system param in Option/If. + +**Why not blocking sprint 37 PRs:** these predate sprint work. Sprint 37 work actively removes 7 archetype-dependent failing tests (archetype_monologue.rs + v01_integration_playthrough.rs) — net improvement to test health. The 6 baseline failures remain, unrelated. + +**Assigned:** Hoshe (QA ownership)', 'done', 'medium', NULL, 'server', NULL, '2026-04-21 17:02:53', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-886', 'task', NULL, 'Generator polish follow-ups to #853: suffix monotony auto-fix + explicit cultural-history prompting', '**Follow-up to #853 (Sprint 37).** Dudley''s #853 patches resolved 5 of 7 subtasks cleanly. Two bits remain as partial/deferred: + +**§3 — Suffix monotony (partial):** `gemma_naming.py` now *detects* when >40%% of a body''s mountain names share a trailing word and emits `suffix_monotony_warning` in the counts dict, but does not auto-regenerate. Rationale (per code comment): the batch pipeline has no voice access, so auto-fix would require a targeted re-run. This ticket: either add a targeted re-run pass when the warning fires, or write a wrapper script that catches the warning and re-queries only affected bodies. + +**§5 — Cultural crossmix (partial):** The existing corridor_substyles refill mechanism (next-adjacent register) provides some cross-cultural blending, but the ticket asked for explicit `corridor + cultural-history` context threaded into the naming prompt. This ticket: extend `build_batch_prompt` to accept and include a cultural-history blurb (drawn from the body''s corridor_substyles description or a new per-corridor history registry) so the LLM sees both the primary register and the secondary influences. + +**Priority:** low — naming generation is functional; these are quality polish that would help after a full atlas regen surfaces visible patterns. + +**Context:** see Sprint 37 #853 original spec and Paula''s analysis notes in `docs/design/atlas-generator-refinement-notes.md`. Paula''s collision script should be re-run after these land to verify measurable impact.', 'done', 'low', NULL, 'server', NULL, '2026-04-22 06:20:44', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-892', 'task', NULL, 'Expand check-systems-db-stamp GENERATOR_SOURCES to cover naming helpers', '**Follow-up to PR #137 / Tyre review of #847 stamp infrastructure.** + +`tooling/check-systems-db-stamp` only tracks `generate_atlas` source files. The atlas generation pipeline now has two naming helpers that feed into the final `systems.db` content but are not covered by the stamp: + +- `tooling/planet-gen/gemma_naming.py` — batch-names bodies/features via Gemma LLM (#833 / #853). +- `tooling/planet-gen/naming_core.py` — shared algorithms (Levenshtein, distinctiveness, batch prompts) used by `gemma_naming.py`. + +If either of these changes without re-running the generator and re-stamping, `make check-systems-db-stamp` will pass while `systems.db` drifts from its source SHAs. This is the exact failure mode `check-systems-db-stamp` exists to prevent. + +**Scope:** + +1. Extend `GENERATOR_SOURCES["generate_atlas"]` in `tooling/check-systems-db-stamp` to include: + - `tooling/planet-gen/gemma_naming.py` + - `tooling/planet-gen/naming_core.py` +2. If there is a parallel `IMPORT_ECONOMICS_SOURCES`-style constant in the atlas pipeline (mirror the `import_economics` pattern), mirror the update there too. Comment at line 35-37 of the stamp script notes the pattern. +3. Decide whether either naming helper warrants its own `generator_name` entry (if naming is ever run independently of the full atlas generation) — default is fold them into `generate_atlas` unless the economy-db precedent applies. +4. Re-stamp via the normal atlas regen path so the SHA captures the new file set, then verify `make check-systems-db-stamp` still says OK. + +**Non-goal:** Do not modify `systems.db` content; this is a stamp-infrastructure expansion only. + +**Cross-reference:** PR #137, #847 (atlas determinism smoke test, merged with the original narrow source list), `tooling/check-systems-db-stamp` line 38–48. + +**Rationale:** The stamp was added specifically to catch the drift-without-regen class of bug. A narrow source list lets that bug through for naming changes, which are now a meaningful and frequent source of atlas content edits.', 'done', 'medium', NULL, 'server', NULL, '2026-04-22 07:58:45', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-899', 'story', NULL, 'District skeleton generator — Phase 1 implementation', 'Implement actual Phase 1 generation logic for DistrictSkeleton. The data model in server/src/simulation/generator.rs is complete but all generation is stubs. + +Input: a city entry from markers.json (name, lat/lon, population_tier, primary_function, planet_class, economy node reference) +Output: a filled DistrictSkeleton with real values — block grid assignments, SettingType, ComplexityTier, WorldTier, ZonePalette, DistrictLayoutMode (Grid vs Organic), reservations list, zone_palette. + +RESCOPED per planet-down-cascade workshop: Stages 1-2 only (classification + block grid). Stages 3-5 deferred. Depends on WorldTier fix and city decomposition. + +Scope for this ticket (Phase 1 skeleton only — no chunk-level tiles): +- Derive SettingType from primary_function + planet_class +- Derive ComplexityTier from population_tier + system WorldTier +- Assign DistrictLayoutMode (grid vs organic) from settlement_pattern +- Populate 4x4 block grid with ZoningType assignments from primary_function +- Generate multi-block reservations for high-population cities (parks, transit terminals) +- No chunk fill, no tile data, no NPC placement + +Blocked by: #897 (generation cascade planning — D-records define the contract this implements), #900 (WorldTier enum fix) + +Key files: +- server/src/simulation/generator.rs — DistrictSkeleton and all related types +- tooling/planet-gen/generate_atlas.py — city placement input (markers.json) +- server/data/systems.db — economy node cross-reference', 'done', 'high', NULL, 'server', NULL, '2026-04-24 10:57:11', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-900', 'bug', NULL, 'Fix WorldTier enum values in generator.rs (D-218)', 'Replace Peripheral/Connected/Core with Epicenter/Regional/Backwater/Passage/Waypoint per D-218. Blocks all generation Rust code.', 'done', 'critical', NULL, 'server', NULL, '2026-05-01 10:38:20', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-901', 'task', NULL, 'Add atlas_body_heightmaps table to systems-schema.sql (D-202)', 'Float32 LE BLOB storage for heightmaps. ~512KB per body. See D-202 for schema.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:38:24', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-902', 'task', NULL, 'Add atlas_city_names table to systems-schema.sql (D-207)', 'Name reservation table replacing authored city positions in markers.json. Columns: body_id, name, economic_role, population, corp_id (nullable), reserved (bool). See D-207.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:38:28', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-903', 'task', NULL, 'Add atlas_feature_names table to systems-schema.sql', 'Geographic feature name reservations (rivers, mountains, passes). Columns: body_id, name, feature_type, priority.', 'done', 'medium', NULL, 'server', NULL, '2026-05-01 10:38:31', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-904', 'task', NULL, 'Add atlas_province_boundaries table to systems-schema.sql (D-205)', 'Watershed boundary polylines per body. See D-205.', 'done', 'medium', NULL, 'server', NULL, '2026-05-01 10:38:34', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-905', 'task', NULL, 'Add body_radius_km column to bodies table (D-204)', 'Physical radius for area_count formula. planet_class fallback for NULL values. See D-204.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:38:38', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-906', 'task', NULL, 'Import heightmap BLOBs into atlas_body_heightmaps', 'Python pipeline step: read heightmap PNGs from planet-gen output, convert to float32 LE BLOBs, insert into atlas_body_heightmaps. Part of generate_regional.py or standalone importer.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:38:42', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-907', 'task', NULL, 'Pre-compute province boundaries from watershed analysis (D-205)', 'Python: extract watershed drainage basin boundaries from heightmaps, store as polylines in atlas_province_boundaries. ~2d effort.', 'done', 'medium', NULL, 'server', NULL, '2026-05-01 10:38:46', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-908', 'task', NULL, 'Populate atlas_city_names from wiki content', 'Python: read wiki settlement data, populate atlas_city_names rows. Named cities with economic_role and population. Corp HQ cross-reference from corporations table.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:38:50', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-909', 'task', NULL, 'Populate atlas_city_names corp HQ entries', 'Python: cross-reference corporations.headquarters_system/body to populate corp_id on atlas_city_names rows.', 'done', 'medium', NULL, 'server', NULL, '2026-05-01 10:38:53', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-910', 'task', NULL, 'Derive body_radius_km from planet_class fallback', 'Python: populate body_radius_km column. Use explicit values where available, planet_class lookup otherwise. 0.5d effort.', 'done', 'medium', NULL, 'server', NULL, '2026-05-01 10:38:57', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-911', 'task', NULL, 'Normalize economic_role values in bodies table', 'Migration: normalize inconsistent values (agriculture->agricultural, resource_extraction->extraction, coordination->service_mixed). Add validation to import_economics.py. See D-194 data quality blocker #3.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:39:02', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-912', 'task', NULL, 'Implement WorldTier, ComplexityTier, SettingType enums in Rust (D-218, D-201)', 'Replace String type aliases with real enums. WorldTier: Epicenter/Regional/Backwater/Passage/Waypoint. Depends on WorldTier bug fix.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:39:06', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-913', 'task', NULL, 'Implement SettlementClass and settlement type enums (D-196)', 'SettlementClass: NameLocked/PopulationBudget/EconomicTriggered/OrganicGrowth. Active/ghost thresholds per class. See D-196.', 'done', 'medium', NULL, 'server', NULL, '2026-05-01 10:39:10', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-914', 'task', NULL, 'Implement DistrictType, PoliticalArchetype, FoundingOrientation enums (D-213, D-214, D-215)', 'All generation-pipeline enums for district classification. See D-213, D-214, D-215.', 'done', 'medium', NULL, 'server', NULL, '2026-05-01 10:39:14', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-916', 'task', NULL, 'Implement heightmap BLOB loader in Rust', 'Load float32 LE heightmap from atlas_body_heightmaps via SQLite. bytemuck reinterpret. ~0.5d.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:39:22', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-917', 'task', NULL, 'Implement BodyWorldState resource and LRU cache (D-203)', 'Bevy Resource holding Layer 1-2 output per body. LRU cache policy, 50 bodies, ~5MB. See D-203.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:39:26', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-918', 'task', NULL, 'Implement D8 drainage routing algorithm (D-208)', 'D8 priority-flood from heightmap. River threshold flow_accumulation > 200. Output: RiverNetwork (river_cells, confluences, mouths), drainage basins. ~50ms/body target. See D-208. ~3d effort.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:39:30', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-919', 'task', NULL, 'Implement attractor-matching pipeline (D-211, D-195)', 'Five-phase pipeline: score matrix build, Tier A greedy, Hungarian Tier B+C, synthetic overflow, name fulfillment. Two-tier mismatch flagging (0.35 warning, 0.15 error). See D-211, D-195. ~4d effort.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:39:35', '2026-05-03 14:00:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-920', 'task', NULL, 'Implement three-component district mix (D-194)', 'Population tier guarantees + 10x9 multiplier table + political archetype modifiers + founding age character. Self-contained per city. See D-194. ~3d effort.', 'done', 'high', NULL, 'server', NULL, '2026-05-01 10:39:39', '2026-05-03 14:00:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-921', 'task', NULL, 'Implement TerritorialStatus derivation (D-212)', 'Priority-ordered classification per Province. 6 values. placed_at_generation flag. See D-212.', 'done', 'medium', NULL, 'server', NULL, '2026-05-01 10:39:42', '2026-05-03 14:00:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-922', 'task', NULL, 'Implement BlockIrregularity from founding_age (D-216)', 'Age-based block grid irregularity. Archetype-specific step values. Minimum 0.05. See D-216.', 'done', 'medium', NULL, 'server', NULL, '2026-05-01 10:39:45', '2026-05-03 14:00:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-923', 'task', NULL, 'Implement tile condition thresholds (D-217)', 'Prosperity-driven tile condition: Intact>0.63, Worn 0.43-0.63, Cracked 0.23-0.43, Broken<0.23. Threshold-crossing cache invalidation. See D-217.', 'done', 'medium', NULL, 'server', NULL, '2026-05-01 10:39:49', '2026-05-03 14:00:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-924', 'task', NULL, 'Implement background generation queue (D-206)', 'Rayon thread pool, priority queue (Immediate/High/Medium/Low), Aho-Corasick SystemNameIndex for event-driven pre-generation. See D-206.', 'done', 'medium', NULL, 'server', NULL, '2026-05-01 10:39:53', '2026-05-03 14:00:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-925', 'task', NULL, 'Implement GeographicAttractor, AttractorType, CompatibilityMatrix types (D-211, D-195)', 'Rust type definitions for the attractor-matching pipeline. GeographicAttractor struct, AttractorType enum (7 variants), CompatibilityMatrix (10x7 scoring table from D-195). Prerequisite types for #919 (attractor-matching pipeline). ~0.5d effort, Tier 3.', 'done', 'medium', NULL, 'server', 'D-211', '2026-05-02 07:46:25', '2026-05-03 14:00:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-926', 'task', NULL, 'Implement SystemNameIndex with Aho-Corasick text scanning (D-206)', 'Aho-Corasick automaton over all body/system names from systems.db. Scans news ticker, NPC dialogue, documents to trigger background pre-generation before player travels. Part of the background generation infrastructure (Tier 5, after #924). ~1d effort.', 'done', 'low', NULL, 'server', 'D-206', '2026-05-02 07:46:35', '2026-05-03 14:00:26', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-927', 'task', NULL, 'Render province boundaries on planetary map (D-205)', 'Load atlas_province_boundaries polylines from systems.db and render on the Godot planetary map. Fill provinces with TerritorialStatus-derived colors. Depends on #907 (province boundary pre-computation in Python). Tier 5, ~2d effort.', 'done', 'low', NULL, 'client', 'D-205', '2026-05-02 07:46:40', '2026-05-03 14:12:45', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-949', 'story', NULL, 'Atlas data delivery — replace client-side file reads with server API calls', 'The client currently reads markers.json and star_map_data.json directly from the filesystem. This bypasses the server layer entirely — the client should request all game data through IPC calls to the Rust backend. + +Implementation can be simple: the server exposes a query/proxy endpoint that reads the JSON file or runs a DB query and returns the result. The client asks, the server responds. No complex protocol needed — just the boundary enforcement that the client never reads files or DB directly. + +Affects: atlas app (reach, system, planet, regional screens), economics monitor. The server-side handler can start as a thin proxy (read file, return contents) and evolve into perception-filtered queries (D-012) later.', 'backlog', 'medium', NULL, 'client', NULL, '2026-05-03 14:14:23', '2026-05-03 14:14:23', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-746', 'epic', 'T-745', 'Phase 1: Wiki content complete — all planets, moons, stations, heightmaps, artwork', 'Deliverable: Implant-ready Godot map of the Reach with click-throughs + wiki/GTTR popups for all systems/planets/moons/stations. Includes: body catalog (epic #738), galaxy map navigator UI, system orbital schematic, heightmap pipeline, planetary shader screenshots, GTTR per-body entries. Schema + tooling already built (atlas CLI, bodies/stations tables, sync-wiki).', 'done', 'critical', NULL, NULL, NULL, '2026-03-25 13:29:07', '2026-05-22 16:56:36', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-747', 'epic', 'T-745', 'Phase 2: Economics layer — supply/demand, transport, corporations, supply chains', 'Deliverable: Economics spreadsheets/graphs showing simulation running in fast-forward with runtime-tweakable values. X4-style production chains adapted to 300-system scale. Hundreds of corporations with supply chains. Reusable as in-game economic news implant components. Depends on Phase 1 (wiki content provides the economic profiles the simulation reads).', 'done', 'high', NULL, NULL, NULL, '2026-03-25 13:29:24', '2026-05-22 17:11:16', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-958', 'story', 'T-750', 'Layer 4 — block irregularity from founding age', 'Apply BlockIrregularity derived from founding_age (D-216) to the block grid geometry — older settlements get more irregular streets. Orthogonal to density. block_irregularity.rs exists.', 'backlog', 'medium', NULL, 'server', 'D-216', '2026-05-22 17:42:34', '2026-05-22 17:42:34', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-959', 'story', 'T-750', 'Layer 5 — Chunk→Tile fill (floors, walls, doors, objects)', 'THE primary gap (generator.rs is stubbed). Generate walkable tiles from the block/chunk skeleton: floors, walls, doors, placed objects, using tile-condition thresholds 0.63/0.43/0.23 (D-217). Output is the walkable world data. + +Refinement (round 2, 2026-05-25): Layer-5 fill is the D-230 on-demand derive phase (<5ms shell derivation Void/Wall/FloorSlab/Roof from the cached tags) plus the BuildingExteriorTag visual grammar and material vocabulary (D-235: WallMaterial/RoofForm/FacadeRhythm/StreetSurface, template-filtered (era = maintenance/wear, not a material gate)) plus interstitial and operations-surface fill driven by BulkClass coverage (D-233). Blocked by 957, 976, 977. + +Refinement (2026-05-26): READY behind 1006/957/976/977/1005. shell_derive = rectangle-containment + z-range over cached tags (~0.5ms/chunk). FillChunk pre-condition: only after SkeletonGenerated; re-enqueue High if block_tags absent. Wire chunk_streaming.rs to enqueue FillChunk on load-radius entry (no GenerationQueue interaction today). Interstitial token derived from setback_tier (D-235) x position; bulk operations-surface tagged built-infra, not open space. Child 988 = exterior grammar, now 3-step template-filtered (era is wear, not a material gate). Files: gen_queue.rs FillChunk arm, workers/stubs.rs, plugin.rs SkeletonGenerated handler.', 'backlog', 'high', NULL, 'server', 'D-217', '2026-05-22 17:42:34', '2026-05-22 17:42:34', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-961', 'story', 'T-750', 'Asset pipeline + catalog (walls, doors, props; rural & station variants)', 'Parallel asset pipeline producing the walls/doors/props/lamp-posts/etc. the tile fill places, with rural and station variants, tracked in a production-status catalog. Runs alongside generation.', 'backlog', 'medium', NULL, 'visual', 'D-166', '2026-05-22 17:42:34', '2026-05-22 17:42:34', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-962', 'story', 'T-750', 'Generation validation pass + Phase 5 dependency gate', 'Validation pass: generated content reads correctly (settlements legible, walkable, named). Establishes the dependency gate that locks Phase 5 (player control, epic #749) behind Phase 4 completion per the cascade rule (D-166 amended 2026-05-22).', 'backlog', 'medium', NULL, 'server', 'D-166', '2026-05-22 17:42:34', '2026-05-22 17:42:34', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-951', 'story', 'T-750', 'Markers → names-only flavored pool + remove 6 hand-authored template machinery (D-223)', 'Implement D-223. (1) Reduce ALL markers.json to a flavored name pool — names only (river/mountain/settlement names), no positions or topographic geometry. River/mountain positions derive from heightmap + D8 drainage (D-208); settlement positions from the economic sim + placement (D-211). (2) Remove the 6 hand-authored template machinery: delete hand-authored marker positioning for Lendel/Edict/Vuurkloof/Røros/Cairnside/Estrade, drop the reserved=1 pinning, and remove all ''template'' special-casing in the atlas pipeline (generate_atlas.py, gemma_naming.py, test_batch_naming.py, apply_name_fixes.py) and the atlas_city_names schema. The 6 BODIES remain real places — keep their wiki/lore/names/economic profiles; only the authored machinery is removed. After this there is no template category. (3) Update atlas pipeline + schema, regen-db. (4) Leave historical archives (sprints, workshops, audits, CHANGELOG, atlas proposals) untouched. Foundation/gating item for the rest of Phase 4. + +## Rework plan (verified 2026-05-22 via pipeline map) +Break + geometry-re-add risk is ENTIRELY in generate_atlas.py; import_economics.py is names-only-safe (reads names/DB only; populates atlas_city_names from cities name/kind/population). +1. generate_atlas.py: RETIRE geometry production. process_body() must stop calling place_cities/generate_infrastructure/place_gate_terminal and stop writing geometry to markers (else it re-adds stripped geometry). load_markers(): drop grid validation. sync_markers_to_db(): stop reading center/path/grid/area_fraction. +2. Atlas geometry tables — empty/drop via MIGRATION_SQL: atlas_cities(center), atlas_roads/rivers/railroads(point_count), atlas_pois/oceans(center), atlas_mountain_ranges(geometry), atlas_body_grids(w/h). SURVIVE: atlas_city_names, atlas_feature_names, atlas_province_boundaries, atlas_city_positions, atlas_body_heightmaps. +3. Meta-stamp: update tooling/check-systems-db-stamp GENERATOR_SOURCES + Makefile regen-db if generate_atlas is reduced/retired. +4. reserved/template machinery: apply_name_fixes.py template patches, gemma_naming.py template-name preservation, import_economics reserved=1 corp-HQ insertion — review per D-223 (name-protection reserved may stay; position pinning already gone via strip). +5. Sol: tooling/planet-gen/sol_markers/*.json + sol_import.py — migrate to names-only (separate, not in regen-db critical path). +6. Verify: make regen-db green; atlas geometry tables empty (reveals the gap for the server cascade).', 'done', 'high', NULL, 'server', 'D-223', '2026-05-22 17:37:25', '2026-05-22 21:30:01', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-964', 'task', 'T-750', 'Phase-4 test hardening — deferred review gaps (#953/#963 review)', 'Follow-ups from the Hoshe/Tyre pre-bake review (the BLOCKER/MAJOR items were fixed inline; these are the deferred MINOR/coverage items): + +TESTS: +- features.rs: full per-type attractor reachability fixtures — craft heightmaps that guarantee LakeShore (enclosed depression), PassEntrance (saddle), PlainCenter (flat), RiverCrossing (confluence). Currently only RiverMouth/CoastalAccess/ValleyFloor are exercised on the slope/sine fixtures. +- heightmap.rs: 8-bit grayscale decode path; sea_level passthrough assertion; downsample identity/upsample early-return. +- drainage.rs: basin area_pct bit-for-bit determinism (only river_cells + basin count checked today). +- layer1.rs: attach_feature_names mountain branch with a non-empty mountain pool + ≥1 Alpine attractor. +- features.rs: thin_by_spacing behavior (spacing collisions, equirectangular column wrap). +- import_economics.py: automated idempotency test — two runs on a scratch DB yield identical atlas_city_names count (not doubled), and 0 rows for system ''GJ 0'' (Sol exemption). Wire alongside check-systems-db / pre-push. +- Wire test_sim_determinism.py into pre-push or a make target. + +MINOR CODE NITS: +- drainage.rs ~480-488: comment the intentional isolated-basin fallback divergence from the old merge-to-basin-0 behavior (Tyre N1). +- planet_simulation.py ~787-788: oasis_water binary_dilation iterations are fixed-pixel — scale by GRID_W/512 for biome-display consistency at 1024 (cosmetic, Atlas only, not cascade; Tyre N2).', 'backlog', 'medium', NULL, 'server', NULL, '2026-05-23 06:09:45', '2026-05-23 06:09:45', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-963', 'story', 'T-750', 'Layer 0 — canonical 16-bit heightmap.png (2048×1024) + rename relief→reliefmap (D-202)', 'Replace the DB heightmap-BLOB model (D-202) with a per-body file-based canonical elevation, and fix the misleading naming. + +(1) RENAME the existing color hypsometric ''heightmap.png'' → ''reliefmap.png'' (display only, keep 1024×512) across all ~2398 bodies. It is a relief render, not a heightmap. +(2) BAKE a new canonical ''heightmap.png'' = 16-bit GRAYSCALE elevation at 2048×1024, from planet_simulation at higher native resolution (value-noise is resolution-independent; rescale gaussian sigma so mountains keep physical size). Single source of truth for elevation — deterministic, viewable, ~0.5-1.5MB/body PNG-compressed. 2048×1024 chosen to bound install size (sub-pixel detail is synthesized procedurally by lower cascade layers anyway). +(3) Rust heightmap.rs: load the 16-bit PNG from the body''s terrain_reference path (add ''png'' crate dep), normalize to f32 [0,1]. Layer 1 (continental drainage/basins/mountain-ranges) DOWNSAMPLES to ~512×256 (keeps the ~45ms benchmark); lower layers (region/block/tile) sample full-res for local detail. Decouples cost from resolution. +(4) DROP atlas_body_heightmaps table + the DB-BLOB write path in import_heightmaps.py (the PNG is now the store). +(5) Update terrain_reference convention, populate_terrain_reference.py, the Atlas client heightmap loader, and AMEND D-202. + +The asset bake + 2398-file rename (1,2) run where numpy/scipy are available; the Rust loader + decision (3,5) land independently in ''rust country''. Foundation for #953 (Layer-1 elevation input) and all lower cascade layers.', 'done', 'high', NULL, 'server', 'D-202', '2026-05-22 22:29:30', '2026-05-23 06:44:16', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-965', 'task', 'T-750', 'Rework or replace pre-push clerk review — non-exhaustive + token-burn', 'Clerk was DISABLED 2026-05-23 in .config/hooks/pre-push (SR_RUN_CLERK=1 to force-run) because it was net-negative in practice during the #963 push: + +PROBLEMS: +1. Non-exhaustive / non-deterministic: a single run reports ~the first concrete contradiction it finds and stops. Across one push, three DISTINCT real D-202 inconsistencies surfaced only on the 1st, 2nd, and 3rd re-push (D-200/D-201 contradiction, stale 2048×1024 docstring, sea_level self-contradiction) — each run missing the others. So an APPROVED verdict cannot be trusted as ''clean''. +2. Token burn: re-reviews the entire origin/main..HEAD range on every push attempt; no per-commit verdict cache, so a one-line fix + re-push re-runs ~20 agent reviews. + +REWORK DIRECTIONS (from the session discussion): +- Exhaustive enumeration: prompt must list ALL contradictions in a pass, not stop at the first; bias toward completeness. +- Holistic D-record check: review the cumulative decisions/ diff for internal + cross-record consistency (consistency is a global property the per-commit model approximates badly — e.g. line 928 vs 930 within D-202). +- Verdict cache: gitignored SHA->verdict log; reuse cached verdict only when both the commit AND the decisions/ state are unchanged (invalidate on any decisions/ change in range, since that can flip an earlier commit''s verdict — exactly what happened with the 2048 docstring once D-202 changed). +- Move the skip mechanism into the cache (mark a SHA as skip) and REMOVE the ''Clerk-Skip:'' commit-message trailer (no magic values in commit messages). +- Consider: is per-commit the right granularity at all, vs one holistic range review? + +Until reworked, decision-record consistency is the author''s responsibility (manual audit).', 'backlog', 'medium', NULL, 'meta', NULL, '2026-05-23 07:49:02', '2026-05-23 07:49:02', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-966', 'task', 'T-750', 'Rust dependency maintenance — rand advisory + freshness + serde_yaml', 'From a security/freshness review (2026-05-23, cargo audit + cargo update --dry-run): + +SECURITY: No CVEs/vulnerabilities (cargo audit clean across 214 deps; cargo deny advisories ok). One advisory: +- rand 0.9.2 RUSTSEC-2026-0097 — ''unsound with a custom logger using rand::rng()''. WARNING-level (unsound, not an exploitable vuln), already allow-listed in deny.toml. Fix available: rand 0.9.4 (semver-compatible). Bump rand → 0.9.4 to clear it (rand 0.10.1 is a major, separate). + +FRESHNESS: ~70 semver-compatible updates available (all routine patch/minor): bevy_ecs/app/tasks 0.18.0→0.18.1, clap 4.5→4.6, rayon 1.11→1.12, pathfinding 4.14→4.15, uuid 1.20→1.23, serde_json, tracing-subscriber, zerocopy, etc. A (lockfile-only) applies them; do as its own commit + cargo test. + +MAINTENANCE: serde_yaml 0.9 is deprecated/archived upstream (no advisory, but unmaintained). Plan a migration (serde_norway / serde_yml) eventually — it parses body-def frontmatter + agent files. + +Do as a focused dep-maintenance pass (not mixed into feature work): (1) rand 0.9.4 bump [security], (2) compatible-update sweep [freshness], (3) serde_yaml migration [maintenance, larger]. Re-run cargo audit + cargo test after each.', 'done', 'low', NULL, 'server', NULL, '2026-05-23 08:34:30', '2026-05-23 09:03:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-967', 'task', 'T-750', 'clippy-1.93 test-code debt + pre-push --all-targets gap', 'Surfaced 2026-05-23 when a warm server/target/ made the pre-push hook actually run clippy (it skips on cold worktrees). Two parts: + +1. HOOK GAP: .config/hooks/pre-push runs ''cargo clippy -- -D warnings'' WITHOUT --all-targets, so it only lints lib+bins (non-test) — test and example targets are never clippy-checked. That''s why test-code clippy debt accumulated unflagged. Decide: add --all-targets to the hook (after cleaning the debt below), or leave tests unchecked. + +2. TEST-CODE clippy-1.93 debt (NOT auto-fixable; needs judgment), all in cfg(test) modules / tests/ — does NOT block the current hook: + - disallowed_types HashSet/HashMap → BTreeSet/BTreeMap: tests/shadowcast_bench.rs (×8), tests/news_ticker.rs (HashSet + HashMap), src/npc/mood.rs (cfg(test)), src/simulation/sound.rs (check if cfg(test) or lib — verify SoundEventKind: Ord before swap). + - field_reassign_with_default: src/npc/disclosure.rs, src/simulation/monologue.rs (×2), src/simulation/save_io.rs (test setup) → struct-init. + - assertions_on_constants: src/simulation/listening.rs, tests/cross_room_transitions.rs (intentional invariant asserts → const block or scoped #[allow] with comment). + - approx_constant: src/settings/types.rs Float(3.14) — DELIBERATE non-pi value → scoped #[allow], do NOT replace with PI. + - drop_non_drop: src/npc/vision.rs drop(Mut) — verify if it''s an intentional early borrow-release (#[allow] + comment) or removable. + - unnecessary_get_then_check: tests/information_boundaries.rs (×3) → contains_key. + - cloned_ref_to_slice_refs: tests/triangle_validation.rs → std::slice::from_ref. + - doc_overindented_list_items: tests/news_ticker.rs. + - unused_must_use: src/simulation/input.rs (cfg(test)) → let _ = . + +Do as one focused clippy-1.93 sweep + cargo test. Machine-applicable ones already landed in the prior commit.', 'done', 'low', NULL, 'server', NULL, '2026-05-23 08:37:58', '2026-05-23 09:03:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-953', 'story', 'T-750', 'Layer 1 — empty-world topography (heightmap → drainage → feature tags → sub-biome)', 'Audit + wire the existing atlas modules into a reproducible Layer-1 pipeline: heightmap BLOB load (D-202) → D8 priority-flood drainage (D-208) → 7 geographic feature tags (D-209) → sub-biome variants + terrain_modification_cost (D-210). Attach river names from the markers name pool (D-223) to the largest computed rivers; mountains take names from the pool (positions given by the fixed heightmap).', 'done', 'high', NULL, 'server', 'D-208', '2026-05-22 17:42:34', '2026-05-23 09:08:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-952', 'story', 'T-750', 'Deterministic seed→output harness + golden-seed regression test', 'End-to-end determinism guarantee: same seed → byte-identical generation output across the whole cascade. Golden-seed regression test that runs the pipeline and diffs against a stored fixture. The load-bearing property — every layer must be reproducible (D-010 principle 4). rng.rs exists; wire it through and lock it with a test. + +--- +Refinement (2026-05-23, /whats-next): +- SCOPE: build an extensible per-layer harness interface (run_cascade(seed, layer_range) -> snapshot) as the primary deliverable; Layer 0->1 golden test is the first instantiation. Layers #954-959 plug in as they land. +- FIXTURE: two golden files under server/tests/golden/ following the UPDATE_GOLDEN=1 pattern -- SHA-256 of heightmap.png bytes (Layer 0) + msgpack of Layer1Output (Layer 1). NOT systems.db (explicitly non-byte-deterministic per asset-pipeline rule / D-202). +- SEEDCHAIN IN SCOPE: implement a real SeedChain type (master world seed -> per-body -> per-district derivation) and thread it through atlas callers (skeleton_gen.rs and generator.rs currently pass a plain seed:u64 with manual wrapping_add). Harness verifies cascade(world_seed=42) derives all sub-seeds deterministically. Replaces the doc-comment-only SeedChain references. +- COUPLING: Q-098 (Layer-1 output persistence vs recompute) is tied to #952; resolve or reference during implementation. +- REUSE: AtlasRng (server/src/atlas/rng.rs), SimRng (server/src/simulation/rng.rs), test_sim_determinism.py (Layer-0 Python guard), drainage.rs inline determinism tests, golden suite (make golden-diff/golden-update).', 'done', 'high', NULL, 'server', 'D-200', '2026-05-22 17:42:34', '2026-05-23 10:26:23', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-968', 'story', 'T-750', 'Activate AnalyzeBody cascade execution + BodyWorldStateCache populate (D-225)', 'Tyre''s #960 design long pole (D-225). gen_queue.rs::run_work_item''s AnalyzeBody is a documented stub (deferred from #142): it returns BodyAnalyzed without running the cascade or populating BodyWorldStateCache. Activate it: on the Rayon background tier, resolve the body heightmap, run run_cascade(Topography) (~45ms), build BodyWorldState from Layer1Output, and deliver the computed state so the main thread inserts it into the D-203 LRU. GenCompletion::BodyAnalyzed must carry the computed BodyWorldState (or a results side-channel), not just body_id (Tyre R3). MUST run off the tick thread (D-203 — no blocking CPU on main). Unblocks the atlas layer-stream proxy (D-225). + +--- +Scope (Tyre, 2026-05-23): #968 owns the full connect-the-queue-to-the-app loop — GenerationQueue (#924) + BodyWorldStateCache (#917) are built but referenced NOWHERE in the running app (inert tier), so this is one closed loop, not separable. (1) un-stub run_work_item AnalyzeBody to run run_cascade(Topography) and map CascadeSnapshot -> BodyWorldState (new constructor); (2) GenCompletion::BodyAnalyzed carries the computed BodyWorldState, not just body_id (was Tyre Risk 3); (3) register GenerationQueue + BodyWorldStateCache as resources (a GenerationPlugin or fold into an atlas plugin) + a Bevy drain system (PreInput per D-206) draining completions -> cache.insert(state); (4) acceptance: submit AnalyzeBody with a test heightmap path -> drain -> cache populated with non-empty Layer-1 data. BOUNDARY: AnalyzeBody carries resolved inputs { body_id, heightmap_path: PathBuf, sea_level: f32, body_seed: SeedChain } — the enqueuer resolves (mod-first BodySourceResolver + SeedDomain::Body derivation are #969/policy); run_work_item is pure compute (inputs -> BodyWorldState), no FS/DB access. #969 proxy is the production submitter. Do NOT split the drain wiring into a middle ticket.', 'done', 'high', NULL, 'server', 'D-225', '2026-05-23 12:23:55', '2026-05-24 08:50:20', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-970', 'story', 'T-750', 'Auto-pause sim on implant-fullscreen (inspection substrate)', 'D-226 layer 1 (substrate). Auto-pause the sim when the client enters a fullscreen implant app (the Atlas). Freeze the world-advancing tick phases (Movement/Simulation/Economy/Storyteller/Knowledge/TickAdvance) via run-conditions keyed to a pause command, but KEEP PreInput (gen-drain), Input (receive resume), Snapshot, PostSnapshot (bridge) alive so the UI keeps fetching data while frozen. Reuse the existing TickRate::Paused + the input.rs paused-allowlist seam; trigger from HudGroups::gameplay_occluded (D-170) -> a pause/resume command over the bridge. For static geography pause is a compute-saver; for dynamic state (economics, later) it is essential. Confirm exactly what TickRate::Paused currently gates (whole loop vs sim-advance) and gate at the phase level.', 'backlog', 'high', NULL, 'server', 'D-226', '2026-05-24 09:22:33', '2026-05-24 09:22:33', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-971', 'story', 'T-750', 'Atlas agent control channel — observe/act named-intent navigation (D-226)', 'D-226 layer 4 (apex). A client-side AtlasAgentInterface exposing a JSON control channel so an automated agent (terminal/curl, headless Godot) can navigate the REAL Atlas UI: observe -> JSON of (a) current data state shown and (b) a walkable UI affordance tree (toggle controls: id/label/state/locked); act -> named SEMANTIC intents (select_system/open_system/select_body/open_regional/select_city/set_overlay/reset_view/back/close_atlas) backed by the same handlers a click calls (the map uses _gui_input, NOT pixel-clicks), plus get_layer_data_summary (attractor/river/basin counts as JSON without rendering). Single AtlasAgentInterface autoload/static class for a stable contract; generic Control-tree walk so economics/saves plug in later. Turns human-eyeball review into an agent QA sweep. Depends on #960 (the viewer) + the auto-pause substrate. Screenshot capture is a separate ticket (kept off the critical path).', 'backlog', 'medium', NULL, 'client', 'D-226', '2026-05-24 09:22:38', '2026-05-24 09:22:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-972', 'story', 'T-750', 'Agent interactive screenshot capture — reuse run-visual primitive (D-226)', 'D-226 layer 5 (capture). A capture_layer_screenshot affordance on the agent channel: set the requested overlays active, clear hover state, render the canvas, return a PNG path. REUSE the existing capture primitive (tests/run-visual + the frame-delayed save_png pattern proven by character_creation.gd standalone capture) — do NOT build a new headless rasterizer. Complements the existing scenario/flow visual-golden regression (that batch/regression role is unchanged); this adds INTERACTIVE agent-driven capture. Isolated from the agent channel (#agent-channel) so the headless-render wrinkle can''t gate the navigation apex. Depends on the agent control channel.', 'backlog', 'medium', NULL, 'client', 'D-226', '2026-05-24 09:22:41', '2026-05-24 09:22:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-969', 'story', 'T-750', 'Atlas layer-stream proxy + bridge protocol (D-225)', 'D-225 layer-stream proxy: server-side delivery of per-body Layer1Output to the Godot client, mod-first, compute-on-demand, no bake. NEW: BodySourceResolver (server/src/atlas/source_resolver.rs) resolves body_id -> heightmap.png across mod dirs + base install (terrain_reference from systems.db, read-only); v1 wires base root only but the resolver + search-order exist and are tested with a synthetic mod root. layer_proxy.rs: cache hit serializes; miss enqueues Immediate AnalyzeBody + replies Pending, pushes response on completion. BRIDGE: additive message tag on the EXISTING IPC stream (no second socket, no envelope-everywhere rewrite) — AtlasLayerRequest{body_id, up_to_layer} / AtlasLayerResponse{status, layer1} as new MessagePack message types disambiguated structurally in v1; single framed response (not chunked); raster NOT streamed (client loads reliefmap.png from disk); whole Layer1Output per response (client composites additive overlays). Depends on #968 (AnalyzeBody activation). See D-225. + +--- +Part of the D-226 inspection harness (data-path, layer 2): the proxy is what the Atlas viewer (#960) and the agent channel (#971) read. See D-226 for the full stack: live-pause substrate (#970) -> proxy (this) -> viewer (#960) -> agent channel (#971) -> capture (#972).', 'done', 'high', NULL, 'server', 'D-225', '2026-05-23 12:24:02', '2026-05-24 16:07:21', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-960', 'story', 'T-750', 'Per-layer Atlas map viewer (generation progress viewer)', 'Render each cascade layer as a MAP in the implant Atlas (D-191, the Phase 3 viewer — D-166 amendment): terrain → water → biome → settlements → political zones → quarter/block skeleton → tiles. This is the progress-viewer deliverable; NO in-world rendering. Grows as each layer lands. + +--- +Refinement (2026-05-23, /whats-next): +- DATA TRANSPORT (resolves Q-098): NO bake — baking derived layer data makes mods second-class. A server-side FILE STREAM PROXY: resolves a body source files across base + mod paths, runs the deterministic cascade on demand (run_cascade, LRU-cached per D-203, ~45ms), and streams serialized layer data to the Godot client over IPC. First-party and mod bodies use the identical path; no pre-baked derived artifacts. Protocol/stream spec designed with Tyre and recorded in a D-record resolving Q-098. +- UI: layer selector in the existing regional Atlas view; layers are ADDITIVE overlays (toggle heightmap + rivers + attractors + sub-biome together and composite), not one-at-a-time — matching the existing overlay-bar model (D-191). +- SCOPE NOW: only Layer 0 (heightmap) + Layer 1 (rivers/basins/attractors/sub-biome) exist; the viewer grows as layers land (D-166). Acceptance: Layer 0 + Layer 1 render as additive, toggleable overlays for a body, fed by the proxy. + +--- +Design (D-226, Araminta, 2026-05-24) — human-visual layer of the inspection harness. Extend OVERLAY_DEFS / AtlasOverlayBar with a generation overlay group (second row) + a left-side legend panel; do NOT build a separate viewer. Encoding: relief base; rivers as blue polylines (mouths = double-circle markers, confluences where in-degree >= 3); basin fills very translucent + thin boundary polylines; attractors as markers where SHAPE encodes the 7 AttractorTypes (circle/half-circle/diamond/down-tri/up-tri/hollow-circle/square) and COLOR encodes sub-biome (shape carries identity in headless/monochrome; color is additive); size scales with strength, skip strength < 0.15. Stable button ids gen_l0_heightmap / gen_l1_rivers / gen_l1_basins / gen_l1_attractors; start pending/locked, unlock+activate via notify_gen_layer_ready(id) as data arrives (grows as layers land, D-166). Consumes the live proxy (#969); the agent channel (#971) drives this same UI.', 'in_progress', 'high', NULL, 'client', 'D-191', '2026-05-22 17:42:34', '2026-05-24 16:08:45', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-973', 'bug', NULL, 'Client test suite — pre-existing failures under bare run-godot', 'Surfaced 2026-05-24 running the full client suite (tests/run-godot, no server) during #960. NOT caused by #960 — verified: test_input_roundtrip fails identically at the pre-change baseline, and the rest are unrelated subsystems. Two categories to triage: + +CATEGORY 1 — server-dependent (expected-fail under bare run-godot): test_e2e_connection (test_send_input_receive_snapshot), test_input_roundtrip (movement/interact/move_then_interact). They error with ''Nil snapshot'' / ''.tick on Nil'' because no sim server is spawned. They need the run-ipc-* harness or SR_LIVE=1. FIX OPTIONS: gate/skip these under bare run-godot (mark as requiring a server) OR have run-godot spawn the server for the e2e tier, so tests/run-godot +{"suite":"godot","total":2522,"passed":2482,"failed":40,"duration_ms":96836,"log":"/tmp/sr-run-godot.1737738.log"} is green without false negatives. + +CATEGORY 2 — genuine logic failures in subsystems unrelated to current work: test_audio_sprint13 (test_d067_chime_duration_spec_is_300_to_400ms, line 547 ''Expecting true but is false''), test_fog_sprint22 (exploration_data_preserved_across_resize), test_fog_shader (visibility_texture_update_performance), test_dialogue_sprint18/20 (signal/audio-dip), test_monologue_display (queue_never_exceeds_max_depth), test_implant_app_lifecycle (on_insert_deactivated_closes_insert_app), test_ai_dialogue_sprint26 (settings_dialog warning label). Triage each: fix or remove/xfail with a reason. + +Goal: a green (or explicitly-gated) bare `make test-client` so client regressions are detectable. Until then, run targeted suites (run-godot --filter ).', 'backlog', 'medium', NULL, 'client', NULL, '2026-05-24 16:49:54', '2026-05-24 16:49:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-974', 'epic', NULL, 'Atlas-to-tile derivation model', 'Foundational world-derivation model from the atlas-derivation workshop. D-227 (deterministic-rebuild world model: pure function of seed+atlas, derived on demand + cached, only tile mutators persisted, fully volumetric voxel/subvoxel, vertical extent physical not floor-count, variable-height floors) + D-228 (composite tile schema: orthogonal axes TerrainMaterial/FloorMaterial/Vegetation/Water/elevation, derived shape/tactical-form, region-level morphology zones, cohesion matrix, dynamic clock-bound region seasonal state). Most implementation lands as the cascade reaches the tile layers (Phase 4+). Open design tracked in Q-100 (biome authority), Q-101 (refinement contract + body-class river density + ocean mask), Q-102 (cohesion-matrix algorithm), Q-103 (mutator op schema), Q-104 (floor-to-voxel-z mapping), Q-105 (region seasonal/clock state: water/snow/weather/crops).', 'backlog', 'high', NULL, 'server', 'D-228', '2026-05-25 10:51:49', '2026-05-25 10:51:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-975', 'story', 'T-974', 'Own the ocean/lake water mask', 'Concrete current gap surfaced by Tyre in the atlas-derivation workshop: D-223 stripped the topographic polygons from markers.json, but D-209 CoastalAccess/LakeShore attractor extraction still references oceans[]/lake polygons that no longer exist. The ocean/lake mask must instead be derived from the heightmap sea-level threshold (or a baked water-bodies layer). Unlike the rest of the epic (which lands with future cascade layers), this affects attractor extraction today.', 'backlog', 'medium', NULL, 'server', 'Q-101', '2026-05-25 10:52:23', '2026-05-25 10:52:23', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-976', 'story', 'T-750', 'Layer 4 — street & footprint geometry (morphology-gated, D-234)', 'Fill the Layer-4 skeleton stub fields (chunk_layout/corridors/access_points) with real geometry, per D-234. (a) Morphology zone -> permitted street patterns lookup gating the D-215 arrangement patterns (fjord/canyon -> ribbon|hub-spoke, delta -> hub-spoke following channels w/ bridges as forced nodes, alluvial-plain -> any, island -> hub-spoke, mountain-pass -> ribbon). (b) Street/corridor network + district access_points within/between blocks (+/-45 deg cap, D-096; no curves). (c) Block footprint subdivision into building plots + interstitial space (parks/lots/gardens), respecting density (D-220) and BulkClass roofed-coverage fraction (D-233). (d) Waterfront footprint rule: pier/quay geometry on water-facing edge, standard frontage inland. Depends on 957 (skeleton). + +Refinement (2026-05-26): READY behind 1006/957. Two-layer streets (D-234 refined): corridors = MST/least-cost graph over access-points + reservations + landmarks (Civ6 arterials, the audit graph; ribbon = MST on linear nodes, hub-spoke = MST + forced centroid hub); chunk_layout = +/-45 grid lattice per block (Civ4 local), modulated by D-096 Grid/Organic. Morphology -> permitted-pattern lookup gates D-215. Bridge node = waterfront block on a corridor (no separate type). Footprint subdivision = recursive bisection over the 128x128 integer grid, aggregate roofed area within the BulkClass coverage range. Waterfront = pier/quay on the water-facing edge. CorridorSpine/AccessPoint typed structs defined in 1006. Files: skeleton_gen.rs, generator.rs. + +--- +Largely SUBSUMED by #957 (2026-06-06): the footprint subdivision (BSP + D-233 coverage), the street network (typed AccessPoint/CorridorSpine/ChunkLayout, morphology-gated arterials per D-234a, ±45° local lattice), and the waterfront rule (D-234b) all landed in skeleton_gen.rs as one coherent walkable-quarter deliverable. REMAINING scope: the per-block-EDGE open-water adjacency refinement — applying pier geometry to the exact block edges that touch water — which needs Layer-1 terrain water-adjacency threaded to the quarter via the Layer-3 placement -> Layer-4 GenerateSkeleton dispatch (city_context_reader still stubs founding_orientation=Cardinal). Blocked on that dispatch; the waterfront rule is implemented and activates when real per-settlement orientation flows.', 'backlog', 'high', NULL, 'server', 'D-234', '2026-05-25 19:08:51', '2026-05-25 19:08:51', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-977', 'story', 'T-750', 'Architecture-flavor pipeline — wiki to generator cultural grammar (D-232)', 'Architecture-domain completion of D-167. (a) Gemma architecture-flavor methodology doc: stage-1 register selection + stage-2 structured output {tag, allow:[ObjectTag], block:[ObjectTag], weight, trauma_decay_rate}, analogous to the D-223 naming methodology. (b) trait_templates catalog + atlas_body_trait_bias bake (see round-3 note) (GTTR+index.md). (c) allow/block weighted filter applied at chunk fill over the D-142 zone-type ObjectTag pool (dominant wins categorical; weighted-avg continuous). (d) ObjectTag vocabulary authoring (Miri+Araminta co-maintenance). Three-layer resolution body x district x era-band (era-band depth = Q-106). NOTE: source-authoring location rides on Q-107 (content consolidation); the table+filter are buildable independently. Formally retires D-104/D-105/D-101-axisA/D-107. Flavor stays purely wiki-authored; economics (D-233) is a parallel channel composing only at the filter. + +Round 3 (2026-05-25): D-232 rewritten to the TRAIT-TEMPLATE model (not per-body Gemma arrays). Build: (1) trait_templates table = shared holistic catalog (~35 floor / 40-45 target); two-tier eligibility = integer-bps hard gates (bulk_class/prosperity/ubiquity) + weight mods (role/faction/age/corridor/morphology); corridor (geographic_sector) is a WEIGHT, never a gate. (2) atlas_body_trait_bias (sparse, ~30-40 hero bodies: pin/boost/suppress); RETIRE atlas_body_culture + atlas_body_culture_era. (3) Three-phase draw: body vocabulary K-draw (K=5/3/1/0 by complexity_tier, SeedChain D-224, coverage-aware, pin counts toward K) -> district-dominant by zone_affinity (one template/district, applied whole) -> within-template seed picks. (4) Deviation/swerve system + (5) visual fallback hierarchy = separate tasks. CI guardrails (Nigel): eligible pool >=5 post-gate, no template >60pct weight, bias per-body, catalog grows with corpus. Result trait_selection: Vec on skeleton, re-derivable. Channel-separate from D-233 (what vs how). Era = maintenance/wear (D-217), NOT a tech ladder. Source location -> Q-107. + +Scope note (2026-05-26): the catalog CONTENT authoring is split out to story #1005 (blocking). 977 is now the MECHANISM only — tables, three-phase draw, district-dominant, deviation system, fallback hierarchy. #1005 (the ~35-template content) blocks the draw/fill/visual tasks. + +Refinement (2026-05-26): READY behind 1006/1005. Mechanism only. trait_templates + atlas_body_trait_bias DDL into import_economics.py MIGRATION_SQL + systems-schema.sql, integer-bps weights throughout. draw_body_vocabulary() inside the GenerateSkeleton Rayon task: hard-gate filter -> weight (mods x bias) -> SeedChain weighted draw of K (5/3/1/0 by ComplexityTier) -> trait_selection on skeleton; pin counts toward K; coverage-aware (>=1 template per present district type, else sparsity escape-hatch). pick_district_dominant() at the FillChunk head (zone_affinity-weighted). CI guardrails in importer validation (pool>=5, weight<=60pct, bias per-body). Swerve (1003) + fallback (1004) are child tasks. SeedChain complete, no change. Files: import_economics.py, generator.rs. + +--- From PR #148 review (Tyre): the trait_templates.geographic_sector column is a pool-narrowing hint for baseline/heritage sub-pools and a SOFT weight (never a gate); it composes with weight_mods.geographic_sector. The draw must join both, not treat the column as a gate. (D-232 corridor = two-part pool.)', 'backlog', 'high', NULL, 'server', 'D-232', '2026-05-25 19:08:55', '2026-05-25 19:08:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-978', 'story', 'T-750', 'Guarantee-audit engine over step-3 tags (D-097)', 'Implement the guarantee-audit engine per the D-097 amendment. Runs after step-3 fill completes for a district; on a failed mandatory check for the district world_tier, fill regenerates with adjusted params. run_guarantee_audit(skeleton, building_tags, street_graph, seed) -> GuaranteeAuditResult. Tier-1 (all inhabited): social_hub_present, informal_zone_present, encounter_corridor. Tier-2 (full-complexity): traffic_chokepoint, institutional_space, insider_space, economic_node, breach_only_zone. Tier-3 A-1..A-4 assassin-lens: elevated_vantage (above_ground>=3 + LOS to chokepoint), egress_multiplicity (>=2 unique street connections), temporal_opacity (>=1 TemporalWindow door), non_institutional_route (Public->insider path avoiding institutional). All pure graph/geometry over building_tags + street_graph -- NO interior generation. Depends on 957 (tag schema) + the street-geometry story (D-234). + +Refinement (2026-05-26): READY behind 1006/976. GuaranteeAuditResult struct replaces the String alias (14 bools). Signature run_guarantee_audit(skeleton, building_tags, street_graph, seed). Mandatory-check gate keys on ComplexityTier (T1 all-inhabited; T2/T3 Full) -- D-097 wording fixed. Each check is a graph/geometry predicate over tags + the MST arterial graph: chokepoint = articulation point; encounter_corridor = Public-node BFS crossing the district; A-1 LOS = 2D footprint occlusion; A-2 = unique perimeter street edges >= 2; A-4 = path avoiding institutional buildings. social_hub eligibility = a social_hub_eligible flag added to the zone-type RONs (D-142). Regenerate-on-fail: MAX_RETRIES const, bump the missing-guarantee zone weight, increment a SeedChain sub-key. Files: generator.rs, the audit module.', 'backlog', 'medium', NULL, 'server', 'D-097', '2026-05-25 19:08:59', '2026-05-25 19:08:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-979', 'story', 'T-750', 'DoorSpec/InteriorDescriptor + condition overlay (D-231, D-198)', '(a) DoorSpec/InteriorDescriptor structs on the building tag (D-231): the step3->step4 boundary descriptor + the COMPLETE Phase-6 interior seed (zone_type_id, entry_class, floor_extent, era, flavor_ref, prosperity, layout_mode). Door-count derivation (Main always; Service/Emergency/Hidden by condition) + initial-state derivation (Public->Open, Commercial->TemporalWindow, Restricted->Locked, BreachOnly->Sealed) + mutator semantics (initial state frozen-amber, runtime changes are tile mutators). The interior FILL is Phase 6 (D-166) -- OUT OF SCOPE; only the descriptor lands here. (b) Condition overlay (D-198 two-pass amendment): BuildingConditionState{New|Maintained|Worn|Derelict|Abandoned}, OccupancyState{Full|Partial|Vacant}, VegetationEncroachment -- a SEPARATE Bevy system triggered by EconEvent (D-180), painting OVER the frozen structural fill, feeding D-100 DamageOverlay. Hard wall: overlay cannot change a BuildingTag; fill_chunk holds no PressureState reference. + +Refinement (2026-05-26): READY behind 1006. Phase-4 scope = DoorSpec/InteriorDescriptor structs (defined in 1006) + derivation here; interior FILL is Phase-6, OUT of scope. Door-count: Main always; Service if logistical zone; Emergency if >=2 floors; Hidden seeded by zone (research 60/admin 20/res 5). Initial state: Public -> Open or Closed (zone decides: market Open, civic Closed); Commercial -> TemporalWindow; Restricted -> Locked + credential; BreachOnly -> Sealed. Mutations via ChunkMutations/TileOverride (exist). Condition overlay = a SEPARATE Bevy system on EconEvent (D-180), painting BuildingConditionState/OccupancyState/VegetationEncroachment (sub-biome whitelist: TropicalWet, TemperateForest, Wetland, Boreal, Savanna) over the frozen fill; refresh on EconEvent + daily. Condition is its OWN overlay layer; it does NOT feed D-100 physical-damage types (no D-100 change). Hard wall: condition system imports nothing from econ_sim::model and holds no PressureState. Files: generator.rs, economy_plugin.rs, econ-sim/src/events.rs.', 'backlog', 'medium', NULL, 'server', 'D-231', '2026-05-25 19:09:04', '2026-05-25 19:09:04', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-981', 'story', 'T-750', 'Wiki to Atlas content-set consolidation (Q-107, blocked)', 'Consolidate all wiki content (pages + heightmaps + markers + architecture-flavor) into one first-class, baked Atlas/gamedata content set with a unified bake pipeline -- instead of per-feature file conventions. Resolves where authored per-body content lives (the D-232 flavor source). BLOCKED on Q-107 (open question -- the target tree structure must be decided first). The generator-facing trait_templates + atlas_body_trait_bias tables (D-232) is invariant to this, so it does NOT block the fill seam; sequence this AFTER the fill-seam work. Jeroen: ''the wiki needs to become part of the atlas content set ... not yet another hack.''', 'backlog', 'low', NULL, 'server', 'Q-107', '2026-05-25 19:09:10', '2026-05-25 19:09:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-982', 'task', 'T-954', 'BulkClass + ProductionUbiquity enums + D-184 bulk_class backfill + dominant-commodity lookup', 'Define BulkClass{BulkSolid|BulkLiquid|PrecisionDense|Perishable|NonPhysical} + ProductionUbiquity{Ubiquitous|Common|Specialist|MonopolySource}; back-fill D-184 bulk_class values; build-time lookup of the settlement dominant commodity from the systems.db catalog. Seed-independent. + +Round-3 batch refinement (2026-05-26): also define the MorphologyZone enum here (closed set: Fjord, Canyon, Delta, AlluvialPlain, Island, MountainPass, Coastal, Lake, Sea, OpenOcean, MeanderReach, Other) -- it had no home and 954/976/1005 all need it. bulk_class is the 8->5 PROJECTION (size variants bulk/standard/compact/oversized -> BulkSolid; precision -> PrecisionDense; the 8 stay on commodities). Note: the bare enum/struct type DEFS now live in the foundational types task; 982 owns the projection + dominant-commodity DERIVATION logic (derived from highest-output location-bound production chain, D-178, not an authored role->commodity table).', 'in_progress', 'medium', NULL, 'server', 'D-233', '2026-05-25 19:11:05', '2026-05-25 19:11:05', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-983', 'task', 'T-954', 'CityGenerationContext extension (morphology_zone, trait_selection, dominant_bulk_class, dominant_production_ubiquity)', 'D-199 amendment: add the four new context fields feeding Layer-4 fill. morphology_zone from the Layer-1 cascade; trait_selection (Arc) drawn via the trait-template catalog (977); the two commodity signals from 954 lookup.', 'backlog', 'medium', NULL, 'server', 'D-199', '2026-05-25 19:11:07', '2026-05-25 19:11:07', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-984', 'task', 'T-957', 'BuildingPropertyTag + FloorExtent/FloorHeightProfile structs; replace BlockSkeleton String stubs', 'Define BuildingPropertyTag (zone_type_id, footprint, extent, entry_class, flavor_ref, era/era_cause, initial_condition) + FloorExtent{base_floor,floor_count,FloorHeightProfile::{Uniform|Variable}}. Resolves Q-104: floor_at_voxel_z / voxel_range_for_floor pure fns. Replaces era/society_profile/zone_palette/chunk_layout String stubs in generator.rs.', 'backlog', 'high', NULL, 'server', 'D-229', '2026-05-25 19:11:10', '2026-05-25 19:11:10', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-985', 'task', 'T-957', 'Extend GenerateSkeleton to emit DistrictWorldState{block_tags} + fix GenCompletion to carry it', 'Plan phase (background, no budget): produce block_tags inside the extended GenerateSkeleton; output DistrictWorldState{skeleton, block_tags: BTreeMap}. Store under BodyWorldState.districts. Fix GenCompletion::SkeletonGenerated to carry DistrictWorldState (today returns only city_id -- code gap).', 'backlog', 'high', NULL, 'server', 'D-230', '2026-05-25 19:11:12', '2026-05-25 19:11:12', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-986', 'task', 'T-957', 'zone_type_id selection + BuildingEntryClass / era / initial_condition derivation', 'zone_type_id from (ZoningType + economic_role + seed) -> one of the 31 D-142 RON files. BuildingEntryClass from (zone_type x layout_mode x prosperity) incl. Commission/Organic credential fork + U-curve degrade. era from founding_age+prosperity+seed; initial_condition from prosperity_baseline (D-217).', 'backlog', 'high', NULL, 'server', 'D-229', '2026-05-25 19:11:15', '2026-05-25 19:11:15', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-987', 'task', 'T-959', 'FillChunk shell derivation <5ms (Void/Wall/FloorSlab/Roof from cached tags)', 'On-demand derive phase: read cached DistrictWorldState; per tag, shell_derive(seed, footprint, extent, z) -> Void|Wall|FloorSlab|Roof per voxel. Pre-condition: only after SkeletonGenerated; re-enqueue High if block_tags absent. Budget ~0.4-0.6ms/chunk.', 'backlog', 'high', NULL, 'server', 'D-230', '2026-05-25 19:11:17', '2026-05-25 19:11:17', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-988', 'task', 'T-959', 'BuildingExteriorTag visual grammar + material vocabulary (template-filtered)', '(architecture_flavor x zone_type x era x density) -> BuildingExteriorTag{wall_material, roof_form, setback_tier, facade_rhythm, color_range}. Vocabulary: WallMaterial/RoofForm/FacadeRhythm/StreetSurface (extends D-228 FloorMaterial). 4-step derivation: flavor filter -> zone bias -> era restrict -> density setback -> interstitial type. Color flavor-bounded/era-adjusted/seed-selected.', 'backlog', 'medium', NULL, 'server', 'D-235', '2026-05-25 19:11:19', '2026-05-25 19:11:19', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-989', 'task', 'T-976', 'Morphology -> permitted street-pattern lookup gating D-215 patterns', 'Lookup: per morphology zone, which D-215 arrangement patterns are legal + the street-shape constraint (fjord/canyon->ribbon|hub-spoke, delta->hub-spoke w/ bridge nodes, alluvial-plain->any, island->hub-spoke, mountain-pass->ribbon). Prevents radial cities in fjords.', 'backlog', 'high', NULL, 'server', 'D-234', '2026-05-25 19:11:22', '2026-05-25 19:11:22', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-990', 'task', 'T-976', 'Street/corridor network + district access_points geometry (+/-45 cap)', 'Fill the chunk_layout/corridors/access_points stubs: street network within/between blocks, district entries/exits, +/-45 deg pathfinding cap (D-096), no curves; straight lines only where authored (D-228 cohesion).', 'backlog', 'high', NULL, 'server', 'D-234', '2026-05-25 19:11:23', '2026-05-25 19:11:23', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-991', 'task', 'T-976', 'Block footprint subdivision + interstitial + waterfront rule', 'Subdivide a block into building plots + interstitial (parks/lots/gardens), respecting density (D-220) + BulkClass roofed-coverage (D-233). Waterfront footprint rule: pier/quay geometry (no setback, dock-orthogonal) on the water-facing edge, standard frontage inland.', 'backlog', 'high', NULL, 'server', 'D-234', '2026-05-25 19:11:25', '2026-05-25 19:11:25', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-992', 'task', 'T-977', 'Gemma architecture-flavor methodology doc (stage1 register + stage2 structured)', 'Methodology doc analogous to the D-223 naming one: stage-1 register selection from wiki prose, stage-2 structured output {tag, allow, block, weight, trauma_decay_rate}. Defines the Gemma prompt + review at GTTR/wiki authoring. + +Round 3 reframe: Gemma is a BOUNDED corpus-distillation pass (one read of all wiki -> propose catalog templates -> human-gated), NOT per-body open-vocab generation. Plus core catalog hand-authoring (Miri = cultural meaning + eligibility; Araminta = matching visual_bundle). + +Round-3 refinement (2026-05-26): reframed as a FOLLOW-ON extension, not a blocker of the core catalog (1005). Runs AFTER the core hand-authored set exists, to propose additional templates (corpus-distillation, human-gated) toward the 40-45 target. Needs an architecture-flavor Gemma methodology doc (analogous to the naming one) defining the extraction prompt + structured output schema + human-review gate.', 'backlog', 'high', NULL, 'server', 'D-232', '2026-05-25 19:11:41', '2026-05-25 19:11:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-994', 'task', 'T-977', 'allow/block weighted filter at chunk fill over zone-type ObjectTag pool', 'Apply the flavor profile as a filter over the D-142 zone-type ObjectTag baseline pool: block removed, allow weighted up by weight; dominant wins categorical, weighted-avg continuous. Three-layer: body x district x era-band (depth Q-106). + +Round 3: this becomes the THREE-PHASE DRAW (body K-draw [K=5/3/1/0 by complexity_tier, SeedChain, coverage-aware] -> district-dominant by zone_affinity -> within-template seed picks) + CI guardrails, per D-232 — not a flat per-body allow/block filter.', 'backlog', 'medium', NULL, 'server', 'D-232', '2026-05-25 19:11:45', '2026-05-25 19:11:45', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-995', 'task', 'T-977', 'ObjectTag vocabulary authoring (Miri + Araminta co-maintenance)', 'Author the ObjectTag + exterior-material vocabulary the allow/block lists and D-235 grammar reference. Carried over from the retired generator-arch D-READY-9 requirement. Content task, Miri + Araminta.', 'backlog', 'medium', NULL, 'server', 'D-232', '2026-05-25 19:11:47', '2026-05-25 19:11:47', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-996', 'task', 'T-978', 'Guarantee-audit T1/T2 checks over building_tags + street_graph', 'Tier-1 (social_hub/informal_zone/encounter_corridor) + Tier-2 (chokepoint/institutional/insider/economic_node/breach_only) checks as graph/geometry queries over the step-3 tags + street graph. Populate GuaranteeAuditResult.', 'backlog', 'medium', NULL, 'server', 'D-097', '2026-05-25 19:11:49', '2026-05-25 19:11:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-997', 'task', 'T-978', 'A-1..A-4 assassin-lens graph queries + regenerate-on-fail', 'A-1 elevated vantage (above_ground>=3 + LOS to chokepoint), A-2 egress multiplicity, A-3 temporal opacity (TemporalWindow door), A-4 non-institutional route. On mandatory-check fail for world_tier, regenerate fill with adjusted params.', 'backlog', 'medium', NULL, 'server', 'D-097', '2026-05-25 19:11:51', '2026-05-25 19:11:51', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-998', 'task', 'T-979', 'DoorSpec/InteriorDescriptor structs + door-count/initial-state derivation', 'Structs on the building tag: the step3->step4 boundary + complete Phase-6 interior seed. Door-count (Main always; Service/Emergency/Hidden by condition), initial-state (Public/Commercial/Restricted/BreachOnly), mutator semantics. Interior FILL is Phase 6 -- out of scope; only the descriptor lands.', 'backlog', 'medium', NULL, 'server', 'D-231', '2026-05-25 19:11:53', '2026-05-25 19:11:53', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-999', 'task', 'T-979', 'Condition overlay Bevy system (BuildingConditionState/OccupancyState) on EconEvent', 'Separate Bevy system triggered by EconEvent (D-180), painting over the frozen structural fill: BuildingConditionState{New|Maintained|Worn|Derelict|Abandoned}, OccupancyState, VegetationEncroachment; feeds D-100 DamageOverlay. Hard wall: cannot change a BuildingTag; holds no PressureState ref.', 'backlog', 'medium', NULL, 'server', 'D-198', '2026-05-25 19:11:55', '2026-05-25 19:11:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1001', 'task', 'T-980', 'Backfill economic_tier (~97% NULL) + normalize economic_role 5 spellings', 'economic_tier NULL on ~97% of systems (gates D-199 context); economic_role has 5 variant spellings -- normalize to one canonical set. Source-canonical + regen-db. + +Scope narrow (2026-05-26, /whats-next activation): economic_tier deferred to follow-up ticket #1007 (no derivation formula, not D-199-required, does not gate the cascade). This ticket now scopes to: role normalization (ALREADY in MIGRATION_SQL at import_economics.py:354-360 + validator at 859-880) -> run make regen-db, run make check-systems-db, verify with SELECT DISTINCT economic_role from bodies. Essentially a regen-and-verify task once #1000 founding_age is also in place.', 'done', 'high', NULL, 'server', NULL, '2026-05-25 19:11:58', '2026-05-25 19:11:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1002', 'task', 'T-980', 'Backfill behavioral_archetype', 'behavioral_archetype mostly NULL across bodies. Source-canonical + regen-db. Lower urgency than founding_age/economic_tier but needed before NPC-adjacent generation.', 'backlog', 'medium', NULL, 'server', NULL, '2026-05-25 19:11:59', '2026-05-25 19:11:59', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1003', 'task', 'T-977', 'Deviation/swerve system — closed-default + rare per-building wildcard', 'Closed vocabulary by default; a rare per-building wildcard draws a COHERENT whole foreign template (cultural-only — function still passes economic hard gates; never an axis-scramble). Two OPPOSED active drivers: foreign-import (another corridor) scaled UP by cosmopolitanism/centrality/transit/Epicenter tier; heritage-callback (the body''s own corridor heritage sub-pool) scaled UP by remoteness/isolation/conservatism. Passive past-vogue holdover from age (D-217 wear). Sparsity escape-hatch = the SAME mechanism triggered by necessity when the closed vocabulary cannot serve a district. Per D-232.', 'backlog', 'medium', NULL, 'server', 'D-232', '2026-05-25 20:36:39', '2026-05-25 20:36:39', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1004', 'task', 'T-977', 'Visual-asset fallback hierarchy (specific->generic tokens, patch-upgradable)', 'Every specific texture/material token declares a generic parent it degrades to: temple_wall_wood -> generic wood_wall placeholder until the specific asset ships, then it upgrades IN PLACE. The logical token a building uses is fixed + deterministic at generation (frozen world); only render fidelity is incremental. This is where patched-in themes/textures live -> NO catalog versioning needed for art (versioning only re-enters if a NEW logical template is added post-launch). Per D-232 + D-235. Cross-refs ticket 988 (exterior visual grammar).', 'backlog', 'medium', NULL, 'server', 'D-235', '2026-05-25 20:36:42', '2026-05-25 20:36:42', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1006', 'task', 'T-750', 'Foundation — define all D-229/D-230/D-231/D-233 shared Rust types + struct plumbing (single PR)', 'Consolidates the type-definition layer every downstream fill-seam ticket waits on (the most-repeated refinement gap). One PR that compiles with stubs/defaults, then the logic tickets fill behavior. Defines: BuildingPropertyTag, FloorExtent + FloorHeightProfile (with floor_at_voxel_z / voxel_range_for_floor, resolving Q-104), BuildingEntryClass (Public|Commercial|Restricted|BreachOnly), ConstructionEra, ZoneTypeId (Box), the enums MorphologyZone / BulkClass(5) / ProductionUbiquity, DoorSpec + InteriorDescriptor structs, DistrictWorldState. Struct plumbing: add fields to CityGenerationContext (morphology_zone, trait_selection, dominant_bulk_class, dominant_production_ubiquity), add block_tags-bearing DistrictWorldState to BodyWorldState.districts, and FIX GenCompletion::SkeletonGenerated to carry DistrictWorldState (+ body_id) not just city_id. AccessTier collision: the existing 5-variant spatial AccessTier in generator.rs is RENAMED ZoneAccessTier (FloorZone/VerticalCorridorSpec); BuildingEntryClass is the new per-building-exterior type. Logic (projection/derivation/draw/fill) stays in 982/983/984/985/998 etc., which build ON these types.', 'done', 'high', NULL, 'server', 'D-229', '2026-05-26 18:13:15', '2026-05-28 21:07:48', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1000', 'task', 'T-980', 'Backfill founding_age_years for 273 inhabited bodies (source-canonical)', 'founding_age_years NULL on all 273 inhabited bodies -- gates ConstructionEra (D-229) + block irregularity (D-216). Edit the TOML/JSON sources + regen-db; never direct-write systems.db. + +Refinement (2026-05-26): EVENTS-FIRST derivation, not pure wave-table (avoids double bookkeeping with the existing per-system historical_events.age_years authored data, e.g. Van Maanen 180yr). MIGRATION_SQL block in import_economics.py: bodies.founding_age_years = COALESCE((SELECT age_years FROM historical_events WHERE system_id = bodies.system_id AND event_type IN (founding,first_settlement,colonization) ORDER BY sort_order LIMIT 1), wave_fallback(settlement_wave)). Canonical wave fallback (founding-edge per lore): wave_1=600, wave_2=500, wave_3=300, wave_4=100, wave_5=40. EXCLUDE Sol bodies entirely: settlement_wave=origin -> NULL (Sol is out of player scope, Atlas highest-level only, deeper Sol is future DLC). Source-canonical + regen-db. + +--- +Refinement (2026-05-30, /whats-next — resolves Si GAPS): EVENTS-FIRST branch uses the REAL authored founding event, not the fictional vocabulary. The named types (founding/first_settlement/colonization) match ZERO rows in historical_events; the actual founding event is event_type=\"colonial_charter\" (9 systems, age_years 480-600, aligns with wave band). civilizational_origin (12900yr = cosmic Earth origin) MUST be excluded. MIGRATION_SQL: bodies.founding_age_years = COALESCE((SELECT age_years FROM historical_events WHERE system_id=bodies.system_id AND event_type=\"colonial_charter\" LIMIT 1), CASE sh.settlement_wave WHEN \"wave_1\" THEN 600 WHEN \"wave_2\" THEN 500 WHEN \"wave_3\" THEN 300 WHEN \"wave_4\" THEN 100 WHEN \"wave_5\" THEN 40 END) -- joined to system_history sh. sort_order NOTE: sort_order=0=MOST RECENT, so do NOT ORDER BY sort_order to pick founding; filter by event_type instead. EXCLUDE settlement_wave IN (\"origin\",\"unsettled\") -> stays NULL (origin=Sol out of player scope per D-236; unsettled=24 systems, literally not settled). Source-canonical: add the UPDATE to MIGRATION_SQL in tooling/economy-db/import_economics.py, then make regen-db; never direct-write systems.db.', 'done', 'high', NULL, 'server', NULL, '2026-05-25 19:11:56', '2026-05-28 21:07:49', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1007', 'task', 'T-750', 'Deferred: economic_tier derivation formula (not D-199-required; post-cascade)', 'Split out of #1001 during /whats-next refinement: economic_tier has no derivation formula in any D-record and is NOT one of D-199''s 6 required generation-context fields, so it does not gate the Phase-4 cascade. Defer until either (a) a derivation formula is decided (likely a population-bracketed map: <100K=1, 100K-1M=2, 1M-10M=3, >10M=4, or similar — needs design) OR (b) economic_tier earns a use case in the rolling sim. Live state: ~97pct NULL in system_economy. Not blocking #1001''s role-normalization work.', 'backlog', 'low', NULL, 'server', NULL, '2026-05-28 21:07:54', '2026-05-28 21:07:54', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1008', 'task', NULL, 'Author economy label for Glimkop (GJ1245Bb) — NULL economic_role in placeholder system', 'Glimkop (GJ1245Bb, pop 4200, system PLACEHOLDER_087) has economic_role NULL despite inhabited>0 — surfaced during #1001 regen-verify. Pre-existing content gap, not a normalization bug. Either author a canonical economic_role in the wiki source, or confirm PLACEHOLDER_* systems are excluded from the Phase-4 generation cascade (in which case close as wontfix).', 'backlog', 'low', NULL, 'server', NULL, '2026-05-31 09:27:38', '2026-05-31 09:27:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1009', 'epic', 'T-750', 'System economic specialization — authored identity layer (D-237)', 'Authored per-system identity layer: three fields (economic_specialization, cultural_specialization, dominant_faction) sourced from wiki/economics/system_specialization.toml, imported via import_economics.py, consumed by city_context_reader.rs. Authored lore wins; deterministic-varied heuristic fallback for unnamed systems. Outcome: Layer 2 generation reads GTTR-consistent system identity rather than a role+planet_class guess. + +Decisions: D-237 (new — authored specialization layer schema + vocabulary + fallback algorithm); D-233 re-amended (authored field is primary driver for BulkClass x ProductionUbiquity; heuristic is fallback); D-199 amended (economic_specialization + cultural_specialization added to read-set); D-232 noted (cultural_specialization drives template pool selection); D-214 noted (authored dominant_faction is primary PoliticalArchetype input). + +Workshop: docs/workshops/system-economic-specialization/ (all rounds + outcomes).', 'backlog', 'high', NULL, 'server', 'D-237', '2026-05-31 16:12:18', '2026-05-31 16:12:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1014', 'task', 'T-1009', 'city_context_reader.rs: authored-primary + deterministic-varied fallback for all 3 specialization fields', 'Wire all three authored specialization fields into CityGenerationContext, with authored value as primary and deterministic-varied heuristic as fallback. + +economic_specialization: + Non-null -> look up in specialization_vocabulary -> read bulk_class_projected + production_ubiquity_projected -> populate CityGenerationContext.dominant_bulk_class / dominant_production_ubiquity. + Null -> deterministic-varied fallback (integer basis points only, D-010): + candidate_weights: Map + for primary role candidates: += 8_000 bps + for secondary role candidates: += 3_000 bps + for each corp HQ in corp_presence: += 5_000 bps (map corp specialization -> vocab id) + for every vocabulary id: += 400 bps // noise term; ~5% off-primary draw across 200 unnamed systems + seed = SeedChain::root(world_seed).derive(SeedDomain::Layer1System, fnv1a_64(system_id)).seed() + weighted draw sorted alphabetically by spec_id (deterministic order) + ROLE_SPEC_MAP table: see burnelli-sheldon-round3.md §(d). + This replaces the #982 dominant-commodity derivation as PRIMARY; #982 output becomes fallback path. + +cultural_specialization: + Non-null -> pass to D-232 template-pool selection (boost matching templates, dampen corridor default for divergent-heritage systems). + Null -> corridor assignment already in D-232 algorithm; no action needed. + +dominant_faction: + Non-null (authored in system_factions) -> direct input to D-214 PoliticalArchetype (authored wins). + Null -> Paula''s hop/currency fallback: hop 0-5 -> concord_assembly; west_reach hop 6+ mark_primary -> compact; west_reach hop 5-6 mixed -> compact_sympathetic; hop 7+ other corridors -> independent; Tier-1 monopolist corp HQ -> syndic_dominant (flagged). Full table: paula-round3.md §2. + D-172/D-174 wiring: authored dominant_faction is the primary input; existing validation unchanged.', 'backlog', 'high', NULL, 'server', 'D-237', '2026-05-31 16:13:29', '2026-05-31 16:13:29', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1018', 'task', 'T-1009', 'settlement_pattern → subsurface/domed/enclosed morphology branch in D-233/D-237 fill', 'The economic-built-world fill model (D-233, re-amended by D-237) is a surface model (roofed-coverage fraction, operations-surface remainder, concentrate-vs-scatter on open ground). bodies.settlement_pattern carries non-surface morphologies (underground_concentrated e.g. Vuurkloof/GJ35c, cave, domed, underground_complex) that nothing in the chain currently reads — not in D-199 read-set, not in city_context_reader, not branched in skeleton_gen. Engine primitives exist (D-110 signed base_z, UndergroundComplex reservation, D-106 vertical scale) but no morphology switch connects settlement_pattern to the built-world layer, so enclosed-habitat bodies would generate as surface towns, contradicting lore. SCOPE: (1) add settlement_pattern to the D-199 read-set + city_context_reader; (2) add a surface-vs-enclosed branch to the D-233/D-237 fill (enclosed coverage/vocabulary reinterpretation); (3) amend D-233/D-237 records accordingly. BLOCKED ON Q-108 debate (subterranean/domed/sealed-habitat morphology design) — do not implement before that resolves. Surfaced via Vuurkloof (GJ 35) in the system-economic-specialization workshop.', 'backlog', 'medium', NULL, 'server', 'Q-108', '2026-05-31 17:07:55', '2026-05-31 17:07:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1010', 'task', 'T-1009', 'Write D-237 + re-amend D-233, amend D-199 / D-232 / D-214', 'Write the new D-237 record to decisions/architecture.md using Burnelli''s draft from docs/workshops/system-economic-specialization/burnelli-sheldon-round3.md §(f). D-237 covers: 3-field schema, 27-value economic vocabulary, unified cultural_specialization vocabulary (12 activity + 9+ heritage values), deterministic-varied fallback algorithm, Groombridge landmark mechanism note. + +Also apply these amendments: +- D-233 re-amendment: authored economic_specialization is now the primary driver for (dominant_bulk_class, dominant_production_ubiquity) in CityGenerationContext; heuristic fallback for NULL. +- D-199 amendment: add economic_specialization and cultural_specialization to the minimum read set (dominant_faction was already field 4). +- D-232 note: cultural_specialization (system_economy) is a template-pool selection signal — non-null directs which cultural tradition pool D-232 draws from; null = corridor assignment stands. +- D-214 note: dominant_faction authored values (8-value vocabulary) are the primary PoliticalArchetype input; hop/currency heuristic is fallback. +- D-237 note on Groombridge landmark mechanism: singular MonopolySource-class institution within a Specialist district → encode district as Specialist in vocabulary + D-222 multi-block reservation + D-232 atlas_body_trait_bias hero pin; not a composite vocabulary value. + +Source material: burnelli-sheldon-round3.md §(f) has complete draft text. Slot in D-237 (already claimed). No new D-records needed beyond D-237.', 'done', 'high', NULL, 'server', 'D-237', '2026-05-31 16:12:34', '2026-05-31 17:33:45', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1011', 'task', 'T-1009', 'Schema: economic_specialization + cultural_specialization columns + specialization_vocabulary table', 'Add two new columns to system_economy and create the specialization_vocabulary table. + +systems-schema.sql changes: + ALTER TABLE system_economy ADD COLUMN economic_specialization TEXT; + ALTER TABLE system_economy ADD COLUMN cultural_specialization TEXT; + -- cultural_specialization avoids collision with system_culture.cultural_register (NPC-voice, wiki_sync.py pipeline, untouched) + + CREATE TABLE IF NOT EXISTS specialization_vocabulary ( + specialization_id TEXT PRIMARY KEY, + commodity_id TEXT NOT NULL REFERENCES commodities(commodity_id), + production_ubiquity_override TEXT, -- NULL = use catalog default + bulk_class_projected TEXT NOT NULL, -- pre-computed BulkClass for D-233 + production_ubiquity_projected TEXT NOT NULL, -- pre-computed ProductionUbiquity + description TEXT NOT NULL + ); + CREATE INDEX IF NOT EXISTS idx_spec_vocab_commodity ON specialization_vocabulary(commodity_id); + +import_economics.py changes: + Add both ALTER TABLE statements to COLUMN_MIGRATIONS list (idempotent). + Add CREATE TABLE IF NOT EXISTS specialization_vocabulary to MIGRATION_SQL block. + +IMPORTANT: system_factions.dominant_faction ALREADY EXISTS as a column (confirmed in schema). Zero schema change for dominant_faction — the import step only upserts authored values. Do not add a new column. + +Cultural vocabulary validation is a string-list check in CI code — no separate DB table needed for cultural_specialization values. + +--- +Refinement (Si, 2026-05-31): READY. Confirmed: system_economy at systems-schema.sql L94; dominant_faction exists L108 (populate-only); commodities PK L254 (FK valid); COLUMN_MIGRATIONS + MIGRATION_SQL idempotent patterns present in import_economics.py. Add the 2 cols INSIDE the system_economy CREATE TABLE block (not ALTER) for fresh builds, AND as COLUMN_MIGRATIONS ALTER entries for existing DBs; add specialization_vocabulary CREATE TABLE to MIGRATION_SQL. check-systems-db-stamp GENERATOR_SOURCES untouched here (belongs to #1013).', 'done', 'high', NULL, 'server', 'D-237', '2026-05-31 16:12:44', '2026-05-31 18:51:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1012', 'task', 'T-1009', 'Source TOMLs: specialization_vocabulary.toml (27 values) + system_specialization.toml (hero-system seeds)', 'Create two new source files consumed by import_economics.py. + +wiki/economics/specialization_vocabulary.toml — 27 economic values: + Burnelli''s 26-value list from burnelli-sheldon-round3.md §(b) (agricultural x5, energy x2, extraction x5, manufacturing x6, high-tech x1, services x7) plus Miri''s addition: research_station (commission_certification, concentrated -> NonPhysical x Specialist, for Keid). + Merge resolutions applied: marine_farming absorbed into terroir_organics; military_production + military_station -> military_industrial; specialist_manufacturing -> precision_tech (identical D-233 output); alloy_hub absorbed into general_industrial. + Each entry: specialization_id, commodity_id, production_ubiquity_override (null = catalog default), bulk_class_projected, production_ubiquity_projected, description. + +wiki/economics/system_specialization.toml — ~28 hero-system entries (seed for full content pass): + Format: + [GJ-144] # Ran + economic_specialization = ''breadbasket'' + cultural_specialization = ''terroir_heritage'' + dominant_faction = ''concord_assembly'' + Use merged vocabulary labels from specialization_vocabulary.toml (not Miri''s pre-merge Round 3 labels). + Hero systems: Ran, Cygni B, Sindri, Nova Roma, Renaissance, Groombridge, Prometheus, ACB, Tessera, Sirius, Parallax, Gateway, Wolf 359, Vuurkloof, Keid, Bastion, Arbour, Lu Ban, Calloway Reach, Confluent/VGV, Braemar, Nyrheim, Ostmark, Dagat, Altmark, Dai Lo, Zenzele + east-reach lattice anchor (GJ TBD). + +CONFLICT to resolve before committing Vuurkloof: Miri says dominant_faction=independent (GTTR engineering community), Paula says concord_assembly (south_reach hop-6 default). Verify against docs/workshops/system-economic-specialization/workshop-outcomes.md. + +cultural_specialization accepts both activity-type values (scholarly, agrarian, industrial_heritage, etc.) and heritage-type values (scottish, vietnamese, afrikaans_cape, zulu, chinese, italian_northern, tagalog, norse_compact, french_provencal, etc.). Heritage takes precedence when both apply. Full combined vocabulary list in miri-round3.md §2. + +--- +Refinement (Si + lead, 2026-05-31): GAP1 RESOLVED — TOML stanza keys use SPACE format [GJ 35], not hyphen [GJ-35]; every wiki/economics TOML + the star_systems PK use spaces (the workshop §1 example was illustrative/wrong). GAP3 RESOLVED — keep lattice_material_source in specialization_vocabulary.toml with NO system stanza yet (east-reach anchor GJ pin is a content-pass item, documented-intentional). GAP2 VUURKLOOF (GJ 35) — author dominant_faction = independent as a PROVISIONAL PLACEHOLDER; flagged OPEN for human decision: harshness/guild-self-governance leans independent vs Assembly wanting a strategic fusion-fuel source leans concord_assembly. Filed D-237 workshop-outcomes §7 currently says concord_assembly — left as-is pending the call; live TOML will carry independent + a # PROVISIONAL comment. Do not treat Vuurkloof faction as final.', 'done', 'high', NULL, 'server', 'D-237', '2026-05-31 16:13:02', '2026-05-31 18:51:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); diff --git a/.pql/changelog/tickets/2026-06.sql b/.pql/changelog/tickets/2026-06.sql new file mode 100644 index 000000000..6ab55d59d --- /dev/null +++ b/.pql/changelog/tickets/2026-06.sql @@ -0,0 +1,162 @@ +INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1013', 'task', 'T-1009', 'import_economics.py: import_system_specialization() function + source stamp tracking', 'Implement import_system_specialization() in import_economics.py and wire it into the main import flow. + +Function steps: + 1. Read wiki/economics/specialization_vocabulary.toml -> validate FK against commodities table -> clear + repopulate specialization_vocabulary table. + 2. Read wiki/economics/system_specialization.toml -> for each authored system: + - UPSERT system_economy.economic_specialization and system_economy.cultural_specialization + - UPSERT system_factions.dominant_faction ONLY when the field is present in the TOML stanza (systems without an entry are unaffected; the system_factions row must already exist) + 3. Run hard validations (see CI ticket) — abort transaction on failure. + 4. Print coverage report and soft warnings. + 5. Call within the main import transaction (same pattern as other import steps). + +Source stamp tracking: + - Add wiki/economics/system_specialization.toml and wiki/economics/specialization_vocabulary.toml to IMPORT_ECONOMICS_SOURCES list. + - Mirror both additions in tooling/check-systems-db-stamp GENERATOR_SOURCES[''import_economics''] dict (keep in sync or the pre-push hook will reject the DB). + +Note: dominant_faction column already exists on system_factions. The import step populates it for named systems; it does NOT add a new column or migrate the schema.', 'done', 'high', NULL, 'server', 'D-237', '2026-05-31 16:13:12', '2026-06-01 07:09:18', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1015', 'task', 'T-1009', 'CI guardrails: specialization vocabulary validation + cross-field checks + coverage report', 'Implement in import_economics.py (called from import_system_specialization()). + +HARD ERRORS (build aborts): + V-SES-01: economic_specialization must be in specialization_vocabulary.specialization_id when present. + V-SES-02: inhabited systems (population > 0) must resolve to a non-null economic value (authored or fallback) — fail build if derivation returns null. + V-SES-03: production_ubiquity_override in specialization_vocabulary must be >= catalog default concentration (ubiquitous < common/regional < concentrated < monopolistic). + V-SES-04: cultural_specialization must be in the combined activity+heritage vocabulary list when present. + V-SES-05: dominant_faction must be in the 8-value vocabulary (concord_assembly|compact|compact_sympathetic|syndic_dominant|veil_institute|independent|disputed|mixed) when present. + V-FAC-01: every inhabited NAMED system (has a GTTR entry or wiki page) MUST have an authored dominant_faction value — hard error. + V-SES-06: specialization_vocabulary.commodity_id must exist in commodities(commodity_id) — FK integrity. + +SOFT WARNINGS (build succeeds, prints): + W-SES-01: MonopolySource systems list for human review (D-177 constraints apply). + W-SES-02: >25% of inhabited systems resolve to same vocabulary value. + W-SES-03: economic_base_primary prose does not mention commodity/sector from vocabulary description. + W-SES-08: estate_farming + population > 5_000_000 (probably breadbasket). + W-FAC-01: compact + tractus_primary currency zone (D-172 violation). + W-FAC-02: compact + MonopolySource extraction excluding marble_monopoly/terroir_* (Compact self-sufficiency doctrine). + W-FAC-03: syndic_dominant + no Tier-1 corp HQ in corp_presence (ungrounded pin). + W-FAC-04: compact_sympathetic + mark_primary currency (may be full Compact member). + W-FAC-05: independent + sole Tier-1 monopolist corp HQ (Calloway Reach pattern — flag for confirm). + W-FAC-06: compact + cultural_specialization missing compact_cooperative reference. + W-FAC-07: syndic_dominant inner-corridor + cultural_specialization = corridor default (institutional culture expected). + +COVERAGE REPORT (always printed): + economic: NNN/MMM inhabited systems authored (NN%); NNN on fallback + cultural: NNN/MMM named systems authored (NN%); NNN on corridor default + faction: NNN/MMM named systems authored (NN%); NNN on derivation + BulkClass distribution: BulkSolid=NN|BulkLiquid=NN|Perishable=NN|PrecisionDense=NN|NonPhysical=NN + ProductionUbiquity distribution: Ubiquitous=NN|Common=NN|Specialist=NN|MonopolySource=NN + MonopolySource systems [D-177 REVIEW REQUIRED]: [list] + D-172 faction/currency mismatches [REVIEW]: [list] + Compact monoeconomy flags [REVIEW]: [list]', 'done', 'medium', NULL, 'server', 'D-237', '2026-05-31 16:13:49', '2026-06-01 10:44:58', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1019', 'story', 'T-1009', 'Heritage rebalancing — convert overrepresented southern-African systems to Arab/Persian/Turkic (DLC/content)', 'The #1016 heritage taxonomy (docs/workshops/system-economic-specialization/heritage-taxonomy-draft.md) surfaced a real worldbuilding imbalance: ~25 of ~300 named systems read southern-African, with afrikaans alone on 15 systems — more than french+italian+russian+arab combined. arab=2, persian=0, turkic=0. Artifact of the original name-balancing overcorrecting in one direction. + +FIX (out of scope for #1016): rewrite a subset of afrikaans/zulu systems into arab/persian/turkic heritage. This is a FULL per-system content rewrite — index.md (name, infobox-adjacent prose) AND gttr.md (founding story, naming, narrative) — not a TOML value flip. The canonical taxonomy already reserves arab/persian/turkic values as write targets. + +Scope when picked up: pick N southern-African systems (candidates: the thinner afrikaans deep-frontier pocket), rewrite name+index+gttr for each into the target heritage, update system_specialization.toml cultural_specialization, regen. Likely DLC-tier content work. Tracked low-priority.', 'backlog', 'low', NULL, 'server', 'D-237', '2026-06-01 14:48:41', '2026-06-01 14:48:41', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1020', 'task', NULL, 'Add East-African-interior heritage token to cultural_specialization taxonomy', 'The #1016 cultural pass found two systems founded by East-African-INTERIOR peoples that the canonical 47-value heritage taxonomy has no token for, so they currently borrow ''swahili'' (a coastal value) as the nearest fit (documented inline in wiki/economics/system_specialization.toml): + + - GJ 667B Kampala Gate — Baganda/Ugandan (Great Lakes interior) + - GJ 1292 Moyale — Kenyan/Ethiopian (Borana/Oromo, Horn) + +(Mwangaza GJ 693 is genuinely coastal Swahili — correct, leave it.) + +SCOPE: add an appropriate heritage value (or values) to the canonical taxonomy at the nationality/people granularity the taxonomy uses — candidates: a Great Lakes / interior East African token and/or a Horn-of-Africa token. Update: + 1. docs/workshops/system-economic-specialization/heritage-taxonomy-draft.md (canon list + count) + 2. _CULTURAL_HERITAGE in tooling/economy-db/import_economics.py + 3. repin GJ 667B and GJ 1292 in system_specialization.toml to the new value(s) + 4. regen-db + verify (V-SES-04) + commit + +Surfaced by the PR #147 (#1016) review (Paula HIGH / Miri). Low priority — current ''swahili'' approximation is documented, not silently wrong.', 'backlog', 'low', NULL, 'server', 'D-237', '2026-06-03 08:27:09', '2026-06-03 08:27:09', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1016', 'story', 'T-1009', 'Content pass: ~300-system economic + cultural_specialization + faction authored pins', 'Author the three specialization fields for all GTTR-named systems (~300 total). Hero seeds are in wiki/economics/system_specialization.toml (T3); this pass extends to the full set. + +AUTHORING SCOPE: + economic_specialization: ~80-100 GTTR-named systems. All inhabited systems fall back to heuristic if unauthed. + cultural_specialization: ~60-100 divergent-heritage systems. Criterion: GTTR names a founding community AND that community''s heritage diverges from the corridor baseline. Unnamed systems fall to corridor default. + dominant_faction: ALL inhabited named systems (GTTR entry or wiki page) MUST have an authored value (V-FAC-01 hard error). ~40-60 entries; remainder on hop/currency heuristic. + +VOCABULARY GROUND TRUTH: wiki/economics/specialization_vocabulary.toml (27 values). Miri''s Round 3 table has pre-merge labels for some entries: + marine_farming -> terroir_organics + military_station -> military_industrial + specialist_manufacturing -> precision_tech + Use TOML labels, not the pre-merge Round 3 table labels. + +AUTHORING METHOD (Miri): + Heritage triage (4-step): (1) system name language — does it diverge from corridor? (2) institution names in non-corridor language family? (3) GTTR founding community mention? (4) if none apply, corridor handles it (no pin). + Heritage values take precedence over activity values when both apply. + +CULTURAL_SPECIALIZATION vocabulary (single field, combined): + Activity/character: scholarly, artistic, institutional, commercial, agrarian, industrial_heritage, medical_elite, ecological, military, financial_technocratic, cosmopolitan, compact_cooperative (12 values). + Heritage: scottish, french_provencal, vietnamese, afrikaans_cape, zulu, chinese, italian_northern, tagalog, norse_compact + more discovered during pass (expandable). + +ASSIGNMENTS: + Miri: economic_specialization pins + cultural_specialization pins (GTTR-truth lens; 4-step heritage triage). + Paula: dominant_faction pins + cultural_register input via three mechanisms: institutional erasure (Sirius, Groombridge, Bastion, Renaissance, Prometheus), deepened corridor (Ostmark, Nyrheim, Calloway Reach, Braemar), heritage preservation (Confluent, Dai Lo, Dagat). Faction list: paula-round3.md §1. + Burnelli: economic credibility review; fallback algorithm validation; distribution balance check (W-SES-02). Flag vocabulary values unclaimed after pass (candidates for retirement: rare_mineral_extraction, precision_tech, legal_archive). + +CONFLICT: Vuurkloof dominant_faction — Miri=independent, Paula=concord_assembly. Resolve against workshop-outcomes.md before committing.', 'done', 'medium', NULL, 'server', 'D-237', '2026-05-31 16:14:10', '2026-06-03 08:27:51', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1017', 'task', 'T-1009', 'atlas_body_trait_bias hero-pin sub-pass (~30-40 bodies) + Groombridge GSH landmark', 'Author per-body atlas_body_trait_bias entries for ~30-40 GTTR-named hero bodies per D-232 design. + +Pin types: + pin: mandatory template; counts toward K; body WILL use this template. + boost: up to 3x weight increase (non-mandatory). + suppress: >= 0.33x (never 0 — preserves second-playthrough surprise). + +RELATIONSHIP TO T7: system-level cultural_specialization (T7) sets the baseline for ALL bodies in a system. Per-body atlas_body_trait_bias pins override for specific bodies. Both are needed — without the system baseline, hero-pinned bodies are surrounded by wrong-character context. T7 must be underway before this pass is useful. + +GROOMBRIDGE GSH LANDMARK (folded in from D-222/D-232 design): + The Groombridge Settling House is the Reach''s singular clearing house — a MonopolySource-class institution within a Specialist financial district. + Mechanism: (1) D-222 multi-block reservation — a reserved block in the financial district for a single named institution, placed at generation time; (2) D-232 atlas_body_trait_bias pin — forces the clearing_house_landmark template onto that reserved block. + Implementation check REQUIRED before authoring: confirm whether the D-222 multi-block reservation mechanism supports named landmark reservations in the Phase 4 generator. If not yet implemented, raise a sub-task for the reservation slot mechanism before authoring the content pin. + Content: add Groombridge body entry with clearing_house_landmark pin. + +BEFORE STARTING: confirm atlas_body_trait_bias import mechanism with Burnelli (wiki TOML -> import vs. direct entry in an existing TOML). The D-232 record (decisions/architecture.md §D-232) specifies storage as a sparse atlas_body_trait_bias table; confirm the authoring pipeline for that table. + +Authoring: Miri (lore truth) + Araminta (template catalog knowledge). + +--- Refinement 2026-06-03 (feasibility gates checked, #1016 done): BLOCKED. Both BEFORE-STARTING gates fail — the infra does not exist yet. (1) atlas_body_trait_bias table + trait_templates catalog: absent from systems-schema.sql, systems.db, and all importer/server code → blocked on #993 (tables+import) and #1005 (catalog content). (2) D-232 architecture-flavor template-draw consumer: not present in server/src/atlas/skeleton_gen.rs → blocked on #977 (pipeline) / #983 (CityGenerationContext trait_selection). (3) D-222 named-landmark reservation: skeleton_gen ReservationFunction has only Park/Terminal (block.landmark is a stub None); named-institution reservation for the Groombridge GSH is NOT implemented → blocked on #957 (quarter-skeleton reservations); confirm #957 scope explicitly covers a named-landmark reservation slot or split a sub-task. This is a CONTENT pass (~30-40 pins + GSH) that requires the above mechanisms first; do not author pins into a non-existent table. Deps wired: 993, 1005, 977, 957. + +--- From PR #148 review (Tyre): when authoring hero pins, validate that the number of pin rows per body stays within that body''s K budget (Full=5/Moderate=3/Minimal=1). complexity_tier is not available in import_economics, so this check belongs either in the draw consumer (#977) or a generator-side validation — add to acceptance.', 'backlog', 'medium', NULL, 'server', 'D-237', '2026-05-31 16:14:27', '2026-06-03 08:31:47', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-993', 'task', 'T-977', 'trait_templates + atlas_body_trait_bias tables + catalog bake', 'Table atlas_body_culture(body_id, flavor_index, tag, allow_tags, block_tags, weight, trauma_decay_rate); baked at import (same slot as atlas_city_names). Generator-facing artifact, invariant to the Q-107 source-location decision. + +Round 3: the tables are trait_templates (shared catalog) + atlas_body_trait_bias (sparse hero bodies). atlas_body_culture + atlas_body_culture_era are RETIRED (not built).', 'done', 'high', NULL, 'server', 'D-232', '2026-05-25 19:11:43', '2026-06-03 09:51:37', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1005', 'story', 'T-750', 'Author the core trait-template catalog (~35 templates — cultural entries + visual bundles)', 'The explicit content-authoring deliverable for the D-232 trait-template catalog, split out of 977 so it is not lost between the mechanism tasks. Author the core ~35 templates (40-45 target): each entry = Miri''s cultural layer (tag, label, cultural_description, two-tier eligibility [hard gates bulk_class/prosperity/ubiquity + weight mods role/faction/age/corridor/morphology], zone_affinity, era_scope) + Araminta''s matching visual_bundle (4-axis WallMaterial/RoofForm/FacadeRhythm/StreetSurface allow-block, color register, fallback parents). Must cover, per corridor, a BASELINE pool + a HERITAGE sub-pool, plus the shared cross-corridor (foreign-import) pool. CI guardrails must pass: >=5 templates eligible per economic class, no template >60pct pool weight. Core hand-curated first; the bounded Gemma corpus-distillation pass (992) proposes additions under human review. BLOCKING: the flavor system produces no real output until this exists. Owners: Miri (cultural/eligibility) + Araminta (visual bundles). + +Round-3 refinement (2026-05-26): the 992 (Gemma methodology) hard-block is REMOVED -- the core ~25-30 templates are hand-authored (Miri cultural + Araminta visual bundles) and do not need the Gemma pass. 992 becomes a follow-on EXTENSION (corpus-distillation to 40-45), gated by the core existing, not a prerequisite. Still blocked by 993 (schema) + 995 (ObjectTag vocab). Per-corridor target: baseline 4-5 + heritage 2-3 each; shared foreign pool 5-8; clear the >=5-eligible-per-economic-class CI guardrail. Color-register vocab: Araminta defines in a TOML preamble. + +Authoring approach (2026-05-26): order west_reach -> north_reach -> east_reach -> south_reach (baseline 4-5 + heritage 2-3 each) -> shared foreign pool last (needs all corridors first) -> core sector. TOML entry = tag, label, cultural_description, hard-gates (min/max prosperity bps, bulk_class, ubiquity), zone_affinity {DistrictType: bps}, era_scope, base_weight, corridor_weights, morphology_weights, visual_bundle (wall/roof/facade/street allow-block + color_register + fallback_chain), pool_type (baseline|heritage|foreign), corridor. economic_role weight-mod keys = the canonical 10 (D-194); dominant_faction = PoliticalArchetype. Color-register vocab defined in a TOML preamble by Araminta.', 'done', 'high', NULL, 'server', 'D-232', '2026-05-26 17:33:34', '2026-06-03 09:51:37', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-954', 'story', 'T-750', 'Layer 2 — wire economic read-set + prosperity_baseline into generation context', 'Wire the 6-field minimum economic read set (D-199) and prosperity_baseline (D-197) into the city-generation context (D-200). Economic sim is independent of spatial layers (D-198) — this is the interface that feeds population/role/prosperity into placement. + +Refinement (round 2, 2026-05-25): Also wire the CityGenerationContext extension (D-199 amend: +morphology_zone, +trait_selection, +dominant_bulk_class, +dominant_production_ubiquity), the BulkClass/ProductionUbiquity enums, the D-184 bulk_class value backfill, and the dominant-commodity lookup (D-233). Economic strength is authored-fixed; locations seed-varied (D-167/D-223). Blocked by 980 (data cleanup). + +Refinement (2026-05-26): READY behind 1006 (types) + 980 (data). bulk_class = the 8->5 projection; dominant commodity DERIVED from the highest-output location-bound production chain (D-178). Denormalize dominant_bulk_class + dominant_production_ubiquity into a systems.db column at build time (import_economics.py, D-200 tier-1), not a runtime Rust join. trait_selection lands as a no-op stub until the catalog (1005) exists. economic_role normalization already in MIGRATION_SQL; confirm via a dry-run importer. Files: import_economics.py, generator.rs CityGenerationContext. + +--- Closed 2026-06-03: core shipped via PR #145 (D-199 read-set + D-197 prosperity wired; CityGenerationContext extended with morphology_zone/trait_selection/dominant_bulk_class/dominant_production_ubiquity; city_context_reader scaffold). The round-2 ''denormalize dominant_bulk_class/ubiquity into a systems.db column'' sub-part was SUPERSEDED by the D-237 reader-resolution path (resolve via specialization_vocabulary / heuristic) owned by #1014 (blocked on #982). Remaining context fields are documented deferred stubs owned by #1014 (#982), #955 (founding_orientation/placement), #956 (political_archetype). Spine-relevant work complete.', 'done', 'medium', NULL, 'server', 'D-199', '2026-05-22 17:42:34', '2026-06-03 10:07:55', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-1021', 'task', NULL, 'Persist deterministic cascade output (build-time bake or local cache)', 'Deferred from the #955 pair session. The Phase-4 cascade (Layers 0-5) is fully deterministic (D-010 + SeedChain) — its output (settlement placements, and eventually the full BodyWorldState) is a pure function of (heightmap, authored context, world seed), so it can be cached rather than re-derived on every cold load. + +CONSTRAINT: systems.db is read-only from the server''s perspective (schema header) — the runtime server CANNOT write it. So a persistent cache is one of: + (A) Build-time whole-cascade bake into systems.db (a tool runs the Rust cascade, bakes BodyWorldState/placements; runtime reads). Matches the D-223/#951 ''cascade fills the geometry tables'' intent; staleness handled by the existing meta-stamp. Cost: committed binary artifact + re-bake on input change. + (B) Runtime local cache in a gitignored .cache/ keyed by (world_seed, schema_version, body_id), written on first derive, read after. No commit/merge issues; per-machine first-derive cost. + +DESIGN DECISION NEEDED: A vs B (or both — A for shipped worlds, B for dev iteration). + +WHY DEFERRED (not now): (1) every cascade layer is a PURE function, so a cache wraps it later at ZERO retrofit — determinism makes deferral free. (2) Layer-2 inputs are still churning (#1014/#982 dominant-commodity, #977 trait_selection, #956 political archetype all change placement inputs) — a bake now would be stale/constantly re-baked. (3) Bake the WHOLE cascade once it is end-to-end (post Layer 5, #959), not one layer. (4) No measured perf need yet (Layer 3 = Hungarian on a small grid). + +TRIGGER: pick this up when the cascade is end-to-end (after #959) OR the Layer-2 context freezes — whichever first. The in-memory hot cache (BodyWorldState / D-203, #968) already covers ''no IO while on a system''; this ticket is only about cross-session/cold-load persistence. + +Seam: run_layer3 (and each run_layerN) is pure — wrap at the run_cascade call site (a // cache seam comment marks it).', 'backlog', 'low', NULL, 'server', 'D-200', '2026-06-03 10:46:13', '2026-06-03 10:46:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-955', 'story', 'T-750', 'Layer 3 — settlement placement (five-phase attractor matching)', 'Five-phase attractor-matching placement (D-211, D-195): largest population areas → capital + cities at terrain features matching role. Derive SettlementClass active/ghost (D-196) and WorldTier (D-218). Settlement names come from the markers name pool (D-223).', 'done', 'high', NULL, 'server', 'D-211', '2026-05-22 17:42:34', '2026-06-03 15:40:48', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-980', 'story', 'T-750', 'Generation data-quality cleanup — founding_age / economic_tier / role / archetype', 'Prerequisite data fixes the placement + tag engines need (surfaced by the round-2 repo scan). (1) founding_age_years NULL on ALL 273 inhabited bodies -- gates ConstructionEra (D-229) + block irregularity (D-216). (2) economic_tier NULL on ~97% of systems -- gates economic context (D-199). (3) economic_role has 5 variant spellings -- normalize to one canonical set. (4) behavioral_archetype mostly NULL. SOURCE-CANONICAL per asset-pipeline rules: edit the TOML/JSON sources + regen-db; NEVER direct-write systems.db. Blocks Layer-2 (954) and Layer-4 (957). + +Refinement (2026-05-26): founding_age DECIDED -> derive from settlement_wave. A MIGRATION_SQL block in import_economics.py writes bodies.founding_age_years from system_history.settlement_wave via EVENTS-FIRST derivation: COALESCE the system''s authored founding/first_settlement/colonization event from historical_events.age_years (the precise per-system value, e.g. Van Maanen 180yr) with a wave fallback ONLY when no founding event exists. Canonical wave->age fallback (founding-edge, from systems-framework-final-miri.md): wave_1=600, wave_2=500, wave_3=300, wave_4=100, wave_5=40 yr. EXCLUDE Sol entirely (settlement_wave=origin) -- Sol is out of player scope (Atlas highest-level only, no zoom; deeper Sol = future DLC), bodies in Sol stay NULL and never enter the generation cascade. economic_role normalization already in MIGRATION_SQL (dry-run importer to surface new variants vs the canonical 10). economic_tier is NOT a D-199 required field -> derive via COALESCE-from-population in the importer, do not mass-author wiki; confirm it does not gate generation. behavioral_archetype (1002) is on corporations, not consumed by the Phase-4 cascade -> low priority, trails the other two. Source-canonical + regen-db throughout.', 'done', 'high', NULL, 'server', NULL, '2026-05-25 19:09:07', '2026-06-03 21:18:13', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-950', 'task', 'T-750', 'Rename DistrictSkeleton→QuarterSkeleton and perception ''sim tile''→Subtile terminology (D-222)', 'Naming alignment follow-up from D-222 (spatial hierarchy rename). The 512m generation cell is now the Quarter (was District). (1) Rename the generation skeleton code: DistrictSkeleton -> QuarterSkeleton (server/src/simulation/generator.rs and references); the 2048m District is a new tier above it. (2) Update perception D-records and any code that says ''0.5m sim tile'' / ''1x1 sim tiles'' to the Tile/Subtile vocabulary (Subtile = 0.5m). Pure naming, no behavior change. Deferred from the D-222 design session.', 'done', 'low', NULL, 'server', 'D-222', '2026-05-22 16:05:10', '2026-06-05 11:26:38', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-956', 'story', 'T-750', 'Layer 3 — territorial status + political archetype + founding orientation', 'Per placed settlement: TerritorialStatus priority-ordered derivation (D-212), PoliticalArchetype (D-214) and its five explicit spatial arrangement patterns (D-215), FoundingOrientation + grid rotation (D-213). Drives the spatial character of each settlement''s grid. + +--- +Refinement (2026-06-03): gaps resolved. (1) TerritorialStatus DATA SOURCE — map existing dominant_faction (8-value D-237 vocab) -> TerritorialStatus variants; NO schema change. concord_assembly->CommissionControlled, syndic_dominant->CorpTerritory, disputed->ContestedZone, independent->FrontierUnclaimed, etc. Loses population-density Derelict nuance (acceptable). AMENDS D-212 derivation method (write the amendment + final mapping table during impl; claim a D- id). (2) GRANULARITY — derive TerritorialStatus per-Province on DrainageBasin (faithful to D-212, it is a territorial/area property); add the field to DrainageBasin; each settlement inherits its containing basin status. (3) D-215 SCOPE — #956 only DERIVES+STORES PoliticalArchetype (D-214) + which of the 5 arrangement patterns applies + FoundingOrientation/bearing; block-adjacency ENFORCEMENT deferred to Quarter-skeleton gen (#957). (4) BEARING (D-213) — currently hardcoded 0; seed-derive integer bearing 0-359 from a per-settlement SeedChain (thread the carried SeedChain into run_layer3 / derive per city_id); stays integer-deterministic (D-010). (5) ATTACH POINT — PoliticalArchetype/FoundingOrientation/arrangement-pattern on CityPlacement (per-settlement); TerritorialStatus on DrainageBasin (per-province). Enums: confirm TerritorialStatus/PoliticalArchetype/FoundingOrientation exist (check #1006 output in generator.rs) or define. run_layer3 becomes seed-consuming for bearing only.', 'done', 'medium', NULL, 'server', 'D-215', '2026-05-22 17:42:34', '2026-06-05 13:14:32', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_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 (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-957', 'story', 'T-750', 'Layer 4 — Quarter skeleton (density + district mix + block grid/zoning/reservations)', 'Generate the Quarter skeleton (512m cell, D-222): density model + footprint/fill (D-220), three-component district mix (D-194), 4×4 block grid with zoning + multi-block reservations. skeleton_gen.rs exists — complete it under the D-222 naming (Quarter, not District). + +Refinement (round 2, 2026-05-25): The skeleton now also emits a BuildingPropertyTag per footprint (D-229: zone_type_id wired to the 31 zone-type RON files, FloorExtent resolving Q-104, BuildingEntryClass, era/era_cause, flavor_ref, initial_condition) inside the extended GenerateSkeleton plan-phase that produces DistrictWorldState{block_tags} (D-230). Also fix GenCompletion::SkeletonGenerated to carry the DistrictWorldState back (current code gap, returns only city_id). Blocked by 954. + +Refinement (2026-05-26): READY behind 1006. Type defs move to 1006; this story owns LOGIC: zone_type_id selection via a static (ZoningType x economic_role) -> candidate-id-slice table, seed-picking from the 31 RON ids; BuildingEntryClass derivation (zone x layout_mode x prosperity, incl. Commission/Organic credential fork + U-curve degrade); era from founding_age + distance-to-origin (wear, not material); initial_condition from prosperity (D-217 thresholds). BlockSkeleton.era String stub REMOVED (era lives on BuildingPropertyTag). Files: skeleton_gen.rs (assign_building_tags), district_mix.rs, generator.rs. + +--- +Refinement (2026-06-05, /whats-next): gaps resolved. GAP1 zone_type_id selection — AUTHORED a (ZoningType x economic_role x setting) -> candidate-ZoneTypeId-slice table for the PLANETARY cascade; setting is a TWEAKER (Maritime->port_maritime/fishing/aquaculture/extraction_platform; Agricultural->rural bias; Wilderness->wilderness_frontier/dispersed), NOT a surface/station switch. Station-only ids (residential_station, extraction_space, port_space, rural_orbital) EXCLUDED — separate cascade (see Q-109). Every cell non-empty; unknown role->ZoningType default; seed-pick from slice. Record as D-229 amendment during impl. GAP2 BuildingEntryClass low-prosperity->BreachOnly uses D-217 bands (<0.23 BreachOnly, 0.23-0.43 Restricted, etc.) + Commission/Organic credential fork. GAP3 era = D-229 (founding_age_years + prosperity_baseline + seed); DROP the ungrounded round-3 distance-to-origin phrase. GAP4 remove BlockSkeleton.era String stub (era lives on BuildingPropertyTag); fix construction sites. GAP5 FloorExtent = D-220 density-class midpoints + seed-jitter within range. GAP6 BuildingPropertyTag.doors OUT OF SCOPE -> belongs to #979 (DoorSpec/D-231); stub Vec::new() here. Confirmed present: #1006 type defs (generator.rs), 31 zone-type RON files (server/content/global/zone-types/), district_mix.rs three-component mix, GenCompletion::SkeletonGenerated already carries QuarterWorldState (gap closed prior merge). New seam Q-109 filed (cascade generation-source dispatch).', 'done', 'high', NULL, 'server', 'D-220', '2026-05-22 17:42:34', '2026-06-06 09:01:11', NULL, NULL, 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); diff --git a/tooling/pql-migrate/seed_tickets.py b/tooling/pql-migrate/seed_tickets.py new file mode 100644 index 000000000..c41265912 --- /dev/null +++ b/tooling/pql-migrate/seed_tickets.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +"""Seed pql.db ticket tables from the legacy settledreach.db (pql migration, Phase 2). + +Reads the legacy SQLite ticket store (read-only) and INSERTs every ticket, dependency, +label, and history row into /.pql/pql.db with the `T-N == #N` id bijection. After +this, run `pql plan export` to write the git-tracked changelog, then `pql plan rebuild` +to verify replay. + +Transforms: + - tickets.id -> 'T-'+id ; parent_id -> 'T-'+parent_id ; sprint_id dropped (legacy/archival) + - enums (type/status/priority) copied verbatim — identical between the two schemas + - decision_ref kept verbatim (multi-value legacy refs preserved losslessly) + - team kept verbatim (incl. the single 'server,client' comma-team ticket) + - deleted_at = NULL ; canonical_version = 1 everywhere + - hash = NULL for tickets/deps/labels (PK-based ON CONFLICT; updated_at drives LWW); + ticket_history gets a deterministic content hash so ON CONFLICT(hash) DO NOTHING + is a real dedup on replay + - ticket_milestones -> labels: active phase milestone -> 'phase:', others -> + 'milestone:' (milestones are otherwise vestigial: milestone_deps empty) + +Idempotent: --apply clears the four replicated tables first, then re-inserts. Decisions +are markdown-sourced and never touched here. Default is a dry-run report. +""" +import hashlib +import os +import re +import sqlite3 +import sys + +APPLY = "--apply" in sys.argv +REPO = "/var/mnt/data/projects/settled-reach/main" +SRC = os.environ.get("SR_DB_PATH", "/var/home/jeroenschweitzer/Projects/settled-reach/settledreach.db") +DST = f"{REPO}/.pql/pql.db" +SEED_TS = "2026-06-06 00:00:00" # well-formed stamp for rows the legacy schema didn't timestamp + + +def tid(n): + return None if n is None else f"T-{n}" + + +def slug(s): + return re.sub(r"[^a-z0-9]+", "-", s.lower()).strip("-") + + +def hist_hash(row): + key = "|".join("" if v is None else str(v) for v in row) + return hashlib.sha256(key.encode()).hexdigest() + + +def main(): + src = sqlite3.connect(f"file:{SRC}?mode=ro", uri=True) + src.row_factory = sqlite3.Row + dst = sqlite3.connect(DST) + + tickets = src.execute("SELECT * FROM tickets").fetchall() + deps = src.execute("SELECT blocker_id, blocked_id FROM ticket_deps").fetchall() + labels = src.execute("SELECT ticket_id, label FROM ticket_labels").fetchall() + history = src.execute( + "SELECT ticket_id, field, old_value, new_value, changed_by, changed_at FROM ticket_history" + ).fetchall() + milestones = {m["id"]: m for m in src.execute("SELECT * FROM milestones").fetchall()} + tms = src.execute("SELECT ticket_id, milestone_id FROM ticket_milestones").fetchall() + + def ms_label(mid): + m = milestones[mid] + return f"phase:{m['cascade_phase']}" if m["cascade_phase"] else f"milestone:{slug(m['name'])}" + + ms_labels = [(r["ticket_id"], ms_label(r["milestone_id"])) for r in tms] + + # --- report --- + multi = [t["decision_ref"] for t in tickets if t["decision_ref"] and re.search(r"[,\s]", t["decision_ref"].strip())] + comma_team = [t["id"] for t in tickets if t["team"] and "," in t["team"]] + print(f"=== seed_tickets.py ({'APPLY' if APPLY else 'DRY-RUN'}) ===") + print(f" source: {SRC}") + print(f" tickets: {len(tickets)}") + print(f" ticket_deps: {len(deps)}") + print(f" ticket_labels: {len(labels)} (existing) + {len(ms_labels)} (milestone-derived)") + print(f" ticket_history: {len(history)}") + print(f" milestone label mapping: " + ", ".join(f"{mid}->{ms_label(mid)}" for mid in milestones)) + print(f" multi/space decision_refs kept verbatim: {len(multi)}") + print(f" comma-team tickets kept verbatim: {comma_team}") + + if not APPLY: + print("\nDry run — pass --apply to write into pql.db.") + return + + cur = dst.cursor() + for t in ("ticket_history", "ticket_labels", "ticket_deps", "tickets"): + cur.execute(f"DELETE FROM {t}") + + for t in tickets: + cur.execute( + """INSERT INTO tickets (id,type,parent_id,title,description,status,priority, + assigned_to,team,decision_ref,created_at,updated_at,deleted_at,hash,canonical_version) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,NULL,NULL,1)""", + (tid(t["id"]), t["type"], tid(t["parent_id"]), t["title"], t["description"], + t["status"], t["priority"], t["assigned_to"], t["team"], t["decision_ref"], + t["created_at"], t["updated_at"]), + ) + for d in deps: + cur.execute( + """INSERT INTO ticket_deps (blocker_id,blocked_id,created_at,updated_at,deleted_at,hash,canonical_version) + VALUES (?,?,?,?,NULL,NULL,1)""", + (tid(d["blocker_id"]), tid(d["blocked_id"]), SEED_TS, SEED_TS), + ) + for tid_, label in [(r["ticket_id"], r["label"]) for r in labels] + ms_labels: + cur.execute( + """INSERT OR IGNORE INTO ticket_labels (ticket_id,label,created_at,updated_at,deleted_at,hash,canonical_version) + VALUES (?,?,?,?,NULL,NULL,1)""", + (tid(tid_), label, SEED_TS, SEED_TS), + ) + for h in history: + row = (tid(h["ticket_id"]), h["field"], h["old_value"], h["new_value"], h["changed_by"], h["changed_at"]) + cur.execute( + """INSERT INTO ticket_history (ticket_id,field,old_value,new_value,changed_by,changed_at, + created_at,updated_at,deleted_at,hash,canonical_version) + VALUES (?,?,?,?,?,?,?,?,NULL,?,1)""", + (*row, h["changed_at"], h["changed_at"], hist_hash(row)), + ) + dst.commit() + print(f"\nApplied. pql.db ticket rows: " + f"{cur.execute('SELECT COUNT(*) FROM tickets').fetchone()[0]} tickets, " + f"{cur.execute('SELECT COUNT(*) FROM ticket_deps').fetchone()[0]} deps, " + f"{cur.execute('SELECT COUNT(*) FROM ticket_labels').fetchone()[0]} labels, " + f"{cur.execute('SELECT COUNT(*) FROM ticket_history').fetchone()[0]} history.") + print("Next: `pql plan export` then `pql plan rebuild`, then verify parity.") + + +if __name__ == "__main__": + main()