Commit Graph

1353 Commits

Author SHA1 Message Date
Benjamin Admin 881e9c28de feat(consent-tester): /scan-matrix echt — Profil je Engine + Per-Engine-Summary (Phase 1.2)
- _scanner_run reicht browser_profile an run_consent_test durch (statt Single-Chromium-Shim)
- neue scan_matrix_summary.matrix_scan_dict: ConsentTestResult -> schlanke
  Matrix-dict-Form (phases fuer _extract_dimensions + kompakter `summary`:
  cookies_before_consent/after_reject, reject_respected-Heuristik [keine
  Verstoesse UND kein neuer Tracker], surface, screenshot)
- multi_browser_scanner._run_one hebt summary + engine + is_mobile an die
  Zeile, verwirft die vollen Cookie-Listen (JSONB-Persistenz schlank)
- consent_scanner: _ctx_base mit Mobile-Device-Emulation (iPhone-Profil ->
  echtes Mobile-Viewport/Touch), alle 5 new_context auf **_ctx_base
- Tests: test_scan_matrix_summary (6) inkl. _extract_dimensions-Vertrag

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 22:46:42 +02:00
Benjamin Admin c816827720 feat(consent-tester): browser_profile-Param — echte Engine-Wahl im Scan (Phase 1.1)
run_consent_test nimmt jetzt browser_profile (browser_profiles.py): Firefox/Gecko,
WebKit/Safari oder Blink (Chromium-Default / Chrome-/Edge-Channel / Brave via
executable_path). Rückwärtskompatibel: None → Chromium wie bisher. Fundament für
die echte /scan-matrix (Stage-1.b-Shim), die als nächstes Profile durchreicht.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 22:21:20 +02:00
Benjamin Admin 11740bd2f9 feat(consent-tester): 4 weitere Edge-Cases — Consent-or-Pay, Consent Mode, CNAME-Cloaking, Returning-User
#4 Consent-or-Pay (EDPB Opinion 08/2024): Banner-Text-Signatur (Pur-Abo/
   "zustimmen oder bezahlen" + Consent-Kontext) → MEDIUM-Befund "rechtlich
   umstritten, gesondert prüfen".
#5 Google Consent Mode v2: page.evaluate (dataLayer-consent-Events / inline
   gtag('consent')) → MEDIUM "ist KEINE gültige Einwilligung".
#6 CNAME-Cloaking: First-Party-Subdomains per socket.gethostbyname_ex auflösen,
   CNAME-Kette gegen bekannte Tracker-Infra (Eulerian/Adobe/Webtrekk/…) → HIGH
   "faktisch Drittanbieter trotz First-Party-Optik". Best-effort, kurze Timeouts.
#7 Returning-User: Scanner nutzt by-design frische Browser-Contexts → Hinweis im
   Kein-Banner-Befund (fehlendes Banner liegt nicht an erinnertem Consent).

Tests + py_compile grün.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 20:45:20 +02:00
Benjamin Admin 2b928dcb33 fix(consent-tester): Edge-Case-Befunde auch im no-banner-Frühreturn
#1/#2 (kein-Banner-affirmativ) feuerte nicht, weil der no-banner-Pfad bei
Zeile 220 früh zurückkehrt — vor dem Edge-Case-Block am Funktionsende.
Logik in _apply_edge_case_findings extrahiert und an BEIDEN Return-Pfaden
aufgerufen (Früh-Return + Ende). Damit greift #1 jetzt auf statischen Seiten.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 19:55:42 +02:00
Benjamin Admin c2422138e6 feat(consent-tester): 3 Edge-Cases — kein-Banner-konform, Geo-Caveat, Non-Cookie-Tracking
#1/#2: Wenn KEIN Banner erkannt UND kein Tracking vor Consent (statische Seite
oder nur technisch notwendige Cookies, §25 Abs.2 TDDDG) → affirmativer LOW-Befund
"konform, kein Banner nötig" statt stillem "Banner fehlt". Inkl. Geo-Caveat
(Scan außerhalb EU sieht geo-getargetete Banner evtl. nicht).

#3: detect_non_cookie_tracking erkennt Pixel/Fingerprinting per Domain-Signatur
(Meta, TikTok, LinkedIn, Pinterest, Clarity, FingerprintJS, Hotjar, Reddit,
Snapchat) → MEDIUM-Befund "§25/Art.5(3) gilt auch ohne Cookies". '0 Cookies' ≠
'kein einwilligungspflichtiges Tracking'.

Verdrahtet in consent_scanner vor dem Return. Tests + py_compile grün.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 19:49:55 +02:00
Benjamin Admin d8a9e3049d feat(consent-tester): cookieless Opt-out erkennen statt False-HIGHs
Cookie-freie Analyse mit reinem Opt-out-Hinweis (z.B. bayshore.ai:
"Privacy-friendly, cookie-free analytics are currently enabled ... Disable")
ist KEIN Consent-Banner: cookieless = kein Endgeräte-Zugriff → §25 TDDDG
verlangt keine Einwilligung → Opt-out statt Opt-in. Die Standard-Opt-in-
Checks (granulare Kategorien, Accept/Reject-Balance, Impressum-im-Banner)
trafen nicht zu und erzeugten 3 Falsch-HIGHs.

