Behebt das Symptom, dass Recherche-Lagen wie staging Lage 6 "Friedrich Merz"
trotz erfolgreichem Refresh leer blieben. Claude lieferte nicht-leere Antworten
(1226-2125 Zeichen), die der bisherige Regex-Parser nicht extrahieren konnte —
die Recherche meldete "0 Artikel" und der Refresh wurde stumm als Erfolg
verbucht.
Aenderungen:
- _parse_response, select_relevant_feeds, extract_dynamic_keywords und
select_relevant_telegram_channels nutzen jetzt json.JSONDecoder.raw_decode
ueber Modul-Helper _extract_json_array/_extract_json_object. Damit werden
auch JSON-Bloecke mit Vor-/Nachtext, Markdown-Fences oder verschachtelten
Objekten zuverlaessig erkannt.
- Bei Parse-Fehlschlag wird jetzt ein gekuerztes Sample der Claude-Antwort
geloggt, damit kuenftige Faelle direkt debuggbar sind.
- Neue ResearcherParseError-Exception unterscheidet "echt 0 Treffer" von
"Antwort kaputt". search() gibt zusaetzlich ein parse_failed-Flag zurueck.
- Orchestrator-Multi-Pass: wenn alle 3 research-Durchlaeufe 0 neue Artikel
ergeben UND mindestens einer am Parser scheiterte, wird der Refresh als
Fehler markiert (statt als stiller Erfolg). Der WebSocket-refresh_error
loest dann die sichtbare UI-Meldung aus.
Adhoc-Lagen sind unveraendert: dort fangen RSS und Telegram die kaputte
Claude-Antwort auf, dafuer ist nur die Diagnose im Log neu.