Die Kontroll-Schleife — KI-generierten Code prüfen lassen, den man selbst nicht lesen kann

Wer Code liest, um ihn zu kontrollieren, braucht zwei Dinge: die Sprache und die Zeit. Im DI²-Projekt fehlen beide. Der Maintainer kommt aus der Datenbank-Entwicklung und kennt weder TypeScript noch die Webentwicklung, in der die Anwendung gebaut ist. Und selbst wer die Sprache beherrscht, liest die Menge an Code nicht mehr durch, die ein Coding-Agent an einem Nachmittag schreibt.

Das ist kein Offenbarungseid, sondern eine Änderung der Arbeitsweise. Wer KI-generierten Code prüfen muss, ohne ihn lesen zu können, braucht Prüfungen, die ein Ergebnis liefern, das auch ohne Sprachkenntnis zu beurteilen ist. Ausführen kann sie der Agent selbst, beurteilen muss ihr Ergebnis der Mensch.

Dieser Artikel beschreibt, wie diese Schleife im DI²-Projekt aussieht, welche Belege es dafür gibt, dass sie tatsächlich läuft, was sie gefunden hat und wo sie versagt hat. Ihr wichtigster Fund war eine Drosselung gegen das Durchprobieren von Passwörtern, die korrekt konfiguriert war und trotzdem niemanden schützte. Die Skills, Tests und Audits sind Agenten-Artefakte. Der Maintainer hat die Auslöser gesetzt, die Kriterien formuliert und abgenommen.

Das Wichtigste vorab:

  • Kontrolle ist eine Schleife, kein Review: Fünf Stationen laufen wiederkehrend — Regeln nachschärfen, Skills schärfen, Tests nachrüsten, Testfälle deklarieren, Updates und Audits fahren. Jede hat einen Auslöser, ein Abnahme-Kriterium und einen Ort, an dem ihr Ergebnis landet.
  • Prüfbar ist, was ein Ergebnis hat: Ein Testlauf, ein Statuscode, ein Zähl-Pass und ein Audit-Bericht sind ohne Sprachkenntnis zu beurteilen. Eine Zeile Code ist es nicht. Ob eine Prüfung das Richtige prüft, ist damit noch nicht gesagt.
  • Die Schleife ist nachträglich entstanden: Das Projekt startete im März 2026, das Test-Fundament kam Anfang Juli, der Katalog manueller Testfälle Ende August. Das war kein Plan von Anfang an.
  • Die Zahlen belegen, dass geprüft wird — nicht, dass es wirkt: 28 Regel-Dateien, 276 Commits darauf, 1 069 automatisierte Tests, 31 Testfälle. Keine dieser Zahlen sagt, dass die Anwendung gut ist.
  • Die Schleife gilt auch für sich selbst: Als der Bug-Bestand schneller wuchs, als er abgearbeitet wurde, fiel der Verdacht auf die neue Modellgeneration. Die Messung fand einen echten Bruch, konnte ihn aber nicht zuordnen: Der Anteil der Bugs aus QA-Durchgängen verdoppelte sich, doch Modellwechsel und nachgerüstetes Test-Fundament fallen auf denselben Tag. Geändert wurde deshalb, was sich ändern ließ — zwei Regeln, die an Urteilsvermögen appellierten, wichen einer Grenze, die sich nachzählen lässt.

Voraussetzung: Keine. Claude-Code-Vorkenntnisse sind nicht nötig, Begriffe werden beim ersten Auftreten erklärt. Der Artikel beschreibt eine Arbeitsweise aus einem Solo-Projekt und ist keine Empfehlung für ein Team mit eigener Qualitätssicherung.

Inhalt

KI-generierten Code prüfen, wenn man die Sprache nicht lesen kann

Die übliche Antwort auf die Frage, wie man KI-generierten Code kontrolliert, lautet: lesen und verstehen, bevor man ihn übernimmt. Das ist ein guter Rat, solange die Voraussetzungen stimmen. Er setzt voraus, dass der Prüfer die Sprache beherrscht, dass er die Bibliotheken kennt und dass die Menge überschaubar bleibt.

Im DI²-Projekt trifft keine dieser Voraussetzungen zu. Die Anwendung ist ein ETL-Generator auf Next.js und PostgreSQL. Die Datenbank-Seite kann der Maintainer beurteilen, denn dort liegt seine Berufserfahrung. Die Frontend-Seite kann er nicht beurteilen, und daran wird sich in diesem Projekt auch nichts ändern. Ein Blick in eine React-Komponente sagt ihm, ob sie ordentlich aussieht. Er sagt ihm nicht, ob sie richtig ist.

Daraus folgt eine unbequeme Einsicht. Wer die Sprache nicht beurteilen kann, gewinnt auch durch Stichproben keine Kontrolle. Eine Stichprobe ist nur dann eine Kontrolle, wenn der Prüfer im Fehlerfall den Fehler bemerken könnte. Sonst ist sie eine Beruhigung. Für den Teil, den man nicht lesen kann, lautet die Frage deshalb nicht, wie viel man davon liest, sondern welche Prüfungen ein Ergebnis liefern, das auch ohne Sprachkenntnis eindeutig ist.

