Implements docs/intent/board-builder-limit-reached-auto-split.md. A card that hits limit_reached twice (manual trigger + its one automatic retry) can now be dragged into a new "Aufteilen angefordert" column, which runs the Planner role read-only against the original intent plus the stored builder_report and splits it into up to 10 independent child intents (===SPLIT-REPORT===/===CHILD=== marker blocks, wrapper writes every docs/intent/<child-slug>.md itself, all-or-nothing on any malformed or oversized proposal). Children land in "Geplant" with parent_id set, no auto-trigger; the parent moves to the new terminal phase "Aufgeteilt" with child_slugs recorded. Implemented directly in this session rather than via the board's own Builder pipeline: the automated Builder run for this exact intent hit its own 20-iteration limit twice, which is the failure mode this feature exists to handle. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F51W1LEGuSvNroZNj7vXqC
7.5 KiB
7.5 KiB
Intent: Automatisches Zerlegen einer zu großen Karte über eine Board-Spalte
Ziel
Für eine Builder-Karte, die auch nach dem automatischen Einzelversuch aus
docs/intent/board-builder-limit-reached-fallback.md erneut am
Iterationslimit hängen bleibt, eine bewusste, manuell ausgelöste
Eskalationsstufe anbieten: eine eigene Board-Spalte, in die man die Karte
zieht, löst einen automatischen Zerlege-Lauf aus, der den zu großen
Intent in mehrere kleinere, unabhängige Kind-Intents aufteilt. Das
Zusammenführen der Ergebnisse am Ende ist kein neuer Mechanismus —
dafür wird der bereits entworfene, aber noch nicht gebaute
Synthese-Schritt aus docs/intent/board-subintent-fanout-synthesis.md
wiederverwendet, indem das Zerlegen genau dessen Datenmodell
(parent_id, Kind-Endzustände) von Anfang an befüllt.
Umfang
- Neue Phase
aufteilen_angefordertintrigger.pysPHASES, erreichbar nur per manuellem Drag einer Karte, derenlast_run_status == "limit_reached"und derenauto_retry_attempts >= 1ist (der automatische Einzelversuch aus dem Fallback-Intent muss bereits verbraucht sein) — verhindert, dass diese teurere Eskalationsstufe vor der billigeren automatischen Wiederholung gezogen wird. - Der Move queued einen neuen
job_type="split"-Job inboard-agents eigener Inbox (analog zu"review"/"research"). worker.pybekommtrun_split(): ruft die Planner-Rolle read-only auf (gleiches Sandbox-Muster wierun_review()— keine Schreibrechte), Kontext ist der vollständige, unveränderte Original-Intent plus der gespeichertebuilder_report-Text aus dem/den gescheiterten Builder-Versuch(en) (bereits auf der Karte vorhanden, kein Zugriff auf Git-Stashes/Diffs nötig), Auftrag: den Intent in N unabhängige, eigenständig umsetzbare Kind-Intents zerlegen.- Antwortformat: ein Marker-Block (
===SPLIT-REPORT===/===END-SPLIT-REPORT===), der pro Kind einen eigenen Unterblock mit Slug und vollständigem Intent-Dokumentinhalt liefert — der Wrapper parst das und schreibt jededocs/intent/<kind-slug>.md-Datei selbst, außerhalb des Modellprozesses (dasselbe „Rolle schlägt vor, Wrapper wendet an"-Muster wie bei Review-/Research-/Commit-Marker). - Für jedes neu geschriebene Kind: initialer State-Eintrag mit
parent_id = <Slug der Elternkarte>, Phase „Geplant" — kein automatischer Trigger, jedes Kind durchläuft den normalen manuellen „Geplant → In Umsetzung"-Weg, exakt wie inboard-subintent-fanout-synthesis.mdfür den Synthese-Intent gefordert. - Obergrenze: maximal 10 Kinder pro Zerlege-Vorschlag. Enthält der
Marker-Block mehr als 10 Unterblöcke, wird der gesamte Vorschlag
verworfen (keine einzige Kind-Datei geschrieben) und der Job endet wie
ein fehlgeschlagener Split — dieselbe Alles-oder-nichts-Validierung,
die
run_review()heute schon für die Entscheidungszeile durchsetzt, keine partielle Anwendung. - Die Elternkarte wechselt nach erfolgreichem Split in eine neue
Endphase
aufgeteilt(analog zuarchiviertbehandelt: kein Vorwärts- Move erlaubt außer der ohnehin immer erlaubten Rückwärtsbewegung), bekommtchild_slugs(Liste) zur Anzeige gesetzt. - Farbliche/visuelle Gruppierung von Eltern-/Kindkarten im Frontend ist
nicht Teil dieses Intents, sondern die bereits in
board-subintent-fanout-synthesis.mdals Folgeintent ausgeklammerte „Board-UI-Änderung (Parent-/Child-Anzeige, Baumdarstellung)".
Explizit ausgeschlossen
- Keine Änderung an der automatischen Einzel-Retry-Logik aus
board-builder-limit-reached-fallback.md— diese Eskalationsstufe setzt exakt dort auf, wo jene endet. - Keine automatische Weiterverkettung über die Kind-Erzeugung hinaus —
kein Kind wird automatisch auf „In Umsetzung" gesetzt, kein
Synthese-Intent wird von diesem Intent selbst erzeugt (das bleibt
vollständig Aufgabe von
board-subintent-fanout-synthesis.md, sobald dieses umgesetzt ist). - Keine Board-UI-Arbeit (Farbgruppierung, Baumdarstellung) — separater, bereits ausgeklammerter Folgeintent.
- Kein Zugriff des Zerlege-Laufs auf Git-Stashes/rohe Diffs vorheriger
Builder-Versuche — nur der bereits gespeicherte
builder_report-Text. - Keine Bearbeitung/Freigabe des Zerlege-Vorschlags vor dem Schreiben der Kind-Dateien — die Prüfung findet stattdessen implizit dadurch statt, dass jedes Kind zunächst in „Geplant" landet und einen normalen manuellen Trigger braucht, nicht durch einen zusätzlichen Freigabeschritt direkt nach dem Split.
- Setzt
board-subintent-fanout-synthesis.mdnicht als Voraussetzung für die Umsetzung dieses Intents selbst voraus (das Schreiben der Kind-Dateien mitparent_idfunktioniert unabhängig davon) — wohl aber für den späteren automatischen Synthese-Schritt, der ohne jenes Intent schlicht noch nicht existiert und die Kinder dann wie jede andere fertige Karte manuell zusammengeführt werden müssten.
Annahmen
- Die Planner-Rolle kann read-only aufgerufen werden, ähnlich der
Reviewer-Rolle heute (
--sandbox read-onlybzw. deaktivierte Schreibwerkzeuge je Runtime). - Ein automatisch vorgeschlagener Zerlege-Plan ist grundsätzlich weniger
durchdacht als ein von Hand erarbeiteter — dieselbe Einschränkung, die
board-subintent-fanout-synthesis.mdschon für automatisch erzeugte Synthese-Intents benennt. Das Landen in „Geplant" statt eines automatischen Triggers ist die bewusste Absicherung dagegen, keine zusätzliche Qualitätsprüfung. docs/intent/<slug>.mdbleibt die einzige Quelle der Wahrheit für den Intent-Inhalt;parent_id/child_slugsleben ausschließlich im Runtime-Overlay (state.json), nicht im Intent-Dokument selbst.
Offene Risiken
- Die Unabhängigkeit der vorgeschlagenen Kind-Intents ist nicht
automatisch geprüft (gleiche Grundannahme wie bei
board-builder-worktree-parallelism.md: Unabhängigkeit ist Planungs-, nicht Werkzeugaufgabe) — ein schlechter Zerlege-Vorschlag mit überlappenden Zielen fällt erst beim manuellen Review jedes Kindes auf, nicht vorher. - Der Zerlege-Lauf selbst könnte bei einem besonders unübersichtlichen Original-Intent an sein eigenes Iterationslimit stoßen; da das Auslösen ein einzelner, manueller Schritt ist (kein automatischer Retry für den Split-Job selbst vorgesehen), bleibt die Karte in diesem Fall einfach wie zuvor stehen — kein Rekursionsrisiko.
- Falls
board-subintent-fanout-synthesis.mdnie umgesetzt wird, bleiben automatisch erzeugte Kinder ohne automatischen Synthese-Schritt am Ende — funktional weiterhin nutzbar (jedes Kind ist eine normale Karte), nur ohne die automatische Zusammenführung.
Erfolgskriterien
- Eine Karte mit
last_run_status == "limit_reached"und bereits verbrauchtem automatischem Retry lässt sich in die neue Spalte ziehen und löst genau einen Zerlege-Lauf aus. - Der Zerlege-Lauf schreibt N (maximal 10) neue
docs/intent/<slug>.md- Dateien mit vollständigem, eigenständigem Intent-Inhalt, jede mitparent_idauf die Elternkarte instate.jsonverknüpft, Phase „Geplant". Bei mehr als 10 vorgeschlagenen Kindern wird keine einzige Datei geschrieben, der Split-Job gilt als fehlgeschlagen. - Die Elternkarte wechselt nach „aufgeteilt" und referenziert ihre Kinder; kein Kind wird automatisch angestoßen.
- Kinder verhalten sich ansonsten wie jede normale Intent-Karte (manueller „Geplant → In Umsetzung"-Trigger, eigener Builder-/Review- Durchlauf).
- Bestehende Tests (
test_board_agent.py) bleiben grün oder werden entsprechend angepasst.