# Instruktion: Hartkodiertes Wissen → Control Library Migration

**Branch:** `feat/zeroclaw-compliance-agent`
**Repo:** `/Users/benjaminadmin/Projekte/breakpilot-compliance/`
**Erstellt:** 2026-04-29
**Review-Deadline:** 2026-07-01

## Problem

Der Compliance Agent hat 6 Dateien mit hartkodiertem Rechtswissen in Python-Dicts.
Das Wissen veraltet und wird nicht von der Pipeline aktualisiert. Langfristig muss
alles aus der Control Library kommen (166k+ Controls in `compliance.canonical_controls`).

## Inventar (alle im Backend: `backend-compliance/compliance/services/`)

| Datei | Hartkodiert | Zeilen | Prioritaet |
|-------|------------|--------|-----------|
| `legal_basis_validator.py` | `CORRECT_BASIS` dict — 7 Lit-Zuordnungen (Art. 6 lit. a-f pro Zweck) | ~50 LOC | HOCH |
| `service_registry.py` | `SERVICE_REGISTRY` dict — 82 Services mit Legal Refs | ~500 LOC | MITTEL |
| `mandatory_content_checker.py` | `MANDATORY_DSE_CONTENT` (9 Felder) + `MANDATORY_IMPRESSUM_CONTENT` (5 Felder) | ~80 LOC | MITTEL |
| `relevance_filter.py` | `CONTROL_RELEVANCE` dict — 7 Controls mit Keyword-Listen | ~60 LOC | MITTEL |
| `consent-tester/services/script_analyzer.py` | `SERVICE_PATTERNS` — 19 Services (Duplikat von Registry) | ~70 LOC | NIEDRIG |
| `consent-tester/services/banner_detector.py` | `CMP_SELECTORS` — 10 CMPs | PERMANENT (technisch) | — |

## Migrationspfad pro Datei

### Schritt 1: Controls in der Pipeline generieren

Fuer jedes Dict-Entry einen entsprechenden Control in der Pipeline generieren lassen.

Beispiel fuer `legal_basis_validator.py`:

```sql
-- Neuer Control in canonical_controls:
INSERT INTO compliance.canonical_controls (title, objective, requirements, scope_conditions, tags)
VALUES (
  'Cookie-Tracking erfordert Einwilligung (lit. a)',
  'Cookie-Tracking und Webanalyse duerfen nur mit ausdruecklicher Einwilligung (Art. 6 Abs. 1 lit. a DSGVO) erfolgen.',
  'Rechtsgrundlage fuer Cookie-Tracking muss Art. 6(1)(a) sein. Art. 6(1)(f) (berechtigtes Interesse) ist nach EuGH C-673/17 (Planet49) nicht zulaessig.',
  '{"applies_when": "cookie_tracking OR web_analytics"}',
  ARRAY['legal_basis', 'lit_mapping', 'cookie', 'planet49']
);
```

Benoetigte Controls (aus legal_basis_validator.py CORRECT_BASIS):
1. `cookie_tracking` → lit. a (Planet49)
2. `web_analytics` → lit. a (DSK Orientierungshilfe, §25 TDDDG)
3. `marketing_email` → lit. a (Art. 7 DSGVO, §7 UWG)
4. `remarketing` → lit. a (§25 TDDDG)
5. `credit_check` → lit. b/f + Art. 22 Pflichthinweis
6. `social_media_embed` → lit. a (Fashion ID Urteil)
7. `session_recording` → lit. a (§25 TDDDG)

Benoetigte Controls (aus mandatory_content_checker.py):
1. DSE muss Verantwortlichen nennen (Art. 13(1)(a))
2. DSE muss DSB-Kontakt nennen (Art. 13(1)(b))
3. DSE muss Zwecke nennen (Art. 13(1)(c))
4. DSE muss Rechtsgrundlagen nennen (Art. 13(1)(c))
5. DSE muss Speicherdauer nennen (Art. 13(2)(a))
6. DSE muss Betroffenenrechte nennen (Art. 13(2)(b-d))
7. DSE muss Beschwerderecht nennen (Art. 13(2)(d))
8. DSE muss Drittlandtransfer nennen (Art. 13(1)(f))
9. DSE muss automatisierte Entscheidungen nennen (Art. 13(2)(f))

