# Anti-Fake-Evidence Architektur **Status:** Phase 3 (aktiv seit 2026-03-23) **Prefix:** CP-AFE **Motivation:** Delve-Vorfall (Maerz 2026) — Compliance-Theater verhindern --- ## Warum dieses System existiert ### Das Delve-Problem Im Maerz 2026 wurde bekannt, wie die Compliance-Plattform Delve ein Compliance-Audit bestand — ohne dass die Firma tatsaechlich compliant war: 1. **LLM-generierte Nachweise** wurden 1:1 als Evidence akzeptiert. Ein GPT-generierter Text "Die Organisation hat ein ISMS implementiert" wurde als Nachweis fuer ISO 27001 Kontrolle A.5 eingesetzt — ohne dass ein ISMS existierte. 2. **Controls ohne Evidence** standen auf "pass". Das System erlaubte es, jeden Control-Status manuell auf "pass" zu setzen, ohne dass ein einziger Nachweis hochgeladen wurde. 3. **100%-Compliance-Dashboards** ohne Validierung. Das Management sah eine gruene 100%-Anzeige und glaubte, das Audit sei bestanden — bis der externe Auditor nach Dokumenten fragte. ### Haftungsrisiko Wenn eine Compliance-Plattform falsche Compliance suggeriert, haftet: - **Die Firma** — Aufsichtsbehoerden (z.B. BfDI, BaFin) akzeptieren "die Software hat gesagt wir sind compliant" nicht als Entschuldigung - **Die Geschaeftsfuehrung** — persoenliche Haftung bei DSGVO/NIS2-Verstoessen - **Der Plattform-Anbieter** — wenn die Software den Eindruck erweckt, Compliance sei nachgewiesen, obwohl sie nur Platzhalter anzeigt ### Die 6 Guardrails Die Anti-Fake-Evidence Architektur implementiert 6 Schutzmechanismen: ```mermaid graph TB G1["1. Evidence Confidence Levels
(E0-E4)"] G2["2. Truth-Status Lifecycle
(generated → validated)"] G3["3. Control Status Machine
(pass erfordert Evidence ≥ E2)"] G4["4. Four-Eyes-Prinzip
(GOV/PRIV: 2 unabhaengige Reviewer)"] G5["5. LLM Truth Labels
(may_be_used_as_evidence = false)"] G6["6. Verbotene Formulierungen
(keine Claims ohne Nachweis)"] G1 --> G3 G2 --> G3 G4 --> G3 G5 --> G1 G3 --> G6 style G1 fill:#fee2e2,stroke:#dc2626 style G2 fill:#fef3c7,stroke:#d97706 style G3 fill:#dbeafe,stroke:#2563eb style G4 fill:#d1fae5,stroke:#059669 style G5 fill:#e0e7ff,stroke:#4f46e5 style G6 fill:#fce7f3,stroke:#db2777 ``` **Zusammenspiel:** Ein Control kann nur auf "pass" stehen, wenn mindestens ein Evidence mit Confidence >= E2 vorliegt, dessen Truth-Status validiert ist. Bei GOV/PRIV-Controls muessen zwei verschiedene Personen den Evidence reviewt haben (Four-Eyes). LLM-generierte Inhalte koennen nie als Evidence zaehlen. --- ## Zusammenspiel mit evidence_type Das [evidence_type Feld](evidence-type.md) (code/process/hybrid) bestimmt, **wie** Evidence gesammelt wird. Das Anti-Fake-Evidence System bestimmt, **ob** die gesammelte Evidence valide ist: | evidence_type | Typische Evidence-Quelle | Confidence | Automatisierbar? | |---|---|---|---| | `code` | SAST-Report, CI/CD-Pipeline, IaC-Scan | E3 (observed) | Ja — System-beobachtet | | `process` | Policy-Dokument, Schulungsnachweis, Vertrag | E1 (uploaded) → E2 (reviewed) | Nein — Review noetig | | `hybrid` | Code-Scan + Prozess-Doku | E1-E3 gemischt | Teilweise | !!! warning "Code Controls sind nicht automatisch valide" Auch ein SAST-Report (E3) muss einen validen Truth-Status haben. Ein veralteter Scan (> 90 Tage) wird als "stale" markiert und reduziert die Evidence Freshness im Dashboard-Score. --- ## Evidence Confidence Levels (E0–E4) | Level | Bezeichnung | Beschreibung | Beispiel | |-------|-------------|--------------|----------| | **E0** | Generated | LLM-Output, Platzhalter | KI-generierter Nachweis-Entwurf | | **E1** | Uploaded | Manuell hochgeladen, ungeprüft | PDF ohne Reviewer | | **E2** | Reviewed | Intern geprüft, Hash verifiziert | Dokument von Compliance-Beauftragtem bestätigt | | **E3** | Observed | System-beobachtet (CI/CD, API) | Automatischer SAST-Report mit SHA-256 | | **E4** | Auditor-validated | Extern validiert | Wirtschaftsprüfer hat akzeptiert | ### Auto-Klassifikation | Source | Confidence | Truth Status | |--------|-----------|--------------| | `ci_pipeline` | E3 | observed | | `api` (mit Hash) | E3 | observed | | `manual` / `upload` | E1 | uploaded | | `generated` | E0 | generated | --- ## Evidence Truth-Status Lifecycle ```mermaid stateDiagram-v2 [*] --> generated : LLM erzeugt [*] --> uploaded : Manuell hochgeladen [*] --> observed : CI/CD Pipeline generated --> rejected : Review abgelehnt uploaded --> validated_internal : Intern geprueft uploaded --> rejected : Review abgelehnt observed --> validated_internal : Intern bestaetigt validated_internal --> provided_to_auditor : An Auditor uebergeben provided_to_auditor --> accepted_by_auditor : Auditor akzeptiert provided_to_auditor --> rejected : Auditor lehnt ab ``` --- ## Control Status-Transition State Machine ```mermaid stateDiagram-v2 planned --> in_progress : immer erlaubt in_progress --> pass : Evidence >= E2 + truth_status valid in_progress --> partial : min 1 Evidence (beliebig) in_progress --> fail : immer erlaubt pass --> fail : Degradation (immer) partial --> pass : Evidence >= E2 + truth_status valid note right of pass Voraussetzung: min 1 Evidence mit confidence >= E2 UND truth_status in (uploaded, observed, validated_internal, accepted_by_auditor) end note ``` ### Transition-Regeln | Von | Nach | Voraussetzung | |-----|------|---------------| | planned | in_progress | keine | | in_progress | pass | min 1 Evidence mit confidence >= E2, truth_status valide | | in_progress | partial | min 1 Evidence (beliebig) | | in_progress | fail | immer erlaubt | | pass | fail | immer erlaubt (Degradation) | | * | n/a | erfordert `status_justification` | | * | planned | immer erlaubt (Reset) | Bei Verstoß: **HTTP 409 Conflict** mit Liste der Violations. --- ## LLM Truth-Labels Jeder LLM-generierte Inhalt wird mit einem Truth-Label versehen: ```json { "generation_mode": "draft_assistance", "truth_status": "generated", "may_be_used_as_evidence": false, "generated_by": "system" } ``` ### Audit-Trail Tabelle `compliance_llm_generation_audit`: | Feld | Typ | Beschreibung | |------|-----|--------------| | entity_type | VARCHAR(50) | 'evidence', 'control', 'document' | | entity_id | VARCHAR(36) | FK zur generierten Entitaet | | generation_mode | VARCHAR(100) | 'draft_assistance', 'auto_generation' | | truth_status | ENUM | generated, uploaded, ... | | may_be_used_as_evidence | BOOLEAN | Default: FALSE | | llm_model | VARCHAR(100) | z.B. 'qwen2.5vl:32b' | | llm_provider | VARCHAR(50) | 'ollama', 'anthropic' | | prompt_hash | VARCHAR(64) | SHA-256 des Prompts | --- ## Multi-dimensionaler Compliance-Score Statt einer einzelnen Prozentzahl zeigt der Score 6 Dimensionen: | Dimension | Gewicht | Beschreibung | |-----------|---------|--------------| | requirement_coverage | 20% | % Requirements mit verlinktem Control | | evidence_strength | 25% | Gewichteter Durchschnitt der Evidence-Confidence | | validation_quality | 20% | % Evidence mit truth_status >= validated_internal | | evidence_freshness | 10% | % Evidence nicht expired + reviewed < 90 Tage | | control_effectiveness | 25% | Bestehende Formel (pass + partial*0.5) | | **overall_readiness** | — | Gewichteter Composite der 5 Dimensionen | ### Hard Blocks Zusaetzlich werden **Sperrgründe** angezeigt, die eine Audit-Readiness verhindern: - Controls auf 'pass' ohne jegliche Evidence - Controls auf 'pass' mit nur E0/E1-Evidence (keine Validierung) --- ## Verbotene Formulierungen Der Drafting-Engine Validator prueft auf Formulierungen, die **ohne ausreichenden Nachweis** nicht verwendet werden duerfen: | Verboten | Sicher stattdessen | |----------|--------------------| | "ist compliant" | "soll compliant sein" | | "erfuellt vollstaendig" | "soll vollstaendig erfuellt werden" | | "wurde geprueft" | "soll geprueft werden" | | "wurde umgesetzt" | "ist zur Umsetzung vorgesehen" | | "ist auditiert" | "soll auditiert werden" | | "vollstaendig implementiert" | "Implementierung ist vorgesehen" | | "nachweislich konform" | "Konformitaet ist nachzuweisen" | **Erlaubt nur wenn:** control_status = pass AND confidence >= E2 AND truth_status in (validated_internal, accepted_by_auditor). --- ## API-Aenderungen ### Neue Endpoints | Methode | Pfad | Beschreibung | |---------|------|--------------| | PATCH | `/evidence/{id}/review` | Evidence reviewen (Confidence upgraden) | | POST | `/llm-audit` | LLM-Generierungs-Audit erstellen | | GET | `/llm-audit` | LLM-Audit-Eintraege auflisten | ### Erweiterte Responses **EvidenceResponse** — 6 neue Felder: ```json { "confidence_level": "E3", "truth_status": "observed", "generation_mode": null, "may_be_used_as_evidence": true, "reviewed_by": null, "reviewed_at": null } ``` **DashboardResponse** — neues Feld `multi_score`: ```json { "multi_score": { "requirement_coverage": 85.0, "evidence_strength": 60.0, "validation_quality": 40.0, "evidence_freshness": 90.0, "control_effectiveness": 70.0, "overall_readiness": 65.0, "hard_blocks": ["3 Controls auf 'pass' haben nur E0/E1-Evidence"] } } ``` **ControlResponse** — neues Feld `status_justification`. **ControlUpdate** — neues Feld `status_justification` (Pflicht fuer n/a-Transitions). ### Status-Transition Fehler (409) ```json { "detail": { "error": "Status transition not allowed", "current_status": "in_progress", "requested_status": "pass", "violations": [ "Transition to 'pass' requires at least 1 evidence with confidence >= E2..." ] } } ``` --- ## Migration ### Phase 1 **Datei:** `backend-compliance/migrations/076_anti_fake_evidence.sql` - Neue ENUM-Typen: `evidence_confidence_level`, `evidence_truth_status` - 6 neue Spalten auf `compliance_evidence` - `in_progress` Wert fuer `controlstatusenum` - `status_justification` auf `compliance_controls` - Neue Tabelle `compliance_llm_generation_audit` - Backfill bestehender Evidence nach Source - Indizes auf neue Spalten ### Phase 2 **Datei:** `backend-compliance/migrations/077_anti_fake_evidence_phase2.sql` - Neue Tabelle `compliance_assertions` (Assertion Engine) - 6 neue Spalten auf `compliance_evidence` (Four-Eyes: approval_status, first_reviewer, etc.) - Performance-Index auf `compliance_audit_trail (entity_type, action, performed_at)` --- ## Phase 2: UI-Badges Badges werden auf Evidence-Cards angezeigt und zeigen den Vertrauensstatus auf einen Blick: | Badge | Farben | Anzeige | |-------|--------|---------| | **ConfidenceLevelBadge** | E0=rot, E1=gelb, E2=blau, E3=gruen, E4=emerald | Immer | | **TruthStatusBadge** | generated=violet, uploaded=grau, observed=blau, validated=gruen, rejected=rot | Immer | | **GenerationModeBadge** | violet + Sparkles-Icon | Wenn LLM-generiert | | **ApprovalStatusBadge** | pending=gelb, first_approved=blau, approved=gruen, rejected=rot | Nur bei Four-Eyes | --- ## Phase 2: Assertion Engine Die Assertion Engine trennt **Behauptungen** von **Fakten** in Compliance-Texten. ```mermaid flowchart LR Text[Freitext] --> Split[Satz-Splitting] Split --> Classify{Normativ?} Classify -->|Pflicht| A[Assertion pflicht] Classify -->|Empfehlung| B[Assertion empfehlung] Classify -->|Kann| C[Assertion kann] Classify -->|Begruendung| D[Rationale] Classify -->|Evidence-Keywords| E[Fact tentativ] E --> Verify[Manuell verifizieren] Verify --> Fact[Verified Fact] ``` ### Assertion-Typen | Typ | Bedeutung | Beispiel | |-----|-----------|----------| | **assertion** | Normative Aussage (unbewiesen) | "Die Organisation muss ein ISMS implementieren" | | **fact** | Verifizierte Tatsache | "ISO-Zertifikat Nr. 12345 liegt vor" | | **rationale** | Begruendung | "Dies ist notwendig, weil..." | ### Normative Tiers | Tier | Signal-Woerter | |------|---------------| | **pflicht** | muss, hat sicherzustellen, ist verpflichtet, shall, must, required | | **empfehlung** | soll, sollte, gewaehrleisten, should, ensure | | **kann** | kann, darf, may, optional | --- ## Phase 2: Four-Eyes-Prinzip ```mermaid stateDiagram-v2 [*] --> pending_first : Evidence erstellt (Gov/Priv Domain) pending_first --> first_approved : 1. Reviewer OK first_approved --> approved : 2. Reviewer OK (andere Person!) first_approved --> rejected : 2. Reviewer lehnt ab pending_first --> rejected : 1. Reviewer lehnt ab note right of first_approved Zweiter Reviewer MUSS eine andere Person sein als der erste Reviewer end note ``` ### Domains mit Four-Eyes-Pflicht | Domain | Four-Eyes? | Begruendung | |--------|-----------|-------------| | `gov` | Ja | Governance-Controls sind audit-kritisch | | `priv` | Ja | Datenschutz erfordert unabhaengige Pruefung | | `ops`, `sdlc`, `ai`, ... | Nein | Operationale Controls mit Single-Review | --- ## Phase 2: Audit-Trail-Erweiterung Neue Audit-Trail-Eintraege: | Entity | Action | Wann | |--------|--------|------| | evidence | create | Bei Evidence-Erstellung | | evidence | review | Bei Confidence/Truth-Status-Aenderung | | evidence | reject | Bei Evidence-Ablehnung | | control | status_change | Bei Control-Status-Aenderung | Jeder Eintrag enthaelt `old_value`, `new_value` und einen SHA-256 `checksum`. Neuer Query-Endpoint: `GET /audit-trail?entity_type=evidence&entity_id={id}` --- ## Phase 2: Neue API-Endpoints | Methode | Pfad | Beschreibung | |---------|------|--------------| | PATCH | `/evidence/{id}/reject` | Evidence ablehnen | | GET | `/audit-trail` | Audit-Trail abfragen (Filter: entity_type, entity_id, action) | | POST | `/assertions` | Assertion manuell erstellen | | GET | `/assertions` | Assertions auflisten (Filter: entity_type, entity_id, assertion_type) | | GET | `/assertions/{id}` | Assertion Detail | | PUT | `/assertions/{id}` | Assertion aktualisieren | | POST | `/assertions/{id}/verify` | Als Fakt markieren | | POST | `/assertions/extract` | Automatische Extraktion aus Freitext | | GET | `/assertions/summary` | Stats (total, facts, rationale, unverified) | ### Erweiterte EvidenceResponse (Phase 2) ```json { "approval_status": "first_approved", "first_reviewer": "reviewer1@example.com", "first_reviewed_at": "2026-03-23T14:00:00Z", "second_reviewer": null, "second_reviewed_at": null, "requires_four_eyes": true } ``` --- ## Phase 3: Durchsetzung (UI + Dashboard) Phase 3 macht das Anti-Fake-Evidence-System **benutzbar und durchsetzbar** im Frontend. ### Evidence Review/Reject UI Die Evidence-Seite bietet jetzt direkte Buttons fuer Review und Ablehnung: - **Reviewen-Button**: Sichtbar wenn `approvalStatus` nicht `approved` oder `rejected` - **Ablehnen-Button**: Sichtbar bei Four-Eyes-Evidence die noch nicht abgeschlossen ist **ReviewModal** erlaubt: - Confidence-Level aendern (E0-E4 Dropdown) - Truth-Status aendern (Dropdown) - Reviewer E-Mail angeben - Four-Eyes-Warnung wenn noch ein weiterer Review noetig ist **RejectModal** erlaubt: - Ablehnungsgrund als Freitext - Reviewer E-Mail angeben Bei Four-Eyes Same-Person-Fehler (HTTP 400) wird eine Fehlermeldung angezeigt. ### Control Status-Transition Fehlerbehandlung Die Controls-Seite zeigt jetzt detaillierte Fehler bei blockierten Status-Transitionen: - **Optimistic Update mit Rollback**: UI aktualisiert sofort, rollt bei Fehler zurueck - **TransitionErrorBanner**: Zeigt Violations-Liste bei HTTP 409 Conflict - z.B. "Transition to 'pass' requires at least 1 evidence with confidence >= E2" - **Link zur Evidence-Seite**: "Evidence hinzufuegen" direkt im Fehler-Banner ### Evidence Audit-Trail Anzeige Neuer "Historie"-Button auf jeder Evidence-Card zeigt den vollstaendigen Audit-Trail: - Timeline mit Zeitstempel, Aktion und Akteur - Details zu Feldaenderungen (old_value → new_value) - Lazy-Loading: Erst beim Aufklappen wird `GET /audit-trail` abgerufen ### Evidence Confidence-Filter Neue Filter-Pills auf der Evidence-Seite: ``` [Alle] [Gueltig] [Abgelaufen] [Ausstehend] | [E0] [E1] [E2] [E3] [E4] ``` Farbcodierung: E0=rot, E1=gelb, E2=blau, E3=gruen, E4=emerald (passend zu den Badges) ### Evidence Confidence-Verteilung (Dashboard) Neuer Endpoint und Dashboard-Bereich: **Endpoint:** `GET /dashboard/evidence-distribution` ```json { "by_confidence": {"E0": 2, "E1": 5, "E2": 3, "E3": 8, "E4": 1}, "four_eyes_pending": 3, "total": 19 } ``` **Compliance Hub** zeigt: - Horizontal gestapelter Balken der Confidence-Verteilung (E0 rot → E4 emerald) - Multi-Score Dimensionen als Fortschrittsbalken (5 Dimensionen + Audit-Readiness) - Four-Eyes-Warteschlange (Anzahl pending) - Hard-Blocks-Liste oder "Keine Hard Blocks" Status ### Assertions-Seite Neue Seite unter `/sdk/assertions` mit 3 Tabs: | Tab | Inhalt | |-----|--------| | **Uebersicht** | Summary-Stats (Assertions, Facts, Rationale, Unverified) | | **Assertion-Liste** | Filterbarer Tabelle (entity_type, assertion_type) mit AssertionCards | | **Extraktion** | Textfeld + Button → `POST /assertions/extract` | **AssertionCard** zeigt: - Normative-Tier als farbiger Badge (Pflicht=rot, Empfehlung=gelb, Kann=blau) - Typ-Badge (Assertion/Fact/Rationale) - "Als Fakt pruefen"-Button → `POST /assertions/{id}/verify` ### Phase 3: Neue API-Endpoints | Methode | Pfad | Beschreibung | |---------|------|--------------| | GET | `/dashboard/evidence-distribution` | Evidence-Verteilung nach Confidence + Four-Eyes-Status | --- ## Sicherheitsarchitektur im Detail ### Warum E0-E4 und nicht einfach "valide/invalide"? Ein binaeres System ("valide" vs. "invalide") haette ein fundamentales Problem: Wo zieht man die Grenze? Ein manuell hochgeladenes PDF ist "besser" als ein LLM-Entwurf, aber "schlechter" als ein automatischer SAST-Report. Die 5-stufige Skala erlaubt: 1. **Graduelle Verbesserung**: Ein Kunde kann mit E1-Evidence starten und schrittweise auf E3/E4 aufruesten 2. **Risiko-basierte Entscheidungen**: Ein Auditor sieht sofort, welche Controls nur auf schwacher Evidence basieren 3. **Automatische Schwellwerte**: Das System blockiert "pass" unterhalb E2, aber zeigt auch E1-Evidence (mit Warnung) ```mermaid graph LR E0["E0
Generated
❌ Kein Nachweis"] E1["E1
Uploaded
⚠️ Ungeprüft"] E2["E2
Reviewed
✓ Intern geprüft"] E3["E3
Observed
✓✓ System-beobachtet"] E4["E4
Auditor
✓✓✓ Extern validiert"] E0 --> E1 --> E2 --> E3 --> E4 style E0 fill:#fee2e2,stroke:#dc2626 style E1 fill:#fef3c7,stroke:#d97706 style E2 fill:#dbeafe,stroke:#2563eb style E3 fill:#d1fae5,stroke:#059669 style E4 fill:#d1fae5,stroke:#047857 ``` ### Confidence-Gewichtung im Score | Level | Gewicht | Bedeutung | |---|---|---| | E0 | 0.00 | Zaehlt nicht als Evidence | | E1 | 0.25 | Minimal — ungepruefte Uploads | | E2 | 0.50 | Schwelle fuer "pass"-Status | | E3 | 0.75 | Stark — system-verifiziert | | E4 | 1.00 | Perfekt — extern validiert | ### Warum Four-Eyes nur fuer GOV und PRIV? Das Four-Eyes-Prinzip erhoert den Aufwand erheblich (jedes Evidence braucht zwei verschiedene Reviewer). Deshalb wird es gezielt nur fuer Domains eingesetzt, bei denen Manipulation besonders gefaehrlich ist: | Domain | Four-Eyes | Begruendung | |---|---|---| | **GOV** (Governance) | Ja | Governance-Controls definieren das Compliance-Framework selbst. Wenn hier manipuliert wird, ist alles darunter wertlos. | | **PRIV** (Datenschutz) | Ja | DSGVO-Nachweise sind rechtlich bindend. Falsche Nachweise koennen zu Bussgeldern fuehren. | | SEC, AUTH, NET, ... | Nein | Technische Controls sind oft automatisch pruefbar (E3). Der Aufwand von Four-Eyes waere unverhältnismäßig. | ### Same-Person-Schutz ```python # Der zweite Reviewer MUSS eine andere Person sein: if review.reviewed_by == evidence.first_reviewer: raise HTTPException( status_code=400, detail="Four-Eyes: second reviewer must be different from first reviewer" ) ``` Dies verhindert, dass eine einzelne Person ein Evidence "durchwinkt". Der Schutz ist auf DB-Ebene durchgesetzt — nicht nur im Frontend. --- ## Hard Blocks — Audit-Sperren Hard Blocks sind **absolute Sperren**, die eine Audit-Readiness verhindern. Sie werden im Dashboard prominent rot angezeigt. ### Block 1: Controls auf "pass" ohne Evidence ```sql -- Controls die "pass" oder "partial" sind, aber keine Evidence haben SELECT control_id FROM compliance_controls WHERE status IN ('pass', 'partial') AND id NOT IN (SELECT control_id FROM compliance_evidence) ``` **Warum kritisch:** Ein Control auf "pass" ohne jeden Nachweis ist die Definition von Compliance-Theater. Der Auditor wird sofort fragen: "Wo ist der Nachweis?" ### Block 2: Controls auf "pass" mit nur E0/E1-Evidence ```sql -- Controls auf "pass" deren beste Evidence nur E0 oder E1 ist SELECT c.control_id FROM compliance_controls c JOIN compliance_evidence e ON e.control_id = c.id WHERE c.status = 'pass' GROUP BY c.control_id HAVING MAX(CASE WHEN e.confidence_level = 'E4' THEN 4 WHEN e.confidence_level = 'E3' THEN 3 WHEN e.confidence_level = 'E2' THEN 2 WHEN e.confidence_level = 'E1' THEN 1 ELSE 0 END) < 2 -- Nur E0 oder E1 ``` **Warum kritisch:** Ein LLM-generierter Text (E0) oder ein ungeprüeftes Upload (E1) reicht nicht aus, um Compliance zu behaupten. Mindestens ein intern geprüeftes Dokument (E2) ist erforderlich. --- ## Datenbank-Schema (Komplett) ### ENUM-Typen ```sql CREATE TYPE evidence_confidence_level AS ENUM ( 'E0', -- Generated / kein echter Nachweis 'E1', -- Hochgeladen, ungeprüeft 'E2', -- Intern geprüeft, Hash verifiziert 'E3', -- System-beobachtet (CI/CD, API mit Hash) 'E4' -- Extern validiert (Auditor) ); CREATE TYPE evidence_truth_status AS ENUM ( 'generated', -- LLM/System-generiert 'uploaded', -- Manuell hochgeladen 'observed', -- Automatisch beobachtet 'validated_internal', -- Intern geprüeft + bestätigt 'rejected', -- Abgelehnt 'provided_to_auditor', -- An Auditor üebergeben 'accepted_by_auditor' -- Auditor hat akzeptiert ); ``` ### compliance_evidence — Erweiterte Spalten | Spalte | Typ | Default | Beschreibung | |---|---|---|---| | confidence_level | ENUM | E1 | Vertrauensstufe (E0-E4) | | truth_status | ENUM | uploaded | Wahrheitsstatus | | generation_mode | VARCHAR(100) | NULL | 'draft_assistance', 'auto_generation' | | may_be_used_as_evidence | BOOLEAN | TRUE | FALSE fuer LLM-Output | | reviewed_by | VARCHAR(200) | NULL | Reviewer E-Mail | | reviewed_at | TIMESTAMPTZ | NULL | Zeitpunkt des Reviews | | approval_status | VARCHAR(30) | 'none' | Four-Eyes Status | | first_reviewer | VARCHAR(200) | NULL | Erster Reviewer | | first_reviewed_at | TIMESTAMPTZ | NULL | Zeitpunkt erster Review | | second_reviewer | VARCHAR(200) | NULL | Zweiter Reviewer (muss anders sein!) | | second_reviewed_at | TIMESTAMPTZ | NULL | Zeitpunkt zweiter Review | | requires_four_eyes | BOOLEAN | FALSE | Ob Four-Eyes-Pflicht besteht | ### compliance_llm_generation_audit Jeder LLM-generierte Inhalt wird in dieser Tabelle protokolliert: | Spalte | Typ | Beschreibung | |---|---|---| | id | VARCHAR(36) | PK | | tenant_id | VARCHAR(36) | Mandant | | entity_type | VARCHAR(50) | 'evidence', 'control', 'document' | | entity_id | VARCHAR(36) | FK zur generierten Entitaet | | generation_mode | VARCHAR(100) | 'draft_assistance', 'auto_generation' | | truth_status | ENUM | Default: 'generated' | | may_be_used_as_evidence | BOOLEAN | Default: FALSE | | llm_model | VARCHAR(100) | z.B. 'qwen3:30b-a3b' | | llm_provider | VARCHAR(50) | 'ollama', 'anthropic' | | prompt_hash | VARCHAR(64) | SHA-256 des Prompts | | input_summary | TEXT | Zusammenfassung des Inputs | | output_summary | TEXT | Zusammenfassung des Outputs | ### compliance_assertions Die Assertion Engine trennt Behauptungen von Fakten: | Spalte | Typ | Beschreibung | |---|---|---| | id | VARCHAR(36) | PK | | tenant_id | VARCHAR(36) | Mandant | | entity_type | VARCHAR(50) | 'control', 'evidence', 'document', 'obligation' | | entity_id | VARCHAR(36) | FK zur Entitaet | | sentence_text | TEXT | Originalsatz | | sentence_index | INTEGER | Position im Text | | assertion_type | VARCHAR(20) | 'assertion', 'fact', 'rationale' | | evidence_ids | JSONB | Verlinkte Evidence-IDs | | confidence | FLOAT | 0.0-1.0 Konfidenz | | normative_tier | VARCHAR(20) | 'pflicht', 'empfehlung', 'kann' | | verified_by | VARCHAR(200) | Verifizierer | | verified_at | TIMESTAMPTZ | Zeitpunkt der Verifikation | --- ## Vollstaendige API-Referenz ### Evidence-Endpoints | Methode | Pfad | Beschreibung | Auth | |---|---|---|---| | GET | `/evidence` | Evidence auflisten (mit Filtern) | Tenant | | POST | `/evidence` | Neues Evidence erstellen | Tenant | | DELETE | `/evidence/{id}` | Evidence loeschen | Tenant | | POST | `/evidence/upload` | Evidence-Datei hochladen | Tenant | | POST | `/evidence/collect` | CI/CD Evidence sammeln (automatisch) | API-Key | | GET | `/evidence/ci-status` | CI/CD Evidence Statusuebersicht | Tenant | | **PATCH** | **`/evidence/{id}/review`** | **Evidence reviewen (Four-Eyes)** | Tenant | | **PATCH** | **`/evidence/{id}/reject`** | **Evidence ablehnen** | Tenant | ### Audit-Trail-Endpoints | Methode | Pfad | Beschreibung | |---|---|---| | GET | `/audit-trail` | Audit-Trail abfragen (entity_type, entity_id, action) | ### Assertion-Endpoints | Methode | Pfad | Beschreibung | |---|---|---| | POST | `/assertions` | Assertion manuell erstellen | | GET | `/assertions` | Assertions auflisten | | GET | `/assertions/{id}` | Assertion Detail | | PUT | `/assertions/{id}` | Assertion aktualisieren | | POST | `/assertions/{id}/verify` | Als Fakt markieren | | POST | `/assertions/extract` | Automatische Extraktion aus Freitext | | GET | `/assertions/summary` | Stats (total, facts, rationale, unverified) | ### LLM-Audit-Endpoints | Methode | Pfad | Beschreibung | |---|---|---| | POST | `/llm-audit` | LLM-Generierungs-Audit erstellen | | GET | `/llm-audit` | LLM-Audit-Eintraege auflisten | ### Dashboard-Endpoints | Methode | Pfad | Beschreibung | |---|---|---| | GET | `/dashboard/evidence-distribution` | Confidence-Verteilung + Four-Eyes-Status | --- ## Haeufige Fragen ### Kann ich E0-Evidence loeschen? Ja, aber es bleibt ein Eintrag in `compliance_llm_generation_audit`. Das stellt sicher, dass die Generierung nachvollziehbar ist, auch wenn der LLM-Output geloescht wurde. ### Was passiert, wenn der erste Reviewer nicht verfuegbar ist? Das Four-Eyes-System hat keinen Timeout. Der erste Review bleibt als `first_approved` gespeichert, bis ein zweiter Reviewer die Evidence prueft. Das ist bewusst so — Compliance-Nachweise sollten nicht durch Zeitdruck kompromittiert werden. ### Kann ein Admin das Four-Eyes-Prinzip umgehen? Nein. Der Same-Person-Check ist auf Backend-Ebene implementiert (HTTP 400 bei gleichem Reviewer). Es gibt keine Admin-Bypass-Option. Dies ist ein bewusstes Design-Prinzip: Wenn selbst der Admin das System umgehen koennte, waere die gesamte Integritaet gefaehrdet. ### Wie funktioniert die Assertion-Extraktion? Der Endpoint `POST /assertions/extract` nimmt einen Freitext und: 1. **Satz-Splitting**: Teilt den Text an `.!?` gefolgt von Grossbuchstaben 2. **Klassifikation**: Prueft jeden Satz auf normative Signal-Woerter 3. **Normative Tiers**: "muss/shall/must" → pflicht, "soll/should" → empfehlung, "kann/may" → kann 4. **Evidence-Keywords**: Woerter wie "liegt vor", "wurde geprueft" → als tentative Fakten markiert 5. **Ergebnis**: Liste von Assertions mit Typ und Normative-Tier ### Was ist der Unterschied zwischen Truth-Status und Confidence? - **Confidence** (E0-E4) sagt: Wie vertrauenswuerdig ist die **Quelle**? (LLM < Upload < Review < CI/CD < Auditor) - **Truth-Status** sagt: In welchem **Lifecycle-Zustand** ist der Nachweis? (generated → uploaded → validated → accepted_by_auditor) Ein E3-Evidence (CI/CD) kann Truth-Status "observed" haben und ist damit sofort verwendbar. Ein E1-Evidence (Upload) muss erst "validated_internal" werden.