One agent doc per repo, and it is CLAUDE.md. Two docs describing one repo drift, and the one nobody read is always the one holding the rule that mattered. Written fresh rather than reformatted, so the structure follows what someone working here actually needs. Two rules from the old file are gone deliberately. The mandate to branch for every change was retired in favour of one linear-history policy, and the release snippet used `git add -A`, which sweeps in whatever else is dirty. The architecture section is the part worth reading. An earlier draft called src/auth, src/controllers, src/clients, src/dns and src/models dead code, derived from grepping main.py's imports. That was wrong: main.py:55 calls initialize_oidc(), which imports and configures src.auth.oidc from inside the function body, so src/auth is configured with live Authentik issuers on every boot. It also missed four genuinely unreferenced packages. The section now states the method used -- import the app in the container and read sys.modules -- and its blind spot, that a cold snapshot cannot see a module imported on a request path. Also records that the README's "runs as non-root user (uid 1000)" is false: the Dockerfile has no USER directive. Flagged rather than fixed, since changing the runtime user is not a docs change. Co-Authored-By: Claude <noreply@anthropic.com>
140 lines
6.2 KiB
SQL
140 lines
6.2 KiB
SQL
-- 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: 2.2.0
|
|
-- 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);
|