### Schritt 2: Agent-Code aendern — Control Library first, Dict as Fallback

```python
# VORHER (hartkodiert):
CORRECT_BASIS = {"cookie_tracking": {"correct": "lit. a", ...}}

# NACHHER (Control Library first):
async def get_legal_basis_rule(purpose: str) -> dict | None:
    controls = await query_controls(tags=["lit_mapping", purpose])
    if controls:
        return controls[0]  # Control Library hat Vorrang
    logger.warning("No control found for %s — using hardcoded fallback", purpose)
    return CORRECT_BASIS.get(purpose)  # Fallback
```

### Schritt 3: Dicts entfernen

Wenn alle Controls in der Library sind und der Agent sie zuverlaessig findet:
- Dicts loeschen
- Warning-Logs entfernen
- Tests aktualisieren

## Welche Datei NICHT migriert wird

`banner_detector.py` — die CMP-Selektoren sind technische CSS-Patterns, kein
Rechtswissen. Die bleiben hartkodiert und werden aktualisiert wenn CMPs ihre UI aendern.

## Erkennungszeichen im Code

Alle betroffenen Dateien haben:
- `⚠️ TECHNISCHE SCHULD` im Docstring
- `Review-Datum: 2026-07-01` im Header
- `logger.warning("... HARDCODED rules ...")` bei Nutzung

## Zusaetzliches Problem: Keyword-basierte Pflichtinhalte-Pruefung

### Problem (identifiziert beim IHK Konstanz Test, 2026-04-29)

Der `mandatory_content_checker.py` prueft ob DSE-Pflichtangaben vorhanden sind
per Keyword-Matching: `"zweck" in text.lower()`. Das bricht wenn:

- Andere Formulierung: "Verarbeitungszwecke" statt "Zwecke"
- Andere Sprache: Englische DSE auf deutscher Website
- Umschreibung: "Wozu wir Ihre Daten nutzen" statt "Zwecke"

Gleiches Problem bei `ECOMMERCE_INDICATORS` in der gleichen Datei — hartkodierte
Shop-Erkennung die neue Shop-Systeme nicht kennt.

### Betroffene Stellen

| Datei | Dict/Liste | Zeilen |
|-------|-----------|--------|
| `mandatory_content_checker.py` | `MANDATORY_DSE_CONTENT` keywords (9 Felder) | ~60 LOC |
| `mandatory_content_checker.py` | `MANDATORY_IMPRESSUM_CONTENT` keywords (5 Felder) | ~30 LOC |
| `mandatory_content_checker.py` | `ECOMMERCE_INDICATORS` | ~10 LOC |

### Loesung: LLM-basierte Pflichtinhalte-Pruefung

Statt hartkodierter Keywords → Qwen fragen:

```python
# VORHER (hartkodiert, bricht bei neuer Formulierung):
found = any(kw in text_lower for kw in ["zweck", "purpose", "verarbeitungszweck"])

# NACHHER (LLM-basiert, sprachunabhaengig):
prompt = f"""
Pruefe ob der folgende Text Angaben zu den Zwecken der Datenverarbeitung
enthaelt (Art. 13 Abs. 1 lit. c DSGVO).
Antworte NUR mit: JA (mit kurzem Zitat) oder NEIN.
Text: {dse_text[:2000]}
"""
result = await query_qwen(prompt)
found = result.startswith("JA")
```

### Aufwand

- 9 Pflichtfelder × 1 LLM-Call = 9 Calls (parallelisierbar)
- ~100 LOC Umbau
- Fallback auf Keywords wenn LLM nicht verfuegbar

### Prioritaet

MITTEL — die erweiterten Keywords funktionieren fuer 90% der Faelle.
LLM-Pruefung ist robuster aber langsamer (~30s statt <1s).

## Memory-Datei

Details: `/Users/benjaminadmin/.claude/projects/-Users-benjaminadmin-Projekte-breakpilot-lehrer/memory/hardcoded_knowledge_debt.md`
