Rewrites the committed .pql/changelog/ from the old T-NNN-keyed format to the record_id identity model (pql 1.10.0, D-26): tickets keyed by a ULID record_id, the friendly T-NNN in ticket_idmap, references and hashes recomputed. Produced by the one-off cmd/migrate-ids in the pql repo. Other clones: install pql >= 1.10.0, then rm .pql/pql.db && pql plan rebuild to regenerate the local DB from this changelog. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
133 lines
5.8 KiB
SQL
133 lines
5.8 KiB
SQL
-- Auto-generated by migrate-ids (D-26). CREATE TABLE statements
|
|
-- for the planning schema; per-table dir keeps the changelog
|
|
-- self-describing per D-15.
|
|
-- pql:created_by: migrate-ids
|
|
-- pql:canonical_version: 2
|
|
|
|
|
|
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)
|
|
);
|
|
|
|
-- Identity split (D-26): a ticket's stable, collision-proof identity is its
|
|
-- record_id (a locally-generated ULID, planning.NewRecordID); the friendly
|
|
-- T-NNN label lives in ticket_idmap and may be reconciled. Every structural
|
|
-- reference (parent, deps, history, labels) targets record_id, so a label
|
|
-- clash never corrupts the graph — only ticket_idmap needs a relabel.
|
|
CREATE TABLE IF NOT EXISTS tickets (
|
|
record_id TEXT PRIMARY KEY,
|
|
type TEXT NOT NULL CHECK(type IN ('initiative','epic','story','task','bug')),
|
|
parent_record_id TEXT REFERENCES tickets(record_id),
|
|
title TEXT NOT NULL,
|
|
description TEXT,
|
|
-- No CHECK enumeration: the ticket status vocabulary is per-vault
|
|
-- configurable (ticket_statuses in .pql/config.yaml). Validation lives
|
|
-- in Go (planning.StatusSet), so adding/renaming statuses needs no
|
|
-- schema change. The DEFAULT is a harmless fallback — CreateTicket
|
|
-- always inserts the configured default explicitly.
|
|
status TEXT NOT NULL DEFAULT 'backlog',
|
|
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
|
|
);
|
|
|
|
-- ticket_idmap maps a record_id to its current friendly label (T-NNN).
|
|
-- ticket_id is intentionally NOT globally unique: two uncoordinated clones
|
|
-- can mint the same label, which surfaces as a duplicate-label collision
|
|
-- (detected at replay) and is fixed with "pql ticket relabel".
|
|
CREATE TABLE IF NOT EXISTS ticket_idmap (
|
|
record_id TEXT PRIMARY KEY REFERENCES tickets(record_id),
|
|
ticket_id 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
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS ticket_deps (
|
|
blocker_record_id TEXT NOT NULL REFERENCES tickets(record_id),
|
|
blocked_record_id TEXT NOT NULL REFERENCES tickets(record_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_record_id, blocked_record_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS ticket_history (
|
|
ticket_record_id TEXT NOT NULL REFERENCES tickets(record_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_record_id TEXT NOT NULL REFERENCES tickets(record_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_record_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_tickets_parent ON tickets(parent_record_id);
|
|
CREATE INDEX IF NOT EXISTS idx_ticket_idmap_label ON ticket_idmap(ticket_id);
|
|
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);
|