KI-generierten Code prüfen: Warum grüne Tests nicht reichen
Vibe Coding beschleunigt die Codeproduktion, aber nicht automatisch die Review-Arbeit. Ein LLM kann schnell einen ordentlich wirkenden Diff liefern. Eine überzeugende Erklärung oder eine grüne Testsuite beweist jedoch nicht, dass die Implementierung produktionsreif ist.
Der Fall ist ein Build-Time-Validator für animierte Terminal-SVGs in diesem Blog-System. Er prüft eingeschränkte XML/CSS-Regeln, Manifest-Pfade und SHA-256 sowie sichtbare Demo-Bilder in acht Sprachen. Ein festes canonical SVG dient als positives Fixture. Alle vier Fehlerklassen wurden vor dem Merge in isolierten Tests gefunden; die Evidenz gilt nur für den Offline-Validator.
Die ursprüngliche Suite bestand 8/8 Tests, doch unabhängiges Review fand zwei unsichere Akzeptanzen. Nach dem ersten Fix bestanden 10/10, danach wurden zwei weitere Fehler entdeckt. Die finale Version bestand 12/12 Top-Level-Tests; vier zusätzliche Angriffsproben wurden separat ausgeführt und alle abgewiesen. Drei JavaScript-Dateien bestanden node —check.
Ich fixiere zuerst Umfang und Invarianten, baue minimale Gegenbeispiele, protokolliere RED nur bei einem tatsächlich beobachteten Fehler, prüfe positive und negative Fälle am exakten Commit unabhängig und entscheide dann nach Risiko. Logiktests ersetzen weder Build noch Plattform- oder Laufzeitprüfung. Für riskante Änderungen genügt eine Evidenzkarte mit Umfang, Base/Head-Commit, Invarianten, positivem Fixture, Gegenbeispiel, echtem Befehl und Umgebung, offenen Grenzen und Ergebnis. Der Validator ist eine Build-Komponente im Blog-Repository, kein separat paketiertes universelles CLI. Review-Zeitersparnis wurde nicht gemessen.
Das öffentliche Repository enthält nur bereinigte synthetische Gegenbeispiele und ausführbare Lehrtests – weder den Produktionsvalidator dieses Blogsystems noch dessen Fixes oder interne Architektur. Die Folge 8/8 → 10/10 → 12/12 stammt aus der ursprünglichen Offline-Prüfung; die öffentlichen Tests reproduzieren nur vier Fehlermuster und bilden die Produktionsimplementierung nicht nach.
Bereinigte Beispiele und ausführbare Tests
Warum akzeptierten 8/8 bestandene Tests trotzdem ungültige Eingaben?
Eine grüne Suite zeigt nur, dass aktuelle Eingaben aktuelle Assertions erfüllen. Sie beweist nicht, dass jede ungültige Eingabe abgelehnt wird.
Das erste Gegenbeispiel setzte ein erlaubtes Bild und einen nicht genehmigten Verweis auf eine Ressource eines anderen Artikels in dieselbe Zeile. Die alte Logik fand ein erlaubtes Bild-Tag und ließ die ganze Zeile durch. Unabhängiges Review erstellte eine echte SVG unter einem anderen Slug und ergänzte den Markdown-Verweis neben dem gültigen Bild in acht Sprachversionen. Die Datei existierte bewusst, um einen Fehlalarm wegen fehlender Zieldatei auszuschließen. Die alte Implementierung meldete weiterhin Erfolg mit posts_checked=8.
<img src="/assets/terminal-demo.svg" alt="Terminal demo" width="356" height="137" /> 
Das zweite Gegenbeispiel war ein Dateisystem-Rennen: Der geprüfte Pfad muss nicht die später geöffnete Datei sein. Ein Elternverzeichnis wurde beim Öffnen ausgetauscht; außerhalb lag eine canonical SVG mit passendem SHA-256. Nach dem Austausch gegen einen Symlink las die alte Implementierung die externe Datei und akzeptierte sie. Umgangen wurde die Herkunftsbeschränkung, nicht die Hash-Prüfung.
Der finale Linux-Pfad öffnet die vertrauenswürdige Checkout-Wurzel und löst Komponenten relativ zu bereits geöffneten Elternverzeichnis-Deskriptoren auf. Zwischenkomponenten müssen Verzeichnisse sein und nutzen O_NOFOLLOW; auch die finale Datei darf kein Symlink sein. Typ, Linkzahl und Größe werden geprüft, Device, Inode und Größe vor und nach dem Lesen verglichen, dann der Digest geprüft. Linux /proc/self/fd wird verwendet; ohne procfs wird geschlossen abgebrochen. Die Garantie setzt einen vertrauenswürdigen Checkout und verfügbares procfs voraus, nicht beliebige Angreifer mit gleicher UID oder Host-Rechten. Siehe Linux openat2(2).
Runde zwei: Der Hash stimmt, aber der Inhalt ist unsichtbar
Nach dem ersten Fix bestanden 10/10 Tests. Der dritte Fehler betrifft Reduced Motion: SVG-Frames starten transparent und werden durch die Animation sichtbar. Wenn die Reduced-Motion-Regel nur die Animation stoppt, ohne den letzten Frame sichtbar zu machen, bleibt das Ergebnis leer.
.f { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
#f0 { animation: none; opacity: 1; }
#f3 { animation: none; } /* letzter Frame bleibt transparent */
}
Der Test berechnete SHA-256, Größe, content-addressed Dateinamen und canonical manifest neu. Er prüfte den Vertrag, dass das Endergebnis sichtbar bleiben muss. Siehe MDN zu prefers-reduced-motion.
Der vierte Fehler kam aus Markdown. Die alte Regex zählte Bild-Tags auch innerhalb von HTML-Kommentaren. Wird das einzige Bild auskommentiert, bleibt der Tag im Quelltext, ist aber nicht sichtbar. Nach den CommonMark-0.31.2-Regeln für HTML-Blöcke ist ein kommentierter Tag kein sichtbares Bild.
<!-- <img src="/assets/demo.svg" alt="Terminal demo" /> -->
Testergebnisse an exakte Versionen binden
| Codeversion | Hauptsuite | Unabhängiges Review danach |
|---|---|---|
| Ausgangsversion | 8/8 bestanden | SEC-01 und SEC-02 unsicher akzeptiert |
| Version nach dem ersten Fix | 10/10 bestanden | SEC-03 und SEC-04 unsicher akzeptiert |
| Finale offline geprüfte Version | 12/12 Top-Level-Tests bestanden | Vier separate Angriffsproben abgewiesen |
Die finale Suite enthält Regressionstests für SEC-01 bis SEC-04. Die vier zusätzlichen Proben zählen nicht zu 12/12 und dürfen nicht zu 16/16 addiert werden. Drei JavaScript-Dateien bestanden node —check, was Syntax und nicht Verhalten prüft.
Die letzten beiden Regressionstests wurden vor dem Quellcode-Fix committed, aber die vollständige Suite lief nicht auf dem reinen Test-Commit. Daher gibt es keinen belegten vollständigen 10/12-RED-Lauf. Belegt sind die Reproduktion durch unabhängiges Review und die erfolgreichen Tests der finalen Version.
Erst nach stabiler Verhaltensevidenz folgt die Komplexitätsprüfung: Welche Invariante schützt ein Helper oder Zweig? Ist Logik doppelt? Gibt es echte Aufrufer? Kürzerer Code ist nicht automatisch einfacher; das Entfernen eines Pfadschutzes kann ein geschlossenes Rennen zurückbringen.
Interaktive Evidenztafel
Wähle ein synthetisches Gegenbeispiel, um Eingabe, Invariante, reproduzierten Fehler und Evidenzgrenzen zu prüfen.
Ausgewählter Fall: SEC-01 · Vorhandensein ist keine Ausschließlichkeit
SEC-01 · Vorhandensein ist keine Ausschließlichkeit
- Eingabebedingung
- Ein erlaubtes Bild und ein nicht genehmigter Verweis auf einen anderen Beitrag stehen zusammen.
- Zu schützende Invariante
- Jeder relevante Verweis muss die Regel erfüllen; ein erlaubter Verweis macht nicht die ganze Eingabe sicher.
- Vom synthetischen Beispiel reproduzierter Fehler
- Die alte Logik akzeptierte die ganze Zeile nach dem ersten erlaubten Bild und übersah den Zusatzverweis.
- Erwartetes korrektes Verhalten
- Alle Verweise prüfen und die Eingabe bei jeder Grenzverletzung ablehnen.
- Ursprüngliche Review-Runde
- In der ersten unabhängigen Prüfung gefunden
- Übertragbare Review-Lehre
- Ein minimales Gegenbeispiel mit gültigem und ungültigem Inhalt bauen und die vollständige Prüfung bestätigen.
SEC-02 · Rennen zwischen Prüfung und Nutzung
- Eingabebedingung
- Nach der Pfadprüfung wird vor dem Öffnen ein Elternverzeichnis oder Symlink ersetzt.
- Zu schützende Invariante
- Geprüftes und verwendetes Objekt müssen identisch bleiben und innerhalb der vorgesehenen Dateisystemgrenze liegen.
- Vom synthetischen Beispiel reproduzierter Fehler
- Wird ein Pfad geprüft und später erneut geöffnet, kann sich das Ziel dazwischen ändern.
- Erwartetes korrektes Verhalten
- Prüfung und Zugriff müssen die Grenze erhalten; das synthetische Beispiel behauptet keine Produktionskorrektur.
- Ursprüngliche Review-Runde
- In der ersten unabhängigen Prüfung gefunden
- Übertragbare Review-Lehre
- Den Zeitraum zwischen Prüfung und Nutzung auf veränderbaren Zustand untersuchen.
SEC-03 · Reduced Motion muss den letzten Frame zeigen
- Eingabebedingung
- SVG-Frames beginnen transparent; bei reduzierter Bewegung stoppt die Animation.
- Zu schützende Invariante
- Das Abschalten der Animation darf wichtige finale Inhalte nicht verbergen.
- Vom synthetischen Beispiel reproduzierter Fehler
- Wird nur die Animation gestoppt, kann das Ergebnis ohne letzten Frame leer sein.
- Erwartetes korrektes Verhalten
- Auch bei reduzierter Bewegung muss der vollständige lesbare Endzustand erscheinen.
- Ursprüngliche Review-Runde
- In der zweiten unabhängigen Prüfung gefunden
- Übertragbare Review-Lehre
- Die Barrierefreiheitseinstellung als separate Eingabe prüfen und Sichtbarkeit bestätigen.
SEC-04 · Kommentare sind keine sichtbaren Inhalte
- Eingabebedingung
- Ein HTML-Kommentar enthält Text, der wie ein Bildelement aussieht.
- Zu schützende Invariante
- Quelltext und tatsächlich gerenderte Elemente sind nicht dasselbe.
- Vom synthetischen Beispiel reproduzierter Fehler
- Einfache Tag-Zählung kann ein Bild im Kommentar als sichtbar zählen.
- Erwartetes korrektes Verhalten
- Kommentarknoten ausschließen und nur tatsächlich gerenderte Elemente bewerten.
- Ursprüngliche Review-Runde
- In der zweiten unabhängigen Prüfung gefunden
- Übertragbare Review-Lehre
- Ein gefälschtes Tag in einen Kommentar setzen und strukturelle Prüfung verlangen.
Öffentliche synthetische Lehrbelege
Das öffentliche Repository reproduziert nur synthetische Fehlermuster. Ein bestandener Test reproduziert den Fehlerfall, nicht eine Produktionskorrektur.
Fixiertes synthetisches Lehr-Repository öffnenOffline-Zusammenfassung des ursprünglichen Projekts
Ursprünglicher Nachweis: 8/8 → 10/10 → 12/12. Vier unabhängige Proben liefen separat und gehören nicht zu 12/12.
Prüfgrenze
Geltungsbereich ist der Offline-Validator unter Node.js v22.16.0 / Linux x64. Native macOS-Prüfung bei bösartigen parallelen Schreibvorgängen und der vollständige Website-Laufzeittest sind ungeprüft.
Verwandte Beiträge: Mutation Testing, OpenQodex’ Pre-Push-Review-Fail-Open-Grenze und Diffles Review-Kommentaranker.
Was fehlt zwischen bestandenen Tests und Produktionsfreigabe?
Die finale unabhängige Prüfung umfasste den Offline-Validator unter Node.js v22.16.0 auf Linux x64: 12/12 Tests bestanden, vier zusätzliche Angriffsproben abgewiesen, canonical SVG/manifest und acht Sprachbindungen bestanden, drei JavaScript-Dateien durch node —check.
Das stützt die begrenzte Aussage, dass vier bekannte falsche Akzeptanzen in dieser Umgebung und unter diesen Regeln behoben wurden. Es beweist nicht die Produktionsreife des gesamten Blogs. Native macOS-Sicherheit gegen bösartige parallele Dateisystem-Schreiber bleibt ungeprüft; vollständiger Site-Build und Laufzeitprüfung lagen außerhalb der Offline-Tests.
Eine reale Freigabe muss nach Risiko geschichtet sein: Unit-Tests prüfen Verhalten, statische Checks Muster, Build und Integration die Zusammensetzung, Plattform- und Laufzeittests die Deployment-Grenzen. Bleibt eine wichtige Grenze ungeprüft, ist ein lokaler Erfolg keine vollständige Produktionsfreigabe.
Verträge und Gegenbeispiele zeigen, welchem Verhalten man misstrauen sollte; Tests des exakten Stands und unabhängige Evidenz entscheiden, wo tiefer geprüft wird. Das ersetzt menschliches Urteil nicht, sondern macht aus „sieht gut aus“ eine überprüfbare Review-Entscheidung.