# Schützen Limits für dekodierte Größe einen Agenten vor komprimierten APIs?

Eine komprimierte Antwort ist nicht klein, nur weil sie klein angekommen ist. Sie bleibt nur klein, bis dein Client sie dekodiert, parst, speichert, protokolliert und vielleicht an einen Agenten übergibt, der sie als Beleg behandelt. Wenn du nur die aus dem Netzwerk empfangenen Bytes begrenzt, misst du den unwichtigsten Teil der Transaktion.

Ich habe erlebt, wie Teams ein scheinbar vernünftiges HTTP-Limit von 5 MB einführten, den Test feierten und dann feststellten, dass wenige Kilobyte komprimierter Wiederholungen trotzdem eine Antwort erzeugen konnten, die einen Prozess blockiert oder einen Agentenlauf verfälscht. Dafür brauchte niemand einen ausgefallenen Exploit. Ein Endpunkt gab einen Bericht zurück, in dem ein Feld viel häufiger wiederholt wurde als erwartet, die Komprimierung arbeitete hervorragend, und der Client tat das Gefährliche: Er sammelte den dekodierten Body, bevor er entschied, ob er ihn überhaupt wollte.

Limits für die dekodierte Größe müssen auf dem dekodierten Stream liegen, bevor ein Parser, Logger, Cache oder Agentenkontext den Body verarbeitet. Behalte ein separates Limit für Übertragungsbytes, denn das stoppt langsame oder unerwartet große Transfers. Die beiden Limits verhindern unterschiedliche Fehler. Wer sie verwechselt, verwandelt eine Schutzprüfung in ein falsches Sicherheitsgefühl.

## Die Übertragungsgröße erzählt nur einen Teil der Geschichte

Content-Length beschreibt normalerweise den übertragenen HTTP-Nachrichtenrumpf. Hat die Antwort Content-Encoding: gzip oder Content-Encoding: br, beschreibt die Zahl also komprimierte Bytes. Ein Body von 40 KB kann nach dem Dekodieren auf Dutzende oder Hunderte Megabyte anwachsen, wenn die Eingabe genügend Wiederholungen enthält. Das genaue Verhältnis ist nicht entscheidend. Jedes Verhältnis, das dein Allokations- oder Kontextbudget übersteigt, reicht für Probleme aus.

RFC 9110 behandelt Inhaltskodierung als Transformation einer Repräsentation. Das ist wichtig: Die Repräsentation, mit der deine Anwendung arbeitet, ist die dekodierte Form, während der Transport eine kodierte Form trägt. Ein Client, der sein Anwendungslimit auf die Transportform stützt, hat die Schranke auf der falschen Seite der Transformation platziert.

Transfer-Encoding macht das Bild noch komplizierter. Eine Chunked-Übertragung hat keinen brauchbaren endgültigen Content-Length-Wert, auf den sich ein Client verlassen kann, und HTTP/2- oder HTTP/3-Antworten verwenden Chunked Transfer nicht auf dieselbe Weise. Auch mit vorhandenem Header kann ein Server einen falschen Wert senden. Nutze den Header als frühen Hinweis zum Ablehnen, nie als Beweis dafür, dass der Body sicher ist.

Für eine Antwort sind drei Werte sinnvoll: gelesene Übertragungsbytes, erzeugte dekodierte Bytes und für den Aufrufer behaltene Bytes. Manchmal sind sie gleich. Oft sind sie es nicht. Eine JSON-Antwort kann auf 12 MB dekodieren, beim Parsen deutlich mehr als 12 MB Speicher belegen und dann auf 64 KB gekürzt werden müssen, bevor ein Agent sie sicher nutzen kann.

Diese Unterscheidung verhindert auch den typischen Streit über eine einzelne Einstellung für die „maximale Antwortgröße“. Eine Person meint Socket-Bytes. Eine andere meint dekodierte Bytes. Eine dritte meint den Text, der in ein Tool-Ergebnis eingefügt wird. Gib jedem Limit einen eigenen Namen und setze es an der Grenze durch, die es beschreibt.

## Vor jedem unbegrenzten Puffern dekodieren

