fix(b19): UNK-Noise drastisch reduzieren

BMW4 zeigte 1037 UNK-Findings — die Mail wurde damit unleserlich.
Drei pragmatische Anpassungen:

1. UNK severity: LOW → INFO. Mail-Renderer zeigt jetzt nur
   HIGH/MEDIUM/LOW; INFO bleibt im API-Payload + CSV.
2. UNK wird NICHT emittiert wenn Vendor=First-Party-Owner
   (z.B. "BMW AG" auf bmw.de). Heuristik _is_first_party_owner
   vergleicht Vendor-Name gegen Domain-SLD.
3. auto_learning threshold ≥3 Sites → ≥1 Site. Second-time-Audit
   einer Site hat ihre eigenen Cookies bereits gelernt → kein
   UNK mehr. Single-site Auto-Learning ist absichtlich
   konservativ (Annotation, kein Truth).

Effekt: erwartete Reduktion bei BMW von 1037 UNK → ~50-100
(nur unbekannte 3rd-party-Vendoren). Mail wird lesbar, MAE-
Findings (Salesforce-as-essential) bleiben prominent sichtbar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-08 08:20:39 +02:00
parent eecbd8fc69
commit 327e6a8984
3 changed files with 54 additions and 12 deletions
@@ -85,6 +85,36 @@ def _is_pseudo_purpose(purpose: str) -> bool:
return False
def _is_first_party_owner(vendor: str, state: dict) -> bool:
"""Heuristik: Vendor ist der Site-Betreiber selbst — first-party.
Vergleicht Vendor-Name (normalisiert) gegen Domain-SLD und gegen
bekannte erste-Doc-URLs im state. "BMW AG" matcht bmw.de;
"Volkswagen Group Charging" matcht elli.eco.
"""
if not vendor:
return False
vn = _norm_vendor(vendor)
if not vn:
return False
# Get domain SLDs from doc-URLs
domains: set[str] = set()
for e in (state.get("doc_entries") or []):
url = (e.get("url") or "").strip().lower()
if "://" in url:
host = url.split("://", 1)[1].split("/", 1)[0]
host = host.lstrip("www.")
parts = host.split(".")
if parts:
domains.add(parts[0])
if len(parts) >= 2:
domains.add(parts[-2])
for d in domains:
if d and len(d) >= 3 and d in vn:
return True
return False
def _norm_vendor(name: str) -> str:
s = (name or "").lower().strip()
s = re.sub(r"\binc\.?$|\bllc\.?$|\bsas\.?$|\bgmbh\.?$|"
@@ -239,12 +269,17 @@ def check_cookie_coherence(state: dict) -> list[dict]:
),
})
# FINDING 5: UNKNOWN_VENDOR
if layer == "unknown":
# FINDING 5: UNKNOWN_VENDOR — nur emittieren wenn Vendor
# *fremd* ist (3rd-party). First-Party Cookies des Site-
# Betreibers selbst (BMW AG, Volkswagen, Allianz) sind kein
# Finding — der Betreiber definiert sie selbst.
if layer == "unknown" and not _is_first_party_owner(
vendor_name, state,
):
findings.append({
"check_id": "COOKIE-COHERENCE-UNK-001",
"severity": "LOW",
"severity_reason": "unknown",
"severity": "INFO",
"severity_reason": "auto_learning",
"cookie_name": cname,
"vendor": vendor_name,
"title": (
@@ -255,8 +290,8 @@ def check_cookie_coherence(state: dict) -> list[dict]:
"evidence": (
"Keine Reference-Klassifikation verfügbar. "
"Wird in cookie_behavior_audits geloggt; bei "
"Cross-Site-Konsens (≥3 Sites) zur kuratierten "
"DB promotion."
"wiederholter Beobachtung (Cross-Site-Konsens) "
"automatisch zur DB promotion."
),
"recommended_action": (
"Manuell prüfen + ggf. zu BreakPilot-KB hinzufügen."