# Doppelte API-Schreibvorgänge verhindern, wenn KI-Agenten Anfragen wiederholen

KI-Agenten machen Wiederholungsfehler schneller als Menschen. Wer ein Timeout sieht, hält vielleicht kurz inne, prüft die Ticketwarteschlange und entscheidet, was passiert ist. Ein Agent sieht dagegen oft eine Ausnahme, folgt der Anweisung zur Wiederholung und sendet eine zweite Schreibanfrage, bevor die erste irgendwo hinter der Netzwerkgrenze abgeschlossen ist.

So entstehen doppelte Tickets, wiederholte Zahlungsversuche, doppelte Einladungen und zwei Deployments derselben Änderung. Die Lösung lautet nicht, den Agenten einfach zur Vorsicht aufzufordern. Du brauchst einen API-Vertrag, der die Identität einer beabsichtigten Aktion über Wiederholungen hinweg erhält, Änderungen hinter einer wiederverwendeten Kennung erkennt und eine neue menschliche Bestätigung verlangt, wenn die Folgen das rechtfertigen.

## Wiederholungen sind normal, doppelte Auswirkungen nicht

Ein Timeout bedeutet nicht, dass der Server nichts getan hat. Vielleicht hat der Server das Ticket angelegt, aber seine Antwort ging auf dem Rückweg verloren. Vielleicht verarbeitet er die Anfrage noch. Ein Load Balancer kann die Verbindung angenommen haben, während der nachgelagerte Dienst die Bytes nie gesehen hat. Aus einem Socket-Fehler kann der Client nicht auf das Ergebnis schließen.

Darum ist die übliche Anweisung an einen Agenten, «bei Netzwerkfehlern wiederholen», unvollständig. Sie behandelt jedes unklare Ergebnis wie eine fehlgeschlagene Aktion. Bei Schreibendpunkten kann ein unklares Ergebnis drei Zustände haben:

- Der Server hat die Anfrage nicht erhalten.
- Der Server hat die Anfrage angenommen und die Arbeit abgeschlossen.
- Der Server hat die Anfrage angenommen, die Arbeit aber noch nicht abgeschlossen.

Dieselbe Wiederholung muss in allen drei Zuständen sicher sein. Wenn sie im abgeschlossenen Zustand eine zweite Auswirkung erzeugt, liegt die unsichere Grenze für Wiederholungen im Endpunkt selbst.

HTTP nimmt dir diese Aufgabe nicht ab. RFC 9110 definiert idempotente Methoden als Methoden, deren beabsichtigte Wirkung nach einer oder mehreren identischen Anfragen gleich bleibt. Genannt werden PUT, DELETE und die sicheren Methoden. Der RFC sagt außerdem, dass ein Client eine idempotente Anfrage nach einem Kommunikationsfehler wiederholen darf. Das ist hilfreich, macht aber nicht jeden Endpunkt sicher, nur weil er eine PUT-Route verwendet. Ein Server kann an einen PUT-Handler den Versand einer E-Mail, die Ausgabe eines Guthabens oder den Start eines Deployments hängen. Ohne passende Gestaltung wird diese Nebenwirkung bei jeder Wiederholung erneut ausgelöst.

Für POST braucht es eine ausdrückliche Vereinbarung. Viele APIs verwenden POST für Aktionen, weil der Server Ressourcenkennungen vergibt oder weil die Anfrage «diese Geschäftsoperation ausführen» bedeutet. Ein Agent darf eine solche Anfrage nur wiederholen, wenn die API festlegt, wie eine Operation über mehrere Versuche hinweg erkannt wird.

Trenne Transportwiederholungen von geschäftlichen Wiederholungen. Bei einer Transportwiederholung wird dieselbe Operation erneut gesendet, weil das Ergebnis unbekannt ist. Eine geschäftliche Wiederholung startet eine neue Operation, weil die erste nachweislich endgültig fehlgeschlagen ist. Wer beides vermischt, produziert den klassischen Incident-Bericht: Der Agent hat erfolgreich wiederholt, und zwar zweimal.

