Zum Hauptinhalt springen

CI/CD für von Agenten geschriebenen Code

Experte
What you'll learn
  • Wissen, warum die Merge-Queue — nicht das Runner-Budget — das Erste ist, was unter dem PR-Volumen von Agenten bricht
  • Die Batching-Rechnung durchführen: wie wenige Prozentpunkte Fehlerrate spekulatives Mergen zum Einsturz bringen
  • Die vier Hebel richtig sortieren, denn 'mehr Runner dazukaufen' ist der schwächste davon
  • Ein Gate ausliefern, das beweist, dass der Test eines Agenten ohne dessen Fix wirklich fehlschlägt
  • Flakes auf Basis von Belegen quarantänisieren statt nach Gefühl, und die Caching-Falle kennen, die CI stillschweigend vergiftet

Deine Coding-Agenten funktionieren. Das ist das Problem.

Ein Team, das 5 Pull Requests pro Tag gemergt hat und jetzt 40 mergt, hat weder seine Testsuite noch sein Runner-Budget noch seine Branch-Protection-Regeln geändert. Es hat die Ankunftsrate in ein Wartesystem geändert, das auf die alte Rate abgestimmt war. Alles nachgelagerte — Merge-Queue, Rauschen durch flaky Tests, Runner-Nebenläufigkeit, Review-Aufmerksamkeit — wurde für menschlichen Durchsatz dimensioniert, und Wartesysteme degradieren nicht graziös. Sie halten, halten, halten, und kippen dann innerhalb einer Woche um.

Diese Seite ist die Pipeline-Seite von dem Verifikations-Engpass. Jene Seite fragt, wer den Code prüft. Diese fragt, ob deine CI das Volumen physisch aufnehmen kann und was zu tun ist, wenn nicht.

Drei Zahlen, die das ganze Problem einrahmen​

−7.2%. DORAs Report Accelerate State of DevOps 2024 modellierte eine Zunahme der KI-Adoption um 25% und schätzte einen Rückgang der Delivery-Stabilität um 7.2% neben einem Rückgang des Durchsatzes um 1.5%. Individuelle Produktivität und Arbeitszufriedenheit gingen nach oben. Die Ergebnisse auf Delivery-Ebene gingen nach unten — der Report führt das auf größere Changesets und schwächere Batching-Disziplin zurück. Der Nachfolger von 2025 rahmt es neu: KI ist ein Verstärker, der vergrößert, was dein Delivery-System ohnehin schon ist. Eine Pipeline, die bei 5 PRs/Tag fragil war, wird bei 40 unbenutzbar.

19%. METRs randomisierte Studie (Juli 2025) nahm 16 erfahrene Open-Source-Maintainer und 246 echte Issues aus deren eigenen Repositories und randomisierte, ob KI-Werkzeuge erlaubt waren. Mit KI brauchten die Aufgaben 19% länger. Die für die CI-Planung entscheidende Lücke ist die der Wahrnehmung: die Entwickler sagten eine Beschleunigung um 24% voraus und glaubten nach der Verlangsamung noch, um 20% schneller gewesen zu sein. Niemand in deinem Team wird dir sagen, dass die Pipeline die Beschränkung ist, weil niemand sie als solche erlebt — man erlebt sie als „Warten", und das fühlt sich wie Wetter an.

1.5% / 16% / 84%. Googles veröffentlichte Flakiness-Daten: rund 1.5% der Testläufe melden ein flaky Ergebnis; etwa 16% ihrer 4.2 Mio. Tests haben irgendwann Flakiness gezeigt; und rund 84% der beobachteten pass→fail-Übergänge betreffen einen flaky Test und keine echte Regression. Behalte diese 1.5% im Kopf — sie sind klein genug, um sie bei 5 PRs/Tag zu ignorieren, und tragend bei 40.

Warum die Merge-Queue zuerst bricht​

Die meisten Teams nehmen an, die Obergrenze sei Rechenleistung. Ist sie nicht. Es ist die Merge-Queue, und der Grund ist ein Mechanismus, für den die meisten Leute nie die Dokumentation gelesen haben.