Die sichere Reihenfolge ist einfach: Begrenze den rohen Antwortstream, wähle und initialisiere den Dekoder, begrenze den dekodierten Stream und parse oder behalte dann nur, was der Aufrufer braucht. Rufe keine Komfortmethode auf, die die ganze dekodierte Antwort in einen Byte-Slice liest und prüfe deren Länge erst danach. Dann hat der Dekoder den Speicher bereits verbraucht, den du schützen wolltest.

Bei einer Gzip-Antwort in Go gehört der Limiter für dekodierte Bytes um den Gzip-Reader. Dieser Helfer liest absichtlich ein Byte mehr als erlaubt. Ohne dieses zusätzliche Byte ist eine Antwort, deren tatsächliche Größe genau dem Limit entspricht, nicht von einer größeren Antwort zu unterscheiden, die am Limit abgeschnitten wurde.

```go
var ErrDecodedBodyTooLarge = errors.New("decoded response exceeds limit")

func readGzipBody(r io.Reader, limit int64) ([]byte, error) {
    zr, err := gzip.NewReader(r)
    if err != nil {
        return nil, err
    }
    defer zr.Close()

    bounded := &io.LimitedReader{R: zr, N: limit + 1}
    body, err := io.ReadAll(bounded)
    if err != nil {
        return nil, err
    }
    if int64(len(body)) > limit {
        return nil, ErrDecodedBodyTooLarge
    }
    return body, nil
}
```

Wende auch vor `gzip.NewReader` ein Rohdatenlimit an. Es ersetzt das dekodierte Limit nicht. Es verhindert, dass ein Gegenüber einen riesigen komprimierten Stream sendet, und begrenzt, wie viel Arbeit der Client annimmt, bevor der Dekoder genügend Eingabe hat, um Fortschritt zu machen.

Schneide nicht still ab und fahre fort. Ein abgeschnittenes JSON-Dokument lässt sich meist nicht parsen, doch abgeschnittener Text oder ein zeilenbasiertes Protokoll kann plausibel wirken. Wenn du für die Diagnose eine Vorschau behältst, markiere sie in einem Feld als Vorschau, das nicht mit dem vollständigen Body verwechselt werden kann. Die Aktion selbst muss fehlschlagen, weil der Client keine vollständige, zulässige Antwort erhalten hat.

Ein Dekoder erkennt eine beschädigte Prüfsumme möglicherweise erst am Ende des Streams. Sobald das dekodierte Limit greift, hör auf zu lesen und lehne die Antwort ab. Du musst die Prüfung eines übergroßen Bodys nicht zu Ende führen, den du bereits verworfen hast. Bleibt eine Antwort unter dem Limit, lies bis EOF und lass den Dekoder abgeschnittene oder beschädigte Daten wie üblich melden.

## Eine Antwort kann den Kontext erschöpfen, bevor sie den Speicher erschöpft

Speicherschutz ist nötig, doch Agenten-Tools haben ein weiteres Budget: die Menge an Ergebnistex, die sicher in die Agentenkonversation gelangen kann. Eine JSON-Antwort von 2 MB kann für einen Desktop-Prozess harmlos und dennoch ein furchtbares Tool-Ergebnis sein. Sie kann die Aufgabe verdrängen, den Agenten zu irrelevanten Datensätzen führen oder das Modell über eine unvollständige Darstellung nachdenken lassen, die vollständig aussieht.

Nutze das Kontextbudget nicht als Grund, das Limit für dekodierte Bodies anzuheben. Sie schützen unterschiedliche Vorgänge. Das dekodierte Limit lässt Transport und Parser sicher abschließen. Das Präsentationslimit steuert, was der Agent nach erfolgreicher Dekodierung und gegebenenfalls strukturiertem Parsen erhält.

Wähle bei strukturierten Daten eine Projektion, statt beliebige Bytes abzuschneiden. Gibt ein Endpunkt eine Liste von Datensätzen zurück, behalte eine begrenzte Zahl von Datensätzen und eine begrenzte Textmenge je Feld. Nenne die Gesamtzahl nur, wenn der Parser sie ermitteln konnte, ohne die ganze Liste zu behalten. Sage, dass das Ergebnis reduziert wurde, und nenne die Auswahlregel, etwa „die ersten 50 nach Zeitstempel sortierten Datensätze“. So bleibt das Ergebnis prüfbar und ein Agent hält ein Fragment nicht für eine vollständige Suche.