## Eine Idempotenzkennung identifiziert eine beabsichtigte Aktion

Eine Idempotenzkennung ist eine vom Client erzeugte, undurchsichtige Kennung. Sie bedeutet: «Alle Anfragen mit diesem Wert sind Versuche, genau diese eine Aktion auszuführen.» Der Agent erzeugt sie vor der ersten Anfrage, speichert sie zusammen mit dem Aufgabenstatus und sendet bei jeder Wiederholung denselben Wert.

Die Kennung muss zur logischen Aktion gehören, nicht zu einem einzelnen HTTP-Versuch. Wenn ein Agent ein Supportticket anlegt, die Antwort verliert und mit einer neuen Kennung erneut anfragt, kann die API die Wiederholung nicht erkennen. Sie sollte ein zweites Ticket anlegen, weil der Aufrufer ihr mitgeteilt hat, dass es sich um eine zweite Operation handelt.

Verwende einen zufälligen Wert mit hoher Entropie. Eine UUID ist üblich, aber jedes Format funktioniert, solange Aufrufer keine Werte erraten können und der Server die Kennung als undurchsichtig behandelt. Übertrage sie im Header `Idempotency-Key` oder in einem dokumentierten Anfragefeld. Ein Header trennt die Identität der Operation vom Geschäftsinhalte und erleichtert es Middleware, sie durch Logs und Traces zu führen.

Eine praktische Anfrage sieht so aus:

```bash
curl -X POST https://api.example.test/v1/tickets \\
  -H 'Authorization: Bearer $TOKEN' \\
  -H 'Content-Type: application/json' \\
  -H 'Idempotency-Key: 81b59b1a-9e75-4de7-a53b-1bb50969c83c' \\
  -d '{"project":"ops","title":"Rotate staging certificate","priority":"high"}'
```

Beim ersten akzeptierten Aufruf speichert der Server die Kennung, einen kanonischen Fingerprint der Anfrage, den Status der Operation und schließlich die Antwort, die er wieder ausgeben wird. Trägt eine spätere Anfrage dieselbe Kennung und denselben Fingerprint, gibt der Server das vorherige Ergebnis zurück, statt ein weiteres Ticket anzulegen.

Der Client braucht einen dauerhaften Speicherort für die Kennung. Ein Agent, der sie nur im aktuellen Prompt oder im Arbeitsspeicher des Prozesses hält, verliert die Identität der Operation nach einem Neustart. Speichere sie neben dem Aufgabeneintrag, dem Job oder dem Workflow-Checkpoint. Wenn ein Mensch den Agenten bittet, ein zweites, bewusst getrenntes Ticket mit demselben Text anzulegen, muss der Agent eine neue Kennung erzeugen. Die Person hat eine neue Absicht geäußert.

Mache die Kennung nicht zu einem veränderlichen Aufgabennamen, einem Zeitstempel oder einer natürlichsprachlichen Anfrage. Solche Werte kollidieren, ändern sich zwischen Wiederholungen oder geben Informationen in Logs preis. Undurchsichtige Kennungen sind langweilig. Genau deshalb funktionieren sie.

## Ein Fingerprint erkennt veränderte Wiederholungen

Eine Kennung beantwortet die Frage, ob der Aufrufer behauptet, zwei Anfragen seien eine Operation. Ein Anfrage-Fingerprint beantwortet die Frage, ob die Anfragen tatsächlich dasselbe bedeuten. Du brauchst beides.

Angenommen, ein Agent bittet eine Deployment-API zunächst, den Commit `a1b2c3` nach Staging auszuliefern. Die Anfrage läuft in ein Timeout, der Agent liest eine neuere Aufgabennotiz und wiederholt sie mit derselben Kennung, aber mit dem Commit `d4e5f6`. Gibt der Server blind die erste Antwort zurück, verbirgt er einen Agentenfehler. Führt er den zweiten Inhalt aus, erlaubt er einer Vorgangskennung, zwei verschiedene Deployments zu autorisieren.

