- Kap. 4 -166, 5 -135, 6 -254, 19 -473, 21 -65, 22 -59 Wort - Freitag-Szene auf Kap. 11/18 begrenzt; Billing nur als Beispiel - 19.10-Anker und 22.9-Verweis auf 19.9 erhalten - Zweitleser: 4 Verweis- und 1 Sachlogik-Befund behoben - Wörter 56 763 -> 55 609 (-1 154); Band verfehlt, AE-60 offen - eBook 245, Print 295; _print_pages bleibt 298 (BP-07)
20 KiB
10. Definition of Done und autonome Loops
Der Agent meldet „fertig“. Du öffnest den Diff — und merkst: kein Test gelaufen, Lint rot, Scope größer als vereinbart. Autonomie ohne Messlatte ist nur schneller Drift. Coding-Agents können in Loops arbeiten — ändern → prüfen → nachbessern — aber nur, wenn die Fertigstellung vom Agent selbst erkannt werden kann.
These 4: Tasks müssen so gestaltet sein, dass die Definition of Done (DoD) vom Agent selbst ermittelbar und verifizierbar ist. Nur dann sind echte autonome Loops möglich.
Das ist eine der härtesten und wertvollsten Regeln dieses Buchs. Ohne sie bleiben Workflow (Kap. 7) und Slices (Kap. 8) Theater: Der Mensch wird zum menschlichen Test-Runner.
10.1 Was „agent-ermittelbar“ heißt
Orakel hier: ein maschinenprüfbarer Check (Command, Exit-Code, Contract), der Done/Not-Done ohne menschliche Geschmacksfrage entscheidet.
Schnelltest: Kannst du den Raum verlassen, und der Agent meldet trotzdem grün oder rot — ohne deinen Geschmack? Wenn du „hmm, fühlt sich clean an“ brauchst, ist das kein Loop-Orakel. Das ist Human-Gate.
Agent-ermittelbar (These-Wortlaut; synonym in Vorlagen oft agent-prüfbar / agent-verifizierbar, im Fließtext auch agent-tauglich): Der Agent entscheidet ohne menschliche Geschmacksfrage — erfüllt / nicht erfüllt. Alle vier meinen dasselbe Orakel-Kriterium.
Agent-tauglich sind zum Beispiel:
pnpm --filter invoices testexit code 0;go test ./...grün- HTTP-Handler antwortet 401 ohne Token (Contract-Test)
- Lint/Typecheck exit 0
- Diff enthält keine Änderungen unter
packages/legacy/**(prüfbar viagit diff --name-only)
Schwach als alleiniger Check: Datei X existiert und enthält Symbol Y — besser deckt ein Test das Verhalten ab.
Nicht agent-tauglich (allein): „Code ist clean“, „UX fühlt sich gut an“, „Performance ist ok“ ohne Budget/Benchmark, „Security ist fein“ ohne Check/Richtlinie, „Wie ein Senior das machen würde“.
Menschliche Kriterien sind legitim — als Exit-Gates für Menschen, nicht als Loop-Bedingung. Kombiniere sie:
Agent-DoD (automatisch) + Human-DoD (Review/Produkt)
Der autonome Loop läuft auf der ersten Schicht. Die zweite stoppt den Merge. Wer beides vermischt, bekommt entweder Pseudo-Autonomie („der Agent sagt done“) oder endlosen Ping-Pong („noch nicht gut genug“ ohne messbare Latte).
Die Anti-Pattern-Form heißt Soft-DoD; die Copy-Paste-Checkliste steht in Kap. 19.4.
10.2 Anatomie einer guten DoD
Vier Teile reichen:
- Verhalten — was wahr sein muss
- Checks — welche Kommandos/Artefakte das beweisen
- Scope-Grenzen — was nicht kaputt / nicht geändert sein darf
- Stop-Bedingung — wann der Agent aufhören oder eskalieren soll
## DoD
- [ ] `POST /invoices` legt Invoice an (Integrationstest grün)
- [ ] Validierungsfehler → 400 mit bestehendem Error-Format (Test)
- [ ] `pnpm --filter invoices test` exit 0
- [ ] `pnpm lint` exit 0
- [ ] Keine Schema-Migration in diesem Slice
- [ ] Stop & frage nach, wenn Public API anderer Module nötig scheint
In der Praxis schreibst du die DoD in den Task-Prompt und spiegelst Default-Verify in AGENTS.md. Was nur „irgendwo im Ticket“ steht, verliert der Agent in der Session-Mitte (Lost-in-the-Middle, Kap. 3).
10.3 Der autonome Loop
Ohne maschinenlesbare Checks entartet der Loop zu:
write → claim done → user: "noch nicht" → write → …
Das ist kein Agent-Loop, das ist Ping-Pong. Der gute Loop steuert gegen Orakel:
attempt → run DoD-checks → if red: fix (narrow) → if green: stop / commit
Max-Iterationen und Eskalation bei „kein DoD-Fortschritt“ gehören dazu. Der Harness kann den Loop tragen; Orakel und Disziplin erzwingen den Stopp.
10.4 DoD in den Harness legen
Dritter Compact am selben Nachmittag: Die DoD stand nur im Ticket. Der Agent „weiß“ sie nicht mehr und meldet done auf dem falschen Subset. Deshalb redundant speichern — Lost-in-the-Middle ist ein Positionsprofil (Kap. 3), kein „der Agent hat kein Gedächtnis“. Die Gegenmaßnahme ist Speicher-Disziplin:
- Im Task-Prompt (primär)
- In
AGENTS.mdDefaults (Verify-Kommandos des Repos) - Als Agent Skill (
SKILL.md, Kap. 16) „before claiming done, run …“ - Nach Compact erneut am Rand (User-Turn oder Handoff)
- Als CI parallel — Agent lokal, Wahrheit in der Pipeline
Eine Schicht allein ist fragil. Prompt + Defaults + CI fangen die üblichen Ausfälle: vergessener Check, veraltete Rule, „lokal grün, Pipeline rot“.
10.5 Partial Done und Slices
Ein Epic hat eine Epic-DoD. Ein Slice hat eine Slice-DoD. Der Agent arbeitet gegen die Slice-DoD.
Do this: „Slice done = mergeable Increment.“
Avoid that: „Agent done = Epic done“ bei großem Scope.
Sonst jagt der Loop eine Latte, die in einer Sweet-Spot-Session nicht erreichbar ist — und endet in Context Rot oder vorgetäuschtem Done. Praktisch: Slice-DoD = Tight-Loop-Orakel plus vereinbarte Slice-Checks; Heavy (Mutation, Fuzzing, volle E2E) bleibt CI/Nightly (siehe 10.6).
10.6 Orakel-Katalog und Verify-Schichten
Der Agent hat die Unit-Suite grün. Im Review crasht der Parser beim ersten kaputten JSON aus dem Ticket-Anhang. DoD ohne passende Härte ist Theater mit Exit-Code.
Eine DoD ist nur so gut wie Härte und Geschwindigkeit der Checks dahinter. Agents multiplizieren deine Orakel — gute wie schlechte. Repo-Verifikation ist Infrastruktur für These 4, nicht Deko im Prompt.
Zwei Achsen:
- Orakel-Härte — wie viel Vertrauen der Check verdient
- Verify-Schicht — wie oft und wann er laufen soll
Härte und Frequenz sind nicht dasselbe. Was der Agent im Tight-Loop zehnmal ausführt, muss schnell, deterministisch und bissig sein. Mutation, Fuzzing, volle E2E kaufen Vertrauen vor dem Merge — sie ersetzen den schnellen Loop nicht.
Orakel-Klassen (Überblick)
Die erste Tabelle ist Härte und Falle. Die zweite macht These 4 kopierbar: eine Klasse, ein Command. Stack-Namen sind Beispiele — im Repo gilt der Task, den CI auch kennt.
| Klasse | Was sie fängt | Tight-Loop? | Typische Falle |
|---|---|---|---|
| Typecheck / Compile | API-Brüche, viele Tippfehler | ja, oft zuerst | „compiles = done“ |
| Lint / Format | Stil, manche Bugs | ja, ergänzend | Lint als Feature-DoD |
| Unit- / Integrationstests | spezifiziertes Verhalten | ja, scoped | Fake Asserts, Overmock |
| Contract / Schema | Halluzination an Grenzen | ja, wenn schnell | veralteter Contract |
| E2E / Systemtests | End-to-End-Pfade, reale Integration | selten (Smoke ok) | Flaky, langsam → CI/Heavy |
| Browser / UI | sichtbares Verhalten, Routing, Formularfluss | Slice-DoD / CI, nicht Tight-Loop | Screenshot-Theater, flaky Selektoren |
| Golden / Snapshot / Characterization | Regressionsfläche, Legacy | ja, wenn stabil | Snapshot akzeptieren ohne Lesen |
| Coverage (Paket-Report) | ungetestete Module als Signal | eher Pre-Merge | globales %-Ziel gamifizieren; Report ≠ Patch-Orakel |
| Diff-Coverage (touched lines) | ungetestete neue Pfade | Pre-Merge | Report ohne Fail-Schwelle |
| Mutation Testing | Tests ohne Biss | Pre-Merge / Nightly, scoped | im Tight-Loop zu teuer |
| Property-based | unspezifizierte Grenzfälle | gezielt Kernmodule | lange Läufe, Flakiness |
| Fuzzing | Crashes, Hangs, Sanitizer-Hits an Parsern/Boundaries | nein (Heavy/CI; kurzer Smoke-Corpus optional) | Endlos-Lauf, Corpus-Müll; Agent „stabilisiert“ Lärm |
| Secrets-Scan / SCA (Software Composition Analysis) / SAST | Leaks, Dep-Risiken, klassische Code-Schwächen | eher Pre-Merge | Alert-Noise, Scan ≠ Verhaltensbeweis |
| Komplexitätsmetriken | Hotspots, smelly Diffs | meist CI / Human | Metrik-Theater |
| Benchmark / Budget | Perf-Regression | wenn in DoD genannt | ohne Fixture gelogen |
Scope-Diff (git diff --name-only) |
Scope-Creep | ja, billig | zu weiche Allowlist |
| Klasse | Beispiel-Command |
|---|---|
| Typecheck / Compile | tsc --noEmit · go build ./... |
| Lint / Format | pnpm lint · ruff check . |
| Unit- / Integrationstests | pnpm --filter invoices test · pytest -k invoices |
| Contract / Schema | pnpm --filter contracts test · make openapi-validate |
| E2E / Systemtests | pnpm test:e2e --grep checkout |
| Browser / UI | npx playwright test --grep invoice-form |
| Golden / Snapshot / Characterization | pytest tests/golden -q |
| Coverage (Paket-Report) | pnpm --filter invoices test --coverage |
| Diff-Coverage (touched lines) | diff-cover coverage.xml --compare-branch origin/main --fail-under=80 |
| Mutation Testing | npx stryker run --mutate src/invoices/** |
| Property-based | pytest -k properties |
| Fuzzing | cargo fuzz run parse_invoice -- -max_total_time=60 |
| Secrets-Scan / SCA / SAST | gitleaks dir . · trivy fs --scanners vuln,secret . |
| Komplexitätsmetriken | npx eslint src --rule 'complexity:[error,15]' |
| Benchmark / Budget | pytest tests/bench.py --benchmark-max-time=2 |
| Scope-Diff | git diff --name-only |
Ohne Command in der DoD bleibt These 4 Prosa. Plan-Freigabe ist ein Alignment-Gate (Kap. 11), kein Loop-Orakel.
Browser/UI: wenn das Produkt eine Oberfläche ist, nicht weil der Agent einen Browser hat. Assert auf Zustand, Route oder Formularvertrag; Screenshot ohne Assert ist kein Orakel. Slice-DoD oder CI — MCP-Zugang (Kap. 17) ersetzt den Exit-Code nicht.
Coverage (Paket-Report) ist Signal, kein Patch-Orakel. Diff-Coverage mit Fail-Schwelle ist das Pre-Merge-Orakel. „≥ 90 %“ als Agent-DoD füllt leere Asserts (Kap. 19). Mutation misst Testqualität, nicht Codequalität — CI/Nightly, scoped, Outcome „keine survived mutants in Modul X“. Fuzzing an Parsern und untrusted Input: Zeitbudget plus Exit-Code, nicht Tight-Loop.
tsc grün heißt nicht „korrekt“; an Grenzen sind Contracts Anti-Halluzination (Kapitel 9). Komplexitätsmetriken sind CI-/Review-Gates, nicht Feature-DoD (Kapitel 8). Golden/Characterization oft Slice 0 (Kapitel 21). Secrets/SCA/SAST fangen Leaks, nicht Verhalten (Kapitel 18).
Verify-Schichten (wann was läuft)
Was zehnmal im Loop läuft, bleibt billig. Was Vertrauen vor dem Merge kauft, darf teurer sein. Im Team dieselben drei Wörter — sonst meint einer „DoD“ die volle Pipeline:
| Schicht | Wann | Härte |
|---|---|---|
| Tight-Loop | nach sinnvollem Patch | schnell, scoped, deterministisch |
| Slice-DoD | vor „done“ / Hand-back | Package- oder Filter-Suite + vereinbarte Contracts |
| Heavy | CI/Nightly oder kritischer Kern | Mutation, Fuzzing, volle E2E, Performance |
Pre-Merge sitzt dazwischen: vereinbarte Pipeline, oft Slice-DoD plus Security-Scans. Nicht jede Schicht muss in jeder Session laufen — aber die Namen sollten im Review fallen, nicht nur im Buch.
Tight-Loop (nach sinnvollem Patch):
typecheck|compile (scoped) + gezielte Tests + optional Lint + Scope-Diff
Slice-DoD / vor „done“:
Package- oder Filter-Suite + vereinbarte Contract-Checks
Pre-Merge / CI:
vereinbarte Pipeline + ggf. Diff-Coverage + Security-Scans
(Secrets-Scan / SCA / SAST)
Heavy (Nightly oder kritischer Kern):
Mutation scoped, Fuzzing scoped, schwere E2E, Performance
Do this: In AGENTS.md die schnellen Defaults nennen; schwere Gates als CI/Nightly kennzeichnen, nicht als „nach jedem Edit“.
Avoid that: Volle Mutation, langes Fuzzing oder Repo-weite E2E im Agent-Loop nach jedem Edit — Context-Novellen und Timeout statt Autonomie.
CI als Mirror: Die Pipeline ist keine zweite Wahrheit. Dieselben Task-Namen, dieselbe Runtime-Pin, dieselben Exit-Codes wie lokal (Kap. 15.8). Wer lokal just test-unit fährt und in CI ein anderes Skript mit anderem Node, hat kein Orakel — er hat zwei Meinungen. Agent-DoD zitiert den Command, den CI auch kennt.
Low-Maturity bleibt ehrlich (Kapitel 21): erst irgendein stabiles Orakel, dann Härte. Mutation, Diff-Coverage und Fuzzing sind Reife-Investments, nicht Einstiegszwang.
Orakel-Ökonomie: warum ausgiebig investieren
Mit Agents läuft Verify zehnmal pro Stunde — Review skaliert nicht mit. Jeder Check, der ohne Geschmacksfrage grün/rot macht, kauft Autonomie statt Ping-Pong. Unterinvest in Tests, Contracts und Types wird Drift × Tempo. „Ausgiebig“ heißt: Biss dort, wo Agents loopen; schwere Härte geschichtet, nicht im Tight-Loop.
| Investition | Kosten (ehrlich) | Nutzen mit Agents | Wann sparsam / später |
|---|---|---|---|
| Strenge Types / Compile | Setup, Strictness-Migration | billiges Dauer-Orakel; weniger API-Halluzination | schrittweise ok, Zielrichtung strenger |
| Unit- + Integrationstests (bissig) | Schreib-/Pflegeaufwand | Tight-Loop-Autonomie | Slice 0 zuerst am Touchpoint |
| Contract / Schema / shared types | Pflege an Grenzen | Anti-Halluzination über Packages/Services | Pflicht bei Polyrepo und Boundaries |
| Diff-Coverage / Assert-Review | CI + Review-Disziplin | gegen ungetestete Agent-Pfade | Pre-Merge; kein Vanity-% |
| Mutation (scoped) | Laufzeit | Testqualität; Fake-Grün | CI/Nightly, Reife, kritischer Kern |
| Fuzzing (scoped Targets) | Harness, Corpus, CI-Zeit | fängt Agent-Blindspots an Boundaries | erst bei Parser/untrusted; nicht Tight-Loop |
| Characterization / Golden | Snapshot-Disziplin | Slice-0-Orakel in Legacy | Snapshots lesen, nicht blind accept |
Struktur ohne Orakel bleibt Ratespiel — und Orakel ohne lesbare Struktur (Kapitel 9) bleiben grüne Inseln an kaputten Grenzen.
10.7 Wenn es keine Tests gibt
Dann ist Autonomie teurer. Optionen in der Reihenfolge des Hebels:
- Zuerst Test/Repro als Slice 0 (oft der höchste Hebel)
- Schwächere Orakel: Compiler, vorhandene Smoke-Scripts, golden files
- Mensch im Loop bewusst einplanen — und nicht so tun, als wäre der Agent autonom
Agents ohne Orakel sind Textgeneratoren mit Shell-Zugang. Ehrlichkeit hier spart peinliche Demos und teure Rollbacks. Das volle Low-Maturity-Regime (Diagnose, Orakel-Leiter, Hygiene-First, Greenfield von Tag 1): Kapitel 21.
10.8 Stop- und Eskalationsregeln
Acht Fix-Versuche, dieselbe Assertion rot, Context voller Fast-gleicher Diffs — und niemand hat „stop“ gesagt. Autonomie ohne Bremse ist Context Rot mit guter Absicht. Die Figur macht den Steuerkreis explizit: DoD-Gate, max N, Escalate oder Human+Handoff.
Autonomie braucht Bremsen: max. N Fix-Versuche pro Fehlerklasse; keine neuen Dependencies ohne Freigabe; keine Erweiterung der Public API ohne Rückfrage; bei flaky tests nicht 15-mal retry — melden.
Wenn DoD nach 3 gezielten Fix-Versuchen nicht grün ist:
stoppen, Ursachenhypothesen listen, Handoff aktualisieren, User fragen.
Eskalation ist nicht nur „User fragen“. Manchmal reicht Capability statt Mensch: ein Versuch auf einem stärkeren Modell-Tier (oder Verify-with-stronger auf dem Diff), bevor der Loop den Context mit denselben schwachen Patches füllt — Model Routing in Kapitel 5.7. Beides braucht Trigger und ein Limit: endloses Modell-Hopping ist nur teurer Rot.
Ohne Stop-Regel optimiert der Agent auf „noch ein Versuch“ und füllt den Context mit gescheiterten Patches. Das ist Context Rot mit guter Absicht.
10.9 Anti-Patterns
| Anti-Pattern | Folge | Fix |
|---|---|---|
| DoD nur Prosa | Pseudo-Autonomie | Commands |
| DoD zu weit (ganzes Epic) | Nie grün / Context tot | Slices |
| DoD zu eng (implementierungsdiktierend) | Fragile Lösung | Outcome-Tests (Kap. 14) |
| Agent „done“ ohne Verify | Regressionen | Harness-Skill |
| User verschiebt DoD still im Chat | Rot | Handoff + Prompt-Update |
| Alles im Tight-Loop | Timeouts, Context-Müll | Verify-Schichten → 10.6 |
| Vanity-Coverage / Fake Asserts | Pseudo-Grün | Diff-Coverage, Mutation, Assert-Review |
Der Punkt „DoD still verschieben“ ist Team-Kultur: Wenn „fertig“ mitten im Chat umdefiniert wird, ohne Handoff und Prompt-Update, misst der Agent gegen eine Latte, die es offiziell nicht mehr gibt.
10.10 Verbindung zu These 5
Nicht zu restriktiv heißt nicht „keine DoD“. Freiheit innerhalb des Slices, Härte an der Grenze zur Fertigstellung. Die Formel steht in Kapitel 14.
10.11 DoD-Bibliothek
Eine anatomische DoD steht in 10.2. Weitere Kopiervorlagen (API, Bugfix, Refactor, Contract, Parser, Docs, Coverage/Mutation) liegen in Anhang A.7 · templates/dod-bibliothek.md. Anpassen, nicht auswendig lernen. Eine DoD ohne Ausschlüsse lädt den Agent ein, „noch mitzuziehen“.
10.12 Autonomie-Stufen
| Stufe | Loop | Voraussetzung |
|---|---|---|
| L0 Assist | Mensch steuert jeden Schritt | — |
| L1 Draft | Agent schreibt, Mensch prüft alles | schwache DoD ok |
| L2 Local Loop | Agent iteriert bis Tests grün | harte Agent-DoD (Tight-Loop-Orakel) |
| L3 PR Loop | Agent öffnet PR bei grün | CI + Richtlinie (+ ggf. Diff-Coverage/Mutation) |
| L4 Merge | Automerge | hohe Reife, selten sinnvoll ohne strenge Gates |
Der Gewinn sitzt meist bei L2 — nicht bei L4-Fantasien ohne Orakel. Wer Stufen ohne Tests und Richtlinie überspringt, endet in schnellerem Merge-Chaos. Härtere Orakel (10.6) stützen L3; sie ersetzen Slice 0 bei Low-Maturity nicht.
10.13 Flaky Tests und der Loop
Flaky DoD-Checks zerstören Autonomie: der Agent „fixt“ Nicht-Determinismus mit Sleeps und noch mehr Chaos. Richtlinie: Flaky → erst stabilisieren (eigener Slice) oder aus der Agent-DoD nehmen und als Human-Gate führen. Nie stillschweigend 10× retry als Strategie. Ein flaky Orakel ist schlimmer als kein Orakel — es trainiert den Loop auf Lärm.
Key Takeaways
- Autonomie braucht agent-ermittelbare Orakel — sonst Ping-Pong.
- Agent-Checks und Human-Gates nicht vermischen. Plan-Freigabe ist ein Alignment-Gate, kein Orakel.
- Tight-Loop · Slice-DoD · Heavy — Härte ≠ Frequenz; CI spiegelt lokal.
- Jede Orakel-Klasse braucht einen Command. Kein Orakel ⇒ keine ehrliche Autonomie.
Praktische nächste Schritte
- Drei aktuelle Tickets: jede DoD-Zeile prüfbar machen oder streichen.
- Verify-Kommandos in
AGENTS.mdnach Tight-Loop / Slice-DoD / Heavy sortieren — eine Klasse, ein Command; CI dieselben Tasks. - Stop-Regel (max. Fix-Versuche → eskalieren); bei ungetestetem Bereich zuerst Slice 0.
- Weiter: Kapitel 11 — DoD nützt wenig bei falschem Verständnis.


