# Retry-Logging für KI-Agenten, das doppelte Seiteneffekte sichtbar macht

Ein Retry des Agenten ist keine zweite Kopie einer Aktion. Es ist ein zweiter Versuch, eine deklarierte Aktion abzuschließen, und der Audit-Trail muss diesen Unterschied bewahren. Wenn deine Aufzeichnungen nur eine Reihe ähnlicher HTTP-Aufrufe zeigen, sehen Wiederherstellung und Wiederholung gleich aus.

Diese Lücke ist besonders wichtig, wenn eine Aktion die Außenwelt verändert: ein Ticket erstellen, Zugriff entziehen, eine Zahlung auslösen, ein Deployment veröffentlichen oder einen Befehl über SSH ausführen. Der Agent kann ein Timeout erhalten, nachdem das Ziel bereits gehandelt hat. Er kann aber auch nach einem lokalen Fehler erneut versuchen, bevor überhaupt Bytes den Rechner verlassen haben. Diese Fälle erfordern unterschiedliche Reaktionen. Trotzdem schreiben zu viele Systeme beide als `request failed, retrying`.

Ich habe Teams erlebt, die mutmaßlich doppelte Aktionen untersuchten, indem sie Zeitstempel und Payloads manuell verglichen. Das ist ein schlechter Ersatz für ein Ereignismodell. Baue die Beziehung in jeden Datensatz ein, sobald die Aktion stattfindet. Ein Ermittler sollte eine Operation auswählen und ihre Absicht, jeden Versuch, den Grund für jeden späteren Versuch und das Ergebnis sehen können, das die Frage schließlich klärt.

## Ein Retry gehört zu einer Operation, nicht zu einer Logzeile

Jede Agentenaktion mit Seiteneffekt braucht zwei Identitäten: eine Operations-ID für das beabsichtigte Ergebnis und eine Versuchs-ID für einen einzelnen Ausführungsversuch. Die Operations-ID bleibt von dem Moment an bestehen, in dem der Agent entscheidet, was er tun will, bis du diese Absicht abschließt oder abgleichst. Jeder Netzwerkaufruf und jede SSH-Ausführung erhält eine neue Versuchs-ID.

Angenommen, ein Agent will ein Konto deaktivieren. Er erstellt die Operation `op_7f2c`. Die erste Anfrage, `att_01`, erreicht die Identitäts-API, aber die Verbindung wird geschlossen, bevor eine Antwort eintrifft. Eine zweite Anfrage, `att_02`, kann ein begründeter Wiederherstellungsversuch sein. Beide Datensätze müssen auf `op_7f2c` verweisen. `att_02` muss außerdem direkt auf `att_01` als den auslösenden Versuch verweisen.

Verwende nicht die Konversations-ID als Operations-ID. Eine Agentenkonversation kann viele Aktionen enthalten, und eine Aktion kann eine Konversation überdauern, wenn ein Supervisor die Arbeit wieder aufnimmt. Verwende auch nicht ausschließlich einen Anfrage-Hash. Ein Hash beschreibt Bytes, eine Operation beschreibt den beabsichtigten Effekt. Zwei Anfragen können sich in harmlosen Transportdetails unterscheiden und trotzdem zu einer Operation gehören. Umgekehrt können identische Bytes zwei verschiedene beabsichtigte Aktionen auslösen, wenn der Agent sie bewusst zweimal sendet.

Verwende eine Operationsidentität, sobald der Agent eine Verpflichtung bildet, etwa «Konto A deaktivieren», «einen Vorfall für Alarm B erstellen» oder «diese Migration einmal auf Host C ausführen». Halte diese Absicht in strukturierten Feldern fest. Eine Zusammenfassung in natürlicher Sprache hilft Menschen, darf aber nicht die alleinige Identität sein, weil sich die Formulierung zwischen Agentenläufen verändert.

Eine klare Hierarchie sieht so aus:

