172 lines
14 KiB
Markdown
172 lines
14 KiB
Markdown
---
|
||
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-Rekonstruktion, Journal-Narration, Detection und Profile-Review liegen in der DB (`mvp.dialogue_turn`, `mvp.journal_reconstruct`, `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.** Minimale Prüfung: Klartext-Identität in der Rohantwort vor Demask wird blockiert. Dieselbe Homonym-Regel wie beim Maskieren (Speise vs. Person). Dialog-Egress maskiert den **gesamten** gerenderten Prompt (Opening-Hinweis, Space-Ausschnitte, Titel), nicht nur `user:`-Zeilen; Detect sieht denselben gerenderten Prompt. Bei einem Leak gibt es einen Korrekturversuch. Der Dialogzug fällt lokal zurück statt leer zu bleiben. Journal-Generate übernimmt ungültiges oder leckendes Stufe-1-JSON nicht; lokal vollständige Nutzerquellen, Stufe 2 analog mit lokalem Entwurf statt der leckenden Antwort. Keine Quasi-Identifikatoren, keine vollständige Platzhalterprüfung, keine inhaltliche Minimierung.
|
||
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.** Journal-Entries haben Soft Delete, Papierkorb und explizites Purge. Kein vollständiges Account-Löschen, keine Portabilität als öffentliches Produkt, keine Datenschutz-Folgenabschätzung.
|
||
|
||
Diese Punkte dürfen nicht stillschweigend als erledigt gelten, nur weil Generate bereits maskiert.
|
||
|
||
## 9.3 Journal-Budget und Context Compression (2026-08-25)
|
||
|
||
Additiv zu §9.1. Fachliche Trennung Inhalt/Stil: `../functional/writing_profile_and_journaling.md` §16. Technische Umsetzung: `mvp_implementation.md` §16.
|
||
|
||
Persönlicher Journal-Egress bleibt ausschließlich über dieses Gateway. Zwei Zwecke: `journal_reconstruct` dann `journal_generate`. Kein stiller Fallback auf ein anderes Modell. OpenRouter-Context-Compression ist für Journal-Calls ausdrücklich deaktiviert (`plugins.id=context-compression`, `enabled=false`). Diese Plugin-Felder gehen nicht an lokale oder fremde OpenAI-kompatible Endpunkte.
|
||
|
||
Journal-Prompts werden nicht mehr durch `MAX_EGRESS_CHARS` still in der Mitte abgeschnitten. Passt der Tagesdialog nicht ins Budget, bricht Kanshō mit `prompt_budget_exceeded` ab. Stufe 2 erhält den vollständigen lokal rehydrierten Nutzerinhalt als `VerifiedArtifact` (`provenance_verification.md`); bei Übergröße ebenfalls Abbruch, kein stilles Kürzen.
|
||
|
||
Usage-Metadaten (Tokens, Kosten, Fenster, Reserve, Marge, Compression-Status) liegen in der Admin-Testspur `trace.budget` bzw. `trace.stages`. Journal-Generate setzt beide Stufen aus den Rückgabewerten der jeweiligen Gateway-Calls zusammen; es gibt keine globale `debug_history` und keinen globalen Promptspeicher. Vollständige Prompts und Antworten höchstens im direkten Admin-Response des aktuellen Requests. Mapping bleibt ausgeschlossen.
|
||
|
||
## 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`
|