# Änderungen am API-Schema: Contract-Tests für sicherere Agenten

Ein Agent kann eine kleine API-Änderung schneller in einen echten Aktionsfehler verwandeln als ein von einem Menschen bedienter Client. Ein umbenanntes Antwortfeld kann dazu führen, dass er alle Ressourcen statt einer einzigen auswählt. Ein neu eingeführter Default-Wert kann eine Abfrage ausweiten. Ein geänderter Status kann wie eine Erlaubnis zum Wiederholen aussehen. Der Wiederholungsversuch kann dann eine Abbuchung, ein Deployment oder eine Löschanfrage erneut ausführen.

Das Gefährliche daran: Solche Fehler sehen in der herkömmlichen Überwachung oft gesund aus. Der Provider liefert HTTP 200. Der Client stürzt nicht ab. Der Agent gibt eine plausible Erklärung aus. Contract-Tests müssen prüfen, welche Bedeutung ein Agent API-Daten zuweist, nicht nur, ob sich das JSON parsen lässt.

## Agentenentscheidungen machen Kompatibilität zu einer Sicherheitseigenschaft

Ein API-Client, den ein Mensch verwendet, fällt bei einer geänderten Antwort oft sichtbar aus. Ein Button zeigt eine leere Tabelle, ein Formularfehler erscheint und jemand untersucht das Problem, bevor die nächste Aktion erfolgt. Agenten wandeln eine Antwort dagegen häufig direkt in eine weitere Anfrage um. Das kann mehrmals geschehen, bevor jemand ein Protokoll sieht.

Betrachte einen Agenten, der zur Bereinigung `GET /projects?state=inactive` aufruft, aus jedem Element das Feld `owner` liest und vor dem Archivieren von Projekten außerhalb einer Allowlist eine Genehmigung einholt. Der Provider ändert später `owner` in `owner_id`, behält aber den alten Endpunkt und den Statuscode bei. Ein toleranter Parser ordnet dem fehlenden `owner` eine leere Zeichenkette zu. Wenn die Regel des Agenten besagt, dass ein leerer Besitzer für «nicht zugewiesen» steht, bereitet er eine viel umfassendere Archivierungsanfrage vor.

Das ist weder ein Authentifizierungsfehler noch ein Prompt-Fehler. Es ist ein Interpretationsfehler an der API-Grenze. Genau dort muss auch die Korrektur ansetzen.

Behandle jedes Feld, das eine dieser Entscheidungen beeinflusst, als Teil eines Sicherheitsvertrags:

- auf welches Objekt der Agent einwirken darf
- ob ein Objekt für die Aktion geeignet ist
- Umfang, Betrag oder Ziel der Aktion
- ob eine vorherige Aktion abgeschlossen oder fehlgeschlagen ist oder wiederholt werden muss
- ob der Agent vor dem Fortfahren eine Person fragen soll

Diese Unterscheidung ist wichtig, weil Transportkompatibilität viel schwächer ist als Verhaltenskompatibilität. Ein Dienst kann Endpunkt, Methode, Authentifizierungsschema und JSON-Syntax beibehalten und trotzdem die Entscheidung brechen, die auf die Antwort folgt. Teams bezeichnen das oft als nicht abwärtskompatibel, weil vorhandene SDKs die Antwort weiterhin deserialisieren. Für einen autonomen Aufrufer kann diese Bezeichnung gefährlich unvollständig sein.

Erstelle eine kleine Übersicht über alle Antwortwerte, die einen Aktionsselektor, eine Autorisierungsentscheidung oder einen Wiederholungszweig erreichen. Beginne nicht mit jeder Eigenschaft einer riesigen API-Spezifikation. Beginne mit den Werten, deren falsche Interpretation die Handlungsmöglichkeiten des Agenten verändert.

## Ein Schema-Diff kann keine Verhaltenskompatibilität beweisen

Tools für Schema-Diffs erkennen wichtige Änderungen. Sie können aber nicht entscheiden, ob eine Änderung für einen bestimmten Agenten sicher ist. Sie vergleichen Deklarationen. Ein Agent hängt von Bedeutungen ab, die oft außerhalb dieser Deklarationen liegen.