Kanonisiere die relevanten Teile der Anfrage und hashe das Ergebnis. Die meisten APIs berücksichtigen die HTTP-Methode, eine normalisierte Route, das authentifizierte Konto oder den Mandanten und den kanonischen JSON-Körper. Manche berücksichtigen ausgewählte Header, wenn diese die geschäftliche Wirkung ändern. Volatile Tracing-Header, Verbindungsmetadaten und den Idempotenz-Header selbst solltest du ausnehmen.

Bei JSON ist Sorgfalt nötig. Hashes der Rohbytes schlagen fehl, wenn gleichwertiges JSON eine andere Eigenschaftsreihenfolge oder andere Leerzeichen verwendet. Eine kanonische Darstellung sortiert Objekteigenschaften, erhält die Reihenfolge von Arrays, verwendet ein festgelegtes Zahlenformat und lässt vom Server vergebene Felder weg. Noch besser ist es, das validierte Befehlsobjekt zu fingerprinten, nachdem die API Standardwerte gesetzt und unbekannte Felder abgelehnt hat. So passt der Fingerprint zu der Operation, die der Server ausführt, und nicht zu einer beliebigen Eingabedarstellung.

Zum Beispiel speichert dieses Pseudocode-Beispiel nach der Validierung einen Digest:

```text
command = validate_create_ticket(request.body)
canonical = canonical_json({
  "method": "POST",
  "route": "/v1/tickets",
  "account_id": authenticated_account.id,
  "command": command
})
fingerprint = sha256(canonical)
```

Wenn eine Kennung bereits existiert, vergleiche die Fingerprints, bevor du ein vorheriges Ergebnis zurückgibst oder darauf wartest. Bei Abweichungen lehne die Anfrage mit einer Konfliktantwort ab. Gib die gespeicherte Vorgangskennung und den Status an, aber keine geschützten Anfragedetails an einen nicht autorisierten Aufrufer.

Ein Fingerprint ist allein kein Duplikatdetektor. Zwei Benutzer können berechtigt identische Tickets einreichen. Ein Gehaltsdienst kann berechtigt gleiche Zahlungen an zwei Beschäftigte ausstellen. Wer einen Payload hasht und jeden Treffer dedupliziert, lässt gültige Arbeit stillschweigend verschwinden. Begrenze die Deduplizierung auf die Idempotenzkennung und verwende geschäftsspezifische Eindeutigkeitsregeln dort, wo sie fachlich erforderlich sind.

Kryptografische Hashes machen zufällige Kollisionen praktisch unmöglich, wenn du eine moderne Funktion wie SHA-256 verwendest. Sie beweisen aber nicht die Absicht des Aufrufers. Die Kennung trägt die Absicht, der Fingerprint erzwingt Konsistenz. Teams, die beides gleichsetzen, landen oft bei einer Deduplizierungsregel, die sie nicht erklären können, wenn sie eine berechtigte Anfrage ablehnt.

## Der Server muss die Kennung vor der Aktion beanspruchen

Eine Idempotenz-Tabelle, die Ergebnisse erst nach Abschluss der Nebenwirkung speichert, enthält weiterhin eine Race Condition. Zwei gleichzeitige Wiederholungen können beide die Tabelle prüfen, nichts finden, zwei Tickets anlegen und anschließend um das Speichern des Ergebnisses konkurrieren. Manchmal wird das als unzuverlässiges Agentenproblem getarnt, obwohl tatsächlich eine Eindeutigkeitsbedingung fehlt.

Der Server muss die Kennung atomar beanspruchen, bevor er irreversible Arbeit ausführt. Lege eine eindeutige Bedingung auf Gültigkeitsbereich und Kennung, üblicherweise auf Konto-ID und Idempotenzkennung. Versuche in einer Transaktion, eine Zeile mit Fingerprint und Status `in_progress` einzufügen. Die Anfrage, die gewinnt, übernimmt die Ausführung. Alle anderen Anfragen lesen die vorhandene Zeile.

