153 Commits, 102 Specs, Konsistenz 9.9/10. So endete Teil 2 dieser Serie, Ende Januar 2026. Ich hatte Templates, Patterns, eine klare Drei-Phasen-Struktur — Constitution, Specify, Plan. Ein Commit trug sogar den Titel "Vollständige Dokumentations-Harmonisierung (Konsistenz 10.0/10)". Template-Compliance 100%, keine broken Links, keine Legacy-Naming-Probleme. Fertig?
Dann kamen 477 weitere Commits.
Keine geplante Phase. Kein "jetzt kommt das große Polishing". Sondern die Erkenntnis, dass "fast fertig" bei 121 Feature-Specs nicht "noch ein paar Kleinigkeiten" bedeutet, sondern dutzende Entscheidungen, die ich noch nicht getroffen hatte. Architektur-Änderungen, die alles wieder aufrissen. Validierungsansätze, die nicht skalierten. Code in Specs, der dort nicht hingehörte.
Heute steht das Desktop-App-Projekt bei 651 Commits, 233 Markdown-Dateien, 121 Feature-Specs, 14 Constitution-Dokumente, 84 Pläne — und exakt 0 Zeilen Produktivcode. Aber ich weiß jetzt, was "fertig" wirklich bedeutet.
Dies ist Teil 3 der SDD-Serie. Teil 1 erklärte die Theorie: Warum AI-Agenten strukturierte Spezifikationen brauchen. Teil 2 zeigte die Praxis: 153 Commits in 10 Tagen, die organische Entdeckung von SDD. Dieser Artikel handelt von der Reife — und von der Frage, warum die letzten 477 Commits wichtiger waren als die ersten 153.
Sprachagnostische Specs: Kein Code in Phase 2 und 3
Die konsequente Phasentrennung war die schmerzhafteste Lektion der gesamten 477 Commits. Und sie begann mit einer Erkenntnis, die im Nachhinein offensichtlich wirkt — aber Monate brauchte, um wirklich anzukommen. Es ist leicht, Phasentrennung als Prinzip zu formulieren. Es ist schwer, sie in einem lebenden Projekt durchzusetzen, wenn der Druck wächst, endlich mit der Implementierung zu beginnen.
In Teil 2 beschrieb ich das Reference-Style Pattern: Statt vollständiger Implementierungen in Feature-Specs nur Function Signatures plus Metadata-Tabellen. Die Entity-Verwaltung schrumpfte von 2.361 auf 818 Zeilen. Minus 65 Prozent. Damals feierte ich das als Durchbruch — eine drastische Reduktion, die die Specs lesbarer und wartbarer machte. Und es war ein guter erster Schritt — aber nicht weit genug.
Denn die Plan-Phase enthielt immer noch vollständige Rust-Codeblöcke. Hunderte Zeilen fn, impl, match-Statements. Jeder einzelne Backend-Plan las sich wie eine halbe Implementierung. Und genau das war das Problem: Sobald sich die Architektur änderte — neue Tabellennamen, andere Datenstrukturen, konsolidierte Status-Werte — waren diese Codeblöcke sofort veraltet. Nicht ein bisschen veraltet. Komplett falsch. Weil konkreter Code konkrete Annahmen enthält, die bei jeder Architektur-Änderung brechen.
Die eigentliche Erkenntnis war radikaler als erwartet: Selbst TypeScript-Interfaces sind Implementierungscode. Sobald du eine Syntax wählst — egal ob Rust, TypeScript oder Python — bindest du die Spec an eine konkrete Technologie. Phase 2 (Specify) beschreibt WAS das System tun soll, nicht WIE es das tun soll. Und Phase 3 (Plan) beschreibt die Strategie der Implementierung, nicht den Code selbst. Code gehört ausschließlich in Phase 4.
Die Konsequenz war schmerzhaft, aber notwendig: 17 Backend-Implementierungspläne mussten zu Mapping-Tabellen migriert werden. Stück für Stück, Plan für Plan. 7.428 Zeilen Code wurden aus 33 Dateien entfernt. Am Ende blieb kein einziger Rust-Codeblock in der Plan-Phase übrig. Das fühlte sich anfangs wie ein Verlust an — all diese sorgfältig geschriebenen Codebeispiele, einfach gelöscht. Aber es war das Gegenteil: Es war eine Befreiung. Die Pläne waren danach kürzer, klarer und — das Entscheidende — resilient gegenüber Architektur-Änderungen.
Was stattdessen in den Plänen steht? Strukturierte Tabellen. Error-Handling-Strategien als Zuordnungstabellen: Welche Fehlerklasse, welche Behandlung, welches Nutzer-Feedback. Datenstrukturen als Feld-Tabellen: Name, Typ, Validierung, Quelle. Commands als Mapping: Funktion, Permission, Validierungsregel, Pattern-Referenz. Service-to-Repository-Mappings: Welcher Service nutzt welches Repository für welche Operation.
Das klingt nach weniger Information. Ist es aber nicht. Claude Code kann aus einer Mapping-Tabelle genauso zuverlässig implementieren wie aus einem vollständigen Codeblock — solange die Tabelle die richtigen Dimensionen hat: Funktion, Permission, Validierung, Pattern-Referenz. Der Unterschied: Die Mapping-Tabelle überlebt Architektur-Änderungen. Ein Rust-Codeblock nicht.
Gleichzeitig führte ich ein Kritikalitäts-System mit vier Kategorien ein. Nicht jede Spec braucht gleich detaillierte Pläne. Standard-CRUD-Operationen brauchen minimale Planung — das Pattern ist bekannt, die Implementierung vorhersagbar. Komplexe Synchronisationslogik dagegen braucht detaillierte Mapping-Tabellen mit Edge Cases und Fehlerszenarien. Vier Stufen, von "Pattern reicht" bis "vollständige Strategie-Dokumentation". Das spart Arbeit, wo Arbeit keinen Mehrwert bringt.
| Vorher | Nachher |
|---|---|
| Vollständiger Rust-Code in Plans | Mapping-Tabellen + Pattern-Referenz |
| ~400 Zeilen pro Plan-Spec | ~120 Zeilen pro Plan-Spec |
| Code und Spec vermischt | Klare Phasentrennung |
| 7.428 Zeilen Code in Plans | 0 Codeblöcke in Plans |

