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
84 lines
3.3 KiB
Markdown
84 lines
3.3 KiB
Markdown
# Intent: Board-Usage-Endpunkt mit Claude-Nutzungsquelle
|
|
|
|
## Ziel
|
|
|
|
Einen neuen, ausschließlich lesenden HTTP-Endpunkt `GET /api/board/usage`
|
|
in `hosts/blunix/localServices/board-agent/trigger.py` einführen, der die
|
|
verbleibenden bzw. verbrauchten Nutzungsanteile der geteilten interaktiven
|
|
`drone`-Identität als Prozentwerte zurückgibt. In diesem Schritt wird nur
|
|
die Claude-Seite tatsächlich befüllt; die Codex-Seite wird bereits im
|
|
Antwortvertrag vorgesehen, aber vorerst als Leerdarstellung (`null`)
|
|
ausgeliefert.
|
|
|
|
## Umfang
|
|
|
|
- Neue Route `GET /api/board/usage` in `do_GET` von `trigger.py`, im Stil
|
|
der vorhandenen `/api/board/...`-Routen und mit `_send_json`.
|
|
- Antwortvertrag (verbindlich, spätere Karten bauen darauf auf):
|
|
|
|
```json
|
|
{
|
|
"claude": {
|
|
"five_hour_used_percent": 42.0,
|
|
"seven_day_used_percent": 7.5,
|
|
"five_hour_resets_at": "2026-09-10T18:00:00Z",
|
|
"seven_day_resets_at": "2026-09-14T00:00:00Z"
|
|
},
|
|
"codex": {
|
|
"five_hour_used_percent": null,
|
|
"seven_day_used_percent": null,
|
|
"five_hour_resets_at": null,
|
|
"seven_day_resets_at": null
|
|
}
|
|
}
|
|
```
|
|
|
|
Alle Werte sind *verbrauchte* Prozent (`used_percent`); die Umrechnung
|
|
auf "übrig" macht das Frontend.
|
|
- Claude-Seite: OAuth-Access-Token aus `~/.claude/.credentials.json`
|
|
lesen und `GET https://api.anthropic.com/api/oauth/usage` mit den
|
|
Headern `Authorization: Bearer <token>` und
|
|
`anthropic-beta: oauth-2025-04-20` aufrufen. Aus dem JSON-Body
|
|
`five_hour.utilization`, `seven_day.utilization` und die jeweiligen
|
|
`resets_at` übernehmen.
|
|
- Kurzes Timeout (wenige Sekunden) und vollständige Fehlerisolierung:
|
|
jeder Fehler (Datei fehlt, JSON kaputt, Netzfehler, Nicht-200,
|
|
unerwartete Struktur) führt zu `null`-Werten für Claude, nicht zu einem
|
|
Fehlschlag des gesamten Endpunkts.
|
|
- Niemals Tokens, Rohantworten, Dollar- oder Limit-Felder an den Client
|
|
durchreichen; nur die oben genannten Schlüssel.
|
|
- Tests in `test_board_agent.py` (Erfolgsfall, Fehlerfälle, kein
|
|
Token-Leck) im Stil der bestehenden Endpunkt-Tests.
|
|
- Kurze Ergänzung der Endpunkt-Übersicht in `README.md`.
|
|
|
|
## Explizit ausgeschlossen
|
|
|
|
- Keine Codex-Anbindung (eigene Folgekarte) und keine Änderung an
|
|
`board-agent.nix`.
|
|
- Keine UI-Änderung in `board.html` (eigene Folgekarte).
|
|
- Kein Verlauf/Graph, keine Alarmierung, keine Aufschlüsselung pro Rolle.
|
|
- Keine Änderung an Board-Spalten oder Trigger-Logik; rein additiv.
|
|
|
|
## Annahmen
|
|
|
|
- `board-agent-trigger.service` hat bereits ausgehenden Netzwerkzugriff
|
|
und `ProtectHome = "read-only"` reicht für das reine Lesen von
|
|
`~/.claude/.credentials.json`; es ist keine Sandbox-Anpassung nötig.
|
|
- Der Endpunkt braucht keine Authentifizierung, weil das Board selbst
|
|
bereits nur lokal erreichbar ist wie die übrigen `/api/board/`-Routen.
|
|
|
|
## Offene Risiken
|
|
|
|
- `/api/oauth/usage` ist ein undokumentierter, privater Endpunkt und kann
|
|
sich ändern; deshalb ist die Fehlerisolierung (Leerdarstellung statt
|
|
Ausnahme) verpflichtend und nicht optional.
|
|
- Die Feldnamen der Upstream-Antwort können abweichen; der Code muss
|
|
fehlende Felder tolerieren.
|
|
|
|
## Erfolgskriterien
|
|
|
|
- `GET /api/board/usage` antwortet mit 200 und dem oben festgelegten
|
|
Objekt; die Codex-Felder sind `null`.
|
|
- Tests belegen Erfolgsfall, Fehlerfälle und dass keine Secrets im
|
|
Antwortkörper landen.
|
|
- Der bestehende Testlauf bleibt grün.
|