-- Festinger schema -- Run once at container init via db.py:init_schema() -- --------------------------------------------------------------------------- -- models — LLM provider configuration -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS models ( id SERIAL PRIMARY KEY, provider VARCHAR(32) NOT NULL, -- 'claude' or 'openai' model_name VARCHAR(128) NOT NULL, api_key TEXT NOT NULL DEFAULT '', created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- --------------------------------------------------------------------------- -- config — runtime key-value configuration -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS config ( key VARCHAR(64) PRIMARY KEY, value TEXT NOT NULL, updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); INSERT INTO config (key, value) VALUES ('saliency_read_threshold', '0.5'), ('saliency_write_threshold', '1.2'), ('recollection_confidence_floor','0.6'), ('recollection_recency_days', '90'), ('resolution_schedule', '0 2 * * *'), ('write_model_id', ''), ('resolve_model_id', '') ON CONFLICT (key) DO NOTHING; -- --------------------------------------------------------------------------- -- soas — concept vocabulary and saliency -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS soas ( id SERIAL PRIMARY KEY, token VARCHAR(256) UNIQUE NOT NULL, encounter_count INT NOT NULL DEFAULT 0, last_seen TIMESTAMPTZ, saliency FLOAT NOT NULL DEFAULT 0.0, novelty FLOAT NOT NULL DEFAULT 0.0 ); CREATE INDEX IF NOT EXISTS soas_token_idx ON soas (token); -- --------------------------------------------------------------------------- -- urd — acyclic concept graph (the IN table) -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS urd ( id INT NOT NULL REFERENCES soas(id), parent_id INT NOT NULL REFERENCES soas(id), dim_id INT NOT NULL REFERENCES soas(id), is_isa BOOLEAN NOT NULL DEFAULT false, confidence FLOAT NOT NULL DEFAULT 1.0, last_confirmed TIMESTAMPTZ NOT NULL DEFAULT now(), source VARCHAR(32) NOT NULL DEFAULT 'cloud_llm', PRIMARY KEY (id, parent_id, dim_id) ); -- One parent per concept per dimension — contradiction-resistance mechanism CREATE UNIQUE INDEX IF NOT EXISTS urd_concept_dim_idx ON urd (id, dim_id); -- --------------------------------------------------------------------------- -- resolution_queue — pending conflicts waiting for nightly resolution -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS resolution_queue ( id SERIAL PRIMARY KEY, concept_id INT NOT NULL REFERENCES soas(id), existing_parent_id INT NOT NULL REFERENCES soas(id), incoming_parent_id INT NOT NULL REFERENCES soas(id), dim_id INT NOT NULL REFERENCES soas(id), collision_type VARCHAR(32) NOT NULL, -- 'isa_isa', 'ispart_ispart', 'misclassification' status VARCHAR(16) NOT NULL DEFAULT 'pending', resolution JSONB, priority BOOLEAN NOT NULL DEFAULT false, -- gutask conflicts reviewed first created_at TIMESTAMPTZ NOT NULL DEFAULT now(), resolved_at TIMESTAMPTZ ); CREATE INDEX IF NOT EXISTS rq_status_idx ON resolution_queue (status); CREATE INDEX IF NOT EXISTS rq_concept_idx ON resolution_queue (concept_id); -- --------------------------------------------------------------------------- -- kg_write_log — immutable audit log of every knowledge graph write -- --------------------------------------------------------------------------- -- op values: -- 'insert' — new URD edge written for the first time -- 'rewrite' — existing edge replaced (ispart_ispart update) -- 'decompose' — isa_isa collision resolved by splitting into two dimensions -- 'reclassify' — concept re-inserted in the correct dimension CREATE TABLE IF NOT EXISTS kg_write_log ( id SERIAL PRIMARY KEY, op VARCHAR(16) NOT NULL, concept_id INT NOT NULL REFERENCES soas(id), concept_token TEXT NOT NULL, parent_id INT NOT NULL REFERENCES soas(id), parent_token TEXT NOT NULL, prev_parent_id INT REFERENCES soas(id), prev_parent_token TEXT, dim_id INT NOT NULL REFERENCES soas(id), dim_token TEXT NOT NULL, is_isa BOOLEAN NOT NULL DEFAULT false, confidence FLOAT NOT NULL DEFAULT 1.0, source VARCHAR(32) NOT NULL DEFAULT 'cloud_llm', resolution_queue_id INT REFERENCES resolution_queue(id), created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS kwl_created_idx ON kg_write_log (created_at DESC); CREATE INDEX IF NOT EXISTS kwl_concept_idx ON kg_write_log (concept_id); CREATE INDEX IF NOT EXISTS kwl_op_idx ON kg_write_log (op); -- --------------------------------------------------------------------------- -- agent_models — per-agent LLM model assignments -- Maps an agent identity (from X-Agent-Name header) to a specific model. -- Priority over write_model_id (global default) when agent_name is present. -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS agent_models ( agent_name TEXT PRIMARY KEY, -- normalised lowercase, e.g. 'gunnar', 'rind' model_id INT NOT NULL REFERENCES models(id) ON DELETE CASCADE, created_at TIMESTAMPTZ NOT NULL DEFAULT now() );