Composite-Korridore und Primärquellen in Kap. 2 ehrlich kalibriert; DoD/Verify, Surfaces und Anhänge in 04–16 geschärft; eBook 119 S. neu gebaut.
12 KiB
9. DoD, Verify und CI
Kern: Fertig ist, was Verify grün und Diff zum Auftrag passend ist — nicht was der Agent für „eigentlich schon gut“ hält. Commands müssen non-interactive und in Instructions / Package-Rules stehen.
Die Orakel-Logik (Tests, Types, Contracts) vertieft das Theorie-Schwesterbuch (Coding Agents in der Praxis, Kap. 10). Agent in CI: produktspezifisch (optional Copilot: Der Copilot-CLI-Harness, Teams/CI). Hier die Enterprise-Übersetzung: Tight-Loop vs. Heavy, Command-Matrix für Angular / Spring Boot / Quarkus, non-interactive Gates und CI als Mirror. DoD ist repo-seitig; der Harness muss Commands nur finden und ausführen können (Instructions/AGENTS.md; Surfaces: Anhang C).
Kapitel 5–8 haben pro Schicht und pro Slice schon Verify verlangt. Dieses Kapitel macht das Betriebssystem explizit: welche Commands wann, warum Full-Suite im Chat teuer ist, und warum „lokal grün“ ohne Runtime-Wahrheit (Kap. 4.1) nur Anekdote ist.
9.1 Die typische DoD-Session, die schiefgeht
Auftrag: „Bestellstatus in der Liste — Backend + ein Test.“ Der Agent patcht, startet nach dem ersten Tippfehler ./mvnw clean verify, wartet auf Testcontainers, holt 600 Zeilen Surefire in den Context und erklärt selbstbewusst, der Fix sei „eigentlich schon grün“. Parallel läuft irgendwo noch npm test im Watch-Mode — Exit-Code unklar, UI hat gefragt. Der Reviewer sieht am Ende: der scoped Test hätte in 20 Sekunden gereicht; die Security-Tests, die hätten mitlaufen sollen, standen nie in der DoD. CI wird später rot — anderes JDK-Image als der Laptop.
Du merkst den falschen Verify-Schnitt daran, dass:
- die Session Minuten pro Loop verbrennt statt Sekunden,
- Observations aus alten Full-Runs den nächsten Fix vergiften,
- „fertig“ nur als Prosa im Chat steht, nicht als benannter Exit-Code,
- lokal und CI andere Toolchains oder Scripts meinen.
Session-Hygiene zuerst
- Einen scoped Command benennen, der den Slice beweist — Exit-Code, nicht Prosa.
- Tight / Slice-DoD / Heavy und Runtime-Pin in drei Zeilen nachziehen (Kap. 4.1).
- Surefire-XML und Full-
verify-Ballast aus dem Context; frische Session am benannten Command. Full-Suite bleibt Heavy (Kap. 2.1).
9.2 Tight-Loop · Slice-DoD · Heavy
Tight-Loop ist der schnelle, scoped Check nach sinnvollen Patches: eine Testklasse, Lint, gezieltes Build-Fragment. Slice-DoD ist „dieser Slice ist baubar und zum Auftrag passend“: Tight bereits grün, plus Package/Build ohne Full-Suite, plus Scope-Check am Diff. Heavy ist CI, Nightly, vor Merge — volle Suite, Integration, e2e, Quality-Gates.
Verify vs. Scope (nicht vermischen):
| Teil von Slice-DoD | Wer | Was „grün“ heißt |
|---|---|---|
| Verify | Agent (Exit-Code) | Tight-Commands + baubar (package / build -x test) non-interactive |
| Scope / Diff-Fit | Review / HITL (Ampel) | Diff = Auftrag; keine Drive-bys — nicht durch den Agent allein „abhakbar“ |
Slice-DoD = Tight grün ∧ baubar ∧ Diff-Fit. Ein Agent, der nur den Build meldet, hat nicht „DoD grün“ im Team-Sinn erledigt. Review-Checkliste: checklists/review-agent-diff-enterprise.md.
Agents, die nach jedem Edit mvn clean install oder die komplette e2e-Suite fahren, verbrennen Zeit und Context (Logs). Agents ohne jedes Verify raten. Beides ist teurer als drei benannte Commands im Repo.
| Ebene | Wann | Ziel | Beispiele |
|---|---|---|---|
| Tight-Loop | nach sinnvollen Patches | schnell, scoped, oft lokal | eine Testklasse, ESLint aufs Projekt, tsc/ng build dev |
| Slice-DoD | vor „done“ am Slice | Tight grün + baubar + Scope-Check | package / build -x test + Diff vs. Auftrag (Scope = Review) |
| Heavy | CI, Nightly, vor Merge | volle Suite, Integration, e2e, Quality-Gates | full mvn verify, Testcontainers, Playwright/Cypress |
Transfer: Die Namen müssen im Team gleich heißen — in Instructions, im Task-Prompt und im Review. Sonst meint der Agent „DoD“, der Reviewer „Heavy“, und niemand hat gelogen.
Framework-Beispiele: Kap. 5.3 (Angular), 6.3 (Spring), 7 (Quarkus). Slice-Reihenfolge: Kap. 8.2.
9.3 Command-Matrix (Muster — anpassen)
Die Matrix ist Muster, kein Dogma. Tragt eure Wrapper-Pfade (mvnw/gradlew), Module (-pl :api), npm-/Nx-Scripts und Runtime-Pin (Kap. 4.1) in Package-AGENTS.md und Root-Instructions/AGENTS.md (Surfaces: Anhang C) ein. Snapshot: Anhang B. Vorlagen: templates/agents-md-*.md, optional Surface-Beispiele templates/copilot-instructions-*.md, Skill templates/skill-verify-stack/.
Angular
# Tight-Loop
npm test -- --watch=false --browsers=ChromeHeadless # oder Jest/Vitest-Script
npm run lint
# optional scoped:
npx nx test my-app --watch=false --testPathPattern=feature-x
# Slice-DoD
npm run build
# Diff-Review: nur Dateien des Slices
# Heavy
npm run test:e2e # non-interactive CI-Config
Spring Boot (Maven)
# Tight-Loop
./mvnw -q -Dtest=UserServiceTest test
# mehrere Klassen im Tight: -Dtest=UserServiceTest,UserControllerTest
./mvnw -q spotless:check # oder checkstyle
# Slice-DoD (Tight bereits grün + baubar + Diff = Auftrag)
./mvnw -q -DskipTests package
# Heavy
./mvnw -q verify # inkl. Failsafe/Integration
Spring Boot (Gradle)
# Tight-Loop
./gradlew test --tests com.example.UserServiceTest
# mehrere Klassen: zwei --tests-Flags (kein Komma)
./gradlew test --tests com.example.UserServiceTest --tests com.example.UserControllerTest
./gradlew spotlessCheck
# Slice-DoD (Tight bereits grün + baubar + Diff = Auftrag)
./gradlew build -x test # oder assemble nach Team-Standard
# Heavy
./gradlew build # inkl. Integrationstests nach Team-Setup
Quarkus
# Tight-Loop (Maven; -q analog Spring)
./mvnw -q -Dtest=GreetingResourceTest test
# Gradle: ./gradlew test --tests com.example.GreetingResourceTest
# Avoid im Agent-Loop: quarkusDev / Continuous Testing (Mensch-Tempo ≠ Exit-Code-DoD)
# Slice-DoD (Tight bereits grün + baubar + Diff = Auftrag / Review)
./mvnw -q -DskipTests package
# Gradle: ./gradlew build -x test
# Heavy
./mvnw -q verify
# Native nur mit Auftrag:
# ./mvnw package -Dnative
Warum die Matrix hier steht: Kap. 5–7 nennen Verify im Vorbeigehen. Ohne eine Stelle, an der Angular, Spring Boot und Quarkus nebeneinander stehen, driftet das Team in drei private „so teste ich“-Varianten — und der Agent erbt die lauteste aus dem Chat.
Multi-module: Maven -pl … -am, Gradle Projektpfade. Surefire-XML, target/, dist/, Coverage-HTML: aus dem Context halten (Ignore-Grenzen Kap. 4).
9.4 Non-interactive ist Pflicht
Ohne Exit-Code, den der Agent lesen kann, gibt es keinen autonomen Loop — nur Theater mit Watch-Mode und „bei mir war grün“.
| Problem | Fix |
|---|---|
CLI fragt y/N |
Flags (-B, --yes, headless browser, CI=true) |
| Test öffnet UI | Headless / CI-Config |
| Snapshot-Update interaktiv | in Agent-DoD verbieten oder explizit freigeben |
| Docker braucht TTY | CI-taugliche Compose-Profile |
Du merkst interaktive DoD daran, dass die Session hängt oder der Agent „angenommen ja“ weiterarbeitet, während der Prozess auf Enter wartet. Fix: denselben Command mit CI=true (oder eurem CI-Äquivalent) einmal selbst fahren und den Flags-Satz in Instructions schreiben.
9.5 CI als Mirror, nicht als Überraschung
CI soll dieselben Commands ausführen wie in Instructions/AGENTS.md — oder eine dokumentierte Obermenge. Drift („lokal grün, CI rot“) ist Context- und Vertrauensgift. Oft steckt der Drift nicht im Script-Namen, sondern in der Runtime: anderes Node/JDK-Image als der lokale Pin, anderer Wrapper-Pfad, stilles Host-Tool. Mirror heißt: dieselbe Toolchain-Wahrheit (Kap. 4.1) und dieselben Task-Einstiege — nicht nur ähnliche YAML-Zeilen.
Nightly darf teurer sein (Mutation, Full e2e); das gehört als Heavy gelabelt, nicht als Tight-Loop. Wer Nightly-Last in den Chat-Loop holt, kauft sich Context-Rot und verliert den Tight-Loop.
Agent in CI (programmatische Läufe, Token- und Permission-Policy) ist produktspezifisch — optional für Copilot: Der Copilot-CLI-Harness (Teams/CI). Hier gilt nur: derselbe Verify-Command und dieselbe Runtime-Annahme wie lokal — keine zweite „Agent-Wahrheit“.
| Do this | Avoid that |
|---|---|
| CI-YAML und Instructions dieselben Einstiege | „lokal npm test, CI nx test anderes Projekt“ still |
| Image/Pin = lokaler Pin (oder dokumentierte Abweichung) | Host-JDK 21, CI-Image 17, „bei mir grün“ |
| Heavy in Nightly/PR-Gate benennen | Full e2e als Tight-Loop im Agent-Prompt |
9.6 DoD-Checkliste pro Slice (kopierbar)
Kurzform für Task und Review — stack-spezifisch ausbauen:
- Akzeptanzkriterien des Task-Prompts erfüllt
- Tight-Loop-Verify grün (genannte Commands)
- Kein Scope-Creep im Diff
- Keine Secrets / keine Debug-
permitAll-Reste - Bei API-Änderung: Contract/OpenAPI mitgezogen
- Heavy nur wenn Slice/Policy es verlangt
Lebende Listen: checklists/dod-angular.md, checklists/dod-spring.md, checklists/dod-quarkus.md. Review-Ampel am Diff: checklists/review-agent-diff-enterprise.md.
Mini-Beispiel (Anschluss Kap. 8): Outcome „Status in der Liste“. Backend-DoD: ./mvnw -q -Dtest=OrderControllerTest test. Frontend-DoD: npm test -- --watch=false --include=order-list + Lint. Heavy: e2e nur wenn Policy es verlangt. Diff: Contract + Controller/Test + List-Component — nicht die Payment-Domain.
9.7 Do this / Avoid that
| Do this | Avoid that |
|---|---|
Scoped -Dtest= / --tests / testPathPattern |
Immer Full Suite im Chat-Loop |
Commands und Runtime-Pin in Instructions/AGENTS.md + CI aligned |
Drei inoffizielle „so teste ich privat“-Varianten; Host-JDK vs. CI-Image still |
| Log-Noise maskieren / nur Assertion+Stack-Kopf | 800-Zeilen Surefire-Dump im Context behalten |
| Failures als Signal nutzen | „baut schon irgendwie“ und weiterfeature |
| Tight / Slice-DoD / Heavy im Task-Prompt benennen | „mach fertig und teste ordentlich“ ohne Command |
Einmal CI=true / CI-Container gegen denselben Pin |
Nur interaktive Dev-Scripts als Agent-DoD |
Key Takeaways
- Kanon Tight-Loop · Slice-DoD · Heavy trennen und benennen — nicht „DoD“ und „Heavy“ synonym.
- Non-interactive Commands mit klaren Exit-Codes sind die Voraussetzung für Agent-Loops.
- Verify-Commands ohne Runtime-Wahrheit (Kap. 4.1) sind unvollständige DoD.
- DoD = Kriterien + Verify + Diff-Fit — nicht Bauchgefühl.
- CI ist Mirror derselben Wahrheit — nicht eine zweite Testphilosophie.
Praktische nächste Schritte
- Pro App/Service in Instructions/
AGENTS.md: Runtime/Einstieg + drei Zeilen Tight / Slice-DoD / Heavy. - Einmal selbst im CI-Container oder mit
CI=truelaufen lassen — gegen denselben Pin wie lokal. - Checklisten
checklists/dod-angular.md(usw.) an eure Scripts hängen. - Nächsten Slice-Task mit benannten Commands schreiben (Vorlage Kap. 8 /
templates/task-prompt-fullstack-slice.md). - Danach Kap. 10 — Instructions, Skills und MCP so schneiden, dass Verify und Boundaries auffindbar bleiben.