Eine vereinfachte Tabelle könnte diese Felder enthalten:

```sql
create table idempotency_operations (
  account_id text not null,
  token text not null,
  fingerprint text not null,
  state text not null,
  response_status integer,
  response_body jsonb,
  created_at timestamptz not null,
  primary key (account_id, token)
);
```

Der Primärschlüssel erledigt hier echte Arbeit. Anwendungscode, der zuerst prüft und später einfügt, lässt eine Lücke, die gleichzeitige Worker, erneut zugestellte Nachrichten und ungeduldige Wiederholungen passieren können.

Nach dem Beanspruchen führt der Handler die Geschäftsaktion aus und schreibt die endgültige Antwort in die Operationszeile. Spätere passende Anfragen erhalten diesen gespeicherten Status und Body. So bekommen Aufrufer eine stabile Antwort, auch wenn der ursprüngliche Handler erfolgreich war, die Verbindung aber vor der Antwort abbrach.

Der schwierige Fall ist eine Anfrage, der eine Zeile gehört, die aber mitten in der Arbeit ausfällt. Lösche die Zeile nicht einfach, weil ein Worker ein Timeout hatte. Ein anderer Worker könnte die Arbeit noch beenden, oder der externe Anbieter könnte die Operation bereits angenommen haben. Markiere die Operation als ausstehend oder unbekannt, speichere genügend Informationen für die Untersuchung und erlaube Aufrufern, ihren Status abzufragen. Ein Reparaturjob darf veraltete Datensätze nur auflösen, wenn er den Zustand des nachgelagerten Systems versteht.

Bei Arbeit, die eine Datenbank und eine externe API verbindet, solltest du das Outbox-Muster oder eine Idempotenzkennung des Anbieters verwenden. Eine Datenbanktransaktion kann keine E-Mail, Zahlung oder Cloud-Bereitstellung zurückrollen, nachdem sie deinen Prozess verlassen hat. Schreibe Absicht und Outbox-Ereignis in einer lokalen Transaktion und lasse anschließend einen Worker das Ereignis mit einer stabilen nachgelagerten Vorgangskennung senden. So hat der Wiederherstellungscode etwas Konkretes, das er erneut ausführen kann, ohne eine zweite Aktion zu erfinden.

## Eine Bestätigung muss an die genaue Operation gebunden sein

Eine menschliche Bestätigung verhindert eine andere Art von Fehler: Ein Agent darf zwar handeln, aber die vorgeschlagene Aktion kann überraschend, zu weitreichend oder nach einer Änderung seines Kontexts wiederholt sein. Eine allgemeine Schaltfläche «Deployment erlauben» löst dieses Problem nicht. Sie erlaubt dem Agenten, unter derselben Genehmigung ein Deployment durch ein anderes zu ersetzen.

Eine nützliche Bestätigung nennt Ziel, Operation, Folge und Vorgangskennung. Zeige bei einem Produktionsdeployment Umgebung, Artefakt oder Commit, betroffenen Dienst und die Möglichkeit eines Rollbacks. Zeige bei einer Zahlung Empfänger, Betrag, Währung und Rechnungsreferenz. Zeige bei einem Ticket Zielprojekt und Titel.

Der Bestätigungsdatensatz sollte an den Anfrage-Fingerprint gebunden sein und ablaufen, sobald der Vorschlag nicht mehr aktuell ist. Ändert der Agent den Body nach der Genehmigung, ändert sich der Fingerprint und das System muss erneut fragen. Eine Genehmigung nach einer geänderten Anfrage weiterzuverwenden, ist eine stille Form der Rechteausweitung, auch wenn sie niemand beabsichtigt hat.