Solche Prüfungen gibt es, und sie haben eine gemeinsame Eigenschaft. Sie enden mit einer Aussage, die wahr oder falsch ist, statt mit einem Eindruck. Ein Testlauf ist grün oder rot. Ein Endpunkt antwortet mit dem erwarteten Status oder nicht. Ein Zähl-Pass findet null Treffer oder mehr. Ein Audit-Bericht führt Befunde mit Schweregrad. Nichts davon verlangt, dass der Prüfer die Zeile versteht, die den Unterschied macht. Eindeutig heißt allerdings weder vollständig noch aussagekräftig. Ein Testlauf kann Tests überspringen, ein Bericht kann einen Vorbehalt tragen, und beides steht in der Ausgabe statt im Verdikt. Ein Test kann außerdem die falsche Eigenschaft prüfen und trotzdem grün sein, und das steht nirgends. Ob eine Prüfung das Richtige prüft, zeigt sich nur daran, ob sie im Fehlerfall anders ausgeht. Was passiert, wenn nur das Verdikt gelesen wird, zeigt weiter unten ein eigener Fall.

Die Schleife: fünf Stationen

Die fünf Stationen sind nicht gleichzeitig entstanden und laufen auch nicht im selben Takt. Was sie zu einer Schleife macht, ist, dass jede von ihnen einen definierten Auslöser hat und ihr Ergebnis an einem festen Ort ablegt, an dem es beim nächsten Durchlauf wieder auftaucht.

Erste Station: aus Feedback wird eine Regel

Wenn der Maintainer eine Korrektur anbringt, soll die Arbeit nicht mit der Korrektur enden. Sie soll damit enden, dass die Korrektur als Regel aufgeschrieben wird, damit derselbe Griff nicht ein zweites Mal nötig ist. Das gilt allerdings nicht für jede Korrektur, sondern für die, deren Wiederholung eine Regel verhindert hätte. Ein einmaliger Sachfehler, eine Geschmacksentscheidung oder ein Fall ohne erkennbares Muster wird korrigiert, mehr nicht. Eine Regel daraus würde die Regel-Dateien verlängern, ohne je wieder zu greifen.

Die Regeln liegen als Dateien im Projekt und werden dem Agenten bei jedem Lauf mitgegeben. Wie diese Dateien aufgebaut sind und warum es viele kleine statt einer großen sind, beschreibt ein eigener Artikel. Zum Zeitpunkt jenes Artikels waren es 27 Dateien. Heute sind es 28, verteilt auf 276 Commits.

Der Auslöser ist eine Korrektur, die sich durch eine Regel hätte vermeiden lassen. Abgenommen ist die Regel, wenn sie den konkreten Fall benennt, der sie ausgelöst hat, und nicht nur ein Prinzip formuliert. Das Ergebnis landet in der Regel-Datei des betroffenen Bereichs.

An dieser Stelle gehört eine Einschränkung hin, die der Station ihren Anspruch nimmt. Dass aus einer solchen Korrektur eine Regel wird, ist ein Vorsatz und kein Mechanismus. Es steht in keiner Regel-Datei, in keinem Skill und in keinem Abschluss-Schritt, und nichts fragt danach. In der Praxis gibt der Maintainer den Anstoß, oder die Korrektur ist so offensichtlich wiederkehrend, dass sie von selbst in einer Datei landet. Die 276 Commits belegen, dass es oft geschieht, nicht dass es zuverlässig geschieht. Die Station hat damit genau die Schwäche, die weiter unten an zwei Bug-Regeln beschrieben wird: Sie appelliert an Urteilsvermögen, und niemand zählt nach.

Wie das konkret aussieht, zeigt ein Fall vom 29. August 2026. An zwei Tagen hintereinander hatte eine Fehlersuche jeweils rund eine Stunde an der falschen Stelle gekostet, weil auf dem Entwicklungs-Rechner zwei Container-Welten nebeneinander liefen und die Anwendung mal die eine und mal die andere Datenbank traf. Aus diesem Vorfall wurde kein Merkzettel, sondern ein Pflicht-Schritt in zwei manuellen Testfällen: Vor dem Testlauf ist der Schema-Stand der Datenbank zu prüfen. Der Testfall-Text begründet das mit dem Datum des Vorfalls und verweist auf die Notiz, in der er aufgearbeitet ist. Zwei Dinge macht dieser Schritt seither. Er verhindert, dass ein Fehlschlag auf veraltetem Stand als Fehler des Programms gelesen wird. Und im zweiten der beiden Testfälle verhindert er echten Datenverlust, weil dort ein Schutz-Mechanismus geprüft wird, den ein veralteter Stand gar nicht enthält.

Dass die Lehre hier nicht in einer Regel-Datei landete, ist kein Versehen. Diese beiden Testfälle führt der Maintainer selbst am Bildschirm aus, und eine Regel-Datei liest nur der Agent. Der Ort richtet sich danach, wer die Anweisung befolgen muss. Den anderen Fall kennt dieselbe Station auch: Nachdem ein Subagent am 4. September für eine Verifikation 220 ungebremste Rechenlasten gestartet und die Workstation zwölf Minuten unbenutzbar gemacht hatte, wurde daraus ein Abschnitt in der Regel-Datei für Tests. Er nennt den Vorfall mit Datum als Quelle und stellt vier Auflagen für künftige Lasttests auf.

Zweite Station: wiederkehrende Prüfungen werden zu Skills

