Academy · Kapitel 7 von 11 · ~55 Minuten

Parallel arbeiten: mehr Agenten, nicht mehr Chaos.

Ein Agent ist schnell. Drei Agenten gleichzeitig sind nicht automatisch dreimal so schnell, denn sie teilen Code, Schnittstellen und Build-Dateien. Dieses Kapitel erklärt, warum Parallelität schwer ist, welche Regeln sie beherrschbar machen und wie die Workflow-Ebene der Fabrik sie mit Child Runs, Besitzregeln, Verträgen, Merge Queue und Integration Gate umsetzt.

~55 Min Single Writer · Verträge Task-Graph → Integration Gate

Lernziele

Nach diesem Kapitel kannst du:

  • erklären, warum parallele Agenten an geteiltem Zustand scheitern und was „Single Writer“ dagegen tut.
  • ein Vorhaben als Abhängigkeitsgraph zerlegen und erkennen, welche Teile wirklich parallel laufen können.
  • begründen, warum gemeinsame Verträge vor der parallelen Implementierung stehen müssen.
  • Leases, Merge-Reihenfolge und Integrationsprüfung als Bausteine der Zusammenführung einordnen.
  • in der Fabrik einen Workflow anlegen, Schreibbereiche und Verträge erklären, die Merge Queue lesen und mit Konflikten, veralteten Tasks und Replanning umgehen.
  • Spec-Bindung je Task nutzen, damit alle parallelen Agenten gegen dieselbe Anforderungsfassung arbeiten.

7.1 Warum überhaupt parallel?

Ein einzelner Agent arbeitet sequenziell: lesen, planen, ändern, testen, nachbessern. Bei größeren Vorhaben dauert das, und vieles daran ist voneinander unabhängig. Das Backend-Modul für Rechnungen und das Frontend-Formular für Adressen berühren sich kaum. Warum sollten sie nacheinander entstehen?

Parallelität verspricht drei Dinge:

  • Durchlaufzeit: Unabhängige Teile entstehen gleichzeitig.
  • Fokus: Jeder Agent bekommt einen kleineren, klar umrissenen Auftrag und damit einen übersichtlicheren Kontext. Kleine Aufträge gelingen erfahrungsgemäß häufiger als große.
  • Spezialisierung: Analyse, Implementierung und Prüfung können unterschiedliche Agenten, Modelle oder Werkzeuge übernehmen.

Der Haken: Software ist kein Stapel unabhängiger Blätter. Teile teilen Schnittstellen, Datenmodelle, Build-Konfiguration und Datenbankmigrationen. Sobald zwei Agenten dieselbe Stelle anfassen oder sich auf unterschiedliche Annahmen über eine gemeinsame Schnittstelle stützen, entsteht Integrationsarbeit. Im schlimmsten Fall ist sie größer als der Zeitgewinn. Die Parallel-Roadmap der Fabrik nennt genau das als Hauptrisiko: Integrationskosten können den Parallelitätsgewinn übersteigen.

Faustregel: Parallelisiere nur, was wirklich unabhängig ist oder durch einen vorher festgelegten Vertrag unabhängig gemacht wurde. Alles andere läuft nacheinander.

7.2 Das Grundproblem: geteilter Zustand

Stell dir zwei Agenten vor, die im selben Arbeitsverzeichnis arbeiten. Agent A ändert eine Klasse und ist halb fertig. Agent B führt in diesem Moment die Tests aus, sieht einen Kompilierfehler in A's halbfertigem Code und „repariert“ ihn. Dann committet B mit git add -A und nimmt A's halbe Arbeit mit. Danach weiß niemand mehr, wer welche Zeile verursacht hat. Ein Review, ein Warum-Trace oder eine Attestierung würden Aussagen über einen Stand treffen, den kein einzelner Agent zu verantworten hat.

Das ist kein Randfall, sondern die zwangsläufige Folge von mehreren Schreibern auf einem gemeinsamen Zustand. Menschliche Teams lösen das, indem jede Person auf ihrer eigenen Arbeitskopie arbeitet und Änderungen über Branches und Merges zusammenführt. Für Agenten gilt dieselbe Lösung, nur konsequenter, weil Agenten sich nicht zwischendurch absprechen.

Single Writer per Workspace

Zu jedem Zeitpunkt schreibt in einem Arbeitsverzeichnis genau ein Agent. Parallelität entsteht durch mehr Arbeitsverzeichnisse, nicht durch mehr Schreiber pro Verzeichnis.

Diese Regel (in der Fabrik ADR-0015) klingt streng, vereinfacht aber alles Weitere: Jeder Stand ist einem Agenten zurechenbar, Konflikte entstehen erst zwischen abgeschlossenen Branches, und beide Seiten eines Konflikts sind in sich konsistent. Ein Merge-Konflikt zwischen zwei fertigen Branches lässt sich analysieren und als Arbeitsauftrag formulieren. Ein Konflikt mitten in einem gemeinsamen Verzeichnis nicht.

