Kansho/docs/architecture/technical/privacy_gateway.md
2026-08-25 13:57:23 +02:00

162 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: "Kanshō Privacy Gateway und AI-Egress"
version: "0.1"
status: "Arbeitsstand"
date: "2026-08-19"
product_family: "Jinkendo"
document_role: "Technical Chapter / Privacy Gateway / Egress"
parent_document: "technische_zielarchitektur.md"
---
# Kanshō Privacy Gateway und AI-Egress
Technische Abbildung der fachlichen Guardrails. Kanonisches Fachhome: `../functional/guardrails.md` (inkl. Root Cause §2, Datenklassen §5, Gateway §6, Entscheidungsstand §22). Dieses Kapitel dupliziert die Herleitung nicht.
**Rang:** Datenschutz und Guardrails sind im Fachkonzept **grundlegend und entschieden**. Sie stehen nicht auf derselben Ebene wie unfertige Dialog- oder MVP-Schnitte. Offene Punkte betreffen Verfahren und rechtliche Ausprägung (Entity Detection, Encryption at rest, DSFA), nicht die Invariante selbst.
## 1. Invariante
> Identität bleibt lokal. Externe Intelligenz erhält nur den für die Aufgabe notwendigen, minimierten und soweit sinnvoll pseudonymisierten Kontext.
Herkunft: `guardrails.md` §2.4; querschnittlich in der fachlichen Zielarchitektur. Providerunabhängig: OpenRouter ist Kandidat, kein Ersatz für das lokale Gateway. OpenRouter-eigene Guardrail-Features ergänzen höchstens, sie ersetzen die Kanshō-Schicht nicht.
Pseudonymisierung ist keine Anonymisierung. Kanshō behauptet keine vollständige Anonymität nach außen.
Persönlicher Kontext wird **nie** direkt aus UI, Dialog-Router, Prompt-Engine oder Admin-Preview an OpenRouter, Provider oder Tools gesendet. Die Engine darf den Provider nur über den Gateway-Callback erreichen (`platform_extensibility.md`).
### 1.1 Guardrail-Vorrang
Fachlich §19: Guardrails haben Vorrang vor Modellqualität, Kosten, Latenz, Komfort und automatischem Provider-Fallback. Eine Anfrage wird abgelehnt oder degradiert, wenn die Policy nicht erfüllbar ist. Administrierbare Prompts, Workflows oder Feature-Flags dürfen das Gateway nicht abschalten.
## 2. Trust Zones
| Zone | Inhalt | Egress |
|---|---|---|
| Local Trusted Zone | Identity Mapping, Klarnamen, Secrets, volle Primärquellen, Obsidian-Pfade | kein Roh-Egress |
| External AI Zone | External Model Context (Klasse B) | nur nach Policy-Check, ZDR |
| Tool-/Plugin-Zone | Suche, Plugins, Speech | eigene Policy, nicht implizit mit LLM-Freigabe |
## 3. Datenklassen
- **A Local Only:** Mapping, Secrets, vollständige Identität, interne IDs soweit identifizierend. Verlassen die Trusted Zone nicht.
- **B Pseudonymized AI Context:** Normalfall persönlicher Dialoge. Stabile, nicht sprechende Platzhalter (`[[SELF]]`, `[[PERSON:PARTNER]]`). Minimierung zusätzlich zur Maskierung.
- **C Low-Identity:** generische, nicht-personalisierte Inhalte; schwächere Transformation zulässig, eigene Policy bleibt nötig.
Quasi-Identifikatoren (Beruf+Ort+Familie) sind fachlich erkannt; die Bewertungsmethode ist offen, der Gateway-Auftrag „nicht nur Klarnamen“ gilt trotzdem.
## 4. Pflichtpipeline
Jeder persönliche Modellaufruf durchläuft lokal:
1. Context Minimization
2. Entity Detection
3. Pseudonymization
4. Policy Check
5. Provider/Endpoint Eligibility (ZDR, kein Training, kein Prompt-Logging)
6. Egress Validation
7. Response Validation
8. Local Rehydration / Demasking
9. Audit Metadata (ohne volle Prompts)
10. Fail Closed
Fail Closed: kein stillschweigender Fallback auf einen weniger geschützten Provider.
LLM-Egress und Tool-/Web-/Transkriptions-Egress sind getrennte Policies. Ein für ZDR-LLM freigegebener Kontext darf nicht automatisch an Web Search oder Speech-Cloud.
## 5. Internal vs. External Context
Der Context Builder darf intern mit Klaridentität arbeiten. Vor dem Socket nach außen existiert eine zweite Repräsentation ohne Mapping-Tabelle.
Demasking ausschließlich in der Trusted Zone, nach Validierung (Platzhalter erhalten, keine erratenen Klarnamen, keine Policy-Verstöße).
## 6. Audit
Speichern: Request-ID, Zeit, Policy, Provider-/Modellkennung, ZDR-/Region-Status, Typ maskierter Entitäten, Prüf- und Fallback-Status.
Nicht speichern: volle Prompts, volle Antworten, echte Namen, Mapping.
Admin-Sichtbarkeit der Mapping-Tabelle nur für besonders berechtigte Rollen (`admin_diagnostics.md`).
## 7. Beziehung zu anderen Kapiteln
- Resurfacing darf keinen breiteren Egress rechtfertigen als der aktuelle Task braucht.
- Re-Grounding läuft lokal und erzeugt danach erneut einen minimierten External Context.
- Voice/Transkription: eigener Egress-Typ (`voice_and_media.md`).
- Lived Experience / Re-Grounding: volle Primärquellen bleiben lokal; externes Modell bekommt erneut nur Klasse B.
- Prompt-Engine: Preview ohne LLM ist erlaubt; Debug-Ausgaben an den Admin ohne Klasse-A-Klartext und ohne Mapping.
## 8. Was Phase H noch offen lässt
Interview H1 (Encryption at rest, vollständiges Löschen, Portabilität, DSFA bei späterem Mehrbenutzerbetrieb) ergänzt diese Invariante, ersetzt sie nicht. Privacy Profiles (Strict / Balanced / Low-Identity) sind fachlich perspektivisch; Default muss die Invariante erfüllen.
## 9. Entscheidungsstand
| Thema | Stand | Status |
|---|---|---|
| Privacy Gateway vor persönlichem Egress | zwingend, nicht abschaltbar | entschieden |
| Guardrails vor Qualität/Kosten/Latenz | ja | entschieden (fachlich) |
| Providerunabhängige Guardrails | ja | entschieden (fachlich) |
| ZDR / kein Training / kein Prompt-Log | persönliche Kontexte | entschieden bzw. bevorzugte verbindliche Policy |
| Fail Closed | ja | bevorzugte Richtung |
| Keine Anonymitätsbehauptung | Pseudonymisierung | entschieden (fachlich) |
| OpenRouter | Kandidat, nicht Gateway-Ersatz | entschieden |
| EU-Routing | bevorzugt | offen in Ausprägung |
| Encryption at rest, Delete, DSFA | Phase H | offen |
| Implementierung Entity Detection | Wörterbuch + optionaler Detect-Provider; Qualität offen | bevorzugte Richtung im Code, nicht abgeschlossen |
## 9.1 Implementierungsstand (MVP-Egress)
**Status: Code vorhanden. Zwei getrennt konfigurierbare Provider.** Fit-Gap und Guardrail-Abstand (Detect-Testphase, Security Layer): `../functional/mvp_stand_und_abgleich.md`.
`backend/privacy_gateway.py` ist die einzige Stelle für den **generativen** Egress. Reihenfolge: Policy-Check → lokale Wörterbuch-Maskierung mit Wortgrenzen (kein Teilstring, kein `ich` in `nicht`) → Entity Detection nur auf user-Zeilen (Muster + Wörterbuch, in der Testphase zusätzlich OpenRouter-Detect) → Remaskierung: im Dialogzug nur `user:`/`assistant:`-Zeilen, beim Journalentwurf der ganze Prompt → ein Generative-Call nur mit Platzhaltern → Antwortprüfung → Demaskierung.
Detect-Vorschläge werden nur gespeichert, wenn das Wort im user-Text steht, kein Funktions- oder Stoffwort ist und nicht zum Promptvokabular gehört. `mit` plus Allerweltsnomen (`mit Getöse`) ist kein Personenname; `mit Anna` bleibt einer. Bereits gespeicherte unzulässige Labels werden beim nächsten Detect entfernt.
Intern in der Testspur ist keine dritte Anfrage, sondern die lokale Klartext-Vorlage desselben Dialogzugs. Detect und Dialogzug bleiben getrennte Calls.
Pronomen werden nicht als eigene Detect-Treffer gespeichert. Nach der Namensmaskierung bindet eine lokale Schicht **im Dialogzug** in `user:`-Zeilen `er`/`sie`/`ihm`/`ihr` an das letzte kompatible Person-Token, damit das Sprachmodell dieselbe Person sieht. **Beim Journalentwurf bleiben diese Pronomen ungebunden**, sonst macht die Demaskierung aus jedem Bezug den Klarnamen. Anrede-`ihr` und pluralisches `sie` bleiben ungebunden. Dieselbe Person behält ein Token; `PERSON:KURZ` ist kein Mapping. Ein Personenname, der auch eine Sache ist, wird bei Verwandtschaftswort maskiert und bei Verben wie essen/kochen/kaufen davor oder danach als Sache stehen gelassen (`Sushi essen`, `esse Sushi`).
Zwei Provider, getrennt konfigurierbar (`providers.py`, Admin **Schnittstellen**):
Drei Schichten, zwei technische Endpunkte (`provider_settings`-Rollen `generate` / `detect` sind Implementierungsnamen):
- **Maskierung** (Rolle `detect`): nur schützenswerte Muster. Keine Operation, kein Impuls, kein Journaltext. Testphase: OpenRouter-Detect auf user-Zeilen. Produktivziel: Muster + lokales Modell. Wiederverwendbar für spätere Dialogtypen.
- **Sprachmodell** (Rolle `generate`): maskierter Kontext. Dient zwei fachlichen Calls: **Dialogzug** (Operation + Impuls) und **Journalentwurf** (explizit). Das größere Modell gehört hierhin, nicht an die Maskierung.
URL, Modell und Policy liegen in `provider_settings` (Seed `config/providers.seed.json`, Admin `GET/PUT /api/admin/providers`). Keys nur in `backend/.env`, nie in der DB und nie in der API-Antwort. Env überschreibt Admin-Werte, wenn gesetzt.
Lokale URLs (localhost / 127.0.0.1) brauchen keine ZDR-Flags. Die Mapping-Tabelle bleibt Klasse A und lokal; neue Treffer werden dort persistiert, damit der nächste Prompt dieselben Platzhalter per Muster nutzen kann, ohne Detection-Call.
Klasse A verlässt die Zone nicht. Mapping wird nicht mitgeschickt. Kein stiller Fallback auf einen unsicheren Generate-Provider.
Prompts für Dialog, Journal, Detection und Profile-Review liegen in der DB (`mvp.dialogue_turn`, `mvp.journal_generate`, `mvp.entity_detect`, `mvp.profile_review`), nicht im Anwendungscode.
`mvp.dialogue_turn` bleibt ein generativer Call (Foundation: ein Hauptcall pro Turn). Ton, Tiefe und Erzählmodus kommen lokal als `register_hint` plus Writing-Profile-Hinweis in denselben Prompt, nicht als zweites Modell. JSON `{operation, impulse}`. Persistiert wird nur `impulse`.
Admin-Testspur (`trace`) zeigt intern gerenderten Prompt und maskierten Egress. Das ist ein bewusster Test-Einblick, nicht der fachliche Default aus §2 (Diagnose ohne volle Prompts). Mapping-Tabelle bleibt ausgeschlossen.
## 9.2 Offene Implementierungspunkte (Security Layer)
**Status: bewusst offen.** Der MVP-Pfad ist durchgängig, der fachliche Security Layer aus `../functional/guardrails.md` ist **nicht vollständig** implementiert. Für Testdaten akzeptabel; nicht als abgeschlossen führen.
Noch offen im Code:
1. **Inhaltliche Context Minimization.** Es geht der zusammengebaute Dialog, nur durch eine Zeichenkappe begrenzt. Minimum-sufficient-context nach Aufgabe fehlt.
2. **Robuste Entity Detection.** Wörterbuch plus Muster plus Detect-Call. Testphase: externes kleines Modell über OpenRouter. Ziel: lokales Ollama. Keine belastbare Erkennung von Quasi-Identifikatoren (Beruf + Ort + Familie, seltene Konstellationen).
3. **Response Validation.** Es wird nur auf leere Antworten geprüft. Keine Prüfung, ob Platzhalter erhalten blieben oder das Modell Klarnamen erraten hat.
4. **Audit ohne Prompt-Inhalt.** Es gibt keine persistente Audit-Spur (Request-ID, Policy, Provider, ZDR-Status, maskierte Entitätstypen) ohne volle Prompts oder Mapping.
5. **Mapping-Härtung.** `identity_mappings` ist lokal, aber unverschlüsselt; keine Pflege-UI; keine Verschlüsselung at rest.
6. **Detect-Klartext in der Testphase.** Der Detect-Provider darf Klartext sehen. Bei externem Detect (OpenRouter) ist das ein bewusster Übergang, nicht der Zielpfad. Produktiv nur lokales Modell.
7. **Weitere Egress-Klassen.** Tool-, Web- und Speech-Egress bleiben getrennt und ungebaut.
8. **Löschen, Export, DSFA.** Kein Hard-Delete, keine Portabilität, keine Datenschutz-Folgenabschätzung.
Diese Punkte dürfen nicht stillschweigend als erledigt gelten, nur weil Generate bereits maskiert.
## 10. Offene Fragen
Übernommen aus `guardrails.md` §21, hier nicht vorentschieden: Entitätstypen, Quasi-Identifikatoren, Pseudonym-Stabilität, Mehrnutzer-Trennung der Mappings, Verschlüsselung der Mapping-Tabelle, rechtliche DSFA bei Mehrbenutzer-Produktbetrieb.
## 11. Querverweise
- Fachlich: `../functional/guardrails.md`
- Technisch: `ai_architecture.md`, `security.md`, `voice_and_media.md`, `platform_extensibility.md`