Verlange nicht für jede risikoarme Wiederholung eine menschliche Freigabe. Das verwandelt eine korrekte Idempotenzlösung in Genehmigungsmüdigkeit. Die erste Genehmigung kann die eine Operation mit ihrem Fingerprint freigeben. Passende Wiederholungen dürfen diese Genehmigung nutzen, weil sie ihre Bedeutung nicht verändern können. Ein geänderter Payload braucht eine neue Entscheidung.

Manche Teams verlassen sich auf eine Chatnachricht wie «Fortfahren?» und nennen die Antwort eine Genehmigung. Unter Zeitdruck scheitert das, weil dem Datensatz oft die genauen Parameter fehlen und der Agent eine spätere Antwort als Zustimmung für eine frühere Anfrage missverstehen kann. Nimm die Vorgangskennung in den Bestätigungsdatensatz auf und verlange vom Ausführer, sie vor dem Senden des Schreibvorgangs zu prüfen.

Ein einfacher Genehmigungs-Payload macht die Bindung sichtbar:

```json
{
  "operation_id": "op_3f8c",
  "idempotency_token": "81b59b1a-9e75-4de7-a53b-1bb50969c83c",
  "fingerprint": "e5c7...",
  "expires_at": "2025-06-14T15:30:00Z",
  "approved_by": "user_42"
}
```

Behandle eine Bestätigung als Autorisierung für einen bestimmten Befehl, nicht als Erlaubnis, bei einer Kategorie von Befehlen zu improvisieren. Diese Unterscheidung hält eine Wiederholung sicher, ohne dem Agenten eine leere Genehmigung zu geben, die er später wiederverwenden kann.

## Ticketsysteme brauchen zusätzlich eine geschäftliche Duplikatprüfung

Idempotenzkennungen stoppen doppelte Transportversuche. Ticketsysteme haben aber eine weitere Duplikatquelle: Agenten können getrennte Operationen starten, die dasselbe Problem beschreiben. Ein Monitoring-Alarm kommt zweimal an, zwei Agent-Läufe lesen denselben Incident-Kanal oder ein Scheduler wacht nach einem Absturz auf und spielt eine Aufgabe ohne ihren ursprünglichen Zustand erneut ab.

Löse das nicht durch eine Deduplizierung nach dem Titeltext. Ticket-Titel unterscheiden sich genug, um Duplikate zu übersehen, und identische Titel können sich auf verschiedene Incidents beziehen. Entscheide stattdessen, was Identität in der Ticketdomäne bedeutet. Das kann eine Alarm-Ereigniskennung, eine Incident-Kennung, ein Repository-Issue oder ein zusammengesetzter Wert aus Dienst, Alarm-Fingerprint und Incident-Zeitfenster sein.

Mache diese geschäftliche Kennung in der API ausdrücklich sichtbar:

```json
{
  "source_event_id": "alert-7c91",
  "project": "operations",
  "title": "Certificate expiry alert",
  "description": "Alert event alert-7c91 crossed its threshold."
}
```

Der Ticketdienst kann die Eindeutigkeit von `source_event_id` im vorgesehenen Gültigkeitsbereich erzwingen. Ein zweiter Agent-Lauf erhält dann die Kennung des vorhandenen Tickets, statt ein weiteres Element in die Warteschlange einzureihen. Das ist etwas anderes als Idempotenz. Die beiden Aufrufe können unterschiedliche Idempotenzkennungen besitzen, weil sie aus zwei verschiedenen Agent-Prozessen stammen, aber dasselbe vorgelagerte Ereignis darstellen.

Agenten sollten vor dem Erstellen nur dann suchen, wenn das Suchergebnis eine stabile Identität liefert, der sie vertrauen können. Die Suche nach dem Titel wirkt attraktiv, weil dafür keine API-Änderung nötig ist. Sie bricht zusammen, sobald die Indexierung verzögert ist, sich das Ranking ändert oder ein Agent den Titel umschreibt. Platziere die Eindeutigkeitsregel dort, wo der Schreibvorgang stattfindet, und gib klar zurück, ob die API ein Ticket erstellt oder ein vorhandenes wiederverwendet hat.

Sei vorsichtig mit automatischen Kommentaren und Statusänderungen. Eine Operation, die ein vorhandenes Ticket findet, könnte trotzdem einen doppelten Kommentar anhängen oder einen erledigten Incident wieder öffnen. Gib jeder wichtigen Teilaktion eine eigene Kennung oder formuliere den Schreibbefehl als vollständigen gewünschten Zustand. Vage Endpunkte wie «dieses Ticket aktualisieren» lassen sich nur schwer sicher wiederholen, weil niemand weiß, welcher Teil der Aktualisierung bereits ausgeführt wurde.

## Zahlungsaktionen brauchen eine Ergebnisabfrage statt Optimismus

Bei Zahlungen gelten strengere Maßstäbe, weil eine doppelte Belastung Kunden schadet, selbst wenn du sie später erstattest. Die Anwendung sollte eine stabile Idempotenzkennung an den Zahlungsanbieter senden und die Transaktionsreferenz des Anbieters zusammen mit dem lokalen Operationsdatensatz aufbewahren.

Bei einem Timeout muss der Client die Zahlung als unbekannt behandeln. Er sollte über die Anbieterreferenz, die Händlerreferenz oder die Idempotenzkennung abfragen, sofern der Anbieter diese Suche unterstützt. Er darf keinen weiteren Zahlungsversuch starten, nur weil der Agent keine Erfolgsmeldung erhalten hat.

Zwei Operationen werden häufig zu einer einzigen zusammengefasst: eine Zahlungsabsicht anlegen und Geld einziehen. Sie können ein unterschiedliches Wiederholungsverhalten haben. Ein Dienst kann ein Zahlungsobjekt mit einer Kennung sicher anlegen oder abrufen und anschließend nach bestandenen Prüfungen eine separate, ausdrücklich ausgelöste Einziehung verlangen. Modellieren die Geschäftsstatus offen, statt alles in einem Endpunkt zu verbergen, der bei jedem Aufruf alles versucht.

Beträge müssen vor dem Fingerprinting kanonisch verarbeitet werden. Wandle Werte in die kleinste unterstützte Währungseinheit oder eine andere exakte Darstellung um, bevor die Anfrage die Deduplizierungsschicht erreicht. Hashe keinen Gleitkomma-Anzeigewert und erwarte, dass gleichwertige Berechnungen zuverlässig verglichen werden. Eine Zahlungsanfrage sollte außerdem eine Rechnungs- oder Bestellreferenz enthalten, sofern es sie in der Domäne gibt. So können Mitarbeitende doppelte Absichten auch jenseits von Netzwerk-Wiederholungen erkennen.

Die Idempotenzfunktion eines Anbieters entbindet deine eigene API nicht von ihrer Verantwortung. Deine Anwendung muss weiterhin verhindern, dass zwei Agent-Aufgaben zwei verschiedene Anbieteranfragen für dieselbe Bestellung starten. Setze eine Eindeutigkeitsbedingung für den zahlbaren Status der Bestellung, verwende einen lokalen Operationsdatensatz und lass den Agenten diesen Datensatz nach einem unklaren Ergebnis abfragen.

Für Rückerstattungen gilt dasselbe. «Rückerstattung wiederholen» kann bedeuten, dieselbe Rückerstattungsanfrage erneut zu senden, oder eine weitere teilweise Rückerstattung zu starten. Verwende für jede Rückerstattungsanweisung eine stabile Kennung und speichere den bereits angeforderten Betrag. Muss der Agent eine zweite Rückerstattung ausstellen, formuliere das als neue, ausdrücklich genehmigte Anweisung mit neuer Kennung.

## Deployments brauchen unveränderliche Referenzen und eine Releasesperre

Eine Deployment-Wiederholung ist nur sicher, wenn sie dasselbe Release benennt. Branches wie `main` und veränderliche Tags wie `latest` erfüllen diesen Maßstab nicht. Nach einem Timeout kann eine Wiederholung denselben Namen zu anderem Code auflösen und scheinbar erfolgreich sein, obwohl sie etwas ausrollt, das die genehmigende Person nie geprüft hat.

