fix(browser-matrix): Tracking-Signal statt Cookie-Rohzahl + Matrix-Schnellpfad

Korrektheit (§ 25 TDDDG): "Cookies vor Consent" ist KEIN Verstoss per se —
technisch notwendige Cookies inkl. des Consent-Cookies (speichert die
Ablehnung) sind nach Abs. 2 erlaubt. Verstoss ist nur nicht-essentielles
TRACKING vor Consent.
- browser_cross_finding: Befund haengt jetzt an violations.before_consent
  (Tracking), nicht an der Cookie-Rohzahl; § 25 Abs. 2-Hinweis im Detail.
  Regressionstest: Cookies-ohne-Tracking → KEIN Befund.
- multi_browser_scanner._extract_dimensions: Score nutzt Tracking-Violations
  + reject_respected-Verdikt statt Rohzahl (Fallback erhalten).
- BrowserBehaviorView: "Cookies vor Consent" nur rot/⚠ bei Tracking,
  "nach Ablehnen" neutral (Verdikt = reject-Spalte); erklaerende Zeile.

Speed: run_consent_test ueberspringt im Matrix-Modus (browser_profile gesetzt)
die teuren Phasen C/D-F/G — nur A+B noetig. Verhindert das 504 beim
Multi-Engine-Scan (BMW 4 Engines lief sonst in den 338s-Gateway-Timeout).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-13 00:10:41 +02:00
parent fa8ad030cb
commit 3f90e40807
5 changed files with 99 additions and 34 deletions
@@ -55,10 +55,26 @@ def _extract_dimensions(banner_result: dict) -> dict[str, float]:
before = phases.get("before_consent") or phases.get("before") or {}
after_reject = phases.get("after_reject") or {}
bv = (banner_result.get("banner_checks") or {}).get("violations") or []
pre_cookies = len(before.get("cookies") or [])
rej_cookies = len(after_reject.get("cookies") or [])
pre_consent = max(0.0, 1.0 - min(1.0, pre_cookies / 10.0))
reject_respect = max(0.0, 1.0 - min(1.0, rej_cookies / 5.0))
summary = banner_result.get("summary") or {}
viol = summary.get("violations") or {}
# Pre-Consent: das rechtliche Signal ist nicht-essentielles TRACKING vor
# Consent, NICHT die Cookie-Rohzahl (essentielle inkl. Consent-Cookie sind
# nach § 25 Abs. 2 erlaubt). Fallback auf Rohzahl nur ohne Summary.
if "before_consent" in viol:
pre_track = viol.get("before_consent") or 0
pre_consent = max(0.0, 1.0 - min(1.0, pre_track / 3.0))
else:
pre_cookies = len(before.get("cookies") or [])
pre_consent = max(0.0, 1.0 - min(1.0, pre_cookies / 10.0))
# Reject: bevorzugt das reject_respected-Verdikt (kein Verstoß UND kein
# neuer Tracker), sonst after_reject-Tracking, sonst Cookie-Rohzahl.
if summary.get("reject_respected") is not None:
reject_respect = 1.0 if summary.get("reject_respected") else 0.2
elif "after_reject" in viol:
reject_respect = max(0.0, 1.0 - min(1.0, (viol.get("after_reject") or 0) / 2.0))
else:
rej_cookies = len(after_reject.get("cookies") or [])
reject_respect = max(0.0, 1.0 - min(1.0, rej_cookies / 5.0))
banner_design = max(0.0, 1.0 - min(1.0, len(bv) / 5.0))
return {
"pre_consent": round(pre_consent, 3),