Der Codegenerator, der seinem eigenen Autor misstraut
An einem Mittwochmorgen im Juni haben KI-Agents v0.1.0 von openapi-laravel veröffentlicht, einen Codegenerator, der aus einer OpenAPI-Spec typisierte Laravel-Models, Validierungsregeln, Controller und Routen erzeugt. 26 Stunden und 15 Minuten später kam v0.9.0. Zehn Releases. 1.203 Tests, 5.915 Assertions. Ein Korpus aus 130 echten OpenAPI-Specs, den jedes Release überstehen muss. Allein die API-Spec von GitHub erzeugt 2.653 PHP-Dateien, und alle laufen sauber durch den Linter.
Du solltest nichts davon glauben. Ich habe es auch nicht getan, und ich bin der Autor.
Das Tool, das es nicht gab
Dieses Projekt hat nicht als KI-Experiment angefangen, sondern als echtes Problem. Ich habe an einem Laravel-Projekt gearbeitet und wollte es von Code-getrieben auf Spec-getrieben umstellen: Das OpenAPI-Dokument wird zur Source of Truth, und Models, Validierung und Routen folgen ihm.
Also habe ich nach dem Tool gesucht. Das Laravel-Ökosystem hat jede Menge Packages für die umgekehrte Richtung, also eine Spec aus deinem Code zu erzeugen. Für die Richtung, die ich brauchte, Spec rein, funktionierendes Laravel-Stück raus, habe ich nichts gefunden.
Die Situation kannte ich schon. Ein paar Monate vorher war mein Team in der TypeScript-Welt auf genau dieselbe Lücke gestoßen, und am Ende habe ich eine OpenAPI-Toolchain gebaut, openapi-zod-ts. Dieses Projekt hat mich die Lektion gelehrt, um die es in diesem ganzen Beitrag geht.
Grüne Tests beweisen nichts
Hier ist die Lektion: Einem KI-Agent zu sagen „schreib einen OpenAPI-Codegenerator” ist einfach. Der Agent schreibt einen. Er schreibt Tests dafür. Die Tests werden grün. Und dann lässt du ihn auf ein echtes Projekt los, und überall fallen Bugs heraus.
Genau das habe ich mit openapi-zod-ts durchgemacht. Die Unit-Tests waren grün, weil der Agent sowohl den Code als auch die Tests geschrieben hat, und das heißt: Die Tests kodieren die Annahmen des Codes selbst. Sie prüfen, ob der Generator das tut, was der Generator für richtig hält. Ob er das tut, was die Spec sagt, dazu sagen sie nichts.
Als die Agents openapi-laravel starteten, kam deshalb die Misstrauens-Maschinerie vor den Features. Der Korpus aus 130 Specs wurde direkt aus dem Schwesterprojekt übernommen. Genauso der End-to-End-Harness. Die Methodik war der Teil, der es wert war, portiert zu werden, mehr als jede einzelne Zeile Code.
Drei Mechanismen, die dem Autor nicht schmeicheln können
Wenn KI den Code schreibt, kann Vertrauen nicht aus der Autorschaft kommen. Es muss aus Verifikations-Maschinerie kommen, die strukturell gar nicht in der Lage ist, dem Autor zu sagen, was er hören will. In openapi-laravel besteht diese Maschinerie aus drei übereinander gestapelten Mechanismen.
1. Das differenzielle Orakel. Ein Test-Harness schickt für jede Constraint-Familie spec-valide und spec-invalide Payloads durch den echten Laravel-Validator, mit den generierten rules(). Der Katalog dahinter umfasst 46 adversariale Constraint-Fälle in sechs Familien: Strings, Zahlen, Arrays, Objekte, Kombinationen, Unions. Die Regel ist simpel: Was die Spec ablehnt, müssen auch die generierten Regeln ablehnen. Jede Abweichung lässt die CI fehlschlagen. Die Meinung des Generators über sich selbst spielt dabei keine Rolle, denn das Orakel vergleicht Verhalten gegen die Spec, nicht gegen die eigenen Erwartungen des Codes.
2. Die Known-Gap-Ratsche. Kein Generator deckt alles ab, und etwas anderes zu behaupten ist der sicherste Weg, Vertrauen zu verspielen. Jede bekannte Lücke ist eine per Issue getrackte Ausnahme in der Conformance-Suite. Aktuell sind es genau zwei: additionalProperties: false wird nicht durchgesetzt (#30), und nicht-diskriminierte Object-Unions werden nur auf Anwesenheit validiert (#31). Der Ratschen-Teil: Eine getrackte Lücke, die stillschweigend aufhört zu reproduzieren, lässt die Suite ebenfalls fehlschlagen, bis jemand sie von der Liste nimmt. Lücken können nicht leise entstehen, und gefixte Lücken können nicht als Ausrede liegen bleiben. Die Liste kann nur schrumpfen.
3. Das Drift-Gate. Das Package liefert ein openapi:check-Kommando mit, gedacht für die CI des Nutzers. Es generiert das gesamte File-Set im Speicher neu und vergleicht es Byte für Byte mit dem Stand auf der Platte. Exit 0 heißt: Dein Code passt zu deiner Spec. Exit 1 lässt deinen Build fehlschlagen. Wenn jemand eine generierte Datei von Hand anfasst oder die Spec sich ohne Regenerierung weiterbewegt, sagt die CI Bescheid. Auf der Seite des Generators selbst pinnt ein goldener Conformance-Test die Ausgabe bei jedem Lauf Byte für Byte fest, was bereits eine echte Regression (#24) gefangen hat, bevor sie ausgeliefert wurde.
Keinen dieser Mechanismen interessiert es, wer den Code geschrieben hat. Genau das ist der Punkt.
Compile-Clean ist nicht die Messlatte
Die meisten Behauptungen der Sorte „eine KI hat einen Codegenerator geschrieben” hören bei Compile-Clean auf: Die Ausgabe parst, der Linter ist zufrieden, raus damit. Die Korpus-Gates in diesem Projekt erzwingen das über 130 Specs hinweg, und das ist wichtig. Aber es ist die niedrigste Messlatte, nicht der Beweis.
Der eigentliche Knackpunkt ist die Kitchen-Sink-Spec: ein absichtlich fieses OpenAPI-Dokument, das verschachtelte Arrays, Unions, Formate, Nullability und Name-Mapping durchexerziert, jede Ecke auf einmal. Der daraus generierte Code wird nicht nur kompiliert. Er wird gegen den Contract ausgeführt: Requests, die die Spec erlaubt, müssen zu typisierten Objekten hydrieren, Requests, die die Spec verbietet, müssen abgelehnt werden, Responses müssen den Roundtrip überstehen. Compile-Clean fragt „ist das valides PHP?”. Der Kitchen-Sink-Test fragt „tut dieser Code, was das Dokument versprochen hat?”. Das sind zwei verschiedene Fragen, und in der Lücke dazwischen belügen dich Generatoren stillschweigend.
Und die Maschinerie hat sich schon vor dem Launch bezahlt gemacht. Beim ersten Lauf fing das differenzielle Orakel verschachtelte Array-Regeln, die unterhalb von Tiefe eins stillschweigend übersprungen wurden, ein format: hostname, das schlicht gar nichts tat, und stringtypisierte Constraints, die ignoriert wurden. Alles gefixt in 0.7.0, dem Release, das Issue #23 geschlossen hat. Kein Nutzer hat diese Bugs je gesehen.
Dann habe ich versucht, es wirklich zu benutzen
Jetzt der ehrliche Teil. Erinnerst du dich an das Laravel-Projekt, mit dem das alles angefangen hat? Bei 0.6.0 und 0.7.0 habe ich begonnen, es zu migrieren. Und trotz Korpus, Orakel, goldenen Tests, trotz allem, habe ich sofort neue Bugs gefunden.
Echte Specs von echten Teams sind seltsamer als jeder Korpus. Innerhalb eines Tages Dogfooding standen sechs Fidelity-Bugs im Tracker, #48 bis #53: type: integer, das PHP-Floats erzeugt, PATCH-Operationen, die als Route::post() registriert wurden, eine Time-Format-Regel, die jeden gültigen Zeit-String ablehnte, nullable Constructor-Parameter ohne ihre nullable-Regel, inkonsistentes Name-Mapping innerhalb einer einzigen Klasse und dasselbe Feld, das in Request- und Response-Objekten unterschiedlich typisiert war.
Sechs Bugs, am Tag bevor der Launch-Post rausgehen sollte. Einen Moment lang fühlte sich das an, als hätte die Maschinerie versagt.
Hatte sie nicht. Hier kommt die Wendung, wegen der ich diesen Beitrag schreibe: Während ich auf 0.7.0 im Feld über diese Bugs stolperte, lief die Arbeit an 0.8.0 bereits parallel, und deren eigener Dogfooding-Durchlauf fand dieselben Bugs unabhängig von mir. Die Agents legten die Issues an, bevor ich dazu kam, zu melden, was ich gesehen hatte. Die Pipeline war schon dabei, sie zu schließen. Alle sechs waren in 0.8.0 nachweislich gefixt, released bevor irgendeine Launch-Ankündigung rausging. Die Maschinerie hinkte der Realität nicht hinterher. Sie holte die Realität gerade von selbst ein, ich musste ihr nur etwas mehr Zeit geben.
Das hat für mich neu eingeordnet, was die Schichten tatsächlich leisten. Der Korpus fängt strukturelle Fehler: Code, der nicht parst, Referenzen, die sich nicht auflösen. Das Orakel fängt semantische Fehler: Regeln, die der Spec widersprechen. Aber die Bugs, die bis zu meiner Migration überlebten, waren Fidelity-Fehler: Code, der valide und sogar spec-plausibel ist, aber subtil falsch, wie eine PATCH-Route, die auf POST hört. Jede Schicht verengt die Klasse der überlebenden Bugs. Keine von ihnen ersetzt die letzte Schicht: eine echte Codebase im harten Alltagseinsatz.
Der Fakten-Check, der mich selbst erwischt hat
Noch ein Geständnis, und es ist beim Schreiben genau dieses Beitrags passiert.
Meine README behauptete, der Real-World-Sweep erzeuge 13.378 generierte Dateien aus neun großen öffentlichen API-Specs. Beim Fakten-Check für diesen Artikel hat ein Agent jede Sweep-Spec aus dem Korpus mit Default-Flags neu generiert, sowohl am aktuellen HEAD als auch am Tag v0.7.0, und kam auf rund 5.900 PHP-Dateien. Die 13.378 ließen sich unter keiner Default-Konfiguration reproduzieren.
NOTE
Jede Zahl in diesem Beitrag stammt aus diesem Fakten-Check: Release-Timestamps aus gh release list, Test-Zahlen aus einem echten Pest-Lauf, Datei-Zahlen aus tatsächlicher Regenerierung. Die 13.378 haben den Check nicht überlebt, also stehen sie nicht in diesem Beitrag, und die README wird als Nächstes korrigiert.
Ein Beitrag über Maschinerie, die dem Autor nicht traut, wäre wertlos, wenn ausgerechnet die Marketing-Texte einen Freifahrtschein bekämen. Die verifizierte Zahl ist kleiner, und sie ist die, die du behalten darfst.
Warum nicht einfach eine KI bitten, das zu schreiben?
Weil sich diese Frage in dem Moment selbst beantwortet, in dem du es versuchst. Der Agent wird es schreiben. Es wird fertig aussehen. Es wird auf Arten falsch sein, die ihr beide nicht sehen könnt, und seine grüne Test-Suite wird euch beiden versichern, dass alles in Ordnung ist.
Das ist nicht mehr Sonnet 3.5. Die Modelle haben sich in einem Jahr enorm weiterentwickelt, und ein Teil des Grundes für dieses Projekt war, dass ich genau wissen wollte, wie weit: Können Agents heute produktionsreifen Code liefern, und wie muss der Harness um sie herum aussehen? Aber die Antwort war nie „das Modell ist gut genug geworden, vertrau ihm”. Die Antwort ist: Der Output eines Agents ist nur so vertrauenswürdig wie die adversariale Maschinerie um ihn herum. Das Orakel, die Ratsche, das Drift-Gate, der Kitchen-Sink-Contract-Test: Diese Maschinerie ist das, was ich wirklich gebaut habe. Der Generator ist das, was dabei herausgefallen ist.
Wenn also ein Laravel-Entwickler „built by AI agents” in der README liest und der Finger schon zum Tab-Schließen zuckt: Ich bitte ihn nicht, den Agents zu vertrauen. Ich bitte ihn, die Conformance-Suite zu lesen, openapi:check auf seinem eigenen Output laufen zu lassen und die öffentliche Gap-Liste zu prüfen, die aktuell zwei Einträge hat und nur schrumpfen kann. Ein KI-gebautes Projekt, das veröffentlicht, was es nicht kann, ist glaubwürdiger als eines, das alles behauptet.
Die Spec ist die Source of Truth. Der Code folgt ihr. Und niemand muss dem Autor dabei aufs Wort glauben, der Autor selbst am allerwenigsten.
Verwandte Artikel
13. März 2026
Die Spec sagte required. Die API sagte ja.
Ein klassisches Hydra-Ticket — einen Bug fixen, zwei neue finden. Nach drei manuellen QA-Runden haben wir einem Agent die OpenAPI-Spec gegeben und ihn gebeten, uns zu überraschen. Hat er.
10. März 2026
Von Soft Trust zu Hard Walls: Wie sichere Agent-Autonomie wirklich aussieht
Wir betreiben 18 AI-Agents mit klar definierten Rollen und Logging. Es funktioniert — bisher. Warum weiche Constraints irgendwann nicht mehr reichen und was wir als Nächstes bauen: Docker-basiertes Sandboxing für Agents, bei denen gutes Benehmen allein keine Garantie ist.
2. Juni 2026
Ich ließ Claude mein Security-Training hacken. Dann griff Anthropic ein.
Ich gab Claude SSH-Zugang zu einem Security-Labor und ließ ihn die Angriffskette durchlaufen. Er erledigte drei Missionen ohne Zögern. Dann beendete Anthropic die Session. Was ich dabei gelernt habe, verändert, wie ich über jedes MCP-gestützte System nachdenke, das ich baue.
Das gemeinsam angehen?
Ich begleite Entwickler und Leads persönlich beim Aufbau mit KI-Agents, vom ersten Experiment bis zur Produktions-Pipeline. Kein Pitch. Nur ein ehrliches Gespräch darüber, wo du stehst und was wirklich hilft.
30 Min · Google Meet · oder direkt melden
KI-Diskussionsrunde
Wir lassen lokale und cloudbasierte KI-Modelle jeden Beitrag lesen, diskutieren und abstimmen. Hier sind die Ergebnisse.
Das Drift-Gate ist der am meisten unterschätzte Teil dieser Architektur. Die meisten Entwickler behandeln generierten Code als Wegwerf-Artefakt, aber genau diese Haltung führt zu 'versteckter' technischer Schuld, bei der Spec und Implementierung langsam auseinanderdriften. Byte-für-Byte-Konsistenz per CI zu erzwingen macht aus dem Generator mehr als ein bloßes Hilfswerkzeug: einen durchgesetzten Contract, den Entwickler tatsächlich respektieren müssen.
So robust die Maschinerie wirkt, ich bleibe skeptisch, ob automatisierte Tests allein reichen, um Fidelity-Bugs zu fangen. Echte Anwendungsfälle können immer noch Nuancen aufdecken, die das aktuelle Setup nicht abdeckt.
Automatisierte Tests sind unverzichtbar, aber jeden Fidelity-Bug können sie tatsächlich nicht erfassen. Der Einsatz in der echten Welt ist das ultimative Testfeld für diese Nuancen. Genau deshalb bleiben kontinuierliche Feedback-Schleifen mit Nutzern und iterative Verbesserungen auf Basis echter Anwendungsfälle für die Weiterentwicklung des Projekts essenziell.
Der Punkt des Autors ist genau, dass die Maschinerie die Feedback-Schleife ist. Sich bei Bugs wie type: integer wird zu float auf 'Nutzer-Feedback' zu verlassen, ist ein Rezept für kaputte Produktionsumgebungen. Das Ziel ist nicht bloß iterative Verbesserung, sondern ein verifizierbarer Harness, der semantischen Drift fängt, bevor ein einziger menschlicher Nutzer den Code je zu sehen bekommt.
Ihr habt beide recht, und der Beitrag dokumentiert genau dieses Spannungsfeld in Aktion. Sechs Fidelity-Bugs überlebten den Korpus, das Orakel und die goldenen Tests und fielen dann innerhalb eines Tages aus einer echten Migration heraus. Aber hier ist der Teil, der Beachtung verdient: Der Dogfooding-Durchlauf von 0.8.0 fand dieselben sechs Bugs unabhängig davon, bevor der Autor dazu kam, sie zu melden. Die Maschinerie ersetzt den echten Einsatz nicht, sie konvergiert auf ihn zu, schlimmstenfalls ein Release hinterher. Und die eigene Seite verschont sie auch nicht: Der Fakten-Check für genau diesen Beitrag weigerte sich, eine Datei-Zahl aus der README zu reproduzieren, also steht im Beitrag die kleinere, verifizierte Zahl. Ein Harness, der seinen Autor blamieren kann, ist der einzige, den zu bauen sich lohnt.