- ENHANCE_PROMPT_ADHOC und ENHANCE_PROMPT_RESEARCH: Umschreibungen durch
echte Umlaute ersetzt (fuer -> fuer, praezises -> praezises, ...). Behebt
den Widerspruch, dass der Prompt "echte Umlaute verwenden" forderte,
die Anweisung selbst aber ae/oe/ue/ss nutzte.
- call_claude() bekommt neuen timeout-Parameter. None = Fallback auf
CLAUDE_TIMEOUT (1800s), sonst Override in Sekunden. asyncio.wait_for
und die cancel-aware Variante nutzen durchgaengig den effective_timeout.
- Enhance-Endpoint ruft call_claude mit timeout=60 auf (Haiku-Single-Shot,
vorher global 1800s).
- chat.py _call_claude_chat: Timeout von 60s auf 120s erhoeht (Chat-Antworten
koennen etwas laenger dauern, haben aber keinen Anspruch auf 30 Min).
- Neue Exception-Klasse ClaudeCliError(error_type, message) in claude_client.py
mit Kategorien rate_limit / auth_error / timeout / cli_error.
- _classify_cli_error() als geteilter Klassifikator (Keywords fuer Rate-Limit
und Auth-Fehler wie "does not have access", "login again").
- call_claude() erkennt jetzt auch is_error=true im JSON bei returncode=0
(Hauptursache des Ausfalls vom 22.04.: CLI liefert "Your organization
does not have access" mit is_error=true statt Exit-Code).
- Orchestrator: ClaudeCliError mit rate_limit/timeout als transient behandelt
(3 Retries mit Backoff 0s/120s/300s). auth_error/cli_error brechen sofort
ab ohne Retry. Behebt den bestehenden Bug, dass Rate-Limit-Fehler gar nicht
retried wurden.
- routers/incidents.py Enhance-Endpoint: ClaudeCliError wird auf
503 (auth_error) / 429 (rate_limit) gemappt, TimeoutError auf 504.
- routers/chat.py _call_claude_chat(): wirft jetzt ClaudeCliError statt
generischem RuntimeError. Chat-Endpoint mappt auth_error auf 503.
- Frontend: neue ApiError-Klasse in api.js mit status+detail.
generateDescription() in app.js zeigt differenzierte Toasts nach
HTTP-Status (503/429/504/403).
- dashboard.html: Cache-Bust api.js + app.js auf v=20260423a
- Neuer Helper charge_usage_to_tenant() in services/license_service.py:
UPSERT in token_usage_monthly und Credits-Abzug aus licenses.credits_used.
Wiederverwendbar fuer alle Claude-Call-Verursacher.
- Orchestrator: Inline-Buchungslogik (35 Zeilen) durch Helper-Aufruf ersetzt.
- routers/incidents.py POST /enhance-description: require_writable_license
statt get_current_user, db_dependency hinzugefuegt, Credits-Buchung mit
source="enhance" nach jedem Claude-Call.
- routers/chat.py POST /: analog require_writable_license + Credits-Buchung
mit source="chat". _call_claude_chat() gibt jetzt zusaetzlich ClaudeUsage
zurueck.
Abgelaufene/gesperrte Lizenzen koennen damit keine Haiku-Calls mehr ausloesen,
und alle Kosten werden konsistent auf Tenant-Ebene verbucht.
Invalid group reference \2 in re.sub entfernt (non-capturing group
hatte keine \2). Tags werden jetzt durch [tag] ersetzt.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>