Ein Skill ist in Claude Code eine versionierte Datei mit einem Auftrag, die sich mit einem kurzen Befehl aufrufen lässt. Für die Kontrolle ist daran das Versionierte entscheidend. Ein Prüf-Auftrag, den man jedes Mal neu formuliert, fällt jedes Mal anders aus. Ein Prüf-Auftrag als Datei ist über Monate derselbe, und wenn er sich ändert, steht die Änderung in der Historie.

Im Projekt gibt es 14 solcher Skills, die beiden für die Kontrolle sind seit dem 16. April 2026 in Betrieb. Der eine fährt einen projektweiten Sicherheits-Audit, also eine Durchsicht des ganzen Projekts entlang einer festen Liste von Prüfbereichen. Der andere prüft Aktualisierungen für Abhängigkeiten und für die Komponenten, die auf dem Server laufen. Der Kopf des Sicherheits-Skills sieht, von den projektspezifischen Prüfbereichen befreit, so aus:

Rolle: erfahrener Security Engineer und Red-Team-Tester.

Fuehre einen projektweiten Security-Audit durch, unabhaengig von
einzelnen Features. Bereiche: Abhaengigkeiten, Authentisierung und
Sitzungen, Injection, Autorisierung, Header, Secrets, Rate Limiting.

Ziel: alle sicherheitsrelevanten Schwachstellen identifizieren und
priorisiert dokumentieren.

Ausloeser: vor Go-Live und nach groesseren Aenderungen.

Drei Eigenschaften daran sind wichtiger, als sie aussehen. Der Auftrag nennt die Rolle, damit der Agent nicht im Modus des Erklärers bleibt, sondern in dem des Prüfers. Er nennt den Auslöser, statt einen Kalender-Rhythmus zu behaupten. Und er verlangt eine priorisierte Dokumentation, also ein Ergebnis mit Schweregraden statt einer Einschätzung im Fließtext.

Der zweite Prüf-Skill trägt eine Eigenschaft, die für die Kontrolle noch wichtiger ist. In seiner Beschreibung steht wörtlich, dass er nichts von selbst verändert. Er prüft, schreibt seine Befunde in einen datierten Bericht und führt eine Historie darüber, welche Aktualisierungen angewendet und welche zurückgestellt wurden. Was daraus geschieht, entscheidet der Maintainer. Ein Prüf-Werkzeug, das seinen Prüfgegenstand selbst ändern darf, prüft beim nächsten Lauf seine eigene Korrektur, und dann ist nicht mehr zu sagen, welchen Stand es geprüft hat.

Der Auslöser dieser Station ist eine Prüfung, die zum zweiten Mal gebraucht wird. Abgenommen ist der Skill, wenn sein Auftrag Rolle, Auslöser und die Form des Ergebnisses nennt. Der Ort ist die Skill-Datei im Projekt. Was der Skill bei jedem Lauf erzeugt, gehört zur fünften Station.

Die Schwäche dieser Station ist das Altern des Auftrags. Der Sicherheits-Skill ist seit dem 25. April unverändert, und sein Abschnitt zur Anmeldung nennt die Bibliothek der Anwendung, nicht den Identitäts-Dienst, der seit dem 18. April davorsteht. Dass der Audit vom August die tote Drosselung trotzdem fand, liegt daran, dass die Bereichsliste allgemein genug ist, und nicht daran, dass jemand den Auftrag nachgezogen hätte.

Dritte Station: Tests nachträglich unter bestehenden Code schieben

Das Projekt startete am 19. März 2026. Das Test-Fundament entstand am 2. Juli, also knapp dreieinhalb Monate später. Es läuft auf Vitest, einem verbreiteten Test-Werkzeug für JavaScript und TypeScript, das die Tests im Terminal ausführt und für jede einzelne Prüfung grün oder rot meldet. Von Anfang an trennt das Fundament zwei Arten: Unit-Tests für reine Funktionen und Komponententests für die React-Oberfläche, für die Vitest das Browser-Umfeld im Speicher nachbaut.

Spezifikation, technischer Entwurf und Umsetzung liegen auf demselben Tag und brachten 6 Test-Dateien mit 57 Tests. Die breite Abdeckung folgte am Tag darauf in drei Schritten und endete bei 28 Dateien mit 566 Tests. Vorher gab es keine automatisierten Tests. Die Schleife war kein Plan, sie ist eine Reaktion.

Tests nachträglich unter bestehenden Code zu schieben hat eine Falle, die ohne Sprachkenntnis nicht zu sehen ist. Ein Test, der gegen den aktuellen Stand geschrieben wird, ist grün, sobald er das aktuelle Verhalten beschreibt. Ob dieses Verhalten richtig ist, sagt er nicht. Er zementiert es nur. Für die Tests des Fundaments gilt das weitgehend: Sie wurden gegen den Code geschrieben, der im Juli lief, und schlagen erst an, wenn sich sein Verhalten ändert, ganz gleich ob die Änderung richtig oder falsch ist. Ein Abnahme-Kriterium, das mehr leistet, gibt es für den Fall, der seither am häufigsten vorkommt, nämlich den Test zu einem behobenen Fehler. Es ist auch für jemanden zu prüfen, der den Test nicht lesen kann:

Schreib einen Test, der diesen Fehler abdeckt.

Abnahme-Kriterium: Der neue Test muss auf dem alten Stand, also vor
dem Fix, ROT sein. Wenn er dort gruen ist, prueft er nicht, was er
zu pruefen vorgibt. Zeig mir beide Laeufe.