Lesende Agenten sind von der Regel nicht betroffen. Reviewer und Analyse-Agenten, die nichts schreiben, dürfen beliebig parallel auf denselben Stand schauen.

Git-Worktrees als Werkzeug

Technisch bietet Git mit Worktrees ein passendes Mittel: Mehrere Arbeitsverzeichnisse teilen sich ein Repository, jedes auf einem eigenen Branch. Das spart Platz gegenüber vollständigen Klonen, und alle Branches sind sofort im gemeinsamen Objektspeicher sichtbar, was die spätere Zusammenführung vereinfacht.

Ein Workflow-Task-Graph verteilt Aufgaben auf drei Agenten, jeder in einem eigenen Git-Worktree (API-Slice, UI-Slice, Tests); zusammengeführt wird über Merge Queue und Integration Gate. Ein Workflow-Task-Graph verteilt Aufgaben auf drei Agenten, jeder in einem eigenen Git-Worktree (API-Slice, UI-Slice, Tests); zusammengeführt wird über Merge Queue und Integration Gate.

Grafik in voller Größe öffnenGrafik in voller Größe öffnen

In der Fabrik

Die Workflow-Ebene über dem Run

Ohne Workflow-Ebene gilt in der Fabrik: ein Run je Projekt-Workspace zur gleichen Zeit (Kapitel 6). Für Parallelität gibt es darüber die Workflow-Ebene:

  • Einschalten: Feature-Flag softwarefabrik.workflow.enabled, Voreinstellung aus. Ist es aus, verhält sich die Plattform exakt wie vorher; die UI unter /workflows zeigt dann einen erklärenden Hinweis.
  • Aufbau: Ein Workflow bildet ein Vorhaben ab und zerfällt in Tasks mit Abhängigkeiten. Jeder Task läuft als eigenständiger Child Run in einem eigenen Git-Worktree unterhalb von <workspace.root>/worktrees/, höchstens drei gleichzeitig je Workflow.
  • Architektur: Die Workflow-Ebene ist ein eigener Slice mit der Richtung workflow → run, niemals umgekehrt (ADR-0014). Der bestehende Run bleibt die atomare Ausführungseinheit und weiß nicht, dass er Teil eines Workflows ist.
  • Run-Sperre je Workspace: Die Sperre vergleicht den effektiven Workspace, nicht pauschal das Projekt. Getrennte Worktrees dürfen parallel laufen, dasselbe Verzeichnis weiterhin nicht.
  • Rollen: Lesen für alle Rollen; Ändern, Starten und Umplanen ab DEVELOPER; Planfreigabe, Integration und Konfliktentscheidung ab MAINTAINER. Workflows erben den Mandanten ihres Projekts, fremde Mandanten sehen „nicht gefunden“.
  • Budget: Ein Workflow-Budget greift vor dem Start des nächsten Tasks.

Ein Workflow durchläuft fachliche Zustände wie PLANNING, WAITING_FOR_PLAN_APPROVAL, RUNNING, INTEGRATING, WAITING_FOR_APPROVAL und COMPLETED. Kein Agent startet, bevor der Plan freigegeben ist.

7.3 Zerlegen: der Abhängigkeitsgraph

Bevor irgendetwas parallel laufen kann, muss das Vorhaben zerlegt werden. Das Ergebnis ist ein gerichteter, azyklischer Graph (englisch DAG): Knoten sind Aufgaben, Kanten sagen „B kann erst beginnen, wenn A fertig ist“. Parallel laufen dürfen genau die Aufgaben, die in diesem Graphen nicht voneinander abhängen und deren Vorgänger fertig sind.

Arten von Abhängigkeiten

Nicht jede Abhängigkeit ist „erst A, dann B“. Die Parallel-Roadmap der Fabrik unterscheidet zum Beispiel:

  • Fertigstellung: B braucht das Ergebnis von A.
  • Vertrag: B braucht eine festgelegte Schnittstelle, nicht A's Implementierung.
  • Artefakt: B braucht ein bestimmtes Erzeugnis, etwa eine generierte Datei.
  • Freigabe: B darf erst nach einer menschlichen Entscheidung beginnen.
  • Exklusive Ressource: A und B fassen dieselbe Datei an, die keine zwei gleichzeitigen Änderungen verträgt.

Die Unterscheidung lohnt sich: Eine Vertragsabhängigkeit lässt sich auflösen, indem man den Vertrag zuerst festlegt. Danach können Anbieter und Nutzer der Schnittstelle gleichzeitig entstehen. Eine Fertigstellungsabhängigkeit lässt sich nicht so einfach auflösen.

