-- Suchprotokoll: Was Agenten mit "recall" suchen und ob sie etwas finden. -- -- ── Warum? ─────────────────────────────────────────────────────────────────── -- -- Ohne diese Zahlen lässt sich nicht beurteilen, ob die Suche gut genug ist. -- Eine Suche ohne Treffer ist das deutlichste Zeichen: Entweder gibt es das -- Wissen nicht — dann ist die Anfrage ein Hinweis, was fehlt — oder es steht -- unter anderen Wörtern da. Beides will man sehen (AUSBAUSTUFEN.md 3.1). -- -- ── Warum nicht im Zugriffsprotokoll (audit_events)? ───────────────────────── -- -- Gesucht wird viel öfter als geschrieben. Im Zugriffsprotokoll würden die -- Suchen die Schreibvorgänge zudecken, um die es dort geht. Außerdem enthält -- eine Anfrage Inhalt („wie kommt man an das Passwort für …"), und Inhalt hat -- eine kürzere Aufbewahrungsfrist verdient als die 90 Tage des Protokolls: -- Die tägliche Aufräumaufgabe löscht Zeilen nach 30 Tagen -- (store.SearchLogRetention). -- -- ── Aufbau ─────────────────────────────────────────────────────────────────── -- -- Eine Zeile je recall-Aufruf. Bewusst ohne IP-Adresse und ohne Namen: Für -- die Auswertung zählt, WAS gesucht wurde, nicht wer. api_key_id bleibt, damit -- sich ein einzelner Agent mit auffälligem Verhalten eingrenzen lässt. -- -- Die ID ist hier eine fortlaufende Zahl (INTEGER PRIMARY KEY) statt eines -- Zufallswerts wie in den anderen Tabellen: Niemand verweist auf eine -- einzelne Zeile, und eine Zahl ist beim Einfügen am billigsten. -- -- PostgreSQL-Fassung: "INTEGER PRIMARY KEY" zählt nur in SQLite von selbst -- hoch. PostgreSQL braucht dafür ausdrücklich eine Identitätsspalte. BIGINT, -- weil die Zahl nie zurückgesetzt wird, auch wenn alte Zeilen gelöscht werden. -- -- Anders als das Zugriffsprotokoll hängt die Tabelle per Fremdschlüssel am -- Projekt: Wird es gelöscht, verschwinden auch seine Anfragen. Sie sind Inhalt -- des Projekts, kein Nachweis darüber, wer was getan hat. CREATE TABLE search_log ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, ts TEXT NOT NULL, project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE, api_key_id TEXT NOT NULL DEFAULT '', query TEXT NOT NULL, synonyms TEXT NOT NULL DEFAULT '', -- mit Komma getrennt, leer = keine results INTEGER NOT NULL -- Zahl der ausgegebenen Treffer ); CREATE INDEX idx_search_log_project ON search_log (project_id, ts);