Angenommen, ein Provider ändert `limit` von einem optionalen Parameter mit einem impliziten Default von 100 zu einem optionalen Parameter mit einem impliziten Default von 1000. Ein gewöhnlicher OpenAPI-Diff zeigt möglicherweise keine Änderung an einer Pflicht-Eigenschaft. Ein Agent, der `limit` auslässt, kann nun jedoch zehnmal so viele Objekte untersuchen und eine Sammelaktion über alle diese Objekte senden.

Die OpenAPI Specification beschreibt ein Schema Object als Obermenge des Vokabulars von JSON Schema und erklärt, dass seine Eigenschaften Informationen für Anfrage- und Antwortdaten liefern. Das ist nützlich für Dokumentation und Validierung. Es sagt jedoch nicht, dass `state: "pending"` einen Wiederholungsversuch erlaubt oder dass ein ausgelassenes `limit` weiterhin auf 100 begrenzt ist. Das sind Workflow-Aussagen. Deine Tests müssen sie in klaren Worten festhalten.

Auch die `default`-Annotation von JSON Schema zwingt einen Validator oder Client nicht dazu, einen Wert einzusetzen. Viele Entwickler nehmen das an. Die Dokumentation von JSON Schema behandelt `default` als Annotierungsdaten, nicht als Befehl, der eine Instanz verändert. Wenn deine Sicherheit von einem Wert abhängt, sende ihn ausdrücklich aus dem Client und teste die exakte ausgehende Anfrage. Erwarte nicht, dass eine Schema-Annotation ein ausgelassenes Feld rettet.

Verwende ein Diff-Tool als Warnsignal. Ordne danach jede gemeldete Änderung dem Aktionspfad zu, den sie beeinflussen kann:

- Ein umbenannter Bezeichner kann das ausgewählte Ziel ändern.
- Ein neuer Enum-Wert kann den Parser in einen ungetesteten Zweig führen.
- Eine Änderung des Default-Werts kann den Umfang ohne Änderung am Anfragecode verändern.
- Eine Änderung der Darstellung kann die Bedeutung von Abschluss oder Fehler umkehren.

Die umgekehrte Situation ist ebenfalls wichtig. Ein Diff-Tool meldet vielleicht ein zusätzliches beschreibendes Feld, das kein Agent liest. Das verdient eine Prüfung, aber keinen Produktionsstopp. Die Kompatibilitätsprüfung wird besser, wenn sie den Daten bis zu einer Entscheidung folgt, statt jede Zeile des Schemas als gleich riskant zu behandeln.

## Contract-Tests müssen Anfragen und Entscheidungen festschreiben

Ein nützlicher Contract-Test hat zwei Hälften: Er prüft die Anfrage, die der Agent tatsächlich sendet, und anschließend die Aktion, die der Agent nach dem Lesen einer Provider-Antwort vorschlägt. Wird nur eine Hälfte getestet, bleibt ein großer blinder Fleck.

Bei Default-Werten solltest du eine echte HTTP-Anfrage an einem lokalen Testserver oder in einer Provider-Sandbox erfassen. Das folgende Python-Beispiel verwendet `httpx.MockTransport`, um eine ausgehende Anfrage zu prüfen. Es verhindert den häufigen Fehler, dass ein Client sich bei einer destruktiven Aktion stillschweigend auf einen Provider-Default verlässt.

```python
import httpx

seen = []

def handler(request: httpx.Request) -> httpx.Response:
    seen.append({
        "method": request.method,
        "path": request.url.path,
        "query": dict(request.url.params),
    })
    return httpx.Response(200, json={"items": []})

client = httpx.Client(transport=httpx.MockTransport(handler))

response = client.get(
    "https://api.example.test/projects",
    params={"state": "inactive", "limit": "100"},
)

assert response.status_code == 200
assert seen == [{
    "method": "GET",
    "path": "/projects",
    "query": {"state": "inactive", "limit": "100"},
}]
```

Die wichtige Assertion ist nicht die 200-Antwort. Es ist das ausdrücklich gesetzte `limit`. Wenn ein Refactoring diesen Parameter entfernt, schlägt der Test fehl, bevor ein neuer Default des Providers die Auswahl ausweiten kann.

Teste danach die Entscheidung. Halte die Planungsfunktion des Agenten vom Code für den HTTP-Aufruf getrennt. So kann der Test eine vorgeschlagene Aktion prüfen, ohne sie auszuführen.