Gute Zerlegung

  • Nach Schreibbereichen schneiden, nicht nach Fachbegriffen. Zwei Aufgaben, die dieselben Dateien ändern, sind nicht parallel, egal wie verschieden sie fachlich klingen.
  • Gemeinsames zuerst: Datenmodell, Schnittstellen, Migrationen und Build-Änderungen in eine frühe, eigene Aufgabe legen.
  • Klein, aber vollständig: Jede Aufgabe soll für sich bauen und testbar sein.
  • Analyse vor Umsetzung: Lesende Analyse-Aufgaben sind ideal für Parallelität, weil sie nichts schreiben. Ihre Ergebnisse fließen in die Planung der schreibenden Aufgaben.

Wie du allgemein plant und Akzeptanzkriterien je Aufgabe festlegst, behandelt Kapitel 5.

In der Fabrik

Analyse-Tasks, Synthese und Capabilities

Die Workflow-Ebene ist schrittweise entstanden; der erste Schritt (v0.21) war parallele read-only Analyse:

  • Mehrere Analyse-Läufe laufen gleichzeitig, jeder in eigenem Worktree, koordiniert über einen Task-Graphen.
  • Ein Synthese-Schritt hängt automatisch an allen Tasks, baut seinen Auftrag aus deren Ergebnissen und hält fest, welche Eingaben eingeflossen sind. Der Auftrag fordert Widersprüche ausdrücklich ein und verbietet das Glätten.
  • Der Warum-Trace eines Child Runs zeigt seinen Workflow-Kontext.

Seit v0.22 sind auch schreibende Capabilities wählbar. Die Roadmap klassifiziert Tasks nicht nach festen Rollen, sondern nach Fähigkeiten, etwa Implementierung von Domäne, API, Persistenz, Frontend oder Tests (schreibend), Anforderungs-, Architektur- oder Sicherheitsanalyse (analysierend) und Code-, Architektur- oder Sicherheitsreview (prüfend). Tasks legst du unter /workflows/{id} an, inklusive Ziel, Capability und Abhängigkeiten.

7.4 Verträge vor paralleler Implementierung

Wenn Frontend und Backend gleichzeitig entstehen, müssen beide wissen, wie die Schnittstelle zwischen ihnen aussieht. Lässt man jeden Agenten seine eigene Annahme treffen, entstehen zwei Builds, die jeweils grün sind und zusammen nicht funktionieren. Kein Test einer einzelnen Änderung zeigt auf dieses Problem, denn der Bruch liegt zwischen den Komponenten.

Daher das Prinzip Contracts before Parallel Implementation: Voneinander abhängige Komponenten dürfen erst parallel implementiert werden, wenn der gemeinsame Vertrag versioniert vorliegt. Verträge können sein:

  • API-Beschreibungen (OpenAPI für REST, AsyncAPI für Ereignisse),
  • Datenschemas (JSON-Schema, DTO-Definitionen),
  • Java- oder TypeScript-Interfaces,
  • Domänenereignisse,
  • Akzeptanzkriterien.

Drei Eigenschaften eines brauchbaren Vertrags

  1. Unveränderliche Fassungen. Eine Änderung erzeugt eine neue Fassung, die alte bleibt bestehen. Sonst verweist der Nachweis „Agent B hat gegen Fassung 3 gebaut“ auf einen Inhalt, der sich inzwischen geändert haben könnte.
  2. Inhaltsprüfsumme. Ein Hash über den Inhalt macht Fassungen eindeutig vergleichbar.
  3. Bindung zum richtigen Zeitpunkt. Welche Fassung gilt, wird festgeschrieben, wenn die Arbeit beginnt, nicht schon bei der Planung. Zwischen Planung und Start kann sich der Vertrag noch ändern.

Wenn sich der Vertrag ändert

Ändert sich ein Vertrag, während Aufgaben gegen die alte Fassung arbeiten, sind diese Aufgaben veraltet. Ihr Ergebnis darf nicht ungeprüft übernommen werden, auch wenn ihr eigener Build grün ist. Die Aufgabe muss neu bewertet werden: erneut gegen die neue Fassung ausführen oder verwerfen.

In der Fabrik

Die Contract Registry