Bei Klartext solltest du nach Möglichkeit vollständige Zeilen bewahren. Eine Log-Vorschau, die mitten in einer Zeile endet, ist weniger nützlich und kann gerade das erklärende Feld verbergen. Lege ein Bytebudget fest, lies zeilenweise mit einem Limit für die Zeilenlänge und melde sowohl die behaltene Anzahl als auch den Grund für ausgelassene Inhalte. Ein Zeilenleser ohne eigenes Tokenlimit verlagert das Allokationsproblem nur in einen anderen Helfer.

Hier scheitert viel Denken nach dem Muster „das Modell kann es doch zusammenfassen“. Das Modell kann Daten zusammenfassen, die du bewusst ausgewählt hast. Es kann keinen unbegrenzten Transport sicher machen und sollte nicht entscheiden, wie viel rohe Remote-Ausgabe dein Prozess allokiert, bevor du sie geprüft hast.

## Inhaltskodierung muss im Client-Vertrag ausdrücklich geregelt sein

Behandle Content-Encoding als Eingabe, die einen Dekoder auswählt, nicht als Dekoration um einen ansonsten identischen Byte-Stream. Akzeptiere nur Kodierungen, die dein Client implementiert, und lehne unbekannte Werte eindeutig ab. Liefert ein Dienst `gzip`, verwende den Gzip-Pfad. Liefert er `br`, nutze einen Brotli-Dekoder mit demselben Limiter für dekodierte Bytes. Gibt es keine Inhaltskodierung, umschließe den rohen Body mit diesem Limiter, denn rohe Bytes sind in diesem Fall auch dekodierte Bytes.

Akzeptiere nicht leichtfertig mehrere Inhaltskodierungen. HTTP erlaubt eine Liste von Kodierungen, und die aufgeführten Transformationen haben eine Reihenfolge. Unterstützung für `gzip, br` bedeutet, dass du in umgekehrter Reihenfolge dekodieren und nach jeder Expansionsstufe eine Größenprüfung anwenden musst. Ein einzelnes abschließendes Limit ist schwächer, als es aussieht, weil eine Zwischenstufe stark wachsen kann, bevor die letzte Stufe sie wieder reduziert. Wenn deine Integrationen keine gestapelten Kodierungen brauchen, lehne sie ab, bis Tests und eine bewusste Implementierung vorhanden sind.

Automatische Dekompression verdient eine Prüfung. Viele HTTP-Bibliotheken fügen Accept-Encoding hinzu, dekodieren Gzip und verbergen die Änderung vor dem Anwendungscode. Das ist bei normalen Anfragen praktisch, kann aber dazu führen, dass der Code Bytes auf der falschen Ebene zählt. Finde heraus, ob dein Antwortbody Übertragungs- oder dekodierte Bytes liefert, ob die Bibliothek Content-Encoding entfernt und ob sie Zähler für komprimierte Bytes bereitstellt. Schreibe einen Test, der das Verhalten für deine genaue Client-Konfiguration belegt.

Brotli braucht dieselbe Behandlung wie Gzip. Es ist verlockend, einen Gzip-Test zu schreiben, weil jede Umgebung einen Gzip-Befehl hat, und die Arbeit dann für erledigt zu halten. Ein anderer Dekoder bedeutet anderes Fehlerverhalten, anderes Puffern und möglicherweise andere Unterstützung durch Abhängigkeitsversionen. Das Limit muss den von jedem Dekoder zurückgegebenen Reader umschließen, nicht in einem Helfer liegen, den nur der Gzip-Pfad aufruft.

Ein Server kann auch eine deklarierte Kodierung mit ungültigem Body senden. Behandle das als Dekodierungsfehler, getrennt von einer zu großen dekodierten Antwort. Verantwortliche müssen erkennen können, ob die Gegenseite schlechte Daten gesendet hat, das konfigurierte Budget zu niedrig ist oder dem Client ein Dekoder für eine deklarierte Kodierung fehlt.