(Dieser Prompt ist aus Auftrag und Ergebnis rekonstruiert, nicht wörtlich protokolliert. Der Skill-Auszug weiter oben steht so im Repository.)

Die Aufforderung, beide Läufe zu zeigen, ist der eigentliche Kern. Sie verwandelt eine Behauptung des Agenten in zwei Ausgaben, die der Maintainer nebeneinander sehen kann. Rot auf dem alten Stand, grün auf dem neuen, und dazwischen liegt genau der Fix.

Das Kriterium setzt voraus, dass sich der Fehler nachstellen lässt. Bei einem Fehler, der nur gelegentlich auftritt, zeigt der alte Stand mal Rot und mal Grün, und dann trägt der Vergleich nicht. Und er belegt nur, dass der Test diesen einen Fehler sieht, nicht, dass er die Anforderung dahinter vollständig abdeckt. Der Auslöser dieser Station ist seit dem Fundament ein Fehler, der behoben wird. Abgenommen ist der Test mit den beiden Läufen, und er liegt danach neben dem Code, den er prüft.

Vierte Station: manuelle Testfälle deklarieren

Nicht alles lässt sich automatisiert prüfen. In dieser Anwendung kann der Nutzer eine Quell-Tabelle abnehmen, also ihre Modellierung für abgeschlossen erklären. Danach soll niemand mehr etwas daran ändern, auch nicht an den Prüfregeln ihrer Spalten und auch nicht der Besitzer des Projekts selbst. Ob diese Sperre auf jedem Weg greift, den die Oberfläche anbietet, prüft am Ende ein Mensch.

Damit auch diese Prüfung ein Ergebnis liefert statt eines Eindrucks, werden die Fälle vorher aufgeschrieben: Schritt für Schritt, jeder Schritt mit seiner Erwartung daneben. Der Katalog entstand Ende August 2026 mit 22 Fällen und steht heute bei 31.

Der Auslöser dieser Station ist ein Verhalten, das kein automatisierter Test erreicht. Abgenommen ist ein Testfall, wenn jeder Schritt seine Erwartung neben sich hat. Der Ort ist der Katalog im Projekt, und jeder Lauf trägt sein Ergebnis in ein Protokoll ein.

Der Nutzen zeigt sich schon vor dem Ausführen. Wer einen Testfall aufschreibt, muss die Erwartung formulieren, und dabei fällt auf, wenn es gar keine eindeutige Erwartung gibt. Neben den Schritten trägt jeder Fall ein Ziel, eine Vorbedingung und einen Aufräum-Schritt, und seine Ausführung wird getrennt davon festgehalten, ein Protokoll pro Lauf.

Ein Testfall braucht dieselbe Pflege wie eine Regel. Am 30. August wurde einer angepasst, nachdem sich das erwartete Verhalten geändert hatte. Die Commit-Nachricht nennt den Grund: einen falschen Fehlschlag vermeiden. Ein Testfall, der nach einer Verhaltens-Änderung unverändert stehen bleibt, meldet ab da Fehler, die keine sind, und wird als Kontrolle wertlos.

Fünfte Station: Aktualisierungen und Audits fahren

Die letzte Station ist die einzige, die von außen getrieben wird. Abhängigkeiten bekommen Sicherheits-Meldungen, das Betriebssystem des Servers bekommt Aktualisierungen, und beides passiert unabhängig davon, ob gerade am Projekt gearbeitet wird. Fünf datierte Sicherheits-Berichte liegen im Projekt, dazu die Audit-Datei, die jeden Lauf mit Datum, geprüften Bereichen und Befunden festhält. Der Auslöser kommt von außen, als Sicherheits-Meldung, oder aus dem Skill, der Auslieferung und größere Änderungen nennt. Abgenommen ist ein Lauf, wenn sein Bericht die Befunde nach Schweregrad führt und der Maintainer entschieden hat, was davon umgesetzt wird. Der Ort sind die Berichte und die Audit-Datei. Die Schwäche dieser Station steht weiter unten als eigener Fall: Ein Prüfbericht kann ein Verdikt tragen, dessen Vorbehalt beim Weiterreichen verloren geht.

Die fünf Stationen im Überblick, mit der Schwäche, die jede von ihnen hat:

StationAuslöserAbnahmeOrtSchwäche
Regeleine Korrektur, die eine Regel verhindert hättenennt den auslösenden FallRegel-Datei des BereichsVorsatz, kein Mechanismus
Skilleine Prüfung, die zum zweiten Mal gebraucht wirdAuftrag nennt Rolle, Auslöser, ErgebnisformSkill-Dateider Auftrag altert
Testein behobener Fehlerrot vor dem Fix, grün danachneben dem Codezementiert bestehendes Verhalten
Testfallein Verhalten, das kein automatisierter Test erreichtjeder Schritt mit ErwartungKatalog, Protokoll pro Laufbraucht Pflege nach jeder Verhaltens-Änderung
AuditSicherheits-Meldung, Auslieferung, größere ÄnderungBericht mit Schweregraden, Maintainer entscheidetBerichte, Audit-Dateider Vorbehalt reist nicht mit

Was die Zahlen belegen und was nicht

Die Zahlen aus dem Projekt lassen sich schnell aufzählen, und genau deshalb ist eine Warnung nötig. Stand 10. September 2026: 14 Skills, 28 Regel-Dateien mit 276 Commits, 85 Test-Dateien mit 1 069 Tests, 31 manuelle Testfälle, 5 Sicherheits-Berichte.

