Files
ClawdDotNet/docs/Staging-Konzept.md
RichardandClaude Opus 5 2853541629 Fruehjahrsputz: WinForms-Altlast entfernt, Dokumentation nachgezogen
Die Avalonia-Portierung ist abgeschlossen, damit ist die in ClawdDotNet.slnx
angekuendigte Aufgabe "WinForms-Oberflaeche entfernen" faellig. Der Stand
davor liegt unter dem Tag vor-fruehjahrsputz-2026-08.

Entfernt (56 Dateien, seit dem Herausloesen der Anwendungsschicht nicht mehr
Teil des Builds): ClawdDotNet.csproj, Program.cs, sieben frm_*-Formulare,
UI/, Models/, EmbeddedUI/, Properties/, Resources/, Services/, das alte
Anwendungssymbol und Deploy-Build.ps1 (ersetzt durch deploy/publish.py).
Dazu configs/*.json - Beispielkonfigurationen aus der Zeit vor dem
Instanzverzeichnis, auf die nur noch die alten Prompts verwiesen.

Die vier Entwicklungs-Prompts der Anfangszeit ziehen nach docs/archiv/ um,
mit README, das ihren Stand einordnet. Eine Regel darin gilt weiter - die
Pflichtfelder fetchedAt/dataAsOf/source der Internet-Tools -, deshalb
Archiv statt Loeschen; der WebSearch-Plan verweist auf den neuen Pfad.

Toter Code
- PlaceholderPageViewModel samt Ansicht: Es gibt keinen Platzhalter-Bereich
  mehr, seit alle neun Seiten portiert sind.
- Snappier als direkter Paketverweis: MongoDB.Driver loest es ohnehin auf
  dieselbe Fassung auf, der Verweis hob nichts an.

Zwei Fehler, die dabei sichtbar wurden
- Die taegliche Sicherung lief ins Leere. Die Oberflaeche bot sie an und
  schrieb Uhrzeit, Zielordner und Anzahl in die Einstellungen, aber der
  BackupScheduler wurde nirgends erzeugt. Jetzt am AppHost verdrahtet und
  in den geordneten Abbau aufgenommen.
- SettingsPageViewModel hielt die vier Sicherungs-Einstellungen doppelt.
  Aus der Ansicht waren sie laengst verschwunden, gelesen und beim
  Speichern zurueckgeschrieben wurden sie weiter: Wer die Uhrzeit auf der
  Sicherungs-Seite aenderte und danach die Einstellungen speicherte, bekam
  den alten Wert zurueck.

Pakete: keine bekannten Sicherheitsluecken mehr
- SQLitePCLRaw.bundle_e_sqlite3 auf 2.1.13 angehoben. Microsoft.Data.Sqlite
  bringt 2.1.11 mit, darin steckt GHSA-2m69-gcr7-jv3q (NU1903, hoch).
- SharpCompress bleibt als direkter Verweis stehen. Beim Aufraeumen erst
  als ungenutzt entfernt - dabei kam die von MongoDB.Driver gezogene
  Fassung 0.30.1 mit GHSA-6c8g-7p36-r338 zurueck. Der Verweis ist eine
  Anhebung, kein Ballast; das steht jetzt als Kommentar dabei.

Dokumentation
- Roadmap mit Statusblock: A1 und A3 erledigt, A2 nur zur Haelfte - Gate,
  Policy und Dienst greifen, aber keine Ansicht ruft ApproveAsync auf, ein
  gestagter Aufruf liegt unbeantwortet. Das ist jetzt Punkt 1 der Reihung.
  Rocket.Chat steht und kollidiert mit A5 (Matrix) - Entscheidung faellig.
- Avalonia-Portierungsleitfaden -> Oberflaechen-Leitfaden: kein Auftrag mehr,
  sondern Beschreibung des Stands.
- Bestandsaufnahme und Linux-Analyse als datierte Befunde gekennzeichnet;
  der teure Teil der Linux-Analyse (8.900 Zeilen WinForms) ist hinfaellig.
- Verweise auf frm_*, WebView2 und ClawdDotNet.csproj in den lebenden
  Dokumenten richtiggestellt.

Build fehlerfrei, 585 Tests gruen (6 uebersprungen).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:26:14 +02:00

5.1 KiB

Staging-Freigabe für irreversible Aktionen

Setzt A2 aus der Roadmap um (F-A1 + S4). Irreversible Aktionen werden gestaged statt ausgeführt: Vorschlag → Review im Hauptfenster → Freigabe/Ablehnung. Aufbauend auf dem Taskboard (A1, Fortsetzung nach Freigabe) und dem Audit-Log (A3, Approval-Records).

Sicherheitswirkung: Eine Prompt-Injection (K2) kann dann nur noch einen Vorschlag erzeugen, keine Ausführung.

Das Gate wird zum Durchsetzungspunkt (S4)

Das bisher wirkungslose PermissionGate (es prüfte nur, ob ein Tool zugewiesen ist) wird zur zentralen Stelle: Policy-Prüfung, Staging-Entscheidung und Audit-Hook an einer Stelle (AgentEngine.ExecuteToolCallAsync), statt ad-hoc in jedem Tool. S4 geht hier auf.

Policy: auto | approve | deny pro Tool/Aktion

Je (Tool, Aktion) eine Entscheidung:

  • auto — läuft wie bisher.
  • approve — wird gestaged; die Ausführung wartet auf eine menschliche Freigabe.
  • deny — wird gar nicht erst vorgeschlagen, sondern abgelehnt.

Auflösung vom Speziellen zum Allgemeinen: Tool.AktionTool → Standard (auto). Die „Aktion" ist das action-Argument des Aufrufs (die meisten Tools haben es).

Eingebaute Standardregeln (nach Sichtung der Tools, überschreibbar per Konfiguration) — genau die in der Roadmap genannten irreversiblen Aktionen:

Tool.Aktion Standard
Mail.send approve
Telegram.send_message approve
Database.insert, Database.upsert approve
FileRW.delete approve
FTP.upload, FTP.delete approve
alles andere auto

Lesende Aktionen (Mail.read_inbox, FileRW.read, Database.query, …) bleiben auto — Staging soll schützen, nicht lähmen.

Plan-Freeze

Freigegeben wird ein eingefrorener, konkreter Aufruf: Tool, Aktion und die exakten Argumente zum Zeitpunkt des Stagings. Ausgeführt wird genau das Eingefrorene (der gespeicherte Argument-JSON), nie eine nachträglich veränderte Fassung. Jede Änderung wäre eine neue Freigabe.

Das ist auch der Grund, warum der Agent den Aufruf nicht nach der Freigabe erneut formuliert (er könnte etwas anderes bauen) — der eingefrorene JSON wird direkt an das Tool gegeben.

Fortsetzung nach Freigabe — kein pausierter Lauf

Die tragende Architektur-Vorgabe (aus der Roadmap-Einstufung): Kein pausierter, im Speicher gehaltener Lauf. Der Ablauf:

  1. Vorschlag. Der Agent ruft eine approve-Aktion auf. Das Gate führt sie nicht aus, sondern legt einen Pending-Datensatz an (eingefrorener Aufruf) und gibt dem Agenten „Zur Freigabe vorgelegt (#id)" als Tool-Ergebnis zurück. Der Lauf endet regulär — der Agent schließt ab, nichts hängt im Speicher.
  2. Review. Ein Mensch sieht die offenen Vorschläge im Hauptfenster und entscheidet. 3a. Freigabe. Der eingefrorene Aufruf wird direkt ausgeführt (standalone, nicht über einen Chat-Lauf). Das Ergebnis wird festgehalten, und ein Folge-Task (A1) weckt den Agenten: „Deine Aktion X wurde freigegeben und ausgeführt, Ergebnis: Y — mach weiter." Der Scanner stellt ihn zu (ChatAsync, bestehender Kontext). 3b. Ablehnung. Ein Folge-Task weckt den Agenten mit der Ablehnung (samt Grund).

Echtes Suspend/Resume eines laufenden ChatAsync wäre Fable-Terrain — und ist mit dieser Vereinfachung unnötig.

Approval-Records (A3)

Jede Entscheidung — Freigabe wie Ablehnung — wird an zwei Stellen verankert:

  • Im Staging-Datensatz selbst: Status, DecidedBy, DecidedAt, Ergebnis-Verweis bzw. Ablehnungsgrund.
  • Als Audit-Eintrag (A3): Tool, Ausgang, source: approval, „Freigegeben von …" bzw. „Abgelehnt von …". Die Herkunft stempelt auch hier das System, nicht der Agent.

Der Vorschlag selbst wird beim Anlegen als Audit-Eintrag mit Status Staged notiert — so ist die ganze Kette (Vorschlag → Entscheidung → Ausführung) im Log nachvollziehbar.

Nebenläufigkeit

Zwei Reviewer dürfen nicht denselben Vorschlag doppelt freigeben. Der Übergang pending → approved/rejected ist ein atomares, bedingtes UPDATE (dieselbe Claim-Technik wie beim Taskboard): Genau einer gewinnt, der zweite Klick läuft ins Leere. Erst nach gewonnenem Übergang wird der eingefrorene Aufruf ausgeführt.

Verdrahtung

  • StagingGate (Policy + Anlegen des Vorschlags) hängt optional an der Engine — ohne es läuft alles wie bisher (auto).
  • Der eingefrorene Aufruf wird über IFrozenCallExecutor (von der Engine implementiert) ausgeführt: gültiger Tool-Kontext, aber ohne LLM-Schleife.
  • StagingService (Freigabe/Ablehnung) nutzt Executor, Audit und das Taskboard für den Folge-Task. Es ist die API, die die Review-Oberfläche aufruft.

Offen

  • Review-Oberfläche im Hauptfenster (Liste der offenen Vorschläge, Freigeben/Ablehnen) — die Dienst-API steht bereit; die Freigabe-Ansicht in src/ClawdDotNet.Desktop ist die verbleibende Integration und der einzige offene Punkt von A2.
  • Output-Scrubbing greift auch hier auf den gespeicherten Argument-JSON, sobald es steht (eigener Roadmap-Punkt).
  • Orders (Handelsaufträge) reihen sich später als weitere approve-Aktionen ein.