The Operator's ===OPERATOR-DECISION=== schema gains an optional "escalation" field (<=2 steps of model/reasoning_effort/iteration_limit, validated against a new per-runtime orchestration.MODEL_POOL allowlist): per-parent for direct_builder, per-child for split. On limit_reached, completion_watcher.py now walks this ladder (via the shared fanout.escalation_ladder_for()) instead of a single flat identical-params retry, escalating model/iteration_limit before falling back to today's manual repair/Aufteilen-angefordert checkpoints. A card that never went through the Operator keeps its existing flat single-retry behavior unchanged. orchestration.child_failed(), fanout.child_terminal(), and trigger.py's Aufteilen-angefordert guard all switch from the old hardcoded ">= 1" threshold to the card's actual ladder length. board.html surfaces the current attempt count on affected cards. Also includes the board-session-usage-indicator research writeup (Codex app-server JSON-RPC + Claude /api/oauth/usage as the two non-interactive usage sources) and its Operator-produced child intents, plus the operator_klaerung_noetig phase-visibility fix already staged in this checkout (distinct phase for a needs_human/crashed Operator run that never produced children, instead of reusing "durch_kinder_blockiert"). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SyeDivnWm6hgiNd3YKjK7Z
8.6 KiB
Intent: Automatische Eskalationsleiter für am Iterationslimit gescheiterte Builder-Läufe
Ziel
Heute erhält jede Builder-Karte bei limit_reached genau einen automatischen
Wiederholungsversuch mit exakt denselben Parametern (Modell, Reasoning-Effort,
Iterationslimit) wie der gescheiterte Lauf -- scheitert auch dieser, bleibt
die Karte stehen und braucht sofort eine manuelle Entscheidung (repair oder,
außer bei Operator-Kindern, Aufteilen angefordert). Live beobachtet
(10.09.2026, board-usage-endpoint-claude): ein Lauf, der seine gesamte
Iterationslimit-Budget mit Planung statt Codeänderungen verbraucht, scheitert
bei identischer Wiederholung mit hoher Wahrscheinlichkeit erneut auf
dieselbe Weise, weil sich an den Bedingungen nichts geändert hat.
Dieser Intent ersetzt den einen flachen Wiederholungsversuch durch eine kurze, vom Operator vorab festgelegte Eskalationsleiter: bis zu zwei weitere automatische Versuche mit höherem Iterationslimit und/oder einem anderen Modell, bevor die Karte wie heute in eine manuelle Klärung fällt. Die Eskalation ist vollständig deterministisch und wrapper-gesteuert -- kein Modell entscheidet zur Laufzeit selbst über eine größere Ausstattung, das Muster folgt damit demselben Vertrauensgrenzen-Prinzip wie der Rest dieses Systems (Operator schlägt vor, Wrapper validiert und führt aus).
Umfang
Schema-Erweiterung der Operator-Entscheidung
- Neues optionales Feld
escalationin===OPERATOR-DECISION===: eine Liste von höchstens zwei zusätzlichen Versuchsprofilen, je{model, reasoning_effort, iteration_limit}.- Bei
direct_builder:escalationgehört zur Parent-Karte selbst. - Bei
split:escalationist auf Parent-Ebene zwingend leer; jedes Kind trägt stattdessen sein eigenesescalation. - Bei
needs_human:escalationist zwingend leer. - Fehlt das Feld in einer Antwort ganz (ältere/kompatible Operator-Läufe),
wird es vor der Schema-Prüfung auf
[]defaultet -- eine Antwort ohneescalationbleibt also weiterhin gültig und erhält schlicht keine Leiter.
- Bei
- Jede Eskalationsstufe validiert serverseitig gegen
orchestration.MODEL_POOL(neue, pro Runtime gepflegte Modell-Allowlist, von Hand synchron gehalten mitboard.htmls bestehenderMODEL_OPTIONS-Dropdown-Liste): das Modell muss ein konkreter, gelisteter Wert für dieselbe Runtime sein wie der erste Versuch, nienull/leer und nie frei erfunden.iteration_limitbleibt innerhalb der bestehenden Grenzen (5 bis 40). Runtime und Lane ändern sich über die gesamte Leiter nie -- nur Modell, Reasoning-Effort und Iterationslimit dürfen je Stufe variieren (die beiden Builder-Lanes haben heute ohnehin dieselben Modellfähigkeiten, nur getrennte Warteschlangen; eine dritte Profil-Ebene ist daher nicht nötig). agents/operator.mdund der inworker.pysOPERATOR_PROMPT_TEMPLATEinjizierte Startauftrag benennen die erlaubten Eskalationsmodelle je Runtime explizit, damit der Operator ausschließlich daraus wählt.
Speicherung und deterministische Ausführung
orchestration.apply_direct()undorchestration._apply_split_unlocked()schreiben die validierte Leiter alsescalation_attemptsauf die jeweilige Karte (Parent beidirect_builder, jedes Kind beisplit).orchestration.escalation_ladder_for(card): liefertescalation_attempts, falls vorhanden, sonst einen synthetischen Ein-Schritt-Fallback, der exakt die aktuellen Werte der Karte wiederholt -- identisch mit dem heutigen flachen Verhalten für jede Karte, die nie durch den Operator gelaufen ist (z. B. eine manuell direkt von Geplant nach In Umsetzung gezogene Karte).completion_watcher.pysprocess_record(): beistatus == "limit_reached"wird nicht mehr starrauto_retry_attempts < 1geprüft, sondern gegenlen(escalation_ladder_for(card)). Ist noch eine Stufe offen, queued der Wrapper den nächsten Builder-Lauf mit genau den Werten dieser Stufe (nicht mit den alten Werten) und erhöhtauto_retry_attemptsum eins. Ist die Leiter erschöpft, verhält sich die Karte exakt wie heute (keine weitere automatische Aktion, sichtbar für einen Menschen).orchestration.child_failed()undtrigger.pys Eignungsprüfung fürAufteilen angefordertverwenden dieselbe dynamische Leiterlänge statt des bisherigen festen Schwellenwerts>= 1-- ein Operator-Kind zählt für den Parent-Scheduler (durch_kinder_blockiert) erst nach vollständig ausgeschöpfter eigener Leiter als gescheitert, nicht schon nach dem ersten Fehlschlag.
Sichtbarkeit
board.htmlzeigt beiauto_retry_attempts > 0eine kompakte Zeile „Versuch X von Y (Modell, Z Iterationen)" auf der Karte, damit sichtbar ist, dass gerade eskaliert wird, statt dass die Karte scheinbar hängt.
Explizit ausgeschlossen
- Kein Modellwechsel über die Runtime/Lane hinweg (kein Sprung von
leichtnachschweroder umgekehrt innerhalb einer Leiter). - Keine dritte, eigene Eskalations-Profil-Konfigurationsebene zusätzlich zu den bestehenden Lane-Spalten -- die Modell-Allowlist ist pro Runtime, nicht pro Lane.
- Keine Eskalation für
repair-/Fixer-Läufe oder für Recherche-Läufe -- ausschließlich Builder-Läufe (in_umsetzung/in_umsetzung_leicht) mitstatus == "limit_reached". - Kein rekursives Splitten und keine sonstige Änderung an den bestehenden
Operator-Kind-Beschränkungen (
board-intent-operator-orchestration.mdbleibt in Kraft). - Keine unbegrenzte oder vom Modell selbst gesteuerte Eskalation -- maximal zwei zusätzliche, vorab vom Operator festgelegte Stufen, ausschließlich vom Wrapper ausgeführt.
- Keine Änderung am bestehenden
repair-Pfad (weiterhin manuell auslösbar, unabhängig vom Leiterstatus, siehetrigger.pysgenuine_failure-Prüfung) oder anAufteilen angefordertfür Nicht-Operator-Karten.
Annahmen
- Die beiden Builder-Lanes (
schwer/leicht) haben heute identische Modellfähigkeiten und unterscheiden sich nur durch separate Warteschlangen/Instanzen (board-builder-weighted-lanes.md) -- deshalb genügt eine Modell-Allowlist pro Runtime statt pro Lane. - Eine Karte, die nie durch den Operator gelaufen ist, soll ihr heutiges Verhalten (ein flacher automatischer Wiederholungsversuch mit identischen Parametern) unverändert behalten, nicht regressieren auf null automatische Versuche.
docs/intent/board-builder-limit-reached-fallback.md(der ursprüngliche einzelne automatische Retry) bleibt als Sonderfall der hier verallgemeinerten Leiter (Leiterlänge 1) inhaltlich gültig, wird aber durch die dynamische Leiterlängen-Logik hier faktisch ersetzt.
Offene Risiken
- Eine vom Operator schlecht gewählte Eskalationsstufe (z. B. ein Modell,
das dieselbe Art Fehler macht) verschwendet bis zu zwei zusätzliche volle
Builder-Läufe, bevor ein Mensch eingreift -- der bestehende
repair-Pfad bleibt jederzeit als sofortiger manueller Ausweg nutzbar, unabhängig vom Leiterstatus. - Mehr automatische Versuche bedeuten mehr Rechenzeit/Kosten pro hartnäckig scheiternder Karte, bevor überhaupt ein Mensch involviert wird -- begrenzt auf maximal zwei zusätzliche Stufen, nicht unbegrenzt.
- Die Modell-Allowlist (
orchestration.MODEL_POOL) undboard.htmlsMODEL_OPTIONSwerden von Hand synchron gehalten, kein gemeinsamer Quellort -- ein vergessenes Nachziehen einer Seite kann zu einer Diskrepanz zwischen der Dropdown-Anzeige und tatsächlich erlaubten Eskalationsmodellen führen.
Erfolgskriterien
- Eine gültige Operator-Antwort mit
escalation-Einträgen wird akzeptiert und auf der/den betroffenen Karte(n) alsescalation_attemptsgespeichert; eine Antwort ohne dieses Feld bleibt weiterhin gültig. - Ein ungültiger Eskalationsschritt (unbekanntes Modell, mehr als zwei Stufen, Iterationslimit außerhalb 5-40, Runtime-/Lane-Wechsel) macht die gesamte Operator-Antwort ungültig, ohne Teilzustand zu erzeugen.
- Ein
limit_reached-Lauf auf einer Karte mit offener Leiterstufe löst automatisch einen neuen Builder-Lauf mit genau den Werten dieser Stufe aus und erhöhtauto_retry_attempts. - Eine Karte ohne Operator-Leiter verhält sich bei
limit_reachedunverändert wie heute (ein automatischer Wiederholungsversuch mit identischen Parametern). - Ein Operator-Kind zählt für den Parent-Scheduler erst nach vollständig ausgeschöpfter eigener Leiter als gescheitert.
Aufteilen angefordertbleibt für Nicht-Operator-Karten erst nach ausgeschöpfter Leiter erlaubt, für Operator-Kinder weiterhin vollständig gesperrt.- Das Board zeigt bei laufender Eskalation sichtbar den aktuellen Versuchsstand.