Keine dieser Zahlen sagt, dass die Anwendung gut ist. Sie sagen, dass die Schleife läuft. Das ist ein Unterschied, den man leicht überliest, weil große Zahlen nach Qualität aussehen. Eine Suite mit 1 069 Tests kann eine Eigenschaft übersehen, auf die es ankommt. Ein Katalog mit 31 Testfällen kann den einen Fall nicht enthalten, der schiefgeht.

Interessanter als die Endstände sind deshalb die Bewegungen. Die automatisierten Tests standen Anfang Juli bei 566 und stehen jetzt bei 1 069. Die Testfälle sind seit Ende August von 22 auf 31 gewachsen, also in knapp zwei Wochen um neun. Die Regel-Dateien haben sich seit dem Artikel, der sie beschreibt, um eine einzige vermehrt, ihre Commit-Zahl aber deutlich stärker. Diese Bewegung ist die aussagekräftigste von allen. Sie heißt, dass kaum neue Themen dazukommen, die bestehenden Regeln aber laufend nachgeschärft werden.

Auch bei den Audits gibt es keinen festen Abstand. Die fünf Sicherheits-Berichte liegen grob im Monatsabstand, was zu der Angabe passt, die im Infrastruktur-Artikel steht. Die Audit-Datei selbst verzeichnet dagegen zwischen dem 30. August und dem 6. September sechs Läufe in acht Tagen. Beides zusammen ergibt die ehrliche Antwort: Der Takt hängt nicht am Kalender, sondern daran, wie viel sich bewegt hat.

Was die Schleife gefunden hat

Der aussagekräftigste Fund stammt aus einem Sicherheits-Audit vom 28. August 2026. Für die Anmeldung stand in der Konfiguration des vorgelagerten Servers eine Begrenzung der Anfragen pro Minute. Sie war korrekt geschrieben, sie war aktiv, und wer sie las, kam zu dem Schluss, dass das Anmelde-Formular gegen automatisiertes Durchprobieren von Passwörtern geschützt ist.

Die Begrenzung lag auf dem Endpunkt eines Anmelde-Verfahrens, das die Anwendung früher selbst durchführte. Nach dem Umstieg auf einen eigenen Identitäts-Dienst gab es diesen Endpunkt nicht mehr. Der gedrosselte Pfad wurde nie aufgerufen, und es gab damit an keiner Stelle eine wirksame Drosselung. Der Befund im Audit hält fest, warum das schlimmer ist als gar kein Schutz: Eine vorhandene Drosselung beruhigt jede Prüfung, die auf die Konfiguration schaut.

Für diesen Artikel ist entscheidend, welche Art von Prüfung den Fund geliefert hat. Code-Lesen hätte ihn nicht geliefert, denn die Datei war ja richtig. Nötig war der Abgleich zweier Dinge, die in verschiedenen Ecken des Projekts liegen: der gedrosselte Pfad in der Server-Konfiguration und die Liste der tatsächlich eingerichteten Anmelde-Verfahren in der Anwendung. Genau solche Abgleiche über Bereichsgrenzen hinweg sind die Stärke eines projektweiten Audits, sofern sein Auftrag beide Bereiche nennt. Der Skill-Kopf weiter oben tut das, denn Authentisierung und Rate Limiting stehen dort in derselben Liste. Der Auftrag allein belegt aber nicht, dass der Abgleich stattgefunden hat. Das belegt erst der Bericht, wenn er beide Fundstellen nebeneinander führt, und der Befund vom 28. August tut das: den gedrosselten Pfad aus der Server-Konfiguration und die Liste der eingerichteten Anmelde-Verfahren aus der Anwendung. Der Abgleich selbst ist unabhängig davon, ob der Auftraggeber die Sprache lesen kann.

Wie derselbe Vorgang von der Diagnose-Seite aussieht und wie die Wirkung anschließend gemessen statt geglaubt wurde, beschreibt der Artikel zur Fehlersuche mit einem Coding-Agenten.

Was die Schleife nicht findet

Die Schleife hat blinde Flecken, und drei davon sind belegt.

Sie findet keinen Code, der von den Regeln abweicht. Die Regeln stehen in Dateien, die der Agent bei jedem Lauf mitbekommt, und trotzdem hält er sich nicht immer daran. Sichtbar wurde das in diesem Projekt an 799 hartkodierten Schriftgrößen. Das war kein Altbestand von vor der Regel: Die Schriftgrößen-Skala stand seit April in der Regel-Datei, und neun von zehn dieser Stellen entstanden erst danach, während der Agent die Skala an anderen Stellen durchaus benutzte. Die Konsequenz war nicht, die Regel besser zu formulieren. Sie war, die Regel maschinell prüfbar zu machen. Wie das geht, wenn kein fertiges Werkzeug die Konvention abdeckt, zeigt der eigene Guard für die SQL-Konventionen.

Sie findet keine Erfolgsmeldung, hinter der nichts steht. Ein Rollout-Lauf druckte zwei Bildschirmseiten voller Häkchen. Aktiv war die Konfiguration danach an keiner Stelle. Der Kopierbefehl war in einem falschen Verzeichnis gelandet und hatte nichts bewirkt, und das Einrichtungs-Skript setzt sein Häkchen, ohne zu prüfen, ob der Befehl davor überhaupt erfolgreich war. Aufgefallen ist es nur, weil in der Ausgabe eine Zeile fehlte, die dort hätte stehen müssen. Der Agent hat daran seinen Anteil. Er hatte die Rollout-Befehle übergeben, ohne den Fix vorher ins zentrale Repository zu übertragen. Der Server holte sich beim Rollout also den alten Stand, und die Befehle konnten gar nicht wirken.