Unter /vertraege liegt die Contract Registry (seit v0.23):

  • Unveränderliche Fassungen mit Nummer und Content-Hash (SHA-256 über den normalisierten Inhalt). Die Normalisierung ist bewusst minimal: Zeilenenden, abschließende Leerzeichen, Datei-Endzeilenumbruch. Eine Umformatierung gilt als Änderung. Ein falsches „veraltet“ kostet eine erneute Prüfung, ein übersehenes einen stillen Vertragsbruch.
  • Bindung beim Start: Ein Task erklärt im Plan nur den Namen des Vertrags, den er benutzt (Vertragsformular am Task unter /workflows/{id}). Die konkrete Fassung wird beim Start des Child Runs festgeschrieben.
  • Stale-Erkennung: Eine neue Fassung setzt jeden daran gebundenen, nicht abgeschlossenen Task auf WAITING_FOR_REPLAN, synchron in derselben Transaktion. Auch ein Task, dessen Vertrag sich während seines Laufs ändert, wird nicht auf PASSED gehoben.
  • Merge-Blockade: Vor dem Einreihen in die Merge Queue und vor dem Merge wird geprüft, ob die gebundene Fassung noch aktuell ist.
  • Auflösung durch den Menschen: erneut gegen die neue Fassung ausführen oder verwerfen. Ein Workflow mit veralteten Tasks geht nach WAITING_FOR_APPROVAL, statt still auf RUNNING stehenzubleiben.
  • Prüfung: Strukturprüfung für OpenAPI, AsyncAPI und JSON-Schema; ein nicht parsebarer Vertrag ist CRITICAL. Breaking-Change-Erkennung zwischen zwei Fassungen: entfernte Pfade, Kanäle, Operationen, Felder und Schemata sowie neue Pflichtfelder sind HIGH, rein additive Änderungen INFO. Befunde laufen als normale ReviewFindings.
  • Nicht blockierend: Eine brechende Änderung ist manchmal genau das Ziel. Das Integration Gate stuft deshalb von PASSED auf WARNING herunter, statt zu scheitern.
Bewusste Grenzen: Die Bruch-Erkennung arbeitet strukturell auf Dokumentebene; sie folgt keinen $ref-Verweisen und versteht keine Typverengungen (etwa string zu enum). Consumer-/Provider-Vertragstests sind nicht enthalten.

7.5 Besitz und Leases

Single Writer pro Verzeichnis verhindert, dass zwei Agenten sich gegenseitig die Arbeitskopie zerschießen. Es verhindert nicht, dass zwei Agenten in ihren getrennten Worktrees dieselbe Datei ändern. Das merkt man erst beim Zusammenführen, und dann ist die Arbeit schon getan. Besser ist, Überschneidungen vor dem Start zu erkennen.

Erklärter Besitz

Dafür erklärt jede schreibende Aufgabe, welche Bereiche sie ändern will (Schreibbereiche), welche sie nur liest und welche sie nicht anfassen darf. Überschneiden sich die Schreibbereiche zweier aktiver Aufgaben, startet die zweite nicht. Bestimmte Dateien sind grundsätzlich exklusiv, weil zwei gleichzeitige Änderungen dort fast sicher kollidieren: zentrale Build-Konfiguration, Datenbankmigrationen, gemeinsame API-Spezifikationen.

Leases statt ewiger Sperren

Ein Besitzanspruch braucht ein Ablaufdatum. Stürzt ein Agentenprozess ab, darf seine Sperre den Rest des Vorhabens nicht dauerhaft blockieren. Daher vergibt man Besitz als Lease: einen Anspruch mit Laufzeit, der per Herzschlag verlängert wird. Bleibt der Herzschlag aus, gilt der Anspruch als verwaist und kann freigegeben werden.

Ein verwandtes Problem tritt bei mehreren ausführenden Prozessen auf: Zwei Worker könnten gleichzeitig dieselbe Aufgabe übernehmen. Die Lösung ist ein atomarer Anspruch, bevor irgendetwas geschieht: Nur einer kann ihn gewinnen. Und wenn ein Worker ausfällt, gilt: Eine Aufgabe, die noch nicht lief, darf zurück in die Warteschlange. Eine, die schon lief, hat einen Arbeitsstand unbekannter Qualität hinterlassen und darf nicht still wiederholt werden.

In der Fabrik

Pfad-Besitzmodell, Leases und Koordinationsschicht

  • Drei Bereichsarten je Task: OWNED (Schreibbereiche), READ_ONLY (Lesebereiche), PROTECTED (Schutzzonen). Du erklärst sie am Task unter /workflows/{id}; die Seite zeigt die Schreibbereiche je Task.
  • Prüfung vor dem Start: Überschneiden sich die Bereiche mit denen eines aktiven Tasks, startet der Task gar nicht erst. Verglichen wird auf Segmentgrenzen, damit src/main und src/mainx nicht fälschlich kollidieren.
  • Immer exklusiv: u. a. Build-Konfiguration (pom.xml, build.gradle, build.gradle.kts), das Migrationsverzeichnis, openapi.yaml und docker-compose.yml, auch wenn ein Task sie nicht anmeldet.
  • Leases mit Laufzeit: softwarefabrik.workflow.lease-laufzeit-minuten (Vorgabe 120), verlängert per Herzschlag. Ein abgestürzter Agent legt den Workflow damit nicht dauerhaft lahm; sein Lease gilt als verwaist und wird beim nächsten Erwerb freigegeben.
  • Koordinationsschicht (v0.26): Worker registrieren sich mit Herzschlag und beanspruchen einen Task atomar, bevor Worktree und Child Run entstehen. Verfällt der Anspruch auf einen Task, der noch nicht lief, geht er zurück nach READY; lief er bereits, geht er nach FAILED. Der Weg zurück führt über das Replanning mit Begründung.
  • Automatischer Versand: softwarefabrik.workflow.dispatcher.enabled (Default aus) startet freigewordene Nachfolger von selbst. Automatisches Starten kostet Tokens, deshalb schaltest du es bewusst ein.