```python
from dataclasses import dataclass

@dataclass
class ArchivePlan:
    project_ids: list[str]
    requires_approval: bool

def plan_archives(items: list[dict], allowed_owners: set[str]) -> ArchivePlan:
    targets = []
    for item in items:
        owner = item.get("owner")
        if owner is None:
            raise ValueError("provider response lacks owner")
        if item["state"] == "inactive" and owner in allowed_owners:
            targets.append(item["id"])
    return ArchivePlan(targets, requires_approval=bool(targets))

items = [
    {"id": "p17", "state": "inactive", "owner": "team-a"},
    {"id": "p18", "state": "inactive", "owner": "team-b"},
]

plan = plan_archives(items, {"team-a"})
assert plan.project_ids == ["p17"]
assert plan.requires_approval is True
```

Dieser Test trifft eine Entscheidung, die toleranter Code oft vermeidet: Ein fehlendes `owner` löst einen Fehler aus. Bei einem Feld, das die Aktionsauswahl steuert, sollte der Prozess sicher abbrechen. Eine leere Zeichenkette, `None` oder ein vermuteter Ersatzwert kann den Ablauf zwar fortsetzen. Er ersetzt aber einen erkennbaren Integrationsfehler durch einen möglicherweise unsicheren Plan.

Halte Fixtures klein genug, damit ein Reviewer erkennt, warum jedes Element enthalten ist. Eine Fixture mit tausend Objekten kann der Produktion ähneln, verbirgt aber die Bedingung, die du eigentlich schützen wolltest.

## Umbenannte Felder brauchen ein ausdrücklich festgelegtes Fehlerverhalten

Ein umbenanntes Feld sollte einen Aktionspfad stoppen, sofern du nicht während einer klar definierten Migration absichtlich beide Namen unterstützt. Stille Fallbacks wirken in einer Demo robust und schaffen in der Produktion ungeprüfte Bedeutungen.

Die schlimmste Variante sieht so aus:

```python
owner = item.get("owner", "")
if owner not in blocked_owners:
    archive(item["id"])
```

Wenn `owner` verschwindet, scheint jedes Element einen Besitzer zu haben, der nicht gesperrt ist. Der Parser tut genau das, was der Code verlangt. Der Entwickler wollte wahrscheinlich einen `KeyError` vermeiden. Diese kleine Bequemlichkeit macht aus fehlenden Daten eine Erlaubnis zu handeln.

Schreibe Tests für alle drei Situationen: das erwartete Feld, das alte Feld, falls du vorübergehend beide Namen unterstützt, und keines der beiden Felder. Der dritte Test muss festhalten, ob der Agent stoppt, das Objekt überspringt oder eine Klärung anfordert. Bei Zielidentität, Autorisierungsstatus und Aktionsumfang ist ein Stopp normalerweise die richtige Antwort.

Wenn du einen Alias unterstützt, muss seine Priorität offensichtlich und die Unterstützung zeitlich begrenzt sein:

```python
def read_owner(item: dict) -> str:
    if "owner" in item:
        return item["owner"]
    if "owner_id" in item:
        return item["owner_id"]
    raise ValueError("owner identity missing")
```

Auch dieser Code braucht einen Test für widersprüchliche Daten. Wenn beide Felder ankommen und nicht übereinstimmen, darfst du nicht stillschweigend eines bevorzugen. Löse einen Fehler aus und lass den Provider die Mehrdeutigkeit klären. Eine Kompatibilitätsschicht sollte eine bekannte alte Bedeutung erhalten, nicht bei widersprüchlichen Datensätzen einen Gewinner erfinden.

Teams argumentieren manchmal, tolerantes Parsen schütze vor der Weiterentwicklung eines Providers. Es schützt vor harmlosen Ergänzungen, wenn unbekannte Felder ignoriert werden. Es schützt nicht vor fehlenden Feldern, die eine Aktion steuern. In diesen Fällen ist das entgegengesetzte Verhalten nötig: Zusätzliche Informationen standardmäßig akzeptieren, aber fehlende erforderliche Bedeutung ablehnen.

## Defaults und ausgelassene Werte brauchen getrennte Tests

Eine ausgelassene Eigenschaft, ein explizites null und ein expliziter Wert sind drei verschiedene Anfragen. Agenten verwischen diese Unterschiede oft, weil auch Serialisierer für allgemeine Zwecke sie verwischen.