GitHubs Merge-Queue macht spekulatives Prüfen. Stelle die PRs #1, #2, #3 in die Queue, und sie baut temporäre Branches: main + #1, main + #1 + #2, main + #1 + #2 + #3 — und testet alle davon parallel. Wenn jeder Check besteht, landen alle drei in einer Runde. Das ist das ganze Wertversprechen: Batching verwandelt N serielle Validierungen in eine.

Jetzt lies den Fehlerpfad. Wenn ein Check für die Gruppe mit PR #1 fehlschlägt, entfernt GitHub #1 aus der Queue — und jede Gruppe dahinter enthielt die Änderungen von #1, diese Gruppen sind also ungültig und werden ohne #1 neu gebaut. Ein schlechter PR kostet dich nicht einen Platz. Er kostet dich die CI-Runde des restlichen Batches.

Damit ist der Queue-Durchsatz eine Funktion deiner Erfolgsrate, und sie ist steiler, als die Intuition nahelegt. Modelliere es: Batchgröße N, jeder PR schlägt unabhängig mit Wahrscheinlichkeit p fehl, und du mergst die Folge von PRs bis zum ersten Fehlschlag. Die erwarteten Merges pro Runde sind ein geometrischer Erwartungswert:

E[merges] = (1 − p) · (1 − (1 − p)^N) / p

Mit N = 10:

Fehlerrate pro PR pErwartete Merges pro RundeRunden, um 10 PRs abzuarbeiten
2%8.9~1.1
5%7.6~1.3
10%5.9~1.7
20%3.6~2.8
30%2.3~4.4

Zwei Konsequenzen, die die meisten Teams falsch herum verstehen:

  1. Eine flaky Suite ist eine Durchsatz-Steuer, keine Ärgernis-Steuer. Flakiness addiert sich direkt auf p. Der Schritt von 5% echten Fehlschlägen zu 5% echten + 5% Flakes bringt dich von 7.6 Merges pro Runde auf 5.9 — rund 23% deiner Merge-Kapazität, verloren an Tests, die nie etwas getestet haben.
  2. Die Batchgröße zu erhöhen ist der falsche Hebel, wenn p hoch ist. Ein größeres N hilft nur, solange (1 − p)^N nahe 1 bleibt. Bei p = 0.2 liefert ein Batch von 10 gerade 3.6 Merges; die Lösung ist, p zu senken, nicht mehr Optimismus in die Queue zu stellen.

Und das Volumen der Agenten drückt p in die falsche Richtung — DORAs Stabilitätsbefund ist genau eine Aussage über ein steigendes p.

Die Kapazitätsrechnung, die niemand macht​

Mach das auf einer Serviette, bevor du Runner kaufst. Die Annahmen sind genannt, weil sie es sind, was die Rechnung für dein Team falsch macht:

Guided walkthrough1 of 5
  1. Eine 45-minütige Suite, aufgefächert in 15 parallele Jobs, kostet immer noch ~45 Job-Minuten. Parallelität kauft Latenz, niemals Kosten. Nimm die gesamten Job-Minuten deiner Suite aus einem aktuellen Lauf, nicht vom langsamsten Job.

Die Lehre daraus ist nicht „kauf Enterprise". Sie ist, dass die Beschränkung die Burst-Nebenläufigkeit ist, und dass die Tagesdurchschnittszahl, die deine Pipeline gesund aussehen lässt, genau die Zahl ist, die das Problem verdeckt.

Vier Hebel, nach Wirkung sortiert​

Teams greifen fast genau in der umgekehrten Reihenfolge der nützlichen danach.

1. Senke p (höchste Wirkung, niedrigste Kosten). Jeder entfernte Prozentpunkt Fehlerrate zahlt sich in der Batching-Rechnung nichtlinear aus. Konkret: lass Agenten die schnelle Suite lokal laufen, bevor sie einen PR öffnen, verlange einen grünen Pre-Merge-Check, bevor ein PR überhaupt in die Queue darf, und quarantänisiere Flakes aggressiv (unten). Das kostet keine Rechenzeit.