Plattenplatz: Jeder Child Run belegt einen Worktree unterhalb von <workspace.root>/worktrees/. Sie werden nach Abschluss entfernt; nach einem harten Abbruch kann git worktree prune im Projekt-Workspace nötig sein.

7.6 Zusammenführen: Reihenfolge, Konflikte, Integration

Wenn alle parallelen Aufgaben fertig sind, liegen mehrere Branches vor, die jeweils für sich gebaut und geprüft wurden. Jetzt kommt der schwierigste Teil: Sie zu einem Gesamtstand zusammenzuführen, der als Ganzes funktioniert.

Feste Reihenfolge

Man könnte Branches in der Reihenfolge zusammenführen, in der sie fertig werden. Dann hängt das Ergebnis aber an zufälligen Laufzeiten, und zwei Durchläufe desselben Plans ergeben unterschiedliche Stände. Reproduzierbar wird es erst mit einer festen Reihenfolge, etwa der Planreihenfolge, und einer sequenziellen Warteschlange (Merge Queue).

Konflikte sind nicht gleich Konflikte

Für Git sieht jeder Konflikt gleich aus: zwei Seiten, die sich an derselben Stelle widersprechen. In der Praxis verlangen sie sehr verschiedene Reaktionen:

  • Zwei Migrationen mit derselben Nummer: umnummerieren, aber sorgfältig, weil Datenbankstände daran hängen.
  • Zwei hinzugefügte Abhängigkeiten in der Build-Datei: meist mechanisch lösbar.
  • Reine Formatierungsunterschiede: harmlos.
  • Ein veralteter Branch: ein Rebase auf den aktuellen Stand kann genügen.
  • Ein echter inhaltlicher Widerspruch: Hier muss jemand entscheiden, was gelten soll.

Ein Agent, dem man nur „löse den Konflikt“ sagt, rät. Wer Konflikte klassifiziert, kann gezielt reagieren: mechanische Fälle automatisieren, inhaltliche eskalieren. Und ein Rebase ist kein Allheilmittel: Er löst Konflikte, die nur daher rühren, dass ein Branch alt ist, aber keine inhaltlichen Widersprüche.

Integration prüfen

Jede Aufgabe wurde für sich geprüft. Das beantwortet nicht, ob die Änderungen zusammen funktionieren. Deshalb braucht es nach dem Zusammenführen eine eigene Prüfung des Gesamtstands: Gesamtbuild, Integrationstests, Architekturtests über den integrierten Stand, Vertragskompatibilität. Erst wenn diese Integrationsprüfung besteht, ist das Vorhaben fertig.

In der Fabrik

Merge Queue, Integration Gate und Konfliktklassifikation

  • Merge Queue (v0.22): Erfolgreiche Child-Branches werden sequenziell und in Planreihenfolge in einen Integrationsbranch wf/<id>/integration geführt, nicht in der Reihenfolge, in der sie zufällig fertig wurden.
  • Integration Gate: Erst der zusammengeführte Gesamtstand wird geprüft. Das lokale Gate je Child Run prüft eine Änderung für sich, das Integration Gate, ob sie zusammen funktionieren. Ein Workflow erreicht COMPLETED nur über dieses Urteil. Integration löst du unter /workflows/{id} aus (ab MAINTAINER).
  • Konflikt hält an: Der Workflow wechselt nach WAITING_FOR_APPROVAL und zeigt die Konfliktdateien. Zu entscheiden ist zwischen erneut versuchen (höchstens zwei Versuche) und Branch verwerfen. Ein verworfener Branch macht das Gate FAILED, denn ein Workflow, dessen Arbeit teilweise liegen blieb, ist nicht erfolgreich.
  • Kaskaden-Abbruch: Scheitert ein Task, werden alle Tasks abgebrochen, die auch mittelbar auf ihm aufbauen, und offene Merge-Einträge verworfen.
  • Konfliktklassifikation (v0.25) in sieben Arten: MIGRATIONSNUMMER, BUILD_KONFIGURATION, SPERRDATEI, NUR_FORMATIERUNG, VERALTETER_BRANCH, INHALTLICHER_WIDERSPRUCH, UNBEKANNT. Geprüft wird von der teuersten zur harmlosesten Art. Die Analyse läuft ohne Nebenwirkung über git merge-tree --write-tree.
  • Rebase vor Merge, nicht statt Merge: Er wird nur versucht, wenn die Einordnung ihn als aussichtsreich einstuft; bei MIGRATIONSNUMMER und INHALTLICHER_WIDERSPRUCH bewusst nicht.
  • Eskalationsbericht: nennt Branch, Task, Capability, Konfliktart, Dateien, bisherige Versuche, Rebase-Ergebnis, beteiligte Vertragsfassungen und die Empfehlung. Die Einordnung wird am Queue-Eintrag festgehalten.

7.7 Umplanen mit Grund

Kein Plan überlebt die Ausführung unverändert. Eine Aufgabe erweist sich als zu groß, ein Vertrag ändert sich, ein Konflikt zeigt, dass zwei Aufgaben eigentlich eine sind. Umplanen ist also normal. Gefährlich wird es, wenn es spurlos passiert oder als Vorwand für blinde Wiederholungen dient.

Zwei Regeln helfen:

  • Jede Planänderung ist versioniert und begründet. Nicht nur „Plan Version 4“, sondern: Was hat sich geändert, warum, wer hat es ausgelöst? Die Frage, die Wochen später kommt, lautet nicht „welche Version“, sondern „warum diese“.
  • Ein Task wird nur mit neuer Eingabe neu gestartet. Das ist dieselbe Regel wie bei Korrekturschleifen in Kapitel 6. Ein anderer Zuschnitt oder eine neue Reihenfolge ordnen Arbeit um, geben dem Agenten aber nichts, was er beim letzten Versuch nicht hatte.

In der Fabrik

PlanRevision, Kennzahlen und Spec-Bindung je Task

Versionierte Planänderungen (v0.24)

  • PlanRevision hält jede Änderung unveränderlich fest: Version, Grund (Kategorie aus einer festen Liste), Pflicht-Beschreibung, Auslöser, betroffene Tasks. Attestiert als WORKFLOW_REPLANNED.
  • AP-6 hart erzwungen: Ein Task wird nur zurückgesetzt, wenn der Grund eine neue Eingabe trägt: Vertragsänderung, Merge-Konflikt, Build-Fehler, Reviewer-Befund, gescheiterter Task oder menschliche Anweisung.
  • Plan-Operationen unter /workflows/{id}: Task aufteilen (Teile erben Abhängigkeiten und Capability, nicht die Schreibbereiche), Tasks zusammenführen (der neue Task erbt die Vereinigung der Schreibbereiche), Reihenfolge ändern. Ein laufender Task lässt sich nicht umschneiden.
  • Der Warum-Trace zeigt die Planhistorie mit Gründen.

Kennzahlen (v0.27)

Unter /kennzahlen misst die Fabrik ohne eigenes Schema, abgeleitet aus vorhandenen Daten: Time to Accepted Merge, Erstdurchlauf-Quote, Korrekturschleifen, Planänderungen, Kosten je Workflow und Child Run, Merge-Konfliktquote nach Konfliktart, Freigabe-Wartezeit und Eingriffe (inklusive Planfreigabe). Was sich nicht ehrlich messen lässt, etwa menschliche aktive Arbeitszeit, wird als Lücke ausgewiesen; eine Quote ohne Nenner erscheint als Strich, nicht als 0 %.

Spec-Bindung je Task (v0.36)

Parallele Agenten müssen nicht nur gegen dieselbe Schnittstelle, sondern auch gegen dieselben Anforderungen arbeiten:

  • Ein Task deklariert Spec und AC-IDs, beim Anlegen oder nachträglich über „Spec-Bezug erklären“ (/workflows/{id}/tasks/{taskId}/spec, ab DEVELOPER, mandantengeprüft).
  • Beim Start des Child Runs wird die zu diesem Zeitpunkt freigegebene Fassung am Task gebunden (Version, Hash, AC-IDs) und als WORKFLOW_TASK_SPEC_GEBUNDEN attestiert. Alle Child Runs eines Workflows arbeiten gegen dieselbe Fassung, auch wenn die Spec zwischenzeitlich neu freigegeben wurde. Der Child Run bekommt die gebundenen Kriterien im Objective-Kopf und im ReviewRequest.
  • Im Spec-Modus STRENG lehnt die Planfreigabe ab, wenn ein schreibender Task keinen Spec-Bezug auf eine freigegebene Fassung hat.
  • Jede Spec-Freigabe spiegelt den Akzeptanzkriterien-Block als Vertrag SPEC-<nnn>-ac der Art ACCEPTANCE_CRITERIA in die Contract Registry; ein unveränderter Block erzeugt keine neue Fassung.
  • Seit v0.38.0 (SPEC-003): Die Registry vergleicht ACCEPTANCE_CRITERIA-Verträge auf AC-Ebene und meldet entfernte Kriterien als Bruch. Ändert oder entfernt eine neu freigegebene Spec-Fassung ein Kriterium, setzt die Fabrik daran gebundene, nicht abgeschlossene Workflow-Tasks auf WAITING_FOR_REPLAN (Anzeige unter „Veraltete Grundlage“) und markiert gebundene offene Backlog-Einträge als veraltet (Spec-Drift, SPEC_DRIFT in der Audit-Kette).