- Eine Sitzung identifiziert einen Lauf eines Agentenprozesses.
- Eine Operation identifiziert einen beabsichtigten externen Effekt.
- Ein Versuch identifiziert einen tatsächlichen Ausführungsversuch.
- Eine Beobachtung identifiziert später erhaltene Belege, etwa einen Callback, eine Prüfung nach dem Schreiben oder eine Entscheidung eines Operators.

Diese Hierarchie löst einen häufigen Sonderfall: Ein Agent sendet eine Anfrage, läuft in einen Timeout und fragt anschließend einen anderen Endpunkt, ob die Aktion stattgefunden hat. Die Abfrage ist kein Retry. Sie ist eine Beobachtung, die an die ursprüngliche Operation angehängt wird. Wenn du sie als weiteren Versuch behandelst, landen die wichtigsten Belege im falschen Bereich.

## Unbekannt ist ein Ergebnis, keine Fehlermeldung

Ein Timeout erzeugt Unsicherheit, keinen Beweis für einen Fehlschlag. Dein Log braucht einen Zustand für diese Unsicherheit und muss ihn bewahren, bis spätere Belege sie auflösen.

Viele Clientbibliotheken fassen mehrere Ereignisse in einer Ausnahme zusammen: abgelehnte Verbindung, DNS-Fehler, ein zu spät eingetroffener Antwort-Body und eine Verbindungsunterbrechung, nachdem der Server bereits geschrieben hat. Für den Kontrollfluss der Anwendung ist diese Vereinfachung in Ordnung. Als endgültiger Audit-Datensatz ist sie nicht akzeptabel. Die Aufzeichnungen müssen festhalten, was der Aufrufer beobachtet hat, und dürfen keine Aussagen über das Ziel machen, die der Aufrufer nicht belegen kann.

Trenne bei einem Versuch die lokale Beobachtung vom aufgelösten Operationszustand. Ein Versuch kann `not_sent`, `sent_no_response`, `response_received` oder `execution_error` sein. Die Operation kann `open`, `succeeded`, `failed`, `unknown` oder `cancelled` sein. Die Namen können variieren, die Trennung nicht.

`not_sent` bedeutet, dass der Client vor dem Versand angehalten hat. Ein lokaler Fehler beim Abrufen von Zugangsdaten kann hierher gehören. Ein Retry kann keinen entfernten Seiteneffekt duplizieren, weil keine Anfrage das Ziel erreicht hat.

`sent_no_response` bedeutet, dass der Aufrufer die Aktion versendet hat, aber keine verwertbare Antwort besitzt. Das ist der gefährliche Zustand. Ein automatischer Retry ist nur dann sicher, wenn das Ziel über einen zuverlässigen Mechanismus zur Deduplizierung verfügt oder die Aktion selbst keinen doppelten Effekt erzeugen kann.

`response_received` bedeutet nicht automatisch Erfolg. Ein Server kann einen Validierungsfehler, eine Konfliktantwort oder eine Erfolgsantwort zurückgeben, die eine asynchrone Arbeit beschreibt. Speichere den Status, einen relevanten Antwort-Fingerprint und jede vom Ziel vergebene Operationsreferenz. Setze den Operationszustand anschließend anhand des Vertrags der jeweiligen API.

Vermeide `failed`, wenn du `unknown` meinst. Das Wort macht Dashboards übersichtlich, sagt dem nächsten Agenten oder Operator aber, er solle eine Aktion wiederholen, die möglicherweise bereits stattgefunden hat. Während eines Vorfalls kann dieses eine unehrliche Feld aus einer einzelnen falschen Aktion eine ganze Serie machen.

## HTTP-Semantik macht eine Geschäftsaktion nicht sicher wiederholbar

HTTP-Methoden beschreiben Protokollsemantik, nicht deine geschäftlichen Garantien. RFC 9110 bezeichnet eine Methode als idempotent, wenn der beabsichtigte Effekt mehrerer identischer Anfragen dem Effekt einer einzelnen Anfrage entspricht. PUT, DELETE und die sicheren Methoden gelten als idempotent, POST dagegen standardmäßig nicht.