Verwende einen unveränderlichen Artefakt-Digest, eine Commit-Kennung oder eine Version, deren Unveränderlichkeit das Releasesystem garantiert. Nimm sie in Fingerprint und Bestätigung auf. Sendet ein Agent dieselbe Idempotenzkennung mit einer geänderten Artefaktreferenz, lehne die Anfrage als Konflikt ab, statt sie als aktualisierte Wiederholung zu behandeln.

Du brauchst außerdem eine Nebenläufigkeitsregel für die Umgebung. Zwei getrennte Operationen können berechtigt unterschiedliche Kennungen tragen und trotzdem kollidieren, weil beide auf Produktion zielen. Eine Releasesperre, eine optimistische Versionsprüfung oder eine Deployment-Warteschlange kann diese Änderungen serialisieren. Idempotenz entscheidet nicht, welches von zwei verschiedenen Deployments gewinnen soll. Sie verhindert nur, dass ein Deployment zweimal ausgeführt wird.

Betrachte diese Fehlerfolge: Der Agent startet das Deployment `dep-118` für Commit `a1b2c3`, und der Deployment-Controller nimmt es an. Der Agent verliert die Antwort, geht von einem Fehler aus und startet wegen eines neueren Commits `dep-119` mit `d4e5f6`. Nun verändern beide Jobs dieselbe Umgebung. Eine Kennung hätte nur eine echte Wiederholung von `dep-118` gestoppt. Die Releasesperre oder eine Prüfung der erwarteten Umgebungsversion stoppt den widersprüchlichen zweiten Plan.

Die Deployment-API sollte eine Statusressource für Operationen bereitstellen, die `queued`, `running`, `succeeded`, `failed`, `canceled` oder `unknown` meldet. Nach einem Timeout sollten Agenten diesen Status abfragen. Sie dürfen den Abschluss nicht aus einer fehlenden Antwort oder einer Logzeile ohne Vorgangskennung ableiten.

Ein Rollback braucht eine eigene Vorgangskennung und Genehmigung. Behandle es nicht als Wiederholung des Deployments, denn dadurch wird eine wesentliche Änderung der Absicht verborgen. Es kann nach einer dokumentierten Sicherheitsregel automatisch erfolgen, muss aber als eigener Datensatz neben dem ursprünglichen Release bestehen.

## Agent-Tools sollten die Vorgangsidentität über die Grenze hinweg bewahren

Eine Tool-Schnittstelle für Agenten sollte sicheres Verhalten einfacher machen als unsicheres. Gib dem Agenten eine Aktion, die eine stabile Vorgangskennung, einen Payload und einen angegebenen Wiederholungsmodus akzeptiert. Gib ein Ergebnis zurück, das angibt, ob der Dienst Arbeit angelegt, ein früheres Ergebnis erneut ausgegeben, eine laufende Operation gefunden oder eine geänderte Wiederholung abgelehnt hat.

Vermeide Tools, die bei jedem Aufruf stillschweigend eine neue Idempotenzkennung erzeugen. In einer Demo wirken sie bequem, beim ersten echten Timeout versagen sie. Wenn das Tool die Kennung erzeugt, muss es sie sofort zurückgeben und an einem Ort speichern, an dem ein späterer Aufruf sie wiederfinden kann. In den meisten Systemen sollte die Workflow-Schicht die Kennung verwalten, weil sie weiß, welche Aufrufe zu einer vom Benutzer angeforderten Aktion gehören.

Sallyport kann API-Zugangsdaten außerhalb des Agenten halten, während der Agent die beabsichtigte HTTP-Aktion über seine MCP-Verbindung sendet. Diese Trennung hilft gegen die Preisgabe von Zugangsdaten, aber die nachgelagerte API braucht weiterhin Idempotenzverhalten. Ein geschütztes Zugangstoken macht aus einem unklaren POST keine sichere Wiederholung.