Mehr zu Specs, Freigabe und Spec-Modi in Kapitel 4.

7.8 Wann du nicht parallelisieren solltest

Parallelität ist ein Werkzeug, kein Ziel. Verzichte darauf, wenn:

  • die Aufgaben dieselben Dateien ändern, etwa einen zentralen Service oder ein gemeinsames Datenmodell. Die Besitzprüfung würde sie ohnehin nacheinander starten.
  • noch kein Vertrag existiert und die Schnittstelle erst beim Bauen entsteht. Lege dann zuerst eine Aufgabe „Vertrag festlegen“ an.
  • das Vorhaben klein ist. Planung, Freigabe, Integration und Prüfung kosten Zeit; für eine Änderung, die ein einzelner Run in einem Durchgang schafft, lohnt sich ein Workflow nicht.
  • die Anforderungen unklar sind. Drei Agenten, die eine vage Anforderung unterschiedlich interpretieren, erzeugen drei inkonsistente Teile. Kläre erst die Spec.
  • niemand die Integration verantwortet. Konflikte und veraltete Tasks brauchen menschliche Entscheidungen. Ohne jemanden, der sie trifft, bleibt der Workflow stehen.
Merksatz: Erst zerlegen, dann Verträge festlegen, dann Besitz erklären, dann parallel bauen, dann geordnet zusammenführen und den Gesamtstand prüfen. Jeder ausgelassene Schritt kommt als Integrationsarbeit zurück.

Übung

Übung: Ein Vorhaben in einen Workflow zerlegen

Vorhaben: „Kunden sollen Rechnungen als PDF herunterladen können. Dazu braucht es einen REST-Endpunkt, eine PDF-Erzeugung im Backend, eine neue Spalte für den Ablageort in der Datenbank und einen Download-Button im React-Frontend.“

  1. Zeichne den Abhängigkeitsgraphen mit vier bis sechs Tasks. Markiere je Kante, ob es eine Fertigstellungs-, Vertrags- oder Ressourcenabhängigkeit ist.
  2. Lege fest, welcher Vertrag zuerst existieren muss, damit Frontend und Backend parallel entstehen können, und in welchem Format (z.B. OpenAPI).
  3. Notiere je schreibendem Task OWNED-, READ_ONLY- und PROTECTED-Bereiche. Welcher Task bekommt die Migration, und warum darf sie nur einer haben?
  4. Überlege, welche Konfliktart der Fabrik-Klassifikation am wahrscheinlichsten auftritt und wie du sie vermeidest.
  5. Wenn du Zugang zu einer Instanz mit softwarefabrik.workflow.enabled=true hast: Lege den Workflow unter /workflows mit dem Mock-Adapter an, erkläre Schreibbereiche und den Vertrag, gib den Plan frei und beobachte Merge Queue und Integration Gate.
Lösungsskizze

Task 1: Vertrag festlegen (OpenAPI für GET /rechnungen/{id}/pdf), schreibt nur die Vertragsdatei. Task 2: Migration und Persistenz (besitzt das Migrationsverzeichnis exklusiv). Task 3: PDF-Erzeugung im Backend (hängt an Task 2). Task 4: REST-Endpunkt (Vertrag aus Task 1, Fertigstellung von Task 3). Task 5: Frontend-Button (nur Vertragsabhängigkeit zu Task 1, läuft parallel zu 2 bis 4; OWNED ist das Frontend-Verzeichnis, Backend ist READ_ONLY). Wahrscheinlichster Konflikt: BUILD_KONFIGURATION, wenn Task 3 und Task 5 Abhängigkeiten hinzufügen; vermeidbar, indem nötige Bibliotheken in einer frühen Aufgabe ergänzt werden. Die Migration gehört genau einem Task, weil die Fabrik das Migrationsverzeichnis ohnehin exklusiv behandelt und konkurrierende Nummern als MIGRATIONSNUMMER-Konflikt enden würden.