Ein Anfrage-Builder kann `dry_run` auslassen, wenn sein interner Wert `None` ist. Der Provider interpretiert das möglicherweise als `false`. In einer späteren Version kann der Provider das Auslassen als «Kontoeinstellung verwenden» verstehen. Diese Kontoeinstellung ist für einen Mandanten false und für einen anderen true. Der Agentencode hat sich nicht geändert, die Aktion aber schon.

Ordne Optionen, die Entscheidungen beeinflussen, einer von zwei Kategorien zu. Bei Optionen mit bekanntem sicherem Verhalten sende den Wert jedes Mal. Bei Optionen, die eine Entscheidung durch einen Operator benötigen, verlange diese Entscheidung, bevor du die Anfrage erstellst. Vermeide bei destruktiven oder extern sichtbaren Aktionen eine dritte Kategorie namens «Der Server soll entscheiden».

Teste die Serialisierung mit einer Tabelle aus exakten Fällen. Entscheidend ist die Darstellung auf der Leitung, nicht nur das Sprachobjekt vor der Serialisierung.

| Absicht | Ausgehende Darstellung | Erwartete Bedeutung beim Provider |
| --- | --- | --- |
| Inaktive Projekte lesen | `state=inactive&limit=100` | Begrenzte Auswahl |
| Archivierung simulieren | `{"dry_run": true}` | Es wird nichts archiviert |
| Ein Projekt archivieren | `{"project_ids":["p17"],"dry_run": false}` | Nur p17 darf geändert werden |
| Keine Auswahl des Operators für den Modus | Anfrage wird lokal abgelehnt | Der Provider erhält nichts |

Sei auch bei Pagination strikt. Eine Antwort, die `next_cursor` ergänzt, kann einen Agenten dazu verleiten, automatisch jede Seite abzurufen. Für einen Bericht kann das sinnvoll sein, für einen Aktionsplaner aber riskant. Teste sowohl die maximale Objektzahl, die der Planer berücksichtigen darf, als auch die Bedingung, die eine zweite Seite erlaubt. Ein Cursor ist ein Mechanismus zum Fortsetzen, keine Zustimmung zu unbegrenztem Umfang.

Defaults des Providers sind auch in Antworten wichtig. Wenn eine API `archivable` nicht mehr sendet, sobald der Wert false ist, ändert Code wie `if item.get("archivable", True)` sein Verhalten in die unsichere Richtung. Bei einem Feld, das eine Berechtigung erteilt, solltest du einen ausdrücklichen Vergleich wie `item.get("archivable") is True` verwenden. Das ist weniger elegant und deutlich leichter zu prüfen.

## Die Antwortvalidierung muss die Bedeutung bewahren, nicht nur die Form

Die Antwortvalidierung sollte fehlerhafte Daten von unbekannten, aber harmlosen Daten unterscheiden. Uneingeschränkte Strenge lässt Clients scheitern, wenn Provider neue Felder ergänzen. Uneingeschränkte Toleranz verwandelt fehlende Belege in Vermutungen.

Definiere ein schmales Antwortmodell für die Werte, die in die nächste Aktion einfließen. Lege für jeden Wert Typ, zulässige Zustände und die Frage fest, ob sein Fehlen den Workflow stoppt. Eine Projekt-ID braucht mehr als den Typ `string`: Der Agent braucht eine nicht leere, stabile Kennung, die später mit der Kennung in der Archivierungsanfrage übereinstimmt. Ein Status braucht mehr als den Typ `string`: Der Agent benötigt einen festgelegten Zustand mit dokumentierter Aktion für jedes mögliche Element.

Dieser Parser behandelt beispielsweise eine geänderte Statusdarstellung, ohne sich selbst die Erlaubnis für einen Wiederholungsversuch zu geben:

```python
ALLOWED_STATES = {"queued", "running", "succeeded", "failed"}

def retryable(job: dict) -> bool:
    status = job.get("status")
    if status not in ALLOWED_STATES:
        raise ValueError(f"unknown job status: {status!r}")
    return status == "failed" and job.get("retry_allowed") is True
```