Mach die Wiederholungsregel des Agenten in seinem Tool-Vertrag ausdrücklich:

```text
if response is a known success:
    record operation complete
if response is a timeout or connection failure:
    query operation status using the same token
    retry only with the same token if the API permits it
if response says fingerprint conflict:
    stop and request a new operation or human review
if response is a known business failure:
    do not retry until the task changes
```

Lass den Agenten exponentielles Backoff nicht als Ersatz für Zustand verwenden. Backoff reduziert den Druck auf einen Dienst, was wichtig ist. Es beantwortet aber nicht die Frage, ob der letzte Schreibvorgang erfolgreich war. Der Agent muss die Vorgangskennung speichern, bevor er wartet.

## Logs müssen nach einem strittigen Schreibvorgang beweisen, was passiert ist

Wenn ein Kunde sagt, er sei doppelt belastet worden, oder ein Engineer zwei Tickets findet, musst du vier Fragen beantworten können: Welcher Agent-Lauf hat jede Anfrage gesendet, welche Kennung wurde verwendet, welchen Fingerprint hat der Server berechnet und welches Ergebnis hat der nachgelagerte Dienst zurückgegeben? Allgemeine Anfrage-Logs lassen mindestens eine dieser Informationen oft aus.

Protokolliere einen Operationsdatensatz an der Grenze, an der die API die Aktion akzeptiert. Nimm den authentifizierten Principal, die Kennung, den Fingerprint, die Anfrageroute, Statusübergänge, die Antwortreferenz und, falls vorhanden, die Referenz des vorgelagerten Anbieters auf. Halte Geheimnisse und vollständige sensible Bodies aus routinemäßigen Logs heraus. Ein Fingerprint erlaubt den Vergleich von Anfragen, ohne jedes private Feld in jedem Logsysten zu speichern.

Ein unveränderliches Audit-Log hilft, wenn ein Agent externe Schreibvorgänge ausführen darf. Der Datensatz sollte zwischen `attempted`, `approved`, `sent`, `accepted`, `completed` und `replayed` unterscheiden. Diese Zustände sind nicht austauschbar. Erhält eine Wiederholung eine gespeicherte frühere Antwort, muss sie `replayed` und nicht `created` melden, sonst zählen deine Operatoren sie als zweite Aktion.

Sallyport zeichnet Agent-Sitzungen und einzelne Aktionen in Journalen auf, die aus einem verschlüsselten, hashverketteten Audit-Log abgeleitet werden. Mit `sp audit verify` lässt sich die Kette offline prüfen. Damit kannst du nachweisen, was das Aktionsgateway passiert hat. Kombiniere diesen Nachweis mit den Idempotenzdaten des empfangenden Dienstes, denn dieser Dienst entscheidet, ob er die Geschäftsaktion ausgeführt hat.

Teste den Ablauf für strittige Schreibvorgänge, bevor du ihm vertraust. Lass den Server eine Anfrage abschließen und die Antwort verwerfen. Sende gleichzeitig mehrere Kopien mit einer Kennung. Starte den Agenten zwischen zwei Versuchen neu. Verwende eine Kennung erneut, aber mit verändertem Payload. Beende einen Worker, nachdem er eine Kennung beansprucht und bevor er den Abschluss speichert. Ein Design, das nur saubere Erfolgsmeldungen übersteht, verhindert noch keine doppelten Schreibvorgänge.

Beginne mit dem Schreibendpunkt, bei dem eine Wiederholung den größten Schaden anrichtet. Füge eine stabile Kennung hinzu, beanspruche sie atomar vor jeder Nebenwirkung, binde sie an einen Fingerprint und gib Aufrufern eine Statusabfrage für unklare Ergebnisse. Danach muss der Agent die Kennung so lange mitführen, bis er beweisen kann, dass die Operation einen endgültigen Zustand erreicht hat.