Diese Vorgabe ist nützlich, wird aber von Entwicklern oft überdehnt. Eine DELETE-Anfrage kann auf Protokollebene idempotent sein, weil das Löschen einer nicht vorhandenen Ressource sie weiterhin nicht vorhanden sein lässt. Deine Auditfrage kann trotzdem anders lauten: Hat der Agent das richtige Konto gelöscht? Hat er eine nachgelagerte Bereinigung zweimal ausgelöst? Wurde beim zweiten Aufruf eine andere Berechtigung verwendet? Das Protokolllabel beantwortet diese Fragen nicht.

Auch PUT kann Probleme verursachen. Ein PUT, der eine Ressource auf eine feste Darstellung setzt, toleriert Retries häufig. Ein PUT-Endpunkt, der bei jedem Eingang eine Benachrichtigung auslöst, einen Datensatz anlegt oder eine Integration startet, bietet die angenommene Sicherheit nicht. Lies den dokumentierten Vertrag des Ziels und teste das Verhalten bei einem erzwungenen Verlust der Antwort. Methodennamen sind keine Belege.

POST-Endpunkte unterstützen oft ein Idempotenz-Token. Sende ein stabiles Token, das aus der Operations-ID abgeleitet ist, nicht aus der Versuchs-ID. Wenn `att_01` und `att_02` unterschiedliche Tokens haben, hast du genau die Funktion ausgehebelt, die dich vor dem Retry schützen soll.

Ein Anfrage-Umschlag kann so aussehen:

```json
{
  "operation_id": "op_7f2c9c",
  "attempt_id": "att_01",
  "idempotency_key": "op_7f2c9c",
  "intent": {
    "kind": "disable_account",
    "subject_ref": "user:1842"
  },
  "destination": {
    "method": "POST",
    "route_template": "/v1/accounts/{id}/disable",
    "authority_ref": "vault:identity-prod"
  },
  "request_fingerprint": "sha256:...",
  "dispatch_state": "sent_no_response"
}
```

Protokolliere weder den Authorization-Header noch Session-Cookies, privates SSH-Material oder einen Body mit Geheimnissen. Speichere eine Zugangsdatenreferenz und einen Fingerprint der kanonischen Anfrage-Darstellung. Ein Fingerprint hilft Ermittlern, Versuche zu vergleichen, ohne den Audit-Trail in einen weiteren Geheimnisspeicher zu verwandeln.

Das Ziel muss das Idempotenz-Token berücksichtigen, damit es wiederholte Effekte verhindert. Wenn es das tut, speichere die vom Ziel zurückgegebene Referenz und ob die Antwort aus einem zuvor gespeicherten Ergebnis stammte. Wenn es das nicht tut, ist das Token nur ein wirkungsloser Header und deine Retry-Regeln müssen sich danach richten.

## Ein SSH-Retry kann mehr als einen Befehl wiederholen

SSH erschwert die Erfassung von Retries, weil eine Verbindung Shell-Syntax, Pipelines, Umleitungen und Befehle enthalten kann, die nur teilweise abgeschlossen werden. Eine fehlgeschlagene SSH-Sitzung zeigt nicht, welche Teile des entfernten Befehls ausgeführt wurden.

Betrachte diesen Befehl:

```sh
create-user deployer \u0026\u0026 install-key deployer /tmp/new.pub \u0026\u0026 restart-service api
```

Wenn der Client nach dem Versand die Verbindung verliert, kann ein Retry scheitern, weil der Benutzer bereits existiert, einen Schlüssel zweimal installieren, wenn der Helfer ihn anhängt, oder einen Dienst ein zweites Mal neu starten. Das `\u0026\u0026` der Shell steuert nur das Verhalten innerhalb einer Ausführung. Es schützt keine neue Verbindung, die die gesamte Zeichenfolge erneut ausführt.

Protokolliere den exakten Befehl nur, wenn er keine Geheimnisse enthält. Andernfalls speichere eine redigierte Anzeigeform und einen kanonischen Fingerprint. Halte das Host-Alias oder die Hostschlüsselreferenz, die Referenz des entfernten Kontos, falls relevant das Arbeitsverzeichnis, den empfangenen Exit-Status und die Ausführungsgrenze fest. Diese Grenze sollte angeben, ob der Helfer den Befehl gestartet und einen Exit-Status erhalten hat, nicht nur, ob der lokale Aufrufer einen Fehler gemeldet hat.

Sicherer ist ein entferntes Skript mit einer Operationsmarkierung, die das Skript prüft, bevor es handelt. Die Markierung muss an einem Ort liegen, den das Zielsystem atomar lesen kann. Je nach Umgebung eignen sich eine Datenbanktransaktion, ein Deployment-Datensatz oder eine Datei, die exklusiv angelegt wird. Ein lokaler Agenten-Cache kann nach einem Prozessabsturz oder einem zweiten Agentenlauf nichts beweisen.

Ein Deployment-Skript kann beispielsweise `OPERATION_ID` akzeptieren, die ID vor der Aktivierung in einen Release-Datensatz schreiben und das vorhandene Ergebnis zurückgeben, wenn der Datensatz bereits existiert. Das Audit-Ereignis enthält dann sowohl die lokale Operations-ID als auch die ID des entfernten Datensatzes. So entsteht eine Brücke zwischen dem Agenten-Datensatz und den Belegen auf dem Host.

Bezeichne beliebige Shell-Befehle nicht als wiederholbar, nur weil sie «meistens sicher» sind. Kategorisiere Befehlsfamilien. Schreibgeschützte Erfassung kann bedenkenlos wiederholt werden. Befehle, die einen Zustand setzen, brauchen eine ausdrückliche Konvergenzbedingung. Befehle zum Anhängen, zu Finanzvorgängen, zur Zerstörung oder zu Benachrichtigungen brauchen einen entfernten Deduplizierungsdatensatz oder nach einem unbekannten Ergebnis eine menschliche Entscheidung.

## Jeder spätere Versuch braucht einen genannten Grund und ein Elternereignis

Ein Retry-Ereignis muss den Versuch nennen, der es ausgelöst hat, und die Bedingung, die einen weiteren Versuch rechtfertigt. `retry_count: 2` ist zu schwach. Es zeigt, dass es frühere Aufrufe gab, identifiziert aber nicht, welcher Aufruf fehlgeschlagen ist, ob der Agent etwas geändert hat oder ob ein Mensch die Fortsetzung genehmigt hat.

Verwende eine kontrollierte Menge von Gründen und hänge zusätzliche Details separat an. Nützliche Gründe sind `connection_not_established`, `rate_limited`, `destination_5xx`, `response_lost_after_dispatch`, `credential_refreshed` und `operator_requested`. Lass einen Agenten keinen beruhigend klingenden Fließtext erfinden, der sich weder gruppieren noch überprüfen lässt.

Bewahre für jeden Retry diese Verknüpfungen auf:

```json
{
  "operation_id": "op_7f2c9c",
  "attempt_id": "att_02",
  "retry_of_attempt_id": "att_01",
  "retry_reason": "response_lost_after_dispatch",
  "retry_decision": "destination_idempotency_confirmed",
  "attempt_budget_remaining": 1,
  "request_fingerprint": "sha256:...",
  "prior_request_fingerprint": "sha256:..."
}
```

Die beiden Fingerprints sollten normalerweise übereinstimmen. Falls sie abweichen, protokolliere den Grund. Ein geänderter Zeitstempel-Header kann erwartbar sein. Eine geänderte Konto-ID, ein anderer Betrag, Hostname, Pfad oder eine andere Berechtigung ist kein gewöhnlicher Retry. Es handelt sich um eine neue Operation oder eine manuell geänderte Absicht, und der Audit-Trail muss das sagen.