Sie findet den Vorbehalt nicht, der in ihrem eigenen Prüfbericht steht. Am 29. August lieferte ein Prüf-Durchgang ein sorgfältiges Ergebnis über elf Prüfpunkte, mit Nachstellung des Fehlers und Gegenprobe gegen den Stand davor. Das Verdikt lautete „bestanden, bereit zum Schließen“. Im selben Bericht stand aber auch, dass ein Teil der Prüfung lokal nicht ausführbar war und deshalb nur als neuer Testfall aufgeschrieben wurde. Ausgeführt wurde er nie. Der nächste Agent übernahm das Verdikt und arbeitete weiter, ohne nachzusehen, ob dieser Testfall je in einem Lauf-Protokoll auftaucht. Aufgefallen ist es durch eine Rückfrage des Maintainers.

Der letzte Punkt gilt allgemeiner. Wird ein Prüfergebnis von einem Schritt zum nächsten weitergereicht, kommt das Urteil an und der Vorbehalt nicht. Ein Vorbehalt, der mitten im Fließtext eines Berichts steht, überlebt dessen Zusammenfassung nicht. Und wer die Zusammenfassung liest, nimmt sie für eine Tatsache, weil sie von jemandem kommt, der gründlicher hingesehen hat als er selbst. Menschen machen denselben Fehler mit Prüfberichten. Neu ist, wie schnell und wie beiläufig es hier passiert. Die Gegenmaßnahme kostet fast nichts: Ein Verdikt nennt nicht nur einen Status, sondern führt die offenen Punkte als Bedingung mit, in der Form „bestanden, sofern X noch läuft“.

Daraus folgt der unbequemste Satz dieses Artikels. Die Kontrolle durch den Agenten braucht selbst eine Kontrolle, und diese kann nicht wieder darin bestehen, den Agenten zu fragen.

Die Schleife, auf sich selbst angewandt

Anfang September fiel auf, dass die Schleife Arbeit erzeugte statt sie zu reduzieren. An einem einzigen Tag kamen 21 neue Bug-Einträge dazu und keiner wurde geschlossen, bei 26 offenen, unter denen sich kein einziger Fall der Stufen Kritisch oder Hoch befand. Ein Bug-Bestand, der wächst, ohne dass etwas Schwerwiegendes darin vorkommt, ist kein Qualitätssignal. Er ist ein Verfahrensproblem.

Der naheliegende Verdacht lag beim Modell. Anfang Juli kam mit Claude Fable 5 eine neue Modellgeneration zum Einsatz, und die schien deutlich genauer zu prüfen und deshalb mehr zu finden. Statt diesen Verdacht zu diskutieren, wurde er gemessen. Das Ergebnis fiel in beide Richtungen aus.

Die Menge neuer Einträge pro Commit blieb über alle eingesetzten Modelle hinweg praktisch gleich. Verändert hat sich, welche Art von Eintrag entsteht. Bis Ende Juni ging knapp ein Drittel der neuen Bugs aus einem Prüf-Durchgang hervor, ab Juli fast zwei Drittel, im August drei Viertel. Der Anteil der Einträge, die ausdrücklich einen Vorgänger nennen, hat sich im selben Zeitraum von 9 auf 18 Prozent verdoppelt. An Fable allein liegt das nicht: Opus 5, das ab August daneben lief, zeigt dasselbe Muster. Und weil diese Einträge aus Prüf-Durchgängen stammen, sagt der Anstieg zunächst etwas über das Prüfen aus und nicht über das Schreiben: Es wird tatsächlich mehr gefunden. Wer nur die Gesamtzahl betrachtet, sieht davon nichts — die erste Messung hatte genau diesen Fehler.

Der Bruch ist damit belegt, seine Ursache aber nicht. An dem Tag, an dem die neue Modellgeneration erstmals zum Einsatz kam, wurde auch das Test-Fundament nachgerüstet. Seither wird systematisch geprüft, und was systematisch geprüft wird, liefert Befunde, ganz gleich wer den Code geschrieben hat. Beide Erklärungen passen auf dieselben Zahlen, und keine Messung an diesem Bestand kann sie trennen. Die ehrliche Antwort lautet deshalb nicht, dass das Modell entlastet ist, sondern dass die Frage offen bleibt.

Ein Anteil ließ sich davon unabhängig benennen, und er liegt im Verfahren. Es gab bereits eine Regel, die begrenzte, was gefixt wird. Es gab keine, die begrenzte, was überhaupt erfasst wird. Jede Beobachtung beim Nachtesten eines Fixes wurde ein eigener Eintrag, jeder davon konnte wieder einen Nachfolger erzeugen, und aus einem Ursprungs-Eintrag wuchsen so über sechs Generationen zehn Nachkommen. Gemessen am Tag der Auswertung stammten 72 von 594 Einträgen aus einer solchen Kette, und zwei Ursprünge hatten zusammen 18 Nachkommen erzeugt.

