// Answers whose citations pointed at nothing. // // The Prometheus counters say how often it happens; this says what happened, // so an admin can read the question and the sources and judge whether the // retrieval came back thin or the model over-cited. // // Only answers with at least one unverifiable citation are stored — this is a // quality signal, not a transcript log — and rows expire, because the question // text is clinical material and should not accumulate indefinitely. exports.up = pgm => { pgm.sql(` CREATE TABLE IF NOT EXISTS citation_audit ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id) ON DELETE SET NULL, question TEXT NOT NULL DEFAULT '', cited_count INTEGER NOT NULL DEFAULT 0, source_count INTEGER NOT NULL DEFAULT 0, -- The numbers the model wrote that no source matched. unverifiable INTEGER[] NOT NULL DEFAULT '{}', -- Titles of what retrieval actually returned, so the two can be compared -- without keeping the passages themselves. source_titles TEXT[] NOT NULL DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), expires_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + INTERVAL '30 days' ); CREATE INDEX IF NOT EXISTS idx_citation_audit_created ON citation_audit(created_at DESC); CREATE INDEX IF NOT EXISTS idx_citation_audit_expires ON citation_audit(expires_at); `); }; exports.down = pgm => { pgm.sql('DROP TABLE IF EXISTS citation_audit;'); };