Warum funktioniert das? Weil ein AI-Agent keine vorgeschriebene Implementierung braucht — er braucht Constraints. "Diese Funktion benötigt Permission X, validiert nach Regel Y und nutzt Pattern Z" ist alles, was Claude Code braucht, um die Funktion zu implementieren. Der Agent kennt die Patterns (sie stehen in der Constitution), er kennt die Architektur, er kennt die Validierungsregeln. Was er nicht braucht, ist ein vorgeschriebener Codeblock, der bei der nächsten Schema-Änderung ohnehin obsolet wird.
Die Kernaussage, die ich aus dieser Phase mitgenommen habe: Specs beschreiben WAS, nicht WIE. Plans beschreiben die Strategie, nicht den Code. Code gehört in Phase 4 — und nur dorthin.
Hybrid-Validierung: Warum LLMs nicht alles prüfen können
Irgendwann im Februar gab ich Claude Code den Auftrag: "Prüfe die Konsistenz der Specs." Claude antwortete zuversichtlich, fand ein paar Probleme, meldete den Rest als sauber. Ich war zufrieden — bis ich manuell eine Datei öffnete, die Claude angeblich geprüft hatte. Dasselbe Problem, das Claude in einer anderen Datei gefunden hatte, existierte hier unbemerkt. Claude hatte Stichproben gemacht. 10 bis 20 von 121 Dateien geprüft, nicht alle.
Das ist kein Bug. Das ist ein fundamentales Verhaltensmuster von LLMs, das ich das "Exhaustive Enumeration Problem" nenne: LLMs können nicht zuverlässig ALLE Instanzen eines Problems in einer großen Datenmenge finden. Sie arbeiten probabilistisch, nicht deterministisch. Wenn du sagst "prüfe alle Dateien", prüft Claude eine repräsentative Auswahl — und ist überzeugt, alles geprüft zu haben. Das ist besonders tückisch, weil du als Nutzer keine Möglichkeit hast, das zu verifizieren, ohne selbst alle Dateien zu prüfen.
Dazu kommt ein zweites Problem: LLM-Validierung ist nicht reproduzierbar. Dieselbe Prüfung in verschiedenen Sessions liefert verschiedene Ergebnisse. Session A findet 12 Probleme, Session B findet 8 andere, Session C findet 15 — mit Überlappungen, aber nie identisch. Für ein Qualitätssicherungssystem ist das inakzeptabel.
Besonders kritisch wird das bei Template-Fehlern. Ein Fehler im Template propagiert in ALLE Specs, die auf diesem Template basieren. Wenn das Template "## Referenzen" statt "## Verweise" als Sektionsheader definiert, haben alle neuen Specs den falschen Header. Und wenn Claude nur Stichproben prüft, findet es den Fehler in drei Dateien — aber übersieht ihn in den anderen vierzig.
Meine Validierung durchlief vier Evolutionsstufen:
Stufe 1: Stichproben
Der Ausgangszustand. "Prüfe die Konsistenz" — und Claude prüft, was es für relevant hält. Das Problem: Du merkst nicht, dass Stichproben gemacht werden, weil Claude nicht sagt "Ich habe 15 von 121 Dateien geprüft". Es sagt "Die Konsistenz ist gut, hier sind die Probleme." Ich entdeckte das Problem erst, als meine manuelle Prüfung einer Datei exakt das gleiche Issue fand, das Claude in einer anderen Datei als behoben gemeldet hatte. Ab diesem Moment vertraute ich keiner LLM-Validierung mehr blind.
Stufe 2: CLAUDE.md-Regeln
Ich schrieb explizite Regeln in die CLAUDE.md: "Bei Konsistenzprüfungen ALLE Dateien prüfen, keine Stichproben." Das funktionierte — teilweise. Die Anzahl gefundener Probleme verdreifachte sich, was zunächst wie ein Rückschritt wirkte, aber eigentlich ein Qualitätsgewinn war: Die Probleme waren vorher da, jetzt wurden sie nur sichtbar. Aber: In neuen Sessions vergisst Claude den Kontext. Die Regeln werden nur teilweise angewandt. Und "alle Dateien prüfen" mit einem LLM dauert ewig und kostet Token — bei 121 Feature-Specs plus Constitution und Plans sind das hunderte Datei-Reads pro Durchlauf.
Stufe 3: Dedizierter Projekt-Skill
Ein eigener Projekt-Skill mit klarem Auftrag: Welche Dateien, welche Checks, welche Toleranzen. Strukturierter als eine CLAUDE.md-Regel, weil der Skill den vollständigen Prüfauftrag enthielt und nicht von Session-Kontext abhing. Aber immer noch LLM-basiert. Das Ergebnis war besser — konsistenter, vollständiger — aber immer noch nicht reproduzierbar. Zwei Aufrufe desselben Skills lieferten unterschiedliche Ergebnisse.
Stufe 4: Bash-Script + minimale LLM-Agenten
Die finale Lösung trennt deterministische von semantischen Prüfungen. Ein Bash-Script prüft in etwa 10 Sekunden alle 233 Dateien auf strukturelle Korrektheit: Sind die richtigen Header vorhanden? Stimmen die Sektionsreihenfolgen? Sind Referenzen gültig? Entspricht die Formatierung dem Standard? Haben alle Specs die obligatorischen Sektionen? Das Script ist deterministisch — jeder Durchlauf liefert exakt dasselbe Ergebnis. Heute um 9 Uhr, morgen um 15 Uhr, nächste Woche — identisches Ergebnis, solange sich die Dateien nicht ändern.
Nur für semantische Prüfungen — "Ist diese Beschreibung konsistent mit der Architektur?", "Passt diese Feature-Beschreibung noch zum aktuellen Datenmodell?" — kommen noch 0 bis 2 LLM-Agenten zum Einsatz. Dort, wo Reproduzierbarkeit nicht kritisch ist, weil es um Interpretation geht, nicht um Fakten. Die Trennung ist entscheidend: Struktur deterministisch, Semantik probabilistisch. Nicht umgekehrt.

