Der Stand lag ueber eine Bestandsaufnahme, drei Konzeptpapiere, vier Umsetzungsplaene und zwei Deploymentcenter-Dokumente verteilt - jedes mit eigener Reihenfolge, teils widersprueglich. Alle offenen Punkte daraus sind in docs/Roadmap.md zusammengefuehrt. Aufbau der neuen Roadmap - Statusvokabular: erledigt / beschlossen-offen / Entscheidung noetig / zurueckgestellt / Idee. Damit steht das Geparkte sichtbar drin, statt in einem Konzeptpapier zu verschwinden. - Herkunft-Spalte traegt das alte Kuerzel (S4, K2, B9, T4, F-A1, C1, DC1), damit die archivierten Papiere auffindbar bleiben, ohne sie zu lesen. - Abschnitt 1 Reihenfolge, 2 offene Entscheidungen, 3 die Vorhaben nach Bereich, 4 Ideenspeicher, 5 Chronik des Erledigten, 6 Modell-Einstufung, 7 Herkunftskarte. Was dabei sichtbar wurde - Neun Entscheidungen blockieren Arbeit, ohne dass sie Aufwand kosten - allen voran Matrix oder Rocket.Chat. Sie stehen jetzt gesammelt in Abschnitt 2 statt verstreut in den Diskussionsteilen der Konzepte. - B8 (keine Tiefenbegrenzung bei AgentComm) ist unveraendert offen. Das ist keine Theorie: A haelt sein Gate, waehrend es auf B wartet - ruft B nun A, warten beide bis zum Timeout. Der Testfall A13 dafuer fehlt bis heute. - Die vier Umsetzungsplaene vom 2026-08-05 sind alle unumgesetzt und waren in keiner Roadmap verzeichnet. Archiv Sechs Dokumente ziehen nach docs/archiv/: Bestandsaufnahme, Konzepte Backup/Finanz/Analyse, Linux-Portierung-Analyse, Lizenz-HardwareId-v2 (gegenstandslos - LicenseLabrador ist ersetzt), Deploymentcenter-Review und der 2.4-Integrationsplan. Sie bleiben als Begruendung lesbar, werden aber nicht mehr fortgeschrieben; das README ordnet jedes einzeln ein und warnt, dass ihre Quelltext-Verweise ins Leere gehen koennen. Bauplan bleibt Bauplan Taskboard, Audit, Staging, Memory, Agentenkommunikation, RocketChat und Deploymentcenter-Integration bleiben in docs/ - sie sind die Detailvorgabe fuer die Umsetzung, nicht Vorhabenlisten. Jedes bekommt oben eine Zeile, die seine Rolle und den Umsetzungsstand nennt und auf die Roadmap zeigt. Dasselbe fuer die vier Umsetzungsplaene: die Reihenfolge gilt in der Roadmap, nicht im Plan. Nebenbei repariert: Taskboard-Konzept und Teststrategie verwiesen auf AgentScheduler und ToolJobScheduler, die seit der Scanner-Konsolidierung geloescht sind. Alle Dokument-Verweise in docs/ sind geprueft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
95 lines
4.4 KiB
Markdown
95 lines
4.4 KiB
Markdown
# 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).
|