Die Konsequenz steht wörtlich in der neuen Regel: Die beiden bestehenden Regeln appellierten an Urteilsvermögen und wurden trotzdem überfahren, und die Kettentiefe ist die einzige Schwelle, die sich prüfen lässt. Ein Folge-Eintrag darf seit dem 6. September keinen eigenen Nachfolger mehr erzeugen. Die Kette endet nach zwei Generationen, dem Ursprung und einer Nachbesserung. Die Vorgänger-Zeile steht im Kopf jedes Eintrags, und deshalb kann ein Skript diese Grenze nachrechnen.

Ein Nachfolger ist dabei ein Eintrag, der beim Nachtesten eines Fixes entsteht und dessen Nummer als Vorgänger trägt. Die Grenze unterdrückt keinen Fehler, sie verlangt eine Neubegründung. Ein Befund jenseits der zweiten Generation wird als eigenständiger Eintrag mit eigener Beschreibung erfasst, wenn er schwer genug ist, und sonst als Zeile beim Vorgänger notiert. Wer einen Befund nicht ohne den Verweis auf seinen Vorgänger erklären kann, hat keinen neuen Fehler gefunden, sondern schreibt die Kette fort. Dass es zwei Generationen sind und nicht drei, ist eine Setzung für dieses Projekt und keine Regel mit Anspruch auf Allgemeinheit. Übertragbar ist die Form der Grenze, nicht ihr Wert: eine Schwelle, die ein Skript nachrechnen kann, statt einer Ermessensfrage.

Das ist dieselbe Lehre wie beim Drift-Befund, nur diesmal am eigenen Verfahren statt am generierten Code. Eine Vorgabe, die Urteilsvermögen verlangt, wird unter Zeitdruck überfahren, auch vom Agenten, auch vom Menschen. Eine Vorgabe, die sich nachzählen lässt, hält, weil ein Skript sie durchsetzen kann und niemand sie unbemerkt überfährt. Ob es die richtige Vorgabe ist, entscheidet das nicht. Wer eine Kontroll-Schleife aufsetzt, sollte deshalb bei jeder Station die Frage stellen, ob ihr Kriterium nachrechenbar ist oder nur einleuchtet. Und danach die zweite Frage, ob das Kriterium im Fehlerfall überhaupt anders ausgeht.

Was das kostet

Der Preis der Schleife ist nicht ihr Aufbau, sondern ihre Pflege. Jede Regel muss aktuell gehalten werden, sonst prüft sie gegen einen Stand, den es nicht mehr gibt. Jeder Testfall muss nach einer Verhaltens-Änderung mitgezogen werden, sonst produziert er falsche Fehlschläge. Jeder Prüfbericht will gelesen werden, und die 276 Commits auf die Regel-Dateien sind genau diese Arbeit in Zahlen.

Dazu kommt die Verlangsamung. Eine Prüfung, die vor jeder Auslieferung laufen muss und sie bei Rot anhält, kostet Zeit, und ihr Nutzen ist unsichtbar, solange nichts passiert. Die Versuchung, die Prüfung einmal zu überspringen, ist an dem Tag am größten, an dem sie am nötigsten wäre.

Der eigentliche Punkt ist aber ein anderer, und er verbindet diesen Artikel mit der übergeordneten These dieses Astes: Die Arbeit verschwindet nicht, sie verlagert sich. In einem Team mit eigener Qualitätssicherung würde ein Teil dieser Aufgaben bei Projektleitung und Testern liegen. Im Solo-Projekt landet alles beim selben Menschen, und zwar zusätzlich zu der Arbeit, die der Agent scheinbar abgenommen hat. Wer die eingesparte Schreibzeit als Gewinn verbucht, ohne die Kontrollzeit dagegenzurechnen, rechnet falsch.

Was am Ende trägt

  • Prüfbar ist, was ein eindeutiges Ergebnis hat. Wer die Sprache nicht liest, braucht Kontrollen, die im Fehlerfall von selbst anschlagen, statt auf einen aufmerksamen Blick zu warten.
  • Ein Kriterium, das nachgerechnet werden kann, hält. Eines, das einleuchtet, nicht. Hält heißt: Es wird eingehalten, auch unter Zeitdruck. Das gilt für den generierten Code ebenso wie für das eigene Verfahren, und es ist an beiden Stellen belegt. Ob es das richtige Kriterium ist, sagt das nicht, und darum geht es im nächsten Punkt.
  • Zahlen belegen, dass geprüft wird — nicht, dass es wirkt. Ein wachsender Test-Bestand sagt, dass gearbeitet wird. Ob das Richtige geprüft wird, sagt nur die Frage, ob eine Prüfung im Fehlerfall tatsächlich anders ausgeht.
  • Ein Verdikt ohne seine Vorbehalte ist unvollständig. Wer ein Prüfergebnis weitergibt oder entgegennimmt, sollte die offenen Punkte als Bedingung mitführen, sonst reist die Bewertung allein weiter.
  • Die Schleife ersetzt kein Verständnis. Sie ersetzt das Lesen als Kontrolle. Der Unterschied ist wichtig, weil er die Grenze markiert: Sie fängt, was sich prüfen lässt, und sie fängt nichts, wofür jemand die richtige Frage hätte stellen müssen.

Übertragbar ist davon die Form, nicht der Wert. Ein Auslöser, ein nachrechenbares Kriterium und ein Ort für das Ergebnis lassen sich für jede Station in jedem Projekt setzen, ebenso die Gegenprobe, ob eine Prüfung im Fehlerfall anders ausgeht. Die Zahlen, die Zwei-Generationen-Grenze und der Zuschnitt der Skills sind dagegen Daten aus einem Projekt und taugen nicht als Vorgabe für ein anderes.