| Vorher (Stufe 1) | Nachher (Stufe 4) |
|---|---|
| "Prüfe Konsistenz" | Bash-Script + 0-2 Agenten |
| Claude wählt Stichprobe | 100% der Dateien, deterministisch |
| ~42 parallele Agenten | 0-2 Agenten + Script (~10 Sek.) |
| Verschiedene Ergebnisse pro Session | Reproduzierbar |
Die Lektion: Deterministische Validierung für Struktur. LLM nur für Semantik, wo Reproduzierbarkeit nicht kritisch ist. Alles andere ist eine Illusion von Qualitätssicherung.
"Fertig" ist ein Mythos
Ein Commit behauptete "Konsistenz 10.0/10". Template-Compliance 100%. Ich erinnere mich an das Gefühl: Endlich. Alles sauber. Jetzt kann ich implementieren. Dann kamen 200 weitere Commits — weil sich die Architektur unter den Specs weiterentwickelte und alles wieder aufgerissen wurde. Nicht weil die bisherige Arbeit schlecht war, sondern weil ein lebendes Projekt sich nicht einfrieren lässt.
Schema-Änderungen waren der größte Treiber. Tabellen wurden umbenannt — payment_records wurde zu bookings, weil der neue Name die Domäne besser abbildete. Status-Werte wurden konsolidiert, weil drei verschiedene Specs drei verschiedene Status-Modelle für verwandte Entitäten hatten. Deutsche Enum-Werte wurden auf Englisch migriert: MONATLICH wurde zu RECURRING, weil die Codebase englisch ist und gemischte Sprachen in Enums zu Verwirrung führen. Jede einzelne dieser Änderungen war sinnvoll. Aber jede einzelne machte dutzende Specs inkonsistent — weil jede Spec, die auf die alte Tabelle, den alten Status oder den alten Enum verwies, aktualisiert werden musste.
Ein bestehendes Feature mit Offline-Fähigkeit war ein ähnlicher Fall. Das Feature existierte bereits in der Dokumentation, aber seine Specs entsprachen nicht dem SDD-Standard. Rust-Code in der Specify-Phase musste zu Mapping-Tabellen migriert werden. Regel-IDs mussten standardisiert werden. Kein neues Feature — aber ein vollständiger Refactoring-Durchgang für ein bestehendes.
Dann die Layer-Disziplin — ein Problem, das erst bei der Vorbereitung auf Phase 4 sichtbar wurde. Content muss in die richtige Schicht: UI-Details gehören in UI-Specs, Backend-Logik in Backend-Specs. Klingt trivial. Ist es nicht. Ich fand Backend-Validierungsregeln in UI-Specs, UI-Flows in Backend-Plänen, Datenbank-Schema-Details in Overview-Dokumenten. Jede falsche Zuordnung wird zum Problem bei der Implementierung — weil Claude Code die Spec liest und daraus die falsche Schicht ableitet.
Block-Tagging war eine Reaktion darauf. Semantische Tags für Code-Blöcke — ui, text, tree, chart — ermöglichen automatisierte Analyse. Statt jeden Block manuell zu prüfen, ob er in der richtigen Spec liegt, kann ein Script alle ui-Blöcke finden und prüfen, ob sie in einer UI-Spec stehen. Automatisierung statt manueller Kontrolle.
Sub-Feature-Renummerierung klingt nach Verwaltungsarbeit — ist es auch. Feature-IDs wie MV-002-R01 oder Dateinamen wie pt-001-wizard.md müssen stabil bleiben, wenn Specs umstrukturiert werden. Aber wenn eine Feature-Spec aufgeteilt wird, ändern sich die Nummern. Und alle Referenzen — in anderen Specs, in Plänen, in der Constitution — müssen aktualisiert werden. Bei 233 Dateien mit Cross-Referenzen ist das kein Fünf-Minuten-Job.
Und schließlich die Design-First-Migration: SDD auf sich selbst anwenden. Statt "einfach refactoren" — erst ein Design-Dokument schreiben, das die Änderung beschreibt. Dann einen Plan. Dann ausführen. Die Methodik auf die eigene Dokumentation anwenden. Das klingt nach Overhead, spart aber Zeit — weil ein durchdachtes Refactoring weniger Folgearbeit produziert als ein spontanes. Und es war eine wichtige Erkenntnis: Wenn die Methodik nicht gut genug ist, um auf sich selbst angewandt zu werden, ist sie nicht gut genug für Produktivcode.
Insgesamt sind im Projekt inzwischen 18 architekturelle Patterns dokumentiert — von CRUD-Standards bis zu komplexen Synchronisationsmustern. Jedes Pattern ist eine Referenz, die in Mapping-Tabellen verlinkt wird. Je mehr Patterns dokumentiert sind, desto weniger Detail braucht jede einzelne Spec. Aber jedes neue Pattern muss in die bestehenden Specs eingearbeitet werden. Auch das treibt Commits.
Die Kernaussage aus diesen 477 Commits: Jede Verbesserung deckt neue Inkonsistenzen auf. Das ist kein Bug, das ist der Prozess. Die Frage ist nicht "Wann bin ich fertig?" sondern "Wann bin ich bereit für den nächsten Schritt?"
Was ich gelernt habe
Specify vor Plan vor Code. Die Phasentrennung konsequent durchziehen. Kein Code in Phase 2 (Specify), kein Code in Phase 3 (Plan). Code gehört ausschließlich in Phase 4 (Implement). 7.428 entfernte Zeilen haben das bewiesen. Wer Code in Specs schreibt, baut technische Schulden auf, bevor die erste Zeile Produktivcode existiert.
Deterministische Validierung schlägt LLM-Validierung. Ein Bash-Script, das in 10 Sekunden alle 233 Dateien prüft, ist wertvoller als 42 parallele Agenten mit inkonsistenten Ergebnissen. LLMs für Semantik, Scripts für Struktur. Wer sich auf LLM-Validierung allein verlässt, hat eine Illusion von Qualitätssicherung.
Template-Qualität ist Spec-Qualität. Ein Fehler im Template multipliziert sich über alle Specs, die auf diesem Template basieren. Das macht Template-Qualität zum kritischsten Einzelfaktor im gesamten SDD-Prozess. Die beste Einzelinvestition ist ein sauberes, vollständig validiertes Template.
Architektur-Änderungen sind Spec-Änderungen. Wenn sich das Datenmodell ändert, werden die Specs inkonsistent. Das ist nicht vermeidbar — aber es muss eingeplant werden. Wer ein neues Feature einführt oder eine Tabelle umbenennt, muss die resultierende Konsistenz-Arbeit mitdenken. Die Spec-Pflege ist nicht abgeschlossen, wenn das Feature dokumentiert ist — sondern wenn alle betroffenen Specs aktualisiert sind.
"Fertig" bedeutet bereit für den nächsten Schritt. Nicht perfekt. Nicht 10/10. Sondern: Die Specs sind konsistent genug, um daraus zuverlässig zu implementieren. Das ist der Maßstab. Alles darüber ist Perfektionismus, alles darunter ist Risiko.
Fazit
651 Commits. 233 Dokumente. 121 Feature-Specs. 14 Constitution-Dokumente. 84 Pläne. 0 Zeilen Produktivcode.
Das sind die Zahlen. Die Geschichte dahinter ist die einer Methodik, die sich selbst entdeckt hat. Was 2025 als 5 DDD-Dokumente begann — ein Domain Model, Bounded Contexts, Ubiquitous Language — ist über 21 initiale Commits, 153 Commits in Teil 2 und 477 weitere Commits ein vollständiges SDD-Specify geworden. Von Domain-Driven Design zu Spec-Driven Development. Nicht geplant, sondern organisch gewachsen, über drei Phasen und Monate hinweg.
Specify ist jetzt abgeschlossen. Der nächste Schritt ist Phase 3: Plan. Aus den 121 Feature-Specs werden jetzt Implementierungspläne erstellt und verfeinert — die letzten Mapping-Tabellen komplettiert, die Kritikalitätsstufen zugeordnet, die Pattern-Referenzen finalisiert. Und erst danach, zum ersten Mal in der Geschichte dieses Projekts, Code. Der erste Commit mit Produktivcode wird ein besonderer Moment — nach 651 Commits reiner Dokumentation.
Fertig war es nie. Aber es ist bereit. Und das ist genug.
Further Reading
- Teil 1 dieser Serie: Warum die AI-Ära strukturierte Specs braucht — Die theoretischen Grundlagen von SDD
- Teil 2 dieser Serie: SDD in der Praxis: Learnings aus 153 Commits — Die praktische Umsetzung
- Claude Code Must-Haves: Claude Code Must-Haves — Januar 2026 — Mein kuratiertes Setup für produktives Arbeiten
- GitHub Spec-Kit Repository: github.com/github/spec-kit — Das Open-Source-Toolkit für SDD
- Thoughtworks SDD-Artikel: Spec-Driven Development: Unpacking 2025 New Engineering Practices — Die konzeptionellen Grundlagen
Dies ist Teil 3 der SDD-Serie. Teil 1 erklärt die theoretischen Grundlagen: Warum die AI-Ära strukturierte Specs braucht. Teil 2 zeigt die praktische Umsetzung: SDD in der Praxis: Learnings aus 153 Commits.
Dieser Artikel erschien ursprünglich auf dem Mayflower Blog.

