package db const Schema = ` -- IMMUTABLE LOG: every observation is append-only, never mutated CREATE TABLE IF NOT EXISTS observations ( id INTEGER PRIMARY KEY AUTOINCREMENT, fingerprint TEXT NOT NULL, source_id TEXT NOT NULL, source_path TEXT, project TEXT, content_type TEXT, title TEXT, summary TEXT, collected_at TEXT NOT NULL DEFAULT (datetime('now')), created_at TEXT, line_start INTEGER, line_end INTEGER, confidence REAL DEFAULT 0.5, ingester_version TEXT DEFAULT '1', trigger TEXT, provenance TEXT DEFAULT '{}', node_id TEXT NOT NULL DEFAULT '', hcl INTEGER, received_at TEXT ); CREATE INDEX IF NOT EXISTS idx_obs_fingerprint ON observations(fingerprint); CREATE INDEX IF NOT EXISTS idx_obs_collected ON observations(collected_at); CREATE INDEX IF NOT EXISTS idx_obs_created ON observations(created_at); CREATE INDEX IF NOT EXISTS idx_obs_source ON observations(source_id, source_path); CREATE INDEX IF NOT EXISTS idx_obs_project ON observations(project); CREATE INDEX IF NOT EXISTS idx_obs_trigger ON observations(trigger); -- MATERIALIZED CACHE: current state, reconstructable from observations CREATE TABLE IF NOT EXISTS entries ( fingerprint TEXT PRIMARY KEY, source_id TEXT NOT NULL, source_path TEXT, project TEXT, content_type TEXT, title TEXT, summary TEXT, first_seen TEXT, last_seen TEXT, ref_count INTEGER DEFAULT 1, last_confidence REAL DEFAULT 0.5 ); CREATE INDEX IF NOT EXISTS idx_entries_project ON entries(project); CREATE INDEX IF NOT EXISTS idx_entries_source ON entries(source_id); CREATE INDEX IF NOT EXISTS idx_entries_seen ON entries(last_seen); -- PROVENANCE LINKS: multi-hop lineage between entries CREATE TABLE IF NOT EXISTS provenance_links ( id INTEGER PRIMARY KEY AUTOINCREMENT, descendant_fp TEXT NOT NULL, ancestor_fp TEXT NOT NULL, hop_distance INTEGER NOT NULL, relation TEXT NOT NULL, created_at TEXT DEFAULT (datetime('now')) ); CREATE INDEX IF NOT EXISTS idx_pl_descendant ON provenance_links(descendant_fp); CREATE INDEX IF NOT EXISTS idx_pl_ancestor ON provenance_links(ancestor_fp); -- REFLECTION STATE: per-session tracking CREATE TABLE IF NOT EXISTS sessions ( session_id TEXT PRIMARY KEY, project TEXT, title TEXT, status TEXT DEFAULT 'active', agent_count INTEGER DEFAULT 0, started_at TEXT, ended_at TEXT, last_seen TEXT DEFAULT (datetime('now')), indexed INTEGER DEFAULT 0 ); -- SOURCE REGISTRY CREATE TABLE IF NOT EXISTS sources ( id TEXT PRIMARY KEY, name TEXT NOT NULL, enabled INTEGER DEFAULT 1, last_event TEXT, created_at TEXT DEFAULT (datetime('now')) ); INSERT OR IGNORE INTO sources (id, name) VALUES ('opencode-session', 'Opencode Session Diffs'); INSERT OR IGNORE INTO sources (id, name) VALUES ('opencode-log', 'Opencode Log Files'); INSERT OR IGNORE INTO sources (id, name) VALUES ('git', 'Git History'); INSERT OR IGNORE INTO sources (id, name) VALUES ('filesystem', 'File System Watcher'); -- KNOWLEDGE THREADS: why observations exist, what questions they answer CREATE TABLE IF NOT EXISTS threads ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, motivation TEXT, status TEXT DEFAULT 'active', priority TEXT DEFAULT 'medium', created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')), resolved_at TEXT, tags TEXT DEFAULT '[]', provenance TEXT DEFAULT '{}' ); -- SETTINGS: key-value store for runtime configuration CREATE TABLE IF NOT EXISTS settings ( key TEXT PRIMARY KEY, value TEXT ); CREATE INDEX IF NOT EXISTS idx_threads_status ON threads(status); CREATE TABLE IF NOT EXISTS thread_observations ( thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, observation_id INTEGER NOT NULL REFERENCES observations(id) ON DELETE CASCADE, relevance TEXT, added_at TEXT DEFAULT (datetime('now')), PRIMARY KEY (thread_id, observation_id) ); CREATE TABLE IF NOT EXISTS thread_notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, thread_id INTEGER NOT NULL REFERENCES threads(id) ON DELETE CASCADE, note TEXT NOT NULL, created_at TEXT DEFAULT (datetime('now')) ); -- TOPICS: TF-IDF clustered groups of related observations CREATE TABLE IF NOT EXISTS topics ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, keywords TEXT, score REAL DEFAULT 0, created_at TEXT DEFAULT (datetime('now')) ); `