# Audit-Log & Receipts — Nachvollziehbarkeit > **Bauplan zu einem gebauten System.** Umgesetzt; der Stand steht in der > [Roadmap](Roadmap.md) 3.1. Setzt A3 aus der [Roadmap](Roadmap.md) um (F-A2). Zwei zusammengehörige Dinge: - **Audit-Log** — ein Eintrag je Tool-Aufruf: wer, wann, welches Tool, mit welchem Ausgang. - **Receipts** — ein Abschluss-Beleg je Lauf: Ergebnis, Schritte, Tokens, Kosten, verknüpft mit dem Task. A3 ist das Fundament für A2 (jede Staging-Entscheidung wird als Datensatz verankert) und für C7 („Kosten pro Ergebnis", fällt aus den Receipts ab). Die Tool-Fehlerquote aus der Leistungsanalyse liest sich direkt aus dem Log. ## Warum eigene Tabellen, nicht der State-Store Dieselbe Überlegung wie bei Gedächtnis und Taskboard: `IStateStore` ist Schlüssel-Wert. Ein Log, das man nach Lauf, Task oder Tool filtern und dessen Fehlerquote man auswerten will, braucht typisierte Spalten. Zwei Tabellen auf dem vorhandenen [`SqliteStorage`](../src/ClawdDotNet.Core/Storage/SqliteStorage.cs): `AuditLog` und `RunReceipts`. ## Provenienz — von der Engine gestempelt, nie vom Agenten behauptet Die entscheidende Regel (aus dem OpenAlice-Provenance-Konzept): - **Herkunft stempelt die Engine.** `AgentId`, `Model` und `Source` kommen aus dem Wissen der Engine über den Lauf, nicht aus dem Tool-Ergebnis. Ein Tool kann seine Herkunft nicht fälschen, weil es sie gar nicht schreibt. - **Einträge sind unveränderlich.** Das Repository hat kein Update und kein Delete — eine Korrektur ist ein neuer Eintrag. Das ist die eigentliche Zusage, keine fehlende Funktion. - **Unbekanntes wird als unbekannt markiert, nicht geraten.** Fehlt die Quelle, steht `unknown`, nicht ein plausibel geratener Kanal. - **Worker-Typ und Session sind getrennt.** `Model` (das ausführende Modell) und `Source` (die verantwortliche Session: `webview`, `telegram`, `task`, `agentcomm`, `job`, `direct`) sind verschiedene Begriffe und stehen in eigenen Spalten. ## Audit-Log Gestempelt an genau einer Stelle: `AgentEngine.ExecuteToolCallAsync` — dort, wo jeder Tool-Aufruf durchläuft. Je Aufruf ein Eintrag mit Ausgang: | Status | Wann | |---|---| | `Ok` | Tool lief und lieferte ein Ergebnis | | `Error` | Tool meldete einen Fehler oder warf | | `Denied` | das `PermissionGate` hat abgelehnt | | `NotFound` | Tool dem Agenten nicht zugewiesen/unbekannt | Ein Abbruch (Cancellation) wird **nicht** protokolliert — der Aufruf kam nicht zum Abschluss. Die Argumente werden roh, aber gekappt abgelegt (4 000 Zeichen); die Ausgangsnotiz kurz (500). **Best effort:** Ein Fehler beim Schreiben des Audits darf den Lauf nie scheitern lassen — dieselbe Linie wie bei der Verbrauchserfassung. Der Eintrag wird geschrieben, nachdem die eigentliche Arbeit getan ist. ## Receipts Je Lauf ein Beleg, geschrieben beim Abschluss von `RunAsync`/`ChatAsync` (neben der vorhandenen `RunUsage`-Erfassung). Er trägt Status, Schritte, Prompt-/Completion-/ Cached-Tokens, geschätzte Kosten (aus dem `ModelPricingCatalog`, mit `CostIsKnown`-Flag) und einen kurzen Ergebnis-Verweis. **Verknüpfung `RunUsage` ↔ Task:** Der Receipt trägt die `TaskId`, wenn der Lauf aus dem Taskboard kam — der `EngineTaskDispatcher` reicht sie (samt `source: task`) durch. Damit ist „Kosten pro Ergebnis" (C7) ein Abfallprodukt: `ListReceiptsForTaskAsync` liefert alle Belege zu einem Task. ## RunId — die Klammer Jeder Lauf bekommt zu Beginn eine `RunId` (GUID). Alle Audit-Einträge **und** der Receipt eines Laufs tragen sie. So lässt sich ein Lauf lückenlos rekonstruieren: `ListForRunAsync(runId)` gibt die Aufrufe in Reihenfolge, `GetReceiptForRunAsync(runId)` den Abschluss. ## Verdrahtung `IAuditRepository` ist optional (wie Gedächtnis und Taskboard): ohne Repo läuft die Engine unverändert. In `Program.cs` wird ein `SqliteAuditRepository` auf der Instanz-DB erzeugt und der Engine übergeben. ## Offen - **Output-Scrubbing** — die `Arguments` können Secrets enthalten. Das zentrale Maskieren bekannter Secret-Werte (eigener beschlossener Roadmap-Punkt) greift, sobald es steht; der Andockpunkt (`ExecuteToolCallAsync`) ist derselbe. - **Review-Oberfläche** — die Anzeige/Durchsicht des Logs und der Receipts gehört zu A2 (Staging-Review im Hauptfenster); die Abfragemethoden dafür stehen bereit. - **Export** — ein JSONL-Export des Logs wäre für externe Auswertung nützlich (später, passt zum A6-Spiegel).