Wenn der Provider `status` von einer Zeichenkette in ein Objekt wie `{"phase":"failed"}` ändert, stoppt dieser Code. Das ist richtig, bis jemand entscheidet, wie die neue Darstellung dem bisherigen Workflow zugeordnet wird. Wenn der Provider `cancelled` ergänzt, ist ein Stopp ebenfalls richtig, bis das Team entscheidet, ob eine Stornierung endgültig ist, wiederholt werden darf oder einen Menschen benötigt.

Mache nicht jeden unbekannten Enum-Wert bei einer reinen Anzeige zu einem Notfall. Die Reaktion sollte zur Aktion passen. Ein Berichtsagent kann einen unbekannten Status kennzeichnen und fortfahren. Ein Agent, der einen Abrechnungsvorgang wiederholen oder eine Ressource löschen soll, muss stoppen, bevor er auf Basis eines nicht verstandenen Status handelt.

Teste auch Beziehungen zwischen Feldern. Eine Antwort kann strukturell gültig sein und trotzdem einen widersprüchlichen Zustand enthalten, etwa `status: "succeeded"` zusammen mit `retry_allowed: true`. Die Schema-Validierung drückt normalerweise nicht jede geschäftliche Invariante aus. Ein Contract-Test sollte festhalten, dass ein erfolgreicher Job keinen Wiederholungsplan erzeugt, unabhängig von einem fehlerhaften booleschen Wert.

## Teste den gesamten Aktionspfad, nicht nur einen bequemen Mock

Unit-Tests für Parser sind notwendig. Sie beweisen aber nicht, dass der bereitgestellte Agent über seinen tatsächlichen Zugang und Ausführungspfad die beabsichtigte Anfrage sendet. Serialisierungsbibliotheken, Wrapper, Tool-Adapter und Wiederholungs-Middleware können das Verhalten auf eine Weise verändern, die ein direkter Funktionsaufruf nicht sichtbar macht.

Starte in CI einen lokalen Contract-Server, der Anfragen aufzeichnet und versionierte Fixtures zurückgibt. Richte die Tool-Konfiguration des Agenten auf diesen Server. Der Test sollte eine realistische Anweisung ausführen, auf den vorgeschlagenen Plan oder Aktionsdatensatz warten und die aufgezeichnete Abfolge prüfen: Methode, Pfad, Query, sicher prüfbare Header, Body und Anzahl der Aktionen.

Lege in dieser Umgebung keine echten Geheimnisse ab. Verwende ein Testkonto ohne Berechtigungen und prüfe, dass der Agent es nie in seinem Prompt, Tool-Ergebnis, Ausnahme-Text oder Trace erhält. Ein Test, der Anfrage-Header unvorsichtig protokolliert, kann genau die Offenlegung von Zugangsdaten reproduzieren, die er verhindern sollte.

Bei Agenten, die über Sallyport externe HTTP- oder SSH-Aufrufe ausführen, kann der Aktionspfad die Zugangsdaten vom Agenten fernhalten und trotzdem ein prüfbares Ergebnis liefern. Diese Grenze behebt jedoch keine falsche Interpretation einer Antwort. Führe Schema- und Entscheidungsverträge aus, bevor die externe Aktion erlaubt wird.

Nimm nicht nur erfolgreiche Antworten, sondern auch Fehler-Fixtures auf. Verwende exakt die Bedingungen, die Provider bei Umstellungen erzeugen: ein fehlendes Auswahlfeld, ein neues Enum-Element, ein leeres Ergebnis mit Fortsetzungscursor, eine Änderung des Content-Types und eine 200-Antwort mit einem Fehlerobjekt. Ein Fehlerkörper in einer 200-Antwort kommt besonders bei älteren APIs häufig vor. Wenn dein Parser annimmt, dass jede 200-Antwort die Erfolgsform enthält, kann er einen leeren Plan erzeugen oder eine Anfrage wiederholen, die bereits erfolgreich war.

Prüfe bei Wiederholungsversuchen das Idempotenzverhalten. Lass der Contract-Server zunächst nach der Aufzeichnung einer Anfrage eine Zeitüberschreitung zurückgeben und bei der Wiederholung eine zweite Antwort liefern. Der Test muss beweisen, dass der Client, sofern die API das unterstützt, ein Idempotenz-Token sendet oder stoppt und eine Bestätigung anfordert, wenn er nicht wissen kann, ob die erste Aktion abgeschlossen wurde. Das Wiederholen eines Lesevorgangs ist meist harmlos. Eine Überweisung, E-Mail, Bereitstellung oder Löschanfrage zu wiederholen ist es nicht.

