diff --git a/migrations/1780200000000_citation-audit.js b/migrations/1780200000000_citation-audit.js new file mode 100644 index 00000000..e8723c15 --- /dev/null +++ b/migrations/1780200000000_citation-audit.js @@ -0,0 +1,34 @@ +// 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;'); +}; diff --git a/public/components/admin.html b/public/components/admin.html index 3d0f3ccb..564a0b7e 100644 --- a/public/components/admin.html +++ b/public/components/admin.html @@ -97,32 +97,32 @@
Configure OpenID Connect for SSO with Azure AD, Okta, Keycloak, PocketID, Google, etc.
Callback URL: