25 KiB
| title | version | status | date | product_family | document_role | parent_document |
|---|---|---|---|---|---|---|
| Kanshō – Privacy Gateway und AI-Egress | 0.1 | Arbeitsstand | 2026-08-19 | Jinkendo | Technical Chapter / Privacy Gateway / Egress | 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:
- Context Minimization
- Entity Detection
- Pseudonymization
- Policy Check
- Provider/Endpoint Eligibility (ZDR, kein Training, kein Prompt-Logging)
- Egress Validation
- Response Validation
- Local Rehydration / Demasking
- Audit Metadata (ohne volle Prompts)
- 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 | Semantische Request-Detection; Detect-Ausgabe nicht auto-persistiert; Qualität des Modells offen | entschieden im Verfahren, Modellqualität unbestätigt |
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. Überholt (2026-08-26): Muster-Fallback, known_labels, automatisches Speichern jedes Detect-Treffers und stilles Abschneiden nach DETECT_MAX_CHARS. Aktuell: §9.5.
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): vollständige semantische Detection des persönlichen Generate-Egress. Keine Operation, kein Impuls, kein Journaltext. Testphase: OpenRouter-Detect darf Klartext sehen. Produktivziel: lokales Modell. Kein Pattern-Fallback. 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. Detect-Ausgaben erzeugen keine aktiven Registry-Einträge; siehe §9.5.
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:
- Inhaltliche Context Minimization. Es geht der zusammengebaute Dialog, nur durch eine Zeichenkappe begrenzt. Minimum-sufficient-context nach Aufgabe fehlt.
- Robuste Entity Detection. Semantische Request-Detection mit Chunking ist gebaut (
§9.5). Testphase: externes Detect-Modell über OpenRouter. Ziel: lokales Ollama. Fake-Provider-Tests beweisen nicht die semantische Modellqualität. Quasi-Identifikatoren (Beruf + Ort + Familie) bleiben unerkannt. - Response Validation. Nach dem Generate: Platzhalterintegrität, lokale Rehydrierung und Kennzeichnung. Aktiver Klartext im Reply wird dem Request-Token zugeordnet (
active_cleartext_normalized) und danach demaskiert. Das verhindert keinen bereits erfolgten Egress und startet keinen zweiten Generate-Call. Journalspezifische Faktentreue entscheidet der Journal-Adapter. Dialog-Egress maskiert den gesamten gerenderten Prompt. Der Dialogzug darf lokal zurückfallen; ein verworfener Journaltext wird nicht als Entwurf gespeichert. Keine Quasi-Identifikatoren, keine inhaltliche Minimierung. - Audit ohne Prompt-Inhalt. Es gibt keine persistente Audit-Spur (Request-ID, Policy, Provider, ZDR-Status, maskierte Entitätstypen) ohne volle Prompts oder Mapping.
- Mapping-Härtung.
identity_mappingsist lokal, aber unverschlüsselt. Admin-Review unter/admin/identitiesexistiert. Keine Verschlüsselung at rest. Legacy-Zeilen sindlegacy_review_required, nicht automatisch bestätigt. - 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.
- Weitere Egress-Klassen. Tool-, Web- und Speech-Egress bleiben getrennt und ungebaut.
- 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. Der normale Journal-Lauf hat genau einen generativen Zweck: journal_generate. Stufe 1 ist lokal (local_source_artifact) und erzeugt kein Providerbudget. 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 Artefakt, Writing Profile und optionaler Bestand nicht ins Stufe-2-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 lokale Stufe 1 und den Gateway-Call der Stufe 2 zusammen; run_log sammelt Detect, Pre-Egress, den Generate-Aufruf, Antwortnormalisierung und Provenienzentscheidung ohne Promptkörper. 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.
Additiv 2026-08-28 (opt-in lokale Persistenz): Admin kann unter /admin/debug eine lokale Debug-Persistenz einschalten. Default bleibt aus. Dann speichert Kanshō die Testspur jedes Admin-Schritts in debug_runs, zugeordnet zu Space / Tag / Gespräch. Mapping-Tabelle, Labels und Secrets bleiben ausgeschlossen. Kein In-Memory-Promptspeicher, kein Egress des Debug-Archivs, kein Bypass. Die Live-Anzeige unter dem Dialog entfällt; der Dialog bietet den Gesprächs-Download, solange der Schalter an ist. Der Journal-Entwurf zeigt die Testspur weiter und erlaubt den JSON-Download des Generate-Laufs. Export kansho.debug_export v2 (JSON-Baum plus chronologische runs, Markdown) nur für das eigene Admin-Profil. Nicht-Admin-Aktionen werden nicht geschrieben. Abschalten stoppt neue Writes; vorhandene Zeilen bleiben bis zum expliziten Löschen. Das ist keine Produktions-Audit-Spur und kein Ersatz für §9.2 Punkt 4.
9.4 Request-scoped Maskierungsmanifest (2026-08-26)
Intent-neutral, im Gateway. Journalspezifische Provenienz- und Ablehnungspolicy bleibt im Journal-Adapter.
Ein Mapping ist nicht allein deshalb aktiv, weil es in der Profiltabelle existiert. Aktiv ist nur, was im aktuellen gerenderten Prompt nach derselben Identitätsregel wie die Maskierung tatsächlich ersetzt wurde. Homonyme, die absichtlich unmaskiert bleiben, werden dadurch nicht aktiv.
Das Manifest ist request-lokal: maskierter Egress-Text, aktive Tokens und Entitätstypen, optionale lokale Vorkommenszahl. local_label bleibt auf dem Request-Objekt und geht nicht in Logs, Compact-Diagnose oder persistente Spuren. Keine globale mutable Speicherung; parallele Requests und Profile bleiben getrennt. mask_for_egress() bleibt als String-Hülle.
Vor dem Provider: Pre-Egress-Validierung. Für bestätigte Registry-Einträge und labelbasierte Safety-Net-Treffer darf kein als Identität klassifiziertes Klartextvorkommen im Egress bleiben. Request-lokale Detect-Spans maskieren nur die erkannten Offsets; derselbe Wortlaut darf an anderer Stelle Allgemeinbegriff bleiben. Fehlschlag: egress_validation_failed, Provider wird nicht aufgerufen.
Nach dem Provider: Response-Verarbeitung ist Inhaltsintegrität, nicht nachträglicher Egress-Stopp. Aktiver Klartext, der exakt zu einem request-scoped Mapping gehört, wird lokal dem Token zugeordnet (active_cleartext_normalized) — das ist die interne Prüffassung. Die sichtbare und gespeicherte Fassung entsteht aus der ursprünglichen Modellantwort; in ihr werden nur tatsächlich ausgegebene aktive Platzhalter rehydriert. Vom Modell bereits im Klartext ausgegebene, quellbelegte Begriffe behalten ihre Oberflächenform (Groß-/Kleinschreibung, Artikel, Numerus, Kasus, Satzstellung, Zeichensetzung). Unbestätigte Detect-Treffer gelten nicht automatisch als bewiesene Klartextidentität. Es gibt keinen automatischen zweiten Generate-Call. Compact-Diagnose: verfügbare vs. aktive Mappings, maskierte Vorkommen, Tokens/Typen ohne Labels, Pre-Egress, response_normalization, generate_calls, model_text_accepted, Laufzeit und Tokenverbrauch des tatsächlich erfolgten Aufrufs, prompt_slug, prompt_revision, generate_ms. Demaskierung nur mit den aktiven Tokens dieses Manifests; unbekannte oder generische Platzhalter führen keinen Klarname ein. Ein Personenname als Subjekt („Clarissa kaufte …“) bleibt Identität; nur Objekt- und Infinitivkonstruktionen wie „Sushi essen“ gelten als Homonym.
Öffentliche, intent-neutrale Identitätsprüfung: canonical_token, identity_label_pattern, is_identity_mention, identity_occurrence_count. Journalspezifische Provenienz (unbelegte heutige Fakten in Titel und Textkörper) bleibt im Journal-Adapter. Ein nicht lokal lösbarer Journalfehler speichert keinen journal_draft und liefert journal_generation_not_accepted.
9.4.1 Sicherheitsgrenze (2026-08-27)
Privacy fail-closed vor dem externen Socket. Faktentreue, Provenienz und Antwortintegrität nach der Modellantwort. Ein Verwerfen der Antwort macht einen bereits erfolgten Egress nicht ungeschehen. Detect-Ausgaben bleiben untrusted und request-scoped: sie dürfen ausgehend konservativ maskieren, erzeugen keine bestätigte Registry und überspringen keine spätere Detection.
Additiv 2026-08-27: Bestätigte Identitäten mit Alias bleiben tokenbasiert. Wird eine Schreibweise eines Tokens im Request maskiert, bleiben alle bekannten Schreibweisen dieses Tokens (kanonisch und Aliase) im request-scoped Manifest. Die lokale Demaskierung auf die kanonische Form ist deshalb kein unattested_identity, sofern irgendeine Schreibweise desselben Tokens in den heutigen Quellen belegt ist. Compact-Diagnose enthält weiterhin keine Labels.
9.5 Semantische Request-Detection und bestätigte Registry (2026-08-26)
Intent-neutral, im Gateway. Journalbegriffe gehören nicht in diese Schicht.
Überholt: wortlistenbasierter Detect-Prompt, known_labels als Ausnahme von der Prüfung, Pattern-Heuristiken (mit/bei/von plus Großschreibung) als Ersatz für semantische Detection, stilles Abschneiden nach DETECT_MAX_CHARS, Pattern-only-Freigabe des Generate-Calls, automatisches Speichern jedes Detect-Treffers als aktive Identität.
Verfahren
Jeder persönliche Generate-Egress wird vollständig semantisch untersucht, bevor der Generate-Provider aufgerufen wird. Der geprüfte Klartext ist derselbe gerenderte Prompt, der anschließend maskiert versendet wird. Bekannte Labels werden nicht ausgenommen. Ergebnisse gelten zuerst nur für diesen Request.
Überschreitet der Egress das Detect-Fenster, wird lokal in überlappende Chunks geteilt. Jeder Chunk muss syntaktisch gültig und lokal gegen den Chunktext prüfbar sein. Erst nach erfolgreicher Prüfung aller Chunks wird Generate freigegeben. Fehlschlag, Abbruch, unvollständiger Output oder finish_reason=length sind fail-closed: kein Generate, kein Pattern-Fallback, keine Weiterarbeit mit veralteten Mappings.
Detect-Schema
Untrusted Input:
{"entities":[{"start":42,"end":47,"text":"Anna","entity_type":"PERSON"}]}
Erlaubte Typen: PERSON, PLACE, ORG, PROJECT. PROJECT ist additiv entschieden für benannte private Vorhaben und Produktbezeichnungen, nicht für Allerweltsgegenstände. Zusätzliche Felder und Tokens werden abgelehnt. Falsche Offsets werden lokal am exakten Wortlaut im Chunk verankert, sofern das gemeldete text dort vorkommt; ein Wort, das im Chunk nicht existiert, wird verworfen, ohne Generate zu sperren. Überlappende Spans: längste Spanne, dann links, dann Typreihenfolge PERSON > PROJECT > ORG > PLACE. Tokens vergibt nur die lokale Schicht, request-scoped. Schemaverletzungen, Abbruch und unvollständige Chunks bleiben fail-closed. Im Dialogzug erzeugt ein solcher Fail-closed lokal einen Halte-Impuls, ohne den Generate-Provider zu rufen. Der Nutzer sieht keine interne Substring-Diagnose.
RequestDetectionManifest vs. ConfirmedIdentityRegistry
- RequestDetectionManifest: erkannte Spans, beobachtete Schreibweise, Typ, lokal vergebener Platzhalter. Keine globale Speicherung. Steuert Maskierung, Response Validation und Demaskierung dieses Requests.
- ConfirmedIdentityRegistry: nur ausdrücklich bestätigte oder lokal autoritative Einträge. Typ, kanonische Schreibweise, optionale bestätigte Aliase, Status, Herkunft, Zeitstempel. Detect-Ausgabe erzeugt niemals automatisch einen aktiven Eintrag.
- Review-Proposals: optional, unbestätigt, nie maskierend, nie detection-skip, nicht in externe Prompts oder Compact-Traces.
Nach der semantischen Detection prüft die bestätigte Registry den vollen Egress als Sicherheitsnetz. Legacy-Zeilen (legacy_review_required) zählen nicht als bestätigt.
Demaskierung
Unbestätigte Request-Treffer werden in der beobachteten Form demaskiert. Bestätigte Identitäten und bestätigte Aliase werden auf die kanonische Schreibweise demaskiert, wenn das Modell den Platzhalter ausgegeben hat. Klartext, den das Modell selbst geschrieben hat, wird nicht über die Prüfnormalisierung auf die gespeicherte Manifestform zurückgebogen. Unbekannte Platzhalter materialisieren keine Namen. Die lokale Wiederherstellung erkennt Platzhalter unabhängig von Groß-/Kleinschreibung, Innenabstand und optionaler Nullauffüllung (PERSON:1 / PERSON:01). Generische Auslassungsplatzhalter ([[…]], [[...]]) werden nicht demaskiert; im Journalentwurf gelten sie als unbelegter Inhalt und führen zu journal_generation_not_accepted, nicht zu einem stillen Rohtext-Entwurf. Der Journal-Seed darf keine Beispiel-Klammern [[…]] enthalten, damit das Modell sie nicht in den Text kopiert.
Persistenz und Migration
Bestehende identity_mappings werden nicht gelöscht und nicht pauschal bestätigt. Additive Migration setzt status=legacy_review_required und origin=legacy_auto. Vor lokaler Bereinigung die Datei backend/data/kansho.sqlite kopieren; Wiederherstellung durch Zurücklegen der Kopie bei gestoppter Anwendung. Admin /admin/identities und /api/admin/identities bestätigen, korrigieren, aliasieren, deaktivieren oder entfernen lokal. Kein externer Egress, keine Klartextlabels in Compact-Logs.
Kosten und Diagnose
Mehrere Detect-Calls bei langen Prompts sind zulässig. Der Nutzer akzeptiert die Laufzeit. Compact-Trace ohne Labels: Detect-Provider/Modell, Zeichen, Chunks, full_detection_coverage (nur technische Chunk-Verarbeitung), confirmed_registry_applied, request_local_hits, semantic_identity_guaranteed (im MVP immer false), Entitäten nach Typ, Detect-Aufrufe, Tokens/Kosten/Laufzeit, generate_called, Abbruchgrund. Technisch verarbeitete Chunks sind kein Anspruch auf vollständige semantische Identitätserkennung.
Normalfall nach erfolgreicher Detection: genau ein Generate-Call. Aktiver Klartext in der Modellantwort erzeugt keinen zweiten Generate-Aufruf.
Bestätigte Registry-Zeilen und bestätigte Aliase werden im gesamten gerenderten Egress labelbasiert maskiert, auch wenn Detect denselben Wortlaut an anderer Stelle nicht gemeldet hat. Request-lokale Spans bleiben span-genau. Kurze bestätigte Namen (unter der Detect-Mindestlänge) bleiben maskierbar, sofern sie nicht strukturell unmaskierbar sind (Pronomen, Rollen, Uhrzeiten).
Tests und Live-Qualität
Contract-Tests: backend/tests/test_privacy_detect.py, backend/tests/test_identity_registry.py, backend/tests/test_privacy_response_integrity.py. Sie beweisen Schema, Fail-closed, span-genaue Maskierung und Datenfluss, nicht semantische Modellleistung. Opt-in: python entity_detect_eval.py --live mit synthetischen Sätzen und exakten erwarteten Spans. Ohne diesen Lauf bleibt die Live-Qualität unbestätigt. Das aktuell konfigurierte openai/gpt-4.1-nano gilt durch reale False-Positive-Vorschläge qualitativ nicht als zuverlässig bestätigt; das Modell wird deshalb nicht stillschweigend gewechselt.
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.
Additiv 2026-08-28: Wie sollen neue, vom Detect verfehlte und lokal nicht bestätigte Identitäten vor dem Egress behandelt werden, ohne span-genaue Homonyme oder Allgemeinbegriffe dauerhaft zu maskieren? Optionen ohne Vorentscheidung: fail-closed vor Generate, Review der Detect-Vorschläge vor Egress, oder ein zweites lokales Verfahren. Keine Heuristik auf Verdacht.
11. Querverweise
- Fachlich:
../functional/guardrails.md - Technisch:
ai_architecture.md,security.md,voice_and_media.md,platform_extensibility.md