"""Auto-Learning für Cookies: nach jedem Audit alle deklarierten + beobachteten Cookies in compliance.cookie_behavior_audits loggen. Cross-Site-Konsens (≥3 Sites mit ähnlichem declared_purpose) macht einen unbekannten Cookie zum Promotion-Kandidaten für die kuratierte BreakPilot-KB. Diese Logik lebt im `cookie_library_lookup._load_auto_learning`. Best-Effort: jeder DB-Fehler wird geloggt aber nicht propagiert — ein Logging-Fail soll keinen Audit abbrechen. """ from __future__ import annotations import logging from urllib.parse import urlparse logger = logging.getLogger(__name__) def _site_url_from_state(state: dict) -> str: req = state.get("req") if req is None: return "" for d in getattr(req, "documents", []) or []: url = getattr(d, "url", "") or "" if url and "://" in url: p = urlparse(url) return f"{p.scheme}://{p.netloc}" return "" def log_observations(state: dict) -> dict: """Persist every (cookie, site, declared) tuple into cookie_behavior_audits. Returns stats dict for logging.""" try: from database import SessionLocal from sqlalchemy import text except Exception: return {"logged": 0, "skipped": "no_db"} check_id = state.get("check_id") or "" site_url = _site_url_from_state(state) if not site_url: return {"logged": 0, "skipped": "no_site_url"} cmp_vendors = state.get("cmp_vendors") or [] if not cmp_vendors: return {"logged": 0, "skipped": "no_cmp_vendors"} db = SessionLocal() inserted = 0 skipped = 0 try: for v in cmp_vendors: vendor_name = (v.get("name") or "").strip() for c in (v.get("cookies") or []): cname = (c.get("name") or "").strip() if not cname: skipped += 1 continue declared_cat = (c.get("category") or v.get("category") or "").strip()[:50] try: db.execute( text( "INSERT INTO compliance.cookie_behavior_audits " "(check_id, site_url, cookie_name, " "cookie_domain, declared_category, " "observed_max_age_seconds) " "VALUES (:cid, :site, :name, :dom, :cat, :age)" ), { "cid": check_id, "site": site_url, "name": cname, "dom": (v.get("domain") or v.get("name") or "")[:200], "cat": declared_cat, "age": None, }, ) inserted += 1 except Exception as e: logger.info("cookie_observations insert skipped %s: %s", cname, str(e)[:120]) skipped += 1 db.commit() except Exception as e: logger.warning("cookie_observations commit failed: %s", e) finally: db.close() return {"logged": inserted, "skipped": skipped, "site_url": site_url}