Hier täuschen sich Agentensysteme häufig selbst. Das Modell liest einen Fehler, ändert einen Parameter, um ihn zu «beheben», und nennt die nächste Anfrage einen Retry. Das ist eine neue Entscheidung mit einem neuen möglichen Effekt. Wenn du sie als Retry verknüpfst, verschleierst du die Änderung des Plans und machst eine Prüfung fast unmöglich.

Begrenze das Versuchskontingent pro Operation und protokolliere die Entscheidung zum Kontingent. Ein Retry einer Rate-Limit-Antwort nach der vom Ziel angegebenen Wartezeit ist etwas anderes als ein Retry eines unbekannten Schreibvorgangs nach einem Timeout. Im ersten Fall liegt oft eine eindeutige Antwort des Ziels vor. Im zweiten Fall brauchst du vor der Wiederholung einen Idempotenzbeleg oder einen Abgleich.

## Idempotenz-Tokens und Audit-Identitäten erledigen unterschiedliche Aufgaben

Ein Idempotenz-Token weist ein Ziel an, wiederholte Übermittlungen als eine Operation zu behandeln. Eine Audit-Operations-ID zeigt deinen Ermittlern, welche Versuche zu einer Absicht gehören. Verwende beides, wenn möglich, aber behandle niemals eines als Ersatz für das andere.

Das Token kann auf einen Pfad, einen Händler, ein Zeitfenster oder ein bestimmtes Konto begrenzt sein. Manche APIs bewahren Tokens nur für eine bestimmte Zeit auf. Manche geben bei einem Duplikat die ursprüngliche Antwort zurück, andere einen Konflikt. Einige lehnen ein wiederverwendetes Token ab, wenn sich der Anfrage-Body ändert. Diese Details gehören in den Vertrag des Connectors und in deine Tests.

Deine Operations-ID hat eine umfassendere Aufgabe. Sie verbindet die Sitzung des Agenten, Genehmigungsbelege, die Erstellung der Anfrage, Transportversuche, die entfernte Antwort und den späteren Abgleich. Sie sollte auch dann gültig bleiben, wenn eine Anbieter-API keine Idempotenz anbietet, die Aktion über SSH läuft oder ein Operator die endgültige Wiederherstellung manuell durchführt.

Erzeuge nach einem Neustart keine neue Operations-ID, nur weil der Prozessspeicher verschwunden ist. Speichere ausstehende Operationen vor dem Versand. Prüfe bei der Wiederherstellung jede ungelöste Operation und wähle einen von drei Wegen: Abgleich anhand entfernter Belege, Retry unter einer dokumentierten Idempotenzgarantie oder Eskalation an eine Person. Ein Neustart ist ein technisches Ereignis, keine Erlaubnis, Unsicherheit zu vergessen.

Eine beliebte, aber falsche Empfehlung lautet, jeden fehlgeschlagenen Schreibvorgang mit exponentiellem Backoff zu wiederholen. Backoff verringert den Druck auf einen überlasteten Dienst. Er macht einen unbekannten Schreibvorgang nicht sicher. Ob ein weiterer Versuch zulässig ist, entscheiden die Wiederholbarkeit der Aktion und das Deduplizierungsverhalten des Ziels.

## Ein Abgleich beendet Unsicherheit, ohne die Geschichte umzuschreiben

Abgleich bedeutet, später Belege zu einer ungelösten Operation zu sammeln. Es bedeutet nicht, den ersten Versuch so lange zu bearbeiten, bis er erfolgreich aussieht.

