fix: Report und Alarm-Mail konsistent (gemeinsamer Renderer)

Behebt vier vom Nutzer gemeldete Inkonsistenzen zwischen Report und E-Mail:

1. E-Mail ⊊ Report: Es gab zwei divergierende Renderer (alerter._format_body
   und __main__._render_markdown). Jetzt EIN gemeinsamer Renderer
   (scanner/report.py:render_markdown), den beide nutzen → identischer Inhalt,
   keine Divergenz mehr möglich.

2. KI im Report unsichtbar: Der Report rief klartext_befunde OHNE ai_result auf
   (KI-Satz fehlte im "Was bedeutet das?") und die Zusammenfassungs-Tabelle
   hatte keine KI-Zeile. Jetzt: KI-Satz im Klartext + Zeilen "KI-Funde" und
   "KI nicht geprüft" in der Tabelle.

3. Fehlende URL in Kommandos: approve/report/ai-dismiss standen ohne Target da
   (nicht ausführbar). Neuer Helfer plain.scanner_cmd(target, rest) injiziert
   das Target überall → "python -m scanner https://site approve --all".

4. "Level: YELLOW" aber "Score: 0": Der angezeigte Score war nur der Inhalts-
   Diff-Score; KI-/Cloak-/Asset-Scores flossen ins Level, aber nicht in den
   Score. cmd_scan/cmd_check aggregieren jetzt alle Teil-Scores → Score und
   Level passen zusammen.

Tests: 254 grün (+4: Body==Report, Kommandos-mit-Target, Score-Anzeige,
Level-Badge). alerter._format_body delegiert nur noch an render_markdown.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-13 03:35:05 +02:00
commit 3ab313e733
5 changed files with 327 additions and 398 deletions

View file

@ -20,6 +20,12 @@ def ampel(level: str) -> tuple[str, str]:
return _AMPEL.get(level, ("", "Status unbekannt."))
def scanner_cmd(target: str, rest: str) -> str:
"""Baut ein direkt ausführbares Kommando mit Target, z. B.
'python -m scanner https://meine-seite.de approve --all'."""
return f"python -m scanner {target} {rest}".strip() if target else f"python -m scanner {rest}"
def ampel_zeile(level: str) -> str:
"""Einzeilige Ampel-Darstellung, z. B. '🟡 Bitte einmal nachschauen.'"""
symbol, satz = ampel(level)
@ -205,7 +211,7 @@ def klartext_befunde(
return saetze
def was_tun(level: str) -> list[str]:
def was_tun(level: str, target: str = "") -> list[str]:
"""Konkrete, laienverständliche Handlungsempfehlung je Level."""
if level == "red":
return [
@ -217,6 +223,6 @@ def was_tun(level: str) -> list[str]:
return [
"Schauen Sie sich die unten genannten Punkte einmal an.",
"Wenn die Änderung von Ihnen oder Ihrem Dienstleister gewollt war, ist alles in Ordnung.",
"Gewollte Änderungen bestätigen Sie mit: python -m scanner approve --all",
"Gewollte Änderungen bestätigen Sie mit: " + scanner_cmd(target, "approve --all"),
]
return ["Sie müssen nichts tun."]