Ein echter Durchlauf auf bredelar.info deckte zwei Bugs auf, die mit
gemockten Tests unsichtbar waren:
1. Hang: attempt_timeout wurde nur als requests-Inaktivitäts-Timeout
übergeben. Ein Free-Modell, das die Verbindung offen hält oder Tokens
langsam tröpfeln lässt, umging ihn → der ganze Scan hing unbegrenzt
(real auf einem Bild >5 min). Fix: _post_with_deadline führt den Call
in einem Worker-Thread mit future.result(timeout=...) aus — hartes
Wanduhr-Limit, bei Überschreitung Eskalation statt Hang.
2. Verlust bei Abbruch: Das Ledger wurde nur ganz am Ende gespeichert,
ein Hang/Crash verwarf alle berechneten Verdikte. Fix: Zwischensicherung
nach der Textphase + im finally — Verdikte überleben einen Abbruch.
Zusätzlich attempt_timeout 30 → 20 s (flottere Eskalation).
Im erneuten Lauf griff der Deadline 4× sauber, der Scan lief vollständig
durch (Gelb: ein off_topic_commercial-Fund auf einer Gewerbe-Seite).
Tests: 239 grün (+2: Deadline kappt Hang <2s, Textverdikte überleben
Bildphasen-Crash).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bisher war das KI-Level hart auf Gelb gedeckelt — auch injizierte
Pornografie oder strafbare/diffamierende Inhalte lösten nie Rot aus.
Das unterschätzt echte Notfälle (Sicherheits- + Rechts-/Reputationsrisiko).
Neu: kategoriebasierter Grave-Override in score_ai_findings. Nur Kategorien
aus red_categories (default ["pornography","defamation_illegal"]) lösen Rot
aus, und nur bei Schwere ≥ red_min_severity (high) UND Konfidenz ≥
red_min_confidence (0.9). Alle anderen Kategorien (Spam, Off-Topic,
Propaganda, Widerspruch) bleiben höchstens Gelb. Die Punktsumme allein
ergibt weiterhin nie Rot. red_categories: [] stellt das alte Verhalten her.
Begründung für die konservative Schwelle: LLM-Konfidenzen sind nicht
perfekt kalibriert — nur die gravierendsten Fälle dürfen die volle
ROT-Dringlichkeit ("Dienstleister informieren, nichts freigeben") tragen.
Rot fließt über die bestehende _worst_level-Verdrahtung automatisch ins
Gesamt-Level + Exit-Code 2; gilt auch für Bildfunde (OCR).
Tests: 237 grün (+7 Rot-Gate, bestehender Cap-Test auf Punktsumme-Logik
umgestellt). Config + Template + README + Bedienungsanleitung aktualisiert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bisher: Konnte die KI kein Verdikt liefern (alle Modellstufen scheitern),
ging der Inhalt still als grün durch — für ein Sicherheitswerkzeug ein
Falsch-Negativ-Risiko ("konnte nicht prüfen" ≠ "sauber").
Zwei Maßnahmen:
1. Retry: _classify wiederholt die ganze Modell-Kette bei Komplettausfall
bis max_retries (Default 1) mit Backoff — fängt transiente Aussetzer ab.
2. Tracking: nicht prüfbare Inhalte landen in ai_result["unchecked"] (statt
stillem skip) und werden sichtbar in Terminal, Report (Markdown), diff-only
und E-Mail — jeweils mit URL. score_ai_findings nimmt sie als Grund auf;
mit unchecked_level="yellow" heben sie das Level auf mindestens Gelb an
(Default "warn" = nur Hinweis, Ampel unberührt).
Config: max_retries, retry_backoff_seconds, unchecked_level (ai_analysis).
Tests: 230 grün (+ Retry-Recovery, unchecked-Tracking, unchecked_level).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reads robots.txt Sitemap directive and fetches sitemap.xml / sitemap_index.xml
before crawling. All listed URLs are added to the crawl queue so pages
without any inbound links are still scanned. Configurable via crawl.sitemap.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the placeholder domain example.com with meine-seite.de
throughout the template directory and config. Tests and scanner defaults
retain example.com as a generic RFC 2606 placeholder.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>