## Release-Gates sollten semantische Fehler blockieren

Führe Schema-Diffs, Provider-Contract-Tests und Agenten-Entscheidungstests im Änderungsprozess sowohl für API-Anbieter als auch für Agenten-Consumer aus. Ein Release-Prozess, der sie erst nach dem Deployment startet, macht aus den Tests lediglich eine Dokumentation des Vorfalls.

Verlange bei einer Provider-Änderung einen Prüfdatensatz, der vier konkrete Fragen beantwortet: Welche Annahmen der Consumer ändern sich? Wie war das alte Verhalten? Wie lange bleiben beide Verhaltensweisen unterstützt? Welche Fixture zeigt das neue Verhalten? Das ist weniger Aufwand, als einen Produktionsfehler mit unvollständigen Logs zu untersuchen.

Führe bei einer Agentenänderung vor dem Merge die vorhandene Suite mit Provider-Fixtures aus. Wenn der Agent jetzt ein neu hinzugefügtes Feld verwendet, ergänze Fixtures für dessen Fehlen und für Werte außerhalb des erwarteten Erfolgsfalls. Auch Änderungen am Prompt-Wortlaut können Tool-Argumente verändern. Teste deshalb den Tool-Aufruf des gesamten Agenten, statt anzunehmen, dass der Planer weiterhin dieselben Parameter auswählt.

Versionierte Fixtures machen Reviews praktikabel. Speichere eine Kennung wie `projects-list-v1` zusammen mit dem erwarteten Anfrage-Antwort-Paar. Wenn ein Provider bewusst `projects-list-v2` einführt, behalte die alte Fixture bis zum Ende der Migrationsregelung. Überschreibe nicht einfach das alte JSON und nenne die Tests aktuell. Sonst verlierst du den Nachweis, welche Kompatibilität du aufgegeben hast.

Ein gutes Gate meldet Fehler in operativer Sprache. «Erforderliches Feld owner fehlt, Planung der Archivierung gestoppt» sagt einem Reviewer, was passiert ist. «ValidationError at path items.0» ist besser als nichts, zwingt den Reviewer aber dazu, das Risiko während eines Releases selbst zu rekonstruieren.

## Genehmigungsansichten können einen irreführenden Plan nicht korrigieren

Die menschliche Genehmigung bleibt eine gute Kontrolle für externe Aktionen. Sie kommt aber zu spät, wenn der Agent aus einem geänderten Vertrag den falschen Plan erstellt hat. Eine Person, die «847 inaktive Projekte archivieren» sieht, kann die Aktion ablehnen. Eine Person, die «Projekt p17 archivieren» sieht, kann nicht erkennen, ob p17 aus einem fehlenden `owner`-Feld, einem ausgeweiteten Default oder einem Parser stammt, der `cancelled` mit `failed` verwechselt hat.

Die Genehmigungsdatensätze sollten die Entscheidungsgrundlagen enthalten, die ein Mensch prüfen muss: Ziel-IDs, Anzahl, angeforderter Modus und die Antwortfelder, durch die das Ziel als geeignet eingestuft wurde. Halte den Datensatz kompakt. Unverarbeitetes JSON auf einer Genehmigungsseite verlagert die Parsing-Aufgabe nur vom Code auf eine müde Person.

Bewahre zusätzlich einen Trace auf, mit dem ein Entwickler die Aktion rekonstruieren kann. Erfasse die Provider-Antwort oder einen geschützten Digest davon, die Parser-Version, die Fixture-Version des Vertrags, die erzeugte Anfrage und die resultierende Antwort. Ein manipulationssicherer Audit-Trail hilft im Nachhinein. Er sollte aber auf die Entscheidungsgrenze verweisen, statt nur festzuhalten, dass ein HTTP-Aufruf stattgefunden hat.

Wenn ein API-Team das nächste Mal sagt, eine Antwortänderung sei kosmetisch, bitte es, die Agenten-Contract-Suite dagegen auszuführen. Wenn die Suite fehlschlägt, hängt an der Änderung ein konkretes Verhalten. Behebe das, bevor aus einer höflichen 200-Antwort eine unsichere Aktion wird.
