E2E auf BMW (macmini, arm64) zeigte: nur Chromium lief, Firefox/WebKit/Mobile-
Safari scheiterten mit "Host system is missing dependencies to run browsers".
Die manuell gepflegte apt-Lib-Liste war fuer Gecko/WebKit unvollstaendig.
`playwright install-deps chromium firefox webkit` (als root) installiert den
vollstaendigen OS-Dep-Satz → alle Engines starten. Betrifft beide Arches.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- browser_cross_finding: deterministische Sicht ueber die Matrix (keine 2.
Engine, kein LLM). Findet Inkonsistenzen ZWISCHEN Browsern (Cookies vor
Consent / Ablehnen nicht universell respektiert / Banner-Links fehlend) und
ordnet ein: Safari-ITP / Brave-Shields / Firefox-ETP maskieren Verstoesse
clientseitig → strenge Engine "sauber" ist KEIN Compliance-Beleg, massgeblich
sind die nachgiebigen (Chrome/Edge). Coverage-Hinweis fuer nicht verfuegbare
Browser. Je Befund Titel/Detail/Severity/affected/Massnahme.
- snapshot_check_routes: cross_findings frisch in run + GET (nicht persistiert).
- BrowserBehaviorView: "Cross-Browser-Befunde"-Block ueber der Tabelle.
- Tests: test_browser_cross_finding (6).
Offen (Folge-Task): Borlabs-Consent-Historie-Live-Erkennung (braucht
consent-tester-Storage-Scan).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- check_snapshot: update_browser_matrix/load_browser_matrix — migrationsfrei
in banner_result.browser_matrix (JSONB jsonb_set, eigener scanned_at)
- snapshot_check_routes: POST /snapshots/{id}/browser-behavior/run laeuft
/scan-matrix LIVE (Re-Crawl je Engine, nur live messbar), persistiert das
Ergebnis; GET /snapshots/{id}/browser-behavior liefert die gespeicherte
Matrix ohne Re-Crawl. Profil-Set = 4 Default-Engines + Brave/Chrome/Edge.
- consent-tester multi_browser_scanner: Semaphore(2) gegen OOM (7 Browser
parallel sprengten das 2g-mem_limit)
- Pydantic-Modell mit Optional[List[...]] (nicht `| None`) → Py3.9-sicher
- Tests: _snapshot_scan_url + Request-Defaults (5)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
P1 of the auto-FMEA build plan: establish the public-domain methodology
foundation (no AIAG-VDA/SAE/IEC tables reproduced).
- fmea_data_sources.go: MIL-STD-882E severity (Cat I-IV→1-10) + probability
(A-F→1-10 with per-hour λ bands), OccurrenceFromRate(λp·α), SeverityForCategory,
MIL-STD-1629A CriticalityCm = λp·α·β·t. Own 1-10 projection, government-anchored.
- 4 versioned source docs (MIL-STD-1629A, MIL-STD-882E, NASA RCM, FMD-91/NPRD-91)
ingested into the new RAG collection bp_iace_fmea_kb (whitelisted).
- Tests for all scales/mappings/criticality (green).
Next (P1 step 2): fetch FMD-91/NPRD-91 bulk λ/α tables from DTIC.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Dockerfile: Brave-apt-Repo + `playwright install --with-deps chrome msedge`,
beide hinter TARGETARCH=amd64-Gate und best-effort (|| echo) → arm64-Dev-
Builds (macmini) brechen NICHT, laufen mit den 4 Default-Engines; Brave/
Chrome/Edge sind amd64-only opt-in-Extras (EXTRA_PROFILES).
- docker-compose.hetzner.yml: consent-tester auf linux/amd64 (statt arm64-
Emulation auf Orca) — Voraussetzung dafuer, dass die echten Browser
ueberhaupt installiert werden.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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>
#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>
#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>
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>
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>
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>
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>
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>
- 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>
- 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>
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>
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>
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>
#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>
- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>
_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>
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>
- 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>
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>
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>
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>
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>
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>
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>