FAQ

Wie prüft man KI-generierten Code, wenn man ihn nicht vollständig lesen kann?

Über Prüfungen, die mit einem eindeutigen Ergebnis enden statt mit einem Eindruck: ein Testlauf, der grün oder rot ist, ein Endpunkt mit dem erwarteten Status, ein Zähl-Pass, ein Audit-Bericht mit Schweregraden. Der Agent führt sie aus, der Mensch beurteilt das Ergebnis, und dafür braucht er die Sprache nicht. Ob die richtige Anforderung umgesetzt wurde, prüft das nicht. Diese Frage muss jemand stellen.

Ersetzt die Schleife ein Code-Review?

Nur dort, wo niemand lesen kann. In einem Team, in dem jemand die Sprache beherrscht, ist ein Review für vieles die billigere Kontrolle, was hier über Tests und Audits läuft. Die Schleife ergänzt es dann um das, was Lesen nicht findet: den Abgleich über Bereichsgrenzen hinweg und die Gegenprobe, ob ein Test im Fehlerfall überhaupt rot wird. Im Solo-Projekt ohne Sprachkenntnis ist sie kein Zusatz, sondern die einzige Kontrolle, die ein Ergebnis liefert.

Was unterscheidet Test, Testfall, Audit und Verdikt in dieser Schleife?

Ein Test ist eine automatisierte Prüfung einer einzelnen Eigenschaft, die grün oder rot endet. Ein Testfall ist ein aufgeschriebener Ablauf mit einer Erwartung pro Schritt, den ein Mensch ausführt und protokolliert. Ein Audit ist eine Durchsicht des ganzen Projekts entlang einer Liste von Prüfbereichen, mit Befunden nach Schweregrad. Ein Verdikt ist der zusammenfassende Status eines Prüfberichts, und es ist nur so viel wert wie die Vorbehalte, die es mitführt.

Wie oft sollte eine solche Kontroll-Schleife laufen?

Nicht nach Kalender, sondern nach Bewegung. Die Prüf-Skills in diesem Projekt sind auf Auslöser gestellt, also vor einer Auslieferung und nach größeren Änderungen. In ruhigen Wochen bedeutet das etwa einen Lauf im Monat, in einer Woche mit vielen Änderungen waren es sechs Läufe in acht Tagen. Ein fester Rhythmus hat den Nachteil, dass er in ruhigen Phasen Aufwand erzeugt und in hektischen zu spät kommt.

Reicht nicht ein automatisierter Abhängigkeits-Check?

Für die Abhängigkeiten deckt ein solcher Check den größten Teil ab, und ein Dienst, der automatisch Aktualisierungs-Vorschläge einstellt, nimmt einem die Beobachtung ab. Nicht abgedeckt ist alles, was nicht in der Paket-Liste steht: die Konfiguration des vorgelagerten Servers, die Einstellungen des Identitäts-Dienstes, die Pakete des Betriebssystems, die Zertifikate. Der Fund mit der wirkungslosen Drosselung lag genau dort, und kein Abhängigkeits-Check hätte ihn geliefert.

Wie rüstet man Tests nach, ohne den Code zu verstehen?

Über das Abnahme-Kriterium statt über den Testinhalt. Ein Test zu einem behobenen Fehler muss auf dem alten, fehlerhaften Stand rot sein und erst auf dem korrigierten grün. Lässt man sich beide Läufe zeigen, ist die Prüfung erledigt, ohne eine Zeile des Tests zu lesen. Fällt der Test auf dem alten Stand ebenfalls grün aus, prüft er nicht das, was er zu prüfen vorgibt, und das ist auch ohne Sprachkenntnis eine eindeutige Aussage. Für Tests, die nur bestehendes Verhalten festhalten, gibt es diese Gegenprobe nicht. Sie schützen vor späteren Änderungen, sagen aber nichts darüber, ob das Verhalten heute richtig ist.

Woran erkennt man, dass ein Prüf-Verdikt unvollständig ist?

An der Lücke zwischen Zusammenfassung und Text. Ein Bericht, dessen Kopfzeile „bestanden“ sagt, dessen Fließtext aber einen nicht ausgeführten Schritt erwähnt, ist genau der Fall. Hilfreich ist, das Verdikt in einer Form zu verlangen, die Bedingungen zulässt, also „bestanden, sofern X noch läuft“ statt eines nackten Status. Wer ein Ergebnis entgegennimmt, sollte außerdem gezielt nach dem suchen, was nicht geprüft werden konnte, statt nur die Liste des Geprüften zu lesen.

Ersetzt das irgendwann das Lernen der Sprache?

Nein, und es ist auch nicht als Ersatz gedacht. Die Schleife fängt, was sich prüfen lässt. Sie fängt nicht die Frage, die niemand gestellt hat, weil niemand wusste, dass sie sich stellt. Wer die Sprache beherrscht, stellt mehr solcher Fragen. Für ein Solo-Projekt, in dem eine zweite Sprache zu lernen keine realistische Option ist, ist die Schleife die beste verfügbare Näherung — und der ehrliche Umgang damit besteht darin, sie als Näherung zu benennen.

Verwandte Artikel

Übergeordnet:

Die Artefakte der Schleife im Einzelnen:

Geschwister-Artikel: