feat(marketing): Saving-Section + Landingpages + Pipeline Lessons-Learned [split-required]
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 35s
CI / test-python-voice (push) Successful in 33s
CI / test-bqas (push) Successful in 35s

Marketing-Website
- Neue SavingsSection auf Homepage: "Compliance entdeckt sechsstellige
  Einsparungen". Pitch-Position der Cookie-Audit-Cost-Optimization-Story
  fuer DAX-Konzern-Sales (BMW-Case-Style: 90 Vendors -> 25 nach
  Konsolidierung, EUR 500k-3M / Jahr).
- /savings-scan: Kostenloser 5-Min-Saving-Scan-Form (URL + E-Mail).
  Form-Submit ist Placeholder, soll an Compliance-Backend gehaengt werden.
- /savings-methodik: 4-Stufen-Erklaerung der Cookie-Tier-Inferenz +
  ehrliche Caveats (Listpreise != Vertragspreise, Media-Spend nicht
  enthalten) + Datenquellen.
- Content-de + Content-en in content.ts beide um savings-Block ergaenzt
  und Section-Numerierung angepasst (03=Savings, 04=Deterministic).
- LOC-Split: savings-Inhalte (DE+EN, ~100 LOC) in content.savings.ts
  ausgelagert damit content.ts unter 500-LOC-Hard-Cap bleibt.

Control-Pipeline
- LESSONS-LEARNED-mc-check-types.md fuer die parallele CRA-MC-Generation.
  Erklaert die TEXT/PROCESS/REVIEW-Klassifikation die im Compliance-Repo
  retrofitted wurde. Verhindert dass CRA-MCs denselben Defekt bekommen.
  Mapping-Heuristik fuer verification_method -> check_type, plus
  Backfill-Workflow fuer ~62 ambiguous Eintraege.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-18 18:38:30 +02:00