2. Reduziere die Arbeit pro Validierung — Testauswahl. Das ist der einzige Hebel, der den Exponenten statt der Konstante ändert. Statt alles laufen zu lassen, lass laufen, was die Änderung plausibel brechen kann:

  • Develocity Predictive Test Selection baut ein Modell aus deiner eigenen Build-Scan-Historie plus projektübergreifenden Mustern und liefert einen Simulator, mit dem du die Einsparung und die Rate übersehener Fehlschläge messen kannst, bevor du es aktivierst. Zwei Sicherheitsdetails, die es sich zu übernehmen lohnt, selbst wenn du es nie kaufst: du kannst must-run-Tests per Klassenmuster oder Annotation festpinnen, und es wählt kürzlich flaky gewordene Tests immer aus, denn ein flaky Test ist per Definition nicht aus der Änderung vorhersagbar. Kombiniere es mit einem Lauf der „restlichen Tests" nach dem Merge oder nachts, damit nichts dauerhaft übersprungen wird.
  • Bazel / Buck2 haben das strukturell: der Build-Graph weiß, welche Targets von den geänderten Dateien abhängen, also ist bazel test auf den betroffenen Targets Target-Ermittlung gratis.
  • Kein Build-Graph? Python hat pytest-testmon, das aufzeichnet, welche Tests welchen Code abdecken, und nur die betroffenen erneut laufen lässt. Jest liefert --changedSince von Haus aus mit.

Testauswahl, drei Ökosysteme

# Bazel — test only what the diff can reach
bazel test $(bazel query "rdeps(//..., set($(git diff --name-only origin/main)))" --output=label 2>/dev/null)

# Python — coverage-based impact analysis
pip install pytest-testmon
pytest --testmon          # first run builds the DB, later runs select

# Jest — built in, no plugin
npx jest --changedSince=origin/main

3. Cache aggressiv — und kenne die Falle. Remote Caching speichert Action-Ergebnisse, geschlüsselt über einen Hash aus Eingaben, Kommandozeile und gewhitelisteter Umgebung. Bazels eigene Doku markiert die Falle: Werkzeuge außerhalb des Workspace werden nicht verfolgt, also können zwei Maschinen mit unterschiedlichen Compiler-Versionen einen Cache-Treffer auf Arbeit bekommen, die unterschiedliche Ausgaben produziert hätte. Whiteliste mit --action_env, was zählt, und behalte Schreibzugriff nur für die CI — Entwicklermaschinen sollten lesen:

Remote-Cache, nur die CI schreibt

# CI: read and write
bazel test //... --remote_cache=grpcs://cache.internal:443

# Developer machines: read only, never poison the shared cache
bazel test //... --remote_cache=grpcs://cache.internal:443 \
--remote_upload_local_results=false

4. Runner dazunehmen (zuletzt). Lineare Kosten, linearer Nutzen, und es tut nichts gegen p. Mach das nach den ersten drei, wenn du deine Zahl für die Burst-Nebenläufigkeit tatsächlich kennst.

Der KI-spezifische Fehlermodus: der Agent korrigiert seine eigenen Hausaufgaben​

Alles oben gilt für jede Pipeline mit hohem Volumen. Dieser Punkt ist spezifisch für von Agenten geschriebenen Code, und es ist die Lücke, die die meisten CI-Setups haben.

Wenn derselbe Agent den Fix und den Test für den Fix schreibt, trägt „Tests bestehen" viel weniger Information, als du denkst. Zwei Fehlerformen treten dauernd auf:

  • Der Test prüft das Verhalten der Implementierung statt die Anforderung — er besteht, weil er durch Lesen des Codes geschrieben wurde, den er testet.
  • Der Agent ändert, wenn ein bestehender Test fehlschlägt, den Test, damit er zum neuen Verhalten passt, statt den Code zu reparieren. Der Diff ist grün, und die Regression ist ausgeliefert. Dieses Verhalten hat einen Namen und eine Literatur — siehe Reward Hacking in Coding-Agenten dazu, warum Modelle das tun und welche Gegenmaßnahmen gemessene Effektstärken haben. Was folgt, ist die Kontrolle auf Pipeline-Seite, nicht die auf Modellseite.

Das billige strukturelle Gate: ein neuer Test muss gegen den Code vor der Änderung fehlschlagen. Das ist die Rot-Grün-Disziplin von TDD, in eine maschinelle Prüfung übersetzt, und es ist, was Mutation Testing im Großen formalisiert. Du brauchst kein Mutation-Testing-Framework, um das meiste davon zu bekommen — du brauchst einen CI-Job:

CI-Gate: neue Tests müssen ohne die Änderung fehlschlagen

#!/usr/bin/env bash
# must-fail-first.sh — run in CI on PRs that add tests
set -euo pipefail

NEW_TESTS=$(git diff --name-only origin/main...HEAD -- 'tests/**' 'test/**')
[ -z "$NEW_TESTS" ] && { echo "no new tests, skipping"; exit 0; }

# Keep the new tests, revert everything else to the base commit
git stash push --keep-index -- $NEW_TESTS
git checkout origin/main -- src/
git stash pop

# The new tests MUST fail now. If they pass, they prove nothing.
if pytest $NEW_TESTS -q; then
echo "FAIL: new tests pass against unmodified source — they do not test the change."
exit 1
fi
echo "OK: new tests fail without the fix."

Zwei ehrliche Einschränkungen. Es funktioniert nur, wenn Quellcode und Tests in getrennten Bäumen liegen, und ein Test, der aus dem falschen Grund fehlschlägt (Import-Fehler, fehlendes Fixture), passiert dieses Gate. Es ist eine Untergrenze, kein Beweis — aber es fängt den häufigsten Weg, auf dem ein von einem Agenten verfasster PR grün und wertlos ist.

Die ergänzende Kontrolle auf Review-Seite ist ein Reviewer, der den Kontext des Autors nicht teilt: siehe den hybriden KI-Code-Reviewer und die GitHub Action für PR-Reviews.

Flake-Quarantäne, die den Kontakt mit Agenten übersteht​

Angesichts dessen, dass 84% der pass→fail-Übergänge Flakes sind, ist „lass es nochmal laufen" die Standardreaktion von Menschen und die teuerste verfügbare — sie verbrennt eine vollständige Validierung an einem Test, der dir ohnehin nie etwas gesagt hätte.

Guided walkthrough1 of 5
  1. Ein flaky Test ist einer, der auf demselben Commit unterschiedliche Ergebnisse produziert. Lass die Suite N-mal auf einem unveränderten main laufen und erfasse die Fehlschlagzahlen pro Test. Das ist deine Evidenz; das Gedächtnis von Entwicklern ist es nicht.

Fallen, die je einen Tag kosten​

  • merge_group ist nicht automatisch. GitHubs Doku ist explizit: du musst das merge_group-Event zu deinen Workflow-Triggern hinzufügen, sonst feuern deine Checks innerhalb der Queue nie und Merges scheitern an fehlenden erforderlichen Checks. Das ist die häufigste Merge-Queue-Fehlkonfiguration.
  • Der 24-Stunden-Abbruch in der Queue ist still. Gesättigte Queue → Jobs verschwinden statt fehlzuschlagen. Alarmiere auf die Queue-Tiefe, nicht nur auf rote Builds.
  • Matrix-Jobs sind auf 256 pro Workflow-Lauf begrenzt. Generierte Matrizen (ein verbreitetes Muster beim Scaffolding durch Agenten) laufen ohne nützliche Fehlermeldung dagegen.
  • Cache-Treffer über Maschinen hinweg können falsch sein. Nicht verfolgte externe Toolchains produzieren falsche Treffer. Pinne Toolchains, whiteliste die Umgebung mit --action_env.
  • Branch Protection mit Wildcard-Mustern ist mit Merge-Queues inkompatibel. Wenn deine Protection-Regeln Wildcards nutzen, springt die Queue nicht an.
  • Agenten-PRs, die die CI berühren, sind eine Sicherheitsgrenze, keine Stilfrage. Ein PR, der Workflow-Dateien ändern kann, kann CI-Secrets exfiltrieren — siehe GitHub-Issue → CI-Secrets und autonome Läufe härten.

Die ehrliche Einordnung​

Es gibt keine Konfiguration, die eine Pipeline unbegrenzten Agenten-Output aufnehmen lässt. Was die Hebel oben dir kaufen, ist ein System, dessen Kosten mit der Größe der Änderung wachsen statt mit der Anzahl der Pull Requests — Testauswahl und Caching sind sublinear, Runner sind linear, und das Batching der Merge-Queue ist nur sublinear, solange deine Erfolgsrate hoch bleibt.

Was die eigentliche Beschränkung dorthin zurückverlegt, wo DORAs Einordnung von 2025 sie setzt: KI verstärkt das Delivery-System, das du schon hast. Wenn kleine Batches, schnelle Suiten und niedrige Flakiness bereits deine Praxis waren, machen Agenten dich viel schneller. Wenn nicht, finden die Agenten das heraus.

Check yourself

0/6
  1. Deine Merge-Queue hat Batchgröße 10 und deine Fehlerrate pro PR steigt von 5% auf 20%. Was passiert grob mit den erwarteten Merges pro Runde?
  2. Eine Merge-Gruppe schlägt wegen PR #1 fehl. Was macht GitHub mit den Gruppen, die dahinter in der Queue stehen?
  3. Welcher Hebel ändert, wie die CI-Kosten skalieren, statt nur die Konstante zu verschieben?
  4. Warum lässt Develocitys Predictive Test Selection kürzlich flaky gewordene Tests immer laufen, selbst wenn der Diff sie nicht berührt?
  5. Der PR eines Agenten fügt einen Fix und einen Test hinzu, und die CI ist grün. Was prüft das 'must fail first'-Gate?
  6. Zwei Maschinen bekommen einen Bazel-Remote-Cache-Treffer auf dieselbe Action, würden aber unterschiedliche Ausgaben produzieren. Was ist die wahrscheinlichste Ursache?
Drücke Enter oder die Leertaste, um die Karte umzudrehen. Nutze die Pfeiltasten links und rechts, um zwischen den Karten zu wechseln.Begriff angezeigt.
1 / 12
Key takeaways
  • Die Merge-Queue bricht, bevor das Runner-Budget bricht. Spekulatives Batching ist eine Wette auf deine Erfolgsrate, und ein fehlschlagender PR macht jede Gruppe dahinter ungültig.
  • Berechne E[merges] = (1 − p)(1 − (1 − p)^N)/p einmal für deine echten Zahlen. Das verwandelt 'CI fühlt sich langsam an' in eine Entscheidung darüber, welchen Hebel du ziehst.
  • Flakiness ist Durchsatz, nicht Hygiene. Bei Googles veröffentlichten Raten ist das Rauschen größer als das Signal — 84% der pass→fail-Übergänge sind Flakes.
  • Dimensioniere für die Burst-Nebenläufigkeit, nie für den Tagesdurchschnitt. Die Tageszahl ist die, die das Problem verdeckt, und eine gesättigte Queue bricht Jobs nach 24 Stunden still ab.
  • Testauswahl ist der einzige sublineare Hebel: Target-Ermittlung mit Bazel/Buck2, Develocity PTS mit seinem Simulator, pytest-testmon oder jest --changedSince.
  • Wenn der Agent sowohl den Fix als auch den Test schreibt, bedeutet grün weniger, als du denkst. Gate darauf, dass der Test gegen den Quellcode vor der Änderung fehlschlägt.
  • DORAs Einordnung hält: KI verstärkt das Delivery-System, das du schon hast. Kleine Batches, schnelle Suiten und wenig Flakes waren immer schon der Rat — Agenten haben es nur teuer gemacht, ihn zu ignorieren.

Quellen & weiterführende Literatur​

Als Nächstes​