## Expansion mit prüfbaren Dateien testen

Eine brauchbare Testdatei beginnt mit dekodiertem Inhalt, den du erkennen und messen kannst. Wiederholte Bytes liefern einen offensichtlichen Expansionsfall. Die folgenden Befehle erstellen einen Textbody von 32 MiB und danach Gzip- und Brotli-Versionen, sofern der Brotli-Befehl installiert ist.

```sh
python3 -c 'open("repeat.txt", "wb").write(b"A" * (32 * 1024 * 1024))'
wc -c repeat.txt
gzip -9 -c repeat.txt > repeat.txt.gz
brotli -f repeat.txt -o repeat.txt.br
wc -c repeat.txt.gz repeat.txt.br
```

Die erste `wc`-Ausgabe sollte die Form `33554432 repeat.txt` haben. Die komprimierten Dateien sollten deutlich kleiner als die Quelle sein, weil die Eingabe ein Byte wiederholt. Lass einen Test keine bestimmte komprimierte Größe erwarten. Komprimierungsversionen und Einstellungen können sie verändern. Prüfe die dekodierte Länge, das Ergebnis beim Client und dass der Client nach der Ablehnung keinen vollständigen Body behält.

Erstelle Grenzfälle aus derselben Quelle: einen dekodierten Body ein Byte unter dem konfigurierten Limit, genau am Limit und ein Byte darüber. Führe jeden Fall über einen lokalen HTTP-Handler aus, der Content-Encoding korrekt setzt. Ein Test für einen Dateidekoder ist nützlich, kann aber keine Client-Bibliothek erkennen, die automatisch dekomprimiert, bevor dein Limit-Code läuft.

Nutze eine zweite Gruppe von Testdaten mit realistischer Struktur. Erzeuge zeilengetrenntes JSON, bei dem jeder Datensatz ein wiederholtes Payload-Feld enthält, und liefere es unter Gzip und Brotli aus. Das findet Code, der einen Byte-Slice korrekt behandelt, aber nach dem Dekodieren einen JSON-Parser oder Zeilenscanner ein unbegrenztes Array aufbauen lässt. Nimm einen Datensatz auf, der länger als dein Feld- oder Zeilenlimit ist, denn Angreifer müssen keine kurzen Zeilen wiederholen, um Parser zu Allokationen zu bringen.

Behalte Testdaten nur im Repository, wenn ihre komprimierten Formen klein sind und ihre Quelle während der Tests erzeugt werden kann. Ein Generator-Skript mit bekannter dekodierter Länge lässt sich leichter prüfen als ein rätselhafter Binärblob. Halte die beabsichtigte dekodierte Größe im Testnamen fest, nicht nur in einem Kommentar, den bei einem Grenzfehler niemand sieht.

## Der Fehler beginnt meist mit einer hilfreichen Komfortmethode

Stell dir einen Agenten vor, der eine API für Issue-Daten aufruft. Der Endpunkt liefert normalerweise eine kleine JSON-Seite. Der Client sendet `Accept-Encoding: gzip`, erhält eine Antwort mit Content-Length von 18 KB und protokolliert den Header als Beleg dafür, dass das Ergebnis überschaubar ist. Sein HTTP-Helfer dekomprimiert den Body dann transparent und ruft vor dem JSON-Parsing `ReadAll` auf.

Eine fehlerhafte Upstream-Antwort enthält in jedem Datensatz ein großes wiederholtes Beschreibungsfeld. Der Transfer von 18 KB expandiert zu weit mehr Daten, als die Seite normalerweise enthalten würde. Der Prozess allokiert den Byte-Slice, erzeugt beim Parsen Strings und Maps und serialisiert ausgewählte Datensätze für den Agenten. Jede Stufe hält zumindest für einen Teil der Anfrage eine andere Kopie. Ein Limit nach dem Parsing bemerkt das Problem erst, nachdem die teure Arbeit bereits passiert ist.

Die erste Reparatur fügt oft nach `ReadAll` `if len(body) > limit` hinzu. Dieser Test lässt den Unit-Test grün aussehen, erhält aber den Allokationssprung. Die zweite Reparatur umschließt den dekodierten Reader, was in die richtige Richtung geht, sendet aber weiterhin die ersten `limit` Bytes als Fallback an den Agenten. Jetzt kann der Agent auf Basis einer halben Antwort handeln, und der Audit-Trail zeigt keinen klaren Fehler.

Die vollständige Reparatur lehnt früh am dekodierten Reader ab, verwirft Teilinhalte, erfasst Kodierung und Bytebudget und gibt dem Aufrufer einen Fehler, den er einordnen kann. Wenn der Endpunkt wirklich große Exporte braucht, verschiebe diesen Fall in einen ausdrücklichen Download-Pfad mit einem höheren genehmigten Limit, einem vom Nutzer gewählten Ziel und ohne automatisches Einfügen der Datei in den Agentenkontext.

Diese Trennung ist wichtig, weil ein Berichtsdownload und eine Suche durch ein Agenten-Tool unterschiedliche Vorgänge sind. Dass beide eine HTTP-Anfrage auslösen, macht weder Risiko noch Budget gleich.

## Limits brauchen einen Endpunktverantwortlichen und eine Begründung

Ein globaler Standard ist ein Ausgangspunkt, keine passende Richtlinie für jede HTTP-Aktion. Weise das Limit für dekodierte Antworten entsprechend dem vorgesehenen Ergebnis eines Endpunkts zu. Eine Statusprüfung braucht vielleicht nur wenige Kilobyte. Eine paginierte Suche kann eine mittelgroße strukturierte Antwort liefern. Ein Binärexport braucht möglicherweise eine höhere Grenze, sollte aber in einen Dateipfad statt in ein Konversationsergebnis gehen.

Schreibe das Limit neben die Aktionsdefinition und begründe es. „Die API-Dokumentation sagt, die Seitengröße sei 100“ reicht nicht, denn ein einzelner Datensatz kann trotzdem riesig sein. Eine gute Begründung benennt die erwartete Repräsentation und Nutzung durch den Aufrufer, etwa „ein Statusobjekt parsen und ausgewählte Felder zurückgeben“ oder „ein vom Nutzer angefordertes Archiv nach ausdrücklicher Genehmigung speichern“.

Leite die Obergrenze nicht allein aus einem vom Server gelieferten Seitengrößenparameter ab. Server können Parameter ignorieren, ein Agent kann eine breite Abfrage anfordern und ein einzelnes Textfeld kann die Antwort dominieren. Begrenze Seitengröße, Breite der Abfrage, dekodierte Bytes, geparste Datensätze und Bytes im Agentenergebnis dort, wo die jeweilige Grenze sinnvoll ist. Diese Kontrollen überlappen absichtlich, weil jede eine andere Art schlechter Anfrage oder Antwort abfängt.

Wenn du eine Antwort ablehnst, erfasse genug Details für die Diagnose: HTTP-Methode, Host oder Aktionskennung, Statuscode soweit vorhanden, deklarierte Inhaltskodierung, beobachtete komprimierte Bytes, dekodiertes Limit und ob der Dekoder bereits Ausgabe erzeugt hatte. Protokolliere den abgelehnten Body nicht standardmäßig. Das könnte das Speicher- und Datenschutzproblem in einem angeblich diagnostischen Pfad erneut erzeugen.

Eine menschliche Genehmigung macht eine Antwort nicht harmlos. Sie kann eine Aktion mit einem Remote-Dienst erlauben, sagt aber nicht voraus, wie viele Daten der Dienst zurückgibt. Setze Antwortgrenzen auch nach der Genehmigung und bevor der Agent Daten erhält durch.

## Abbruch und Timeouts verhindern einen anderen Fehlermodus

Eine Obergrenze für dekodierte Größe stoppt Wachstum, sobald der Dekoder genügend Ausgabe erzeugt. Sie stoppt kein Gegenüber, das Bytes quälend langsam sendet, keinen Dekoder mit übermäßigem CPU-Verbrauch bei einem präparierten Stream und keine Antwort, die nie endet. Setze Anfrage-Deadlines und stelle sicher, dass ein Abbruch den Antwortbody schließt und den Reader unterbricht.

Halte Zeit, komprimierte Bytes, dekodierte Bytes und die Zahl geparster Elemente in Metriken und Fehlern getrennt. Wenn alle Fehler als „Anfrage fehlgeschlagen“ erscheinen, erhöht jemand das Größenlimit, um ein Timeout zu lösen, oder verlängert ein Timeout, um einen Parserfehler zu lösen. Solche Änderungen erschweren die Diagnose von Vorfällen und vergrößern oft die Angriffsfläche.

Teste einen Abbruch gegen einen Endpunkt, der ein gültiges komprimiertes Präfix sendet und dann pausiert. Der Client sollte seinen Timeout- oder Abbruchfehler zurückgeben, ohne dass eine Goroutine auf den Dekoder wartet. Teste anschließend einen Body, der rasch über die dekodierte Obergrenze wächst. Dieser Pfad sollte den Größenfehler zügig erzeugen, selbst wenn der Server weitere komprimierte Bytes senden würde.

Bei einer frühen Ablehnung muss die Wiederverwendung von Verbindungen sorgfältig behandelt werden. In vielen Clients reicht das Schließen des Bodys, um Ressourcen freizugeben, aber die Verbindung ist möglicherweise nicht wiederverwendbar, wenn der Client den Rest der Antwort nicht konsumiert hat. Das ist akzeptabel. Korrektheit und begrenzter Ressourcenverbrauch sind wichtiger als eine weitere Keep-Alive-Verbindung aus einer feindlichen oder defekten Antwort herauszupressen.

Wiederhole eine übergroße Antwort nicht automatisch. Ein vorübergehender Netzwerkfehler kann unter einer begrenzten Richtlinie einen Wiederholungsversuch rechtfertigen. Eine Antwort, die ein bekanntes Limit überschreitet, ist meist deterministisch. Sie zu wiederholen verschwendet Bandbreite und kann den Druck auf einen Prozess vervielfachen, der bereits mit einer übergroßen Aktion umgeht.

## Parsing-Limits gehören nach das Dekodieren, nicht an dessen Stelle

Ein Streaming-JSON-Parser kann verhindern, dass du jeden Datensatz speicherst, doch er ersetzt kein Limit für dekodierte Bytes. Parser brauchen weiterhin Puffer, einzelne Strings können riesig sein und Fehlerberichte können Quellfragmente behalten. Setze das Byte-Limit vor den Parser und ergänze dann Formatlimits, die zu den akzeptierten Daten passen.

Ziehe bei JSON eine maximale Verschachtelungstiefe, maximale Stringlänge, maximale Datensatzanzahl und ein striktes Schema für Felder in Betracht, die der Agent nutzen wird. Setze für CSV oder Zeilenprotokolle eine maximale Zeilenlänge und maximale Zeilenzahl. Deaktiviere bei XML die Verarbeitung externer Entitäten und setze Parserlimits, wenn die Bibliothek sie anbietet. Das sind Parsing-Regeln, während die Obergrenze für den dekodierten Body eine Transportgrenze ist. Erzwinge nicht, dass eines für das andere eintritt.

Validiere vor dem Rendern. Ein Feld namens `instructions`, `command` oder `message` aus einem Remote-Dienst bleibt Remote-Inhalt. Seine Größe kann innerhalb des dekodierten Limits liegen und trotzdem ungeeignet sein, in den Kontrollfluss eines Agenten zu gelangen. Wähle Felder nach Schema aus und kodiere sie als Daten. Das Größenlimit verhindert eine Klasse von Fehlern, es schafft kein Vertrauen in den Inhalt der Bytes.

Diese Trennung macht die Fehlerbehandlung übersichtlicher. Ein Body, der das dekodierte Limit überschreitet, darf den Parser nie erreichen. Ein passender Body mit zu vielen Datensätzen sollte einen Parsing- oder Anwendungslimitfehler liefern. Ein Body, der dem Schema entspricht, aber das Präsentationsbudget des Agenten überschreitet, sollte durch eine ausdrückliche Ergebnisregel reduziert werden. Jedes Ergebnis zeigt Verantwortlichen, was sich gegebenenfalls ändern muss.

## Das Audit-Protokoll als Grenzbericht behandeln

Ein hilfreicher Audit-Eintrag sagt, was der Prozess versucht hat und warum der Client nicht weitermachen wollte. Er braucht keinen abgelehnten Inhalt. Speichere Aktionskennung, Autorisierungskontext, Ziel, Anfragezeit, Antwortstatus soweit bekannt, Kodierung, Anzahl der Übertragungsbytes, dekodierte Bytezahl oder Untergrenze und das Limit, das den Aufruf beendet hat.

Bei einer frühen Ablehnung kann die dekodierte Zahl `limit + 1` statt der tatsächlichen Endgröße sein, weil der Client absichtlich nicht weiterliest. Erfasse das ehrlich. Zu behaupten, die volle dekodierte Größe zu kennen, legt nahe, dass du genau den Stream konsumiert hast, den du begrenzen solltest. Eine Untergrenze reicht aus, um die Entscheidung zu erklären.

Das ist besonders nützlich, wenn ein Agent eine Aktion wiederholt, nachdem eine Person die Abfrage geändert hat. Du siehst dann, dass der erste Aufruf das Präsentations- oder Dekodierungsbudget überschritt und der zweite mit einer engeren Anfrage erfolgreich war. Ohne diese Unterscheidung sieht ein fehlgeschlagener Tool-Aufruf genauso aus wie ein Authentifizierungs- oder Netzwerkproblem, und Menschen greifen zur falschen Lösung.

Sallyports Aktivitätsspur kann den Pfad des Aktionsergebnisses bewahren, ohne dem Agenten selbst die API-Zugangsdaten zu geben. Der Aufrufer muss ein übergroßes Ergebnis dennoch als begrenzten Fehler melden, statt den Aktivitätseintrag in eine zweite Kopie der Antwort zu verwandeln.

## Den übergroßen Fall zum Teil der Release-Schranke machen

Lass Dekompressionsprüfungen nicht als Sicherheitstest liegen, der nur läuft, wenn sich jemand daran erinnert. Nimm eine Grenz-Testdatei für Gzip und Brotli in die normale Client-Testsuite auf. Führe dieselben Prüfungen durch jeden HTTP-Codepfad aus, der Daten an einen Agenten zurückgeben kann, einschließlich Weiterleitungen, falls dein Client ihnen folgt, und Fehlerantworten, falls er deren Bodies zu Diagnosezwecken liest.

Die Assertions sollten konkret sein. Unter dem Limit erwartest du ein vollständiges dekodiertes Ergebnis und eine erfolgreiche Prüfsummenvalidierung. Genau am Limit erwartest du dasselbe. Ein Byte darüber erwartest du den typisierten Größenfehler, kein geparstes Objekt, kein Agentenergebnis und einen geschlossenen Antwortbody. Bei fehlerhafter Kodierung erwartest du einen Dekodierungsfehler. Bei nicht unterstützter Kodierung erwartest du vor Beginn des Parsens einen ausdrücklichen Fehler für nicht unterstützte Kodierung.

Füge einen Test für einen komprimierten Body mit geringer Übertragungsgröße und einer dekodierten Größe über der Obergrenze hinzu. Dieser Test entdeckt den ursprünglichen Fehler. Ein großer unkomprimierter Body beweist nur, dass ein normaler Byte-Limiter funktioniert. Er sagt nichts über die Grenze am Dekoder aus.

Prüfe jede Änderung, die eine neue HTTP-Bibliothek, einen neuen Komfort-Helfer zum Abrufen oder einen neuen Pfad zum Protokollieren von Antworten einführt. Solche Änderungen umgehen den sorgfältig begrenzten Reader häufig, weil sie isoliert betrachtet harmlos wirken. Die Frage in der Code-Review ist einfach: Wo werden dekodierte Bytes zuerst verfügbar, und welches Limit umschließt genau diesen Reader?

Ist die Antwort unklar, ist die Implementierung nicht bereit für einen autonomen Aufrufer. Eine kleine Antwort auf dem Übertragungsweg hat kein besonderes Vertrauen verdient. Sie muss ihre Größe nach dem Dekodieren belegen, bevor sie deinen Speicher oder die Aufmerksamkeit deines Agenten verbrauchen kann.