parent 9783657da3
commit 911697bab4
7 changed files with 735 additions and 2 deletions
@@ -0,0 +1,132 @@
# Lessons Learned — MC `check_type` Klassifikation (KRITISCH fuer CRA + alle neuen Frameworks)
Datum: 2026-05-17
Auslöser: Compliance-Check BMW lieferte 0/381 Cookie-MCs, 3/75 Impressum-MCs, 43/571 DSE-MCs — alle Doc-Typen unter 20%.
## TL;DR
**Die heutigen Master-Controls (MCs) vermischen drei strukturell unterschiedliche Klassen von Pruefungen in einer einzigen Tabelle (`compliance.doc_check_controls`). Nur eine der drei Klassen lässt sich gegen Dokument-Text matchen. Die anderen zwei werden faelschlich als "failed" gezaehlt, weil sie ueberhaupt nicht ueber Text-Matching gepruefbar sind.**
Bei der CRA-MC-Generierung (laeuft jetzt im Pass 0a mit Haiku) **MUSS** jeder MC ein **`check_type`-Feld** bekommen, bevor er in die Datenbank geht. Sonst wiederholt sich das Problem.
## Die drei Klassen
| `check_type` | Pruefungsfrage-Pattern | Beispiel | Wie pruefbar? |
|---|---|---|---|
| **`text`** | "Enthaelt das Dokument...", "Wird im X die Y benannt?", "Ist im Text aufgelistet..." | "Wird im Impressum die Aufsichtsbehoerde benannt?" | Regex / Embedding-Match gegen Doc-Text |
| **`process`** | "Ist sichergestellt...", "Ist implementiert...", "Wird durchgefuehrt..." | "Ist sichergestellt, dass Cookies erst nach Einwilligung gespeichert werden?" | Evidence/TOM-Check — kein Doc-Text vorhanden |
| **`review`** | "Sind ALLE / Werden ALLE / Stimmt X mit Y ueberein?" | "Sind alle Verarbeitungszwecke vollstaendig erfasst?" | Mensch (DSB) — Checkliste, nicht automatisch |
## Befund aus den BMW-Daten
| Doc-Type | TEXT (matchbar) | PROCESS | UNKLAR/REVIEW | Total | % TEXT |
|---|---|---|---|---|---|
| cookie | 30 | 49 | 302 | 381 | **8%** |
| dse | 72 | 139 | 359 | 571 | **13%** |
| impressum | 14 | 14 | 47 | 75 | **19%** |
| agb | 24 | 20 | 69 | 113 | 21% |
| widerruf | 29 | 26 | 96 | 153 | 19% |
| loeschkonzept | 38 | 39 | 232 | 309 | 12% |
**Selbst mit perfektem Matching liegt die Obergrenze fuer doc_check bei 8-20%**, weil 80-92% der MCs nicht ueber Text-Matching pruefbar sind. Es sind keine "schlechten MCs" — sie sind in der falschen Schublade.
## Konsequenzen fuer CRA-Generation (Pass 0a)
### 1. Prompt-Aenderung (Hauptmassnahme)
Der Pass-0a-Prompt fuer Haiku/Sonnet MUSS pro generiertem Control ein `check_type`-Feld erzwingen. Vorschlag:
```jsonc
{
"control_id": "CRA-...-A01",
"title": "...",
"check_question": "...",
"check_type": "text" | "process" | "review", // PFLICHT
"rationale_for_check_type": "..."
}
```
Klassifikations-Regel im Prompt:
> Wenn deine `check_question` mit "Enthaelt", "Wird … genannt/aufgelistet/erwaehnt", "Steht im Text" beginnt -> `text`.
> Wenn sie mit "Ist sichergestellt", "Ist implementiert", "Wird durchgefuehrt", "Existiert ein Prozess" beginnt -> `process`.
> Wenn sie mit "Sind ALLE", "Werden ALLE", "Stimmt X mit Y ueberein" beginnt -> `review`.
> Im Zweifel: lieber `review` als `text`.
### 2. Doc-Type-Zuordnung kritisch validieren
Bei den heutigen MCs sind viele falsch zugeordnet (z.B. "Bestellbestätigung implementieren" landet im `impressum`-doc_type, gehoert aber zu AGB/Widerruf). Fuer CRA:
- **`doc_type` darf nur Werte aus einer expliziten Liste annehmen** — pro Regulation festlegen.
- Fuer CRA z.B.: `produkt_konformitaetserklaerung`, `risiko_management_dossier`, `sbom`, `cra_dse`, `meldepflichten_doku`.
- Falsche Zuordnung im Prompt explizit verbieten: "Wenn der Control nicht eindeutig zu EINEM dieser Doc-Typen passt, setze `doc_type: 'unassigned'` und `check_type: 'review'`."
### 3. Zwei Tabellen statt einer
Heutige Architektur:
- `compliance.doc_check_controls` <- alle 1874 MCs (mit allem vermischt)
Empfohlen fuer CRA + Refactor:
- `compliance.text_check_controls` <- nur `check_type='text'`
- `compliance.process_check_controls` <- nur `check_type='process'`, gepruefte via Evidence/TOM
- `compliance.review_checklist_controls` <- nur `check_type='review'`, gepruefte via DSB-Workflow
Falls Schema-Aenderung nicht moeglich (CLAUDE.md: DB ist frozen), Sidecar-SQLite mit `mc_classification.db` oder neue Spalte als Add-only-Migration.
### 4. Dedupe-Phase respektieren
In Pass 0b (Dedup) muss `check_type` ein **Pflicht-Dedupe-Key** sein:
- Zwei MCs mit gleicher Aussage aber unterschiedlichem `check_type` sind **nicht** Duplikate — sie pruefen verschiedene Dinge ("ist im Text genannt" vs "ist technisch implementiert").
- Heute werden solche faelschlich gemerged → noch mehr Vermischung.
### 5. Matching-Engine danach umbauen
Das eigentliche doc-check-Match-System muss nur noch `check_type='text'`-MCs verarbeiten. Andere werden in ihre eigenen Module geroutet:
- `text` MCs -> `rag_document_checker` (Regex + spaeter Embedding)
- `process` MCs -> neuer `evidence_check_runner` (Kunde lieferte Nachweise/TOM hoch)
- `review` MCs -> neuer `review_checklist_ui` (DSB beantwortet manuell)
## Checkliste fuer CRA-Session
- [ ] Pass-0a-Prompt um `check_type`-Pflichtfeld erweitert (Wortlaut-Regel + Beispiele)
- [ ] Pass-0a-Prompt zwingt `doc_type` aus expliziter Whitelist
- [ ] Pass-0b-Dedup-Key enthaelt `check_type`
- [ ] Output-Validator weist MCs ohne `check_type` zurueck
- [ ] DB-Schema (oder Sidecar) hat `check_type`-Spalte mit Default `review` (sicherer Fallback)
- [ ] Stichprobe von 50 generierten CRA-MCs vor Bulk-Run: TEXT-Anteil sollte 30-50% sein (mehr als bei den alten DSGVO-MCs, weil CRA stark dokument-fokussiert ist).
## Update 2026-05-17 — Parallel-CRA-Session-Findings
Die laufende CRA-Generation hat ein Feld `verification_method` (document/tool/hybrid/code_review/empty), das **NICHT identisch** mit `check_type` ist:
- `verification_method` fragt: **WAS schaust du dir an?** (Dokument, Tool-Output, Code)
- `check_type` fragt: **KANN das per Text-Match geprueft werden?** (text/process/review)
Ein Control kann `verification_method=document` haben UND trotzdem `check_type=process` sein. Beispiel: "Wird die SBOM regelmaessig (mindestens monatlich) aktualisiert?" — Du schaust ins Dokument SBOM-Historie, prüfst aber einen Prozess. Text-Match findet das nie.
**Mapping-Heuristik (gut genug fuer 80% der Faelle, Rest LLM):**
| `verification_method` | Auto-Mapping `check_type` | LLM noetig? |
|---|---|---|
| `tool` | `process` | nein |
| `code_review` | `process` | nein |
| empty/null | `review` (sicherer Default) | nein |
| `document` | erstmal `text`, Stichprobe pruefen | 10-20% sampling |
| `hybrid` | LLM klassifizieren | ja, alle |
**Idealfall (fuer alle KUENFTIGEN Pass-0a-Generationen — auch CRA falls man nochmal generiert):** Beide Felder gleichzeitig generieren, nicht eins aus dem anderen ableiten.
## Backfill-Workflow fuer die laufende CRA-Generation
1. Aktueller Haiku-Job laeuft fertig (kein Restart, kein Verlust)
2. Nach Job-Ende: Auto-Mapping fuer eindeutige Buckets (tool/code_review/empty)
3. Sonnet-Klassifikation nur fuer `document`+`hybrid` Subset (~62 Calls fuer 1500 Controls, ~$0.05 statt $2)
4. Wiederverwenden: `breakpilot-compliance/backend-compliance/scripts/classify_mc_check_type.py` — nur DB-Query anpassen (Source-Tabelle + WHERE-Filter)
5. Validierung: TEXT-Anteil bei CRA sollte 40-60% sein (CRA ist dokument-zentrierter als DSGVO-Cookie)
## Quervewweise
- BMW-Run-Befund: `breakpilot-compliance` E-Mail vom 2026-05-17, check_id `08bcc9dd`
- Bestehender Klassifikations-Skript fuer Retrofit der alten 1874: `backend-compliance/scripts/classify_mc_check_type.py`
- Doc-Type-Audit-Query: dieselbe Datei, am Ende