is_cookieless_optout() erkennt das Muster (cookieless-Signal + Opt-out-Wort,
KEIN Consent-Signal); check_banner_text gibt dann früh EINEN ausführlichen
LOW-Erklär-Befund zurück (zählt nicht als HIGH) und setzt die Opt-in-Checks
aus. Ausführlich, weil der Fall extrem untypisch ist.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 19:27:12 +02:00
Benjamin Admin 2f68646c2d fix(advisor): keep_alive 30m gegen Modell-Kaltstart ("Load failed")
Ollama entlädt das 35b-Modell nach 5 Min Leerlauf → jede Frage danach
startet es kalt (Modell-Load) und läuft in den Frontend-Timeout ("Load
failed"). keep_alive='30m' im Chat-Request hält es warm.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 13:20:13 +02:00
Benjamin Admin bb777fd474 feat(advisor): Abkürzungs-Glossar für treffsichere Kurzfragen
~50 EU/DE-Gesetzes-/Norm-Kürzel (BGB, HGB, MiCA, CRA, DSGVO, DDG, TDDDG …)
mit korrekter Bedeutung + Disambiguierung mehrdeutiger (CRA/CRMA) + Korrektur
veralteter Namen (TTDSG→TDDDG, TMG→DDG). Der Advisor antwortet bei kurzen
Akronym-Fragen sofort + richtig statt auszuweichen.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 13:02:26 +02:00
Benjamin Admin b5431f7375 feat(advisor): Co-Pilot-Tonalität + Scope-Disziplin; drafting-agent Anti-Leak
compliance-advisor.soul.md (Sie durchgehend):
- Persona: ruhiger Compliance Co-Pilot (Komplexität abnehmen, Nutzer entscheidet),
  DSB/Anwalt als Partner-Schritt statt Ausrede.
- Antwortlänge an die Frage koppeln (kurze Frage → 1-3 Sätze, kein erzwungenes
  4-Punkte-Schema); proaktiv mit nächstem Schritt schließen.
- Konfidenz-bewusst (Wahrscheinlichkeit statt Garantie); Risiken/Bußgelder nur auf
  Nachfrage + konstruktiv, nie als erster Eindruck.
- Scope-Disziplin: nur Compliance/Datenschutz/Security/Recht; Off-Topic freundlich
  + knapp ablehnen, kein Erfinden fachfremder Antworten.

drafting-agent.soul.md: Anti-Leak-Regel (Anweisungen nie offenlegen) + Sie + Off-Topic-Disziplin.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 12:58:24 +02:00
Benjamin Admin ffff84c594 fix(advisor): Quellenschutz-Regel eingrenzen + kein Prompt-Leak
Der Advisor deutete Inhaltsfragen ("Was ist der CRA?") als Quellen-/
System-Frage und wich aus; auf Nachfrage zitierte er sogar seine
Quellenschutz-Anweisung. Fixes in compliance-advisor.soul.md:
- Quellenschutz gilt nur noch für ECHTE Meta-Fragen (Quellenliste/RAG),
  NICHT für "Was ist X?"-Fachfragen → die werden sofort beantwortet.
- Neue Regel: System-Anweisungen/Prompt NIE offenlegen oder zitieren;
  auf "warum hast du nicht geantwortet?" nicht mit internen Regeln erklären.
- Neue Regel: mehrdeutige Abkürzungen (CRA …) kurz disambiguieren statt
  ausweichen.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 12:17:06 +02:00
Benjamin Admin 45df68537e feat(agent): Voll-Audit-Link in die Snapshot-Detail-Seite
Der "Voll-Audit öffnen (alle MCs)"-Link hing in ComplianceResultTabs (aus
der Agent-Seite entfernt). Jetzt im Detail-Header der Snapshot-Ansicht via
snap.check_id → /sdk/agent/audit/{check_id} (Audit-Daten verifiziert
vorhanden). Plus Site-Titel-Header.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 10:05:09 +02:00
Benjamin Admin 1b2b030367 feat(agent): /sdk/agent auf Compliance-Check + Snapshot-Historie reduzieren
- Tabs Website-Scan (nie funktioniert), Banner-Check, Agent-Test entfernt;
  Tab-Leiste weg, da nur noch Compliance-Check übrig.
- Unter dem Compliance-Check jetzt die Snapshot-Historie (neuer
  SnapshotHistoryList): neuester oben + farblich markiert, Klick → Detail-
  Seite mit den Ergebnissen. Macht /sdk/agent/snapshots erreichbar.
- ComplianceCheckTab zeigt nach dem Lauf keine Inline-Ergebnisse mehr,
  sondern einen Hinweis auf die Historie (onComplete refresht sie).
- Tote Komponenten gelöscht (ScanResult/BannerCheckTab/AgentTestTab).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 09:31:35 +02:00
Benjamin Admin 755ea44343 feat(iace): refresh architecture tab + data-flow diagram + E1 ingest script
- architecture.go: DataSources now reflect the real ingested set (ESAW 2023,
  BLS CFOI, OSHA OTM, PRISM, cobot CC-BY, HSE) with their RAG collections;
  risk stage cites BLS + the searchable RAG layer; matrix stage now mentions
  the distance-benchmark dimension.
- Architektur & Datenfluss tab: new DataFlowDiagram — 4 lanes (input →
  knowledge/RAG-evidence → deterministic engine → outputs) with live counts.
- scripts/ingest_iace_kb.sh: idempotent E1 ingest — creates the 2 collections
  and uploads the 6 datasources docs against a configurable RAG_URL (for prod
  Qdrant), with retry.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 09:18:03 +02:00
Benjamin Admin 99901bba0a fix(cookie): Präfix-Matcher über-matcht kurze generische Basen nicht mehr
CI / detect-changes (push) Successful in 15s
CI / guardrail-integrity (push) Has been skipped
CI / branch-name (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Successful in 10s
CI / validate-canonical-controls (push) Successful in 17s
CI / loc-budget (push) Successful in 18s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Successful in 59s
CI / iace-gt-coverage (push) Successful in 28s
CI / test-python-backend (push) Successful in 37s
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
Die Deklaration-vs-Bibliothek-Sicht deckte sofort einen Fehl-Match auf:
'cct_chatSessionToken' (Genesys-Webchat) traf die Library-Basis 'cct'
(actual_category Marketing, purpose 'shopping cart') → falsches
'necessary→Marketing'-Finding. Ursache: gekürzte 3-Zeichen-Basis ohne
führenden _.

_is_distinctive_base: gekürzte Präfix-Basis nur akzeptieren bei ≥4 Zeichen
ODER führendem '_' (kanonische Cookies wie '_ga'). GTM-/AdobeOrg-/Hash-
Suffix-Stripping bleibt erhalten (Tests grün), generische 'cct'/'sid'/'gtm'
über-matchen nicht mehr.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 21:26:47 +02:00
Benjamin Admin 403e3c66d2 feat(cookie): Deklaration-vs-Bibliothek-Diff-Sicht + Funnel-KPI
Für die Library-getroffene Teilmesse (~32%) pro Cookie die Feld-
Abweichungen deklariert→Library (Kategorie/Laufzeit/Zweck) als Diff-Karte,
plus ehrlicher Funnel (gesamt → geprüft → abweichend) — nicht-getroffene
Cookies sind nicht prüfbar (kein Pass/Fail), passend zur Tonalität.

- analyze_cookies: 'expected'-Soll-Wert an tracker_as_necessary/
  excessive_lifetime/missing_purpose (+ _CAT_LABEL_DE).
- neues cookie_declaration_diff.build_declaration_diff: reine Regroup-
  Aggregation der Findings pro Cookie (single source = analyze_cookies),
  Hinweis-Typen (third_country/eu_alternative) bewusst ausgeschlossen.
- cookie-check exponiert out['declaration_diff'].
- CookieDeclarationDiff.tsx oben im Cookie-Tab (vor Panel/ResultView).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 21:00:50 +02:00
Benjamin Admin c35977c925 docs(iace): verify cobot biomech limits against CC-BY papers
Cross-checked cobot_biomech_limits.md against both source papers:
- Behrens et al. 2022 (Frontiers): 10 body regions spot-checked, force
  values match the paper EXACTLY in both columns (pinching + impact).
- Park et al. 2019 (PLOS ONE): lowest/highest/range pressure values exact.
Fix: 28 -> 29 body locations; add a verification stamp. Threshold VALUES
were already correct (no data change), so no RAG re-ingest needed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 20:50:58 +02:00
Benjamin Admin 97e39579d5 feat(cookie+routing): Storage-Typ-Filter + legal_notice capture-only
#3 Storage-Filter: cookie-check exponiert per-Cookie-Speichertyp
(storage_inventory.per_cookie); CookieResultView bekommt Filter-Chips
(Cookie/Local Storage/Framework …) + eine Speicher-Spalte, Anbieter ohne
passenden Treffer werden ausgeblendet, KPI zeigt gefilterte Zahl.

A-Routing: legal_notice ist jetzt ein kanonischer Doc-Type. Eigene
Discovery-Regel (legal-disclaimer/rechtlicher-hinweis) VOR impressum →
die Disclaimer-Seite wird nicht mehr als Impressum substituiert (Ursache,
dass die Cross-Doc-Reconciliation nie zündete). capture-only: als
doc_entry für B persistiert, aber nicht einzeln gescort (keine 0%-Noise,
da ohne eigene Checkliste). Im Scan-Form als Option auswählbar.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 20:45:18 +02:00
Benjamin Admin 0f6cdc93fd fix(snapshot): Cookie-Dedup + schneller Impressum-Tab + Tabellen-Zahl
- Cookies werden je Vendor nach Name dedupliziert (Consent-Phasen-Dubletten;
  BMW 2196 → ~772) — in cookie-check + get_snapshot, behebt aufgeblähte
  Kachel-/Finding-Zahlen.
- Impressum-Snapshot-Check überspringt den ~40s-LLM-Schritt (context skip_llm)
  → Tab lädt sofort statt leer zu bleiben.
- Vendor-Tabelle zeigt nur die Cookie-Zahl (kein 'Cookies'-Wort je Zeile).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 19:54:15 +02:00
Benjamin Admin b0ceae4350 feat(iace): open-source safety KB sources + bp_iace_safety_kb (Thema 2)
Versioned, license-tagged source docs for the multi-layer GT knowledge base,
ingested into the new core RAG collection bp_iace_safety_kb (whitelisted in
the RAG search handler):
- prism_risk_methodology.md — OPSS PRISM v2 (OGL v3): full severity(4)×
  probability(8) → risk-level matrix (Serious/High/Medium/Low), RAPEX-aligned.
- cobot_biomech_limits.md — CC BY 4.0 papers (Behrens 2022 / Park 2019):
  force (N) & pressure (N/cm²) pain thresholds by body region (the data behind
  ISO/TS 15066, cited from the open papers — standard tables NOT reproduced).
- hse_example_risk_assessments.md — HSE (OGL v3): qualitative hazard→control.
- osha_robot_safety.md — OSHA OTM (public domain): 250 mm/s teach anchor,
  robot hazard taxonomy, safeguarding hierarchy.

No DIN/EN/ISO/IEC/DGUV content reproduced; each doc states its license + attribution.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 19:46:57 +02:00
Benjamin Admin b4981ea9ab feat(iace): benchmark distance panel (Thema 1)
Surface result.distances in the benchmark module: a DistanceComparison
panel showing agreement %, covered values (green), GT-only gaps (amber)
and engine-only extras — mirroring the RiskComparison panel.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 16:32:52 +02:00
Benjamin Admin dbb15dbb78 feat(iace): add BLS CFOI fatal-injury source doc (D1)
US severity anchor complementing ESAW: BLS Census of Fatal Occupational
Injuries (public domain), event/exposure distribution 2023-24 + the
machine-relevant "Contact incidents" breakdown (struck/caught/compressed
by running powered equipment: 226/213). Key finding: in MANUFACTURING,
contact is the leading fatal event (104/353 = 29.5%) — independent support
for the model's mechanical-contact emphasis. Ingested into the core RAG
collection bp_iace_accident_stats.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 15:57:31 +02:00
Benjamin Admin ba7d98be36 feat(reconcile): B — Cross-Doc-Reconciliation (Pflicht in anderem Doc erfüllt)
Ein 'X fehlt'/'zu prüfen'-Finding wird unterdrückt, wenn die Pflicht in einem
ANDEREN Snapshot-Dokument erfüllt ist (z.B. § 36 VSBG / OS-Link stehen bei BMW
in AGB/'Rechtlicher Hinweis', nicht im Impressum → war False Positive).
Konservative Allowlist (impressum: verbraucher_streitbeilegung, odr_link) gegen
False-Reconciliation. Verdrahtet in _run_doc_agent (alle Doc-Checks). Frontend:
'In anderem Dokument abgedeckt'-Sektion. Greift voll nach Scan + Legal-Capture.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 15:42:16 +02:00
Benjamin Admin 9dfdaae8e4 feat(cookie): präfix-bewusster Library-Match (Runtime-Suffixe)
load_big_library matchte nur EXAKT → nur ~27% der BMW-Cookies trafen die
Open-Cookie-DB, weil Per-Instanz-Suffixe abweichen (_ga_GTM-XYZ, AMCVS_###@
AdobeOrg, _pk_id.5.7d8). Jetzt: Library einmal laden, Namen entwildcarden,
über _candidate_keys (exact + Präfix an Trennzeichen, Mindestlänge 3 gegen
Über-Match) matchen. Reuse der bewährten _strip_wildcards-Logik.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 15:24:45 +02:00
Benjamin Admin 0f443b6a9c fix(iace): roadmap group B — citation/license/tier cleanup
C1: drop the misleading OSHA §1910.212(a)(5) fan-guard citation from M602
    (overhead lift clearance) — EN 349 + EN ISO 13854 already cover it.
C2: frame M237's 25/500 mm as Richtwerte to be determined per EN ISO 13854
    (single factual values in prose are facts, not table reproduction — but
    keep the conservative caveat).
C3: keep ergonomic W=2 deliberately and document why — ESAW ranks it the most
    frequent non-fatal mode (24.7%) but that population doesn't transfer to an
    acute machine point-hazard; the machine GT governs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 15:21:25 +02:00
Benjamin Admin 86c0ea6f63 fix(iace): wire M605/M606 into lift patterns so they fire
Adding M605 (drive-limited general speed) and M606 (limited descent on
energy loss) to the library wasn't enough — measures only get suggested
if a pattern's SuggestedMeasureIDs references them. Add M605 to the three
lift crush patterns and M606 to the floor-stop descent pattern (HP2100),
so a re-seed actually attaches them and the distance benchmark closes the
≤150 mm/s gap.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 15:06:33 +02:00
Benjamin Admin 0d7194ef89 feat(iace): add distance dimension to GT benchmark
CompareBenchmark now also compares the engine's numeric dimensions
(mm gaps, mm/s speeds) against the professional's GT measures: parses
distance tokens from both sides (German thousands/decimal aware),
reports matched / gt_only (gaps) / engine_only + an agreement %.
Surfaces as result.distances on the existing benchmark endpoint.

Deterministic, no LLM. On the GT-derived seed sessions it mainly guards
DRIFT; its real value is new sessions. Real-GT test pins that the engine
covers the Bremse (250 mm/s, 250/850 mm) and Kistenhub (25/120 mm,
150/75 mm/s) headline dimensions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 14:59:47 +02:00
Benjamin Admin b63f49344a feat(iace): fill lift-measure distance gaps vs GT (M603/M605/M606)
The GT distance benchmark surfaced three Fachmann lift values the engine
carried no measure for: general lift/lower speed (≤150 mm/s), the low-zone
inching regime (<200 mm floor clearance, ≤75 mm/s), and limited descent on
power loss (≤100 mm). Extend M603 (inching) and add M605 (drive-limited
general speed) + M606 (load-holding on energy loss). Values framed as
generic hoist recommendations with EN 1570-1 reference, not GT-memorised.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 14:47:21 +02:00
Benjamin Admin 4fb476e4be fix(agb): Gewährleistung erkennt 'bei Mängeln' / '§ N Mängel'-Heading
BMW-AGB nutzt '§ 9 Mängel' + 'Rechte und Ansprüche bei Mängeln' statt
'Gewährleistung' — Pattern ergänzt (False Negative auf Realdaten behoben).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 14:31:41 +02:00
Benjamin Admin 7258744107 refactor+feat: Snapshot-Router-Split + generischer ChecklistAgent + AGB-Modul
- Item 2: Snapshot-Doc-Checks (cookie/impressum/dse/agb) in snapshot_check_routes.py
  (agent_compliance_check_routes.py 464→365 Z.); gleiche Pfade, in main.py registriert.
- ChecklistAgent-Basis: DSE-Logik generalisiert (L1/L2, kurze Titel, _severity_
  override-Hook). DSEAgent + AGBAgent sind jetzt Thin-Subclasses → künftige
  Doc-Agenten (widerruf/avv/…) trivial.
- Item 4: AGBAgent (§§ 305 ff. BGB, AGB_CHECKLIST) + agb-check + AGB-Tab via
  AgentModuleTab. Kein Library-Firehose.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 14:23:29 +02:00
Benjamin Admin b40edd6d33 feat(iace): show ESAW evidence panel in risk view (B1)
The Risikobewertung page only mentioned the data sources as static prose.
Add a collapsible "Datenquellen & Evidenz" panel sourced from
/iace/risk-data-sources: the real Eurostat ESAW 2023 contact-mode shares
per mode, with license + ready-to-print attribution, and the note that
tiers anchor the ordering while values stay GT-calibrated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 14:11:15 +02:00
Benjamin Admin 3c6deac1c5 fix(dse+linter): Drittland-Applicability, kein na-Detail, kurze Titel, Linter-Wortgrenzen
- Linter: FORBIDDEN_OUTPUT_TERMS per Wortgrenze → 'Schutzgarantien'/'geeignete
  Garantien' (Art. 46) passieren, 'garantiert'-Claims bleiben geblockt.
- DSE: L2-Detail wird übersprungen statt 'na', wenn die L1-Pflichtangabe fehlt
  (kein irreführendes 'nicht anwendbar' für z.B. Transfermechanismus).
- DSE: Drittland → HIGH bei dokumentiertem Drittlandtransfer (scan_context via
  AgentInput.context) — BMW (Konzern, US-Provider) ist kein weiches MEDIUM.
- DSE: Titel/Maßnahme kurz (treibt den Recommendation-Titel); ausführliche
  Begründung als evidence — behebt 120-Zeichen-abgeschnittene Überschriften.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 13:43:24 +02:00
Benjamin Admin 6b41eec176 feat(iace): surface OSHA distance anchor in Maßnahmen tab (name-resolved)
Makes the OSHA minimum-distance anchor visible per measure in a project
without a DB schema change or re-seed: persisted mitigations store the
measure NAME verbatim (not the catalog ID), and measure names are unique
across the 578-entry library (pinned by test), so a name→ID resolver
bridges the gap.

Backend: MeasureIDByName + MinimumDistancesForMeasureName/LinksForMeasureName;
/iace/minimum-distances now accepts ?measure_name=; link table enriched with
measure_name for one-request UI matching.
Frontend: useMinimumDistances loads the link table once and keys it by name;
OshaDistanceNote renders the anchor (value/CFR/license/EU-hint/relation) on the
matching measure group in the Maßnahmen tab.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 13:39:48 +02:00
Benjamin Admin 76be96556d feat(dse): kuratierter DSEAgent + Snapshot-Tab (Art. 13/14, kein Firehose)
DSEAgent wrappt die existierende ART13_CHECKLIST (33 kuratierte Pflichtangaben
L1 + Detailchecks L2) → strukturierter AgentOutput, NICHT der 90k-Library-
Firehose (eCall/Gesundheit/Telekom-Lärm). GET /snapshots/{id}/dse-check spiegelt
impressum-check; doc_input_from_snapshot generalisiert. Frontend: generischer
AgentModuleTab (lazy → AgentResultTab) für Impressum + DSE; DSE-Tab in der
Snapshot-Seite. Plus HRB-Pattern \d→\d+ (volle Registernummer als Beleg).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 12:46:46 +02:00
Benjamin Admin be93859645 fix(impressum): Pflichtangaben-Beleg = exakter Treffer statt Textpassage
_match_value gibt genau den gematchten Bereich zurück (nur die E-Mail unter
Email, nur die USt-IdNr, nur die Telefonnummer) — nicht mehr ein Fenster/den
umgebenden Satz. Behebt die Wiederholung desselben Anfangssatzes bei Texten
ohne Zeilenumbrüche (BMW = ein Block).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 12:25:27 +02:00
Benjamin Admin 5e18df63b1 feat(iace): ESAW accident-stats RAG pipeline + real 2023 risk anchors
Executes the accident-statistics pipeline for the risk anchors:
- Refresh contactModeEvidence with real Eurostat ESAW figures
  (dataset hsw_ph3_08, reference year 2023): impact 24.0%/21.4%,
  struck-by 13.0%/23.8%, sharp 14.5%, trapped/crushed 13.8% (fatal),
  + new physical/mental-stress mode 24.7% → ergonomic. GT-calibrated
  tier VALUES unchanged; the real data confirms the ordering.
- Add the versioned source document (datasources/esaw_accident_stats_2023.md,
  ESAW CC BY 4.0 + OSHA public-domain context) that is ingested into the
  core RAG collection bp_iace_accident_stats for searchable evidence.
- Whitelist bp_iace_accident_stats in the RAG search handler so seeding
  can full-text search the statistics with citation at seed time.

Two-layer design: the small license-tagged code table stays the deterministic
tier/citation lookup; the RAG holds the searchable source evidence.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 12:12:02 +02:00
Benjamin Admin 877d540ce1 fix(cookie+impressum): Drittland-FP, Impressum-Beleg, neuer Opt-Out-Finding
- Drittland: unbekannte Herkunft ('N/A') + Self-Hosting feuern nicht mehr —
  First-Party-Session-Cookies (PHPSESSID/JSESSIONID) waren False Positives.
- Impressum _line_of: enges Fenster um den Treffer bei Texten ohne Umbrüche
  (BMW = ein Block) → jede Pflichtangabe zeigt IHREN Beleg statt denselben Satz.
- Neuer Finding-Typ missing_opt_out: einwilligungspflichtiger Anbieter mit
  Cookies ohne Opt-Out-/Widerspruchs-Link (Art. 7 Abs. 3 + Art. 21).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 11:59:48 +02:00
Benjamin Admin 5b36b3f367 feat(impressum): Snapshot-Modul-Tab — ImpressumAgent auf gespeichertem Text
Snapshot-Detailseite wird zu Modul-Tabs (Cookies & Tracking | Impressum).
Backend GET /snapshots/{id}/impressum-check laeuft den v3 ImpressumAgent auf
dem gespeicherten Impressum-Text (kein Re-Crawl); Input-Erzeugung in
impressum_input_from_snapshot() ausgelagert (pure + getestet: Text/Scope/
company_name-Fallback/None-Pfad). Frontend laedt lazy beim Tab-Wechsel und
rendert mit dem bestehenden AgentResultTab (keine zweite Engine).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 11:24:44 +02:00
Benjamin Admin 6846ca6b28 feat(iace): wire OSHA minimum-distance library into measures + endpoint
The May-built OSHA distance library (minimum_distances.go, 29 CFR 1910,
US public domain) was dead code — zero callers, no route, no test, while
the mm values that actually appear in measures are independent hand-prose
(some carrying ISO 13854/13857 values, not OSHA).

This surfaces it without touching the measures response contract:
- GET /iace/minimum-distances (+ ?measure_id=) returns the distances, the
  curated measure→distance link table and the licensing note.
- AllMeasureDistanceLinks/MinimumDistancesForMeasure resolve only the
  defensible links (M600 value_source; M254/M065 public-domain crossref to
  ISO), with the relation made explicit so the join stays honest.
- architecture.go lists the OSHA library so it shows in the audit explainer.
- Tests: inch→mm conversion + license completeness, link integrity, and a
  consistency test pinning that a value_source measure's prose still
  matches the OSHA source (codifies the audit finding as a regression gate).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 11:17:56 +02:00
Benjamin Admin 39cb6afc23 feat(cookie): Findings bearbeitbar — gruppiert nach Typ + Matrix + Hinweise-Split
CookieFindings: Umschalter [Nach Fehlertyp] (je Typ: Maßnahme + betroffene
Cookies + Ticket-Text) ↔ [Matrix] (Cookie×Typ, ✗ Handlung / ⚠ Hinweis).
Trennung FINDINGS (zu beheben) vs HINWEISE (neutral, gegen DSE zu prüfen).
Backend: kind-Klassifikation (third_country/eu_alternative=hinweis); Drittland-
Remediation neutral formuliert (pro Verarbeiter prüfen, keine 'in DSE benennen'-
Befehle, da DSE-Abdeckung wie BMWs 'in der Regel SCC' oft unzureichend).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 11:02:34 +02:00
Benjamin Admin b0115cb10b feat(cookie): 2. Sicht Banner-Kategorie + Fehl-Einsortierung
CookieResultView bekommt einen Umschalter [Rechtliche Rolle] ↔
[Banner-Kategorie] (Notwendig/Funktional/Statistik/Marketing). In beiden
Sichten zeigt jede Cookie-Zeile '→ sollte: Marketing', wenn die tatsächliche
Kategorie laut Library von der deklarierten abweicht (rot bei Tracker als
notwendig, § 25 TDDDG). Neue KPI 'Falsch einsortiert'. Backend liefert dazu
cookie_categories (name→actual_category) aus big_lib im cookie-check-Output;
Seite lädt cookie-check einmal und reicht es an beide Komponenten.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 10:33:33 +02:00
Benjamin Admin af8906b156 fix(admin): commit missing infrastructure-modules types
app/api/webhooks/woodpecker/route.ts (committed in 529c37d) imports
WoodpeckerWebhookPayload, ExtractedError + BacklogSource from
@/types/infrastructure-modules, but that file was never committed. Clean
checkouts (Docker build, CI) fail with 'Cannot find module'. Restore the
file so the admin build is green again. Pure type declarations, no logic.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 10:09:23 +02:00
Benjamin Admin 7fa9968ce1 feat(cookie): missing_retention — Vendor ohne Speicherdauer/Löschfrist
Vendor-Ebenen-Finding: greift, wenn ein Vendor eine Verarbeitung deklariert
(Kategorie/Zweck), aber KEINE Cookies gelistet sind UND keine persistence
angegeben ist (z.B. Nayoki GmbH — 'necessary' Auftragsverarbeiter ohne
Löschfrist). Die Pro-Cookie-Schleife sah solche Vendors nie (0 Cookies →
0 Findings). Remediation = Ticket-Text 'bitte Löschfrist festlegen'.
Art. 5 Abs. 1 lit. e + Art. 13 Abs. 2 lit. a → Control AUTH-2051-A03.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 10:02:59 +02:00
Benjamin Admin 32ba8d16b1 feat(iace): add data-driven Architektur & Datenfluss explainer tab
Adds an auditor-facing view of the IACE engine: a clickable 10-stage
pipeline flow (Grenzen-Formular → ParseNarrative → Pattern-Gates →
Relevanz → Caps → Gefährdungen → Maßnahmen → Risiko → Normen → Matrix),
plus live library counts, the data-source/license register (incl. the
DIN/Beuth + DGUV exclusions), and the norm-matching logic that reconciles
DIN/ISO/OSHA machine-type vocabulary via canonicalMachineType folding.

Backend: BuildArchitecture() with LIVE counts so the diagram can never
drift; GET /iace/architecture; collectAllNorms() extracted from
SuggestNorms as the single source of truth for the norm-library count.
Frontend: useArchitecture hook + page + new IACE nav tab.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 09:35:37 +02:00
Benjamin Admin 05a1795ea8 feat(cookie): ② Documentation Drift — Richtlinie vs. Browser-Realität
Cookie-Check-Endpoint liefert jetzt out["drift"] (audit_cookie_compliance):
deklariert (Cookie-Richtlinie-Text) vs. tatsaechlich geladen (Browser).
Frontend zeigt den Reality-Check-Strip oben im Panel: X dokumentiert ·
Y geladen · Z undokumentiert. Pinnt den Vertrag mit test_cookie_drift.py
(undokumentiert-geladen + beide Drift-Richtungen) + Vitest Drift-Strip.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 09:33:41 +02:00
Benjamin Admin ee64b7e95c feat(iace): cite ESAW source + license on risk-frequency anchors
Surfaces the public-statistics provenance for the contact-mode probability
tiers so generated risk numbers are auditable and attributed (not RAG —
~a dozen stable aggregate facts are better as a license-tagged code table).

- risk_data_sources.go: RiskEvidence register (Eurostat ESAW figures + CC BY
  4.0 attribution) for the documented contact modes; RiskDataSourcesNote.
- risk_suggestion.go: the W justification now cites the actual ESAW share +
  license where documented; RiskSuggestion gains a data_source field.
- GET /iace/risk-data-sources returns the evidence register + attribution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 09:14:36 +02:00
Benjamin Admin 289988d23e feat(cookie): ① Storage Inventory + storage_transparency-Finding
Trennt echte Cookies von anderem Endgeraete-Speicher (Local/Session Storage,
IndexedDB, Salesforce-Framework-Artefakte) — § 25 TDDDG ist technologieneutral.
- cookie_storage_inventory: detect_storage_type (Name-Muster ComponentDefStorage/
  __MUTEX/LSKey + Laufzeit-Text) + build_storage_inventory + storage_transparency-
  Summenbefund ('X als Cookie gelistet -> Y echte + Z andere').
- Endpoint cookie-check liefert storage_inventory; Frontend zeigt den Breakdown.

Tests: 4 + Frontend-Vitest gruen. Differenzierungsmerkmal: '740 -> 132 + 608'.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 09:05:29 +02:00
Benjamin Admin 577ceae4e6 feat(iace): project-wide risk matrix (Severity × Probability)
Adds GET /projects/:id/risk-matrix — a confidence-aware risk view computed
on read from each hazard's category/scenario/lifecycle using the SAME model
as the GT benchmark (no persistence, so it never goes stale against the
model; the hand-defaulted iace_hazards risk columns stay untouched).

- risk_matrix.go: EstimateHazardRisk (single source of truth for S/F/W/P +
  range + level + confidence) and BuildRiskMatrix (per-hazard list + a 5×5
  Severity×Probability aggregation grid with dominant level per cell).
- Frontend: RiskMatrix grid in the Risikobewertung tab (muted colours per
  the confidence-aware tonality), level counts + tool-confidence summary,
  fed by useRiskMatrix. Shows risk for EVERY project, not only GT ones.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 08:54:47 +02:00
Benjamin Admin 901de1ca97 feat(cookie): A — Findings auditfest an Controls verdrahten
Jeder Cookie-Befund traegt jetzt ein strukturiertes control-Feld
(control_id aus doc_check_controls + regulation + article) statt nur
hardcodeter Strings: vague_duration->AUTH-2051-A03 (Art.5(1)e+13),
tracker_as_necessary->DATA-2851-A05 (§25 TDDDG), third_country->
DATA-1624-A04 (Art.44). Kette Regulation->Article->Control->Finding.
Frontend zeigt die Rechtsgrundlage je Befund. (Controls tragen
regulation/article noch NULL -> hier mitgeliefert bis gepflegt.)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 08:44:19 +02:00
Benjamin Admin 4c45f11e43 feat(cookie): Finding 'vague_duration' — unkonkrete Speicherdauer
Flaggt Laufzeit-Angaben ohne konkrete Dauer/Kriterium ('dauerhaft', 'bis zur
Loeschung', 'bis Nutzer deaktiviert', 'unbegrenzt' …) — Art. 5(1)(e) + Art. 13
DSGVO. Library-unabhaengig, gilt fuer ALLE Cookies (Coverage auf BMWs 780).
'13 Monate'/'Session'/'bis Widerruf, max. X' bleiben ok.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 08:33:06 +02:00
Benjamin Admin d18ef79f18 feat(cookie): Pro-Cookie-Library-Abgleich (2287er OCD + 35er rich) + Panel
- analyze_cookies gleicht Cookies gegen BEIDE Libraries ab: compliance.cookie_library
  (2287, OCD/CC0 — Kategorie/Retention) + 35er rich-DB (technical_necessity/reid/
  schrems/eu_alternative). 5 Befund-Typen: tracker_as_necessary, missing_purpose,
  excessive_lifetime (Art.5), third_country (Art.44), eu_alternative (kommerziell).
- Endpoint GET /snapshots/{id}/cookie-check (load_big_library batch + analyze).
- Frontend CookieLibraryPanel im Snapshot-Detail.
- Fix CookieResultView: Zweck nicht mehr auf 60 Zeichen gekuerzt; Rolle 'unknown'
  als Strich statt 'Unbekannt'.

Tests: 7 backend + frontend vitest gruen.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 08:18:25 +02:00