Angenommen, ein Agent erstellt einen Vorfall mit einer vom Client gelieferten Referenz im Anfrage-Body. Der anfängliche POST endet mit `sent_no_response`. Vor einem Retry fragt der Agent Vorfälle anhand dieser Referenz ab. Findet er einen passenden Datensatz, fügt er ein Beobachtungsereignis an, das auf die ursprüngliche Operations-ID und den Fingerprint der Abfrage verweist und die zurückgegebene entfernte ID sowie die Kriterien des Treffers festhält. Anschließend schließt er die Operation durch Abgleich als erfolgreich ab.

Findet die Abfrage nichts, ist Vorsicht geboten. Die Abwesenheit eines Ergebnisses beweist wenig, wenn die API Replikationsverzögerungen, eine verzögerte Suchindexierung oder schwache Filterung hat. Protokolliere die negative Beobachtung mit der verwendeten Zeit und dem Endpunkt. Wiederhole nur dann, wenn der Vertrag des Ziels sagt, dass das Idempotenz-Token weiterhin wirksam ist, oder warte und hole eine Entscheidung ein.

Findet die Abfrage zwei passende Datensätze, darfst du die Operation nicht einfach als erfolgreich bezeichnen und weitermachen. Schließe sie als `duplicate_effect_confirmed`, bewahre beide entfernten IDs auf und erstelle eine separate Korrekturoperation. Die Korrektur darf nicht dieselbe Operations-ID verwenden, weil sie einen anderen beabsichtigten Effekt hat.

Verwende unveränderliche Ereignisse statt veränderlicher Statuszeilen als Quelle der Wahrheit. Für eine Benutzeroberfläche kannst du einen praktischen aktuellen Status ableiten, aber die Belege müssen die Übergänge bewahren: Absicht erstellt, Versuch versendet, Antwort verloren, Abfrage durchgeführt, entfernter Datensatz gefunden, Operation aufgelöst. Ein Ermittler braucht die Reihenfolge, einschließlich eines irrtümlichen Retries, falls einer stattgefunden hat.

Ein manipulationssicheres Log bietet eine zusätzliche Eigenschaft: Es ermöglicht zu prüfen, ob ein späterer Prozess den ersten unbekannten Versuch nicht heimlich entfernt hat. Sallyport erfasst Agentensitzungen und einzelne Aktionen in einem schreibblinden, verschlüsselten und hash-verketteten Audit-Log. `sp audit verify` prüft die Kette offline über den Chiffretext. Das hilft, die Zeitleiste zu bewahren. Das Ereignisschema braucht aber weiterhin die hier beschriebenen Verknüpfungen von Operation und Versuch.

## Bei Agentendelegation braucht es einen Besitzer der Operation

Subagenten machen doppelte Effekte wahrscheinlicher, weil jeder Prozess glauben kann, er sei für die Aufgabe zuständig. Gib einem Prozess die Verantwortung für die Operations-ID und verlange, dass jeder delegierte Worker diese ID in seinem Aktionskontext mitführt.

Ein Planer kann einen Worker bitten, Informationen zu sammeln, und einen anderen, eine Aktion auszuführen. Die Aufrufe zur Informationssammlung sollten eigene Operationen erhalten, weil sie separate Absichten sind. Der ausführende Worker sollte die ursprüngliche Operations-ID nur dann erhalten, wenn er denselben deklarierten Effekt ausführt. Seine einzelnen Aufrufe verwenden neue Versuchs-IDs und nennen den Workerprozess, der sie ausgeführt hat.

Lass Worker einen unbekannten Schreibvorgang nicht unabhängig wiederholen, während der übergeordnete Prozess ihn ebenfalls wiederholt. Der übergeordnete Prozess muss den Versandstatus des Workers erhalten, bevor er entscheidet, was zu tun ist. Beendet sich der Worker unerwartet, markiere die Operation als ungelöst und führe einen Abgleich durch. Ein fehlendes Ergebnis des untergeordneten Prozesses ist keine Einladung, den Befehl durch einen Supervisor erneut abzuspielen.

Auch Genehmigungsdatensätze pro Sitzung gehören in die Beweiskette. Wenn ein Agentenprozess die Berechtigung erhält, eine Gruppe von Aufrufen auszuführen, protokolliere Prozessidentität, Genehmigungszeitpunkt und Widerrufszeitpunkt getrennt vom Ergebnis der Aktion. Die Genehmigung erklärt, wer einen Versuch starten durfte. Sie beweist nicht, ob das Ziel die Aktion ausgeführt hat.

Bei sensiblen Operationen solltest du für den Retry selbst eine Genehmigung pro Aufruf verlangen, wenn der erste Versuch ein unbekanntes Ergebnis hatte. Menschen treffen eine bessere Entscheidung, wenn die Genehmigungskarte die ursprüngliche Absicht, den bisherigen Versandstatus und die geplante Wiederherstellungsmethode nennt. Eine allgemeine Aufforderung wie «API-Aufruf erlauben» verbirgt genau die Tatsache, die sie innehalten lassen sollte.

## Die Untersuchungsansicht muss eine Zeitleiste zeigen, keinen Stapel von Anfragen

Ein Ermittler braucht eine einzelne Operationsseite oder ein Abfrageergebnis, das mit der Absicht beginnt und mit dem bestmöglich belegten Ergebnis endet. Nach Zeit sortierte Anfrage-Logs zwingen die prüfende Person, unter Druck die Elternbeziehungen zu rekonstruieren, oft über mehrere Systeme mit leicht unterschiedlichen Uhren hinweg.

Zeige oben den Operationszustand, stelle darunter aber alle Belege bereit. Jeder Versuch sollte seine Nummer, den Versandstatus, den übergeordneten Retry, den Grund, die Berechtigungsreferenz, das Ziel, den Anfrage-Fingerprint, eine Zusammenfassung der Antwort und die Dauer anzeigen. Jede Beobachtung sollte zeigen, was geprüft wurde und warum dieser Beleg den Zustand verändert hat oder nicht.

Verberge doppelte Anfragen nicht, nur weil der endgültige Effekt harmlos war. Eine heute harmlose Verdoppelung kann nach einer API-Änderung oder der Ergänzung eines Webhooks einen teuren Seiteneffekt auslösen. Der Datensatz sollte es ermöglichen, «der Agent hat korrekt wiederholt und das Ziel hat dedupliziert» von «der Agent hat die Anfrage zweimal gesendet und hatte Glück» zu unterscheiden.

Behandle eine Änderung des Anfrage-Bodys während der Wiederherstellung als ausdrückliche Abzweigung. Die ursprüngliche Operation bleibt offen oder erhält ihr aufgelöstes Ergebnis. Die geänderte Aktion bekommt eine neue Operations-ID und eine Verknüpfung wie `supersedes_operation_id`. Dieser Datensatz sagt die Wahrheit: Der Agent hat nicht einfach wiederholt, sondern seine Absicht geändert.

Führe einen Test mit absichtlich erzwungenem Fehler durch, bevor du dem Design vertraust. Lass das Ziel eine bekannte idempotente Testaktion ausführen und unterbrich dann die Antwort an den Aufrufer. Prüfe, dass der nächste Agentenlauf die ursprüngliche Operations-ID beibehält, dasselbe Ziel-Token verwendet, den ersten Versuch als unbekannt protokolliert, den dokumentierten Abgleich oder Retry durchführt und die Operation mit Belegen abschließt. Wenn dein Test diese Punkte nicht beantworten kann, wird es ein Vorfall ebenfalls nicht können.

Das erste Feld, nach dem ich in einem Aktionslog des Agenten suche, ist kein HTTP-Status. Es ist die stabile Operations-ID. Ohne sie beginnt jede Untersuchung eines Retries mit Vermutungen. Mit ihr kannst du die entscheidenden Fragen stellen: Was wollte der Agent tun? Was hat den Rechner verlassen? Was hat sich zwischen den Versuchen geändert? Und welche Belege stützen das endgültige Ergebnis?