Kapitelfragen

  1. Was besagt das Prinzip „Single Writer per Workspace“, und welches Problem verhindert es?

    Musterantwort

    In einem Arbeitsverzeichnis schreibt zu jedem Zeitpunkt genau ein Agent; Parallelität entsteht durch mehr Arbeitsverzeichnisse. Es verhindert, dass ein Agent die halbfertige Arbeit eines anderen mitcommittet oder „repariert“, wodurch Stände niemandem mehr zurechenbar wären und Review, Warum-Trace und Attestierung ihre Aussagekraft verlören.

  2. Warum dürfen Reviewer und Analyse-Agenten beliebig parallel laufen, schreibende Tasks aber nicht?

    Musterantwort

    Lesende Agenten verändern keinen Zustand, also können sie sich nicht gegenseitig stören oder Arbeit vermischen. Schreibende Agenten erzeugen Änderungen, die zurechenbar bleiben und kontrolliert zusammengeführt werden müssen; deshalb bekommen sie eigene Worktrees und erklärte Schreibbereiche.

  3. Erkläre „Contracts before Parallel Implementation“ an einem Beispiel aus Frontend und Backend.

    Musterantwort

    Bevor Frontend-Formular und Backend-Endpunkt parallel entstehen, wird die Schnittstelle als versionierter Vertrag festgelegt, etwa als OpenAPI-Dokument. Beide Agenten arbeiten gegen dieselbe, beim Start gebundene Fassung. Ohne Vertrag träfe jeder eigene Annahmen; beide Builds wären grün, zusammen funktionierten sie nicht.

  4. Was passiert in der Fabrik, wenn ein Vertrag eine neue Fassung bekommt, während ein daran gebundener Task noch läuft?

    Musterantwort

    Die Stale-Erkennung setzt den Task auf WAITING_FOR_REPLAN. Auch wenn sein Lauf danach erfolgreich endet, wird das Ergebnis nur festgehalten, der Task aber nicht auf PASSED gehoben. Die Merge-Blockade verhindert die Integration, und der Workflow geht nach WAITING_FOR_APPROVAL. Ein Mensch entscheidet: erneut gegen die neue Fassung ausführen oder verwerfen.

  5. Warum führt die Merge Queue Branches in Planreihenfolge zusammen und nicht in der Reihenfolge, in der sie fertig werden?

    Musterantwort

    Sonst hinge das integrierte Ergebnis an zufälligen Laufzeiten, und zwei Durchläufe desselben Plans könnten unterschiedliche Stände und Konflikte erzeugen. Die feste Reihenfolge macht die Integration reproduzierbar und nachvollziehbar.

  6. Ein Agent schlägt vor, jeden Merge-Konflikt per Rebase zu lösen. Was antwortest du?

    Musterantwort

    Ein Rebase löst nur Konflikte, die daher rühren, dass ein Branch veraltet ist. Er löst keine inhaltlichen Widersprüche und verschiebt Migrationsnummer-Kollisionen nur. Deshalb klassifiziert die Fabrik Konflikte zuerst und versucht den Rebase nur, wenn die Einordnung ihn als aussichtsreich einstuft; bei MIGRATIONSNUMMER und INHALTLICHER_WIDERSPRUCH bewusst nicht.

  7. Wozu braucht man ein Integration Gate, wenn jeder Child Run bereits sein eigenes Gate bestanden hat?

    Musterantwort

    Das lokale Gate prüft eine Änderung für sich. Ob mehrere Änderungen zusammen funktionieren, zeigt erst die Prüfung des integrierten Gesamtstands. In der Fabrik erreicht ein Workflow COMPLETED nur über das Urteil des Integration Gates; ein verworfener Branch macht es FAILED, ein Vertragsbruch stuft auf WARNING herunter.

  8. Jemand möchte einen gescheiterten Task einfach „noch mal laufen lassen“. Unter welcher Bedingung erlaubt die Fabrik das, und warum?

    Musterantwort

    Nur über ein Replanning, dessen Grund eine neue Eingabe trägt, etwa Build-Fehler, Reviewer-Befund, Merge-Konflikt, Vertragsänderung oder eine menschliche Anweisung. Die Änderung wird als PlanRevision mit Beschreibung festgehalten und als WORKFLOW_REPLANNED attestiert. Grund ist AP-6: Eine Wiederholung ohne neue Information kostet Tokens, ohne die Erfolgschance gezielt zu erhöhen.

  9. Transfer: Drei Child Runs eines Workflows setzen Teile derselben Spec um. Während der zweite läuft, gibt eine Maintainerin eine neue Spec-Fassung frei. Gegen welche Fassung arbeiten die drei Runs, und warum ist das gewollt?

    Musterantwort

    Gegen die Fassung, die beim Start am Task gebunden wurde (WORKFLOW_TASK_SPEC_GEBUNDEN); alle Child Runs eines Workflows arbeiten nachweislich gegen dieselbe Fassung. Das verhindert, dass parallele Teile gegen unterschiedliche Anforderungen gebaut werden und erst bei der Integration auseinanderfallen. Die neue Fassung wird bewusst über eine neue Planung bzw. einen neuen Workflow übernommen; seit v0.38.0 setzt die Spec-Drift-Erkennung betroffene, nicht abgeschlossene Tasks auf WAITING_FOR_REPLAN.

  10. Nenne drei Situationen, in denen du auf einen Workflow verzichtest und einen einzelnen Build-Run vorziehst.

    Musterantwort

    Wenn die Teilaufgaben dieselben Dateien ändern, wenn das Vorhaben so klein ist, dass Planung und Integration mehr kosten als die Parallelität bringt, und wenn Anforderungen oder Schnittstellen noch unklar sind. Auch ohne verantwortliche Person für Integrationsentscheidungen bleibt ein Workflow stehen.