Kansho/docs/architecture/technical/memory_storage_and_offline.md

173 lines
13 KiB
Markdown
Raw Normal View History

---
title: "Kanshō – Memory-Speicher, Sync und Offline"
version: "0.1"
status: "Arbeitsstand"
date: "2026-08-19"
product_family: "Jinkendo"
document_role: "Technical Chapter / Memory Storage / Sync / Offline"
parent_document: "technische_zielarchitektur.md"
---
# Kanshō – Memory-Speicher, Sync und Offline
Kanonisches Home für Gedächtnisschichten und Offline, sobald der Fachstand sie trägt. Die Schichtenbeschreibungen unten spiegeln den **heutigen** Fach-Arbeitsstand (`memory_and_context.md`) und sind nicht als finales Speichermodell zu implementieren. Offline-Ausprägung bleibt offen.
## 1. Schichten
| Schicht | Lebensdauer (fachlich) | Technische Konsequenz |
|---|---|---|
| Working Context | Minuten bis Stunden | lokal, hohe Schreibfrequenz, an die aktive Session/Conversation gebunden |
| Thread Memory | Tage bis Monate+ | persistiert, quellengebunden, darf nicht die Originalnachrichten ersetzen |
| Episodic / langfristig | Jahre | Handoff nach mindnet/Obsidian; Kanshō behält Provenance-Referenzen |
Ein LLM-Kontextfenster ist kein Speicher. Context Builder wählt Ausschnitte; das Gateway minimiert sie erneut vor Egress.
## 2. Primärquelle und Re-Grounding
**Status: fachliche Invariante** (Re-Grounding / Originalquelle). Kein SQL-Schema, keine Drift-Formel in v0.1.
- Vollständige Dialoge bzw. eine verlässliche Originalrepräsentation bleiben erhalten.
- Summaries dürfen laufend fortgeschrieben werden, auch mitten im Dialog, nicht nur am Session-Ende.
- Drift-Erkennung und Re-Grounding arbeiten **lokal** auf Originalquellen. Für externe Inferenz wird danach ein neuer minimierter External Model Context erzeugt. Privacy Guardrails werden dabei nicht umgangen.
Keine unbegrenzte Kette Summary → Summary ohne Rückgriff auf die Quelle.
Konkrete Drift-Metrik, Granularität und Update-Algorithmen: **offen**.
## 3a. Strukturelle Vorsorge (Verträge, kein SQL)
**Status: entschieden als Vorsorge.** Felder, Enums und Tabellennamen bleiben offen. Festgezogen wird, **welche Objektarten und Beziehungen** das Langzeitdialog- und Erinnerungssystem tragen müssen. Herkunft: `memory_and_context.md`, `dialogue_model.md`, `resurfacing_and_saturation.md`, `context_fidelity_and_regrounding.md`, `self_model_and_lived_experience.md`, `reflection_outputs.md`, `reflection_spaces.md`.
Ein späteres Schema **füllt** diese Verträge. Es darf sie nicht kollabieren (z. B. Thread in der Session aufgehen lassen, Summary als Primärquelle, Handoff als Kanshō-Todo).
### Objektarten
| Art | Fachliche Rolle | Darf nicht |
|---|---|---|
| **Conversation** | Geordnete Originalrepräsentation (Layer 0). Stabile Message-IDs, Reihenfolge, Zeit. | Durch Summary ersetzt oder nur im LLM-Fenster existieren |
| **Session** | Eine Nutzungssitzung / Interaktionszyklus inkl. Checkpoint am Ende | Thread mitabschließen |
| **Thread** | Reflexionsfaden über Sitzungen hinweg; Zustand und Wiedervorlage am Faden, nicht an der Session | Geschlossene State-Machine vortäuschen; jeder Nebenfaden muss sichtbar sein |
| **Thread-Kandidat** | Intern markierter möglicher Faden | Automatisch eigener Chat oder bestätigtes Wissen |
| **Working Context** | Kurzlebiger Arbeitsstand der aktiven Conversation | Langzeitgedächtnis; Egress ohne Gateway |
| **Thread Memory** | Quellengebundene Verdichtung eines Fadens (Layer 1, versioniert) | Original ersetzen; still als Erkenntnis schreiben |
| **Reflection Space** | Lebendiger Kontext über Conversations/Threads | Bloßer Ordner; interne Feinstruktur 1:1 in der UX |
| **Reflection Intent** | Absicht *dieser* Interaktion, orthogonal zum Space | Mit Space identisch sein |
| **Derived record** | Summary, Hypothese, Emotionseinordnung, Pattern, Kandidat | Ohne Provenance, ohne Zeit, ohne „abgeleitet“-Kennzeichnung |
| **Handoff** | Journal / Reflection Memory / Knowledge Delta / Action Candidate | Kanshō-Aufgabenliste; mindnet-Graphkopie |
| **External ref** | Nullable Verweis mindnet / Obsidian | Besitz des Langzeitgraphen oder des Archivs |
| **Re-grounding event** | Wann, warum, aus welchen Quellen neu abgeleitet wurde | Nur Debug-Log ohne Quellenbindung |
| **Identity mapping** | Klasse A, lokal | In Summaries, Prompt-Archiv, mindnet-Handoff |
Point-in-Time Self / Lived Experience ist **keine eigene frühe Tabelle**, sondern die Konsequenz: Original + zeitgebundene Ableitungen, die frühere Versionen nicht überschreiben.
### Beziehungen, die das Modell skalieren
- `profile_id` an jeder personenbezogenen Struktur.
- Session 1:n Conversations (oder 1:1, später festlegbar) – **ohne** 1:1 mit Thread.
- Conversation n:m Threads (ein Gespräch, mehrere Fäden; ein Faden über mehrere Gespräche).
- Thread n:1 oder n:m Spaces (Zuordnung darf vorläufig/unsicher sein).
- Jede Ableitung: `source_ids[]` auf Messages/Conversations, `as_of`, `confidence`/`uncertainty`, `kind`.
- Sichtbarkeit getrennt von Existenz: intern vs. nutzersichtbar (Space-Regel: KI strukturiert, Nutzer verwaltet nicht die Feinstruktur).
- Handoffs referenzieren Kanshō-Quellen; sie sind nicht der Dialogspeicher.
- Message-IDs idempotent (späteres Offline, Sync-Hypothese).
### Schichtenzuordnung
| Layer | Hier |
|---|---|
| 0 | Conversation/Messages, Session, Thread-Identität und Anker (Wiedervorlage), Space-Identität, Mapping |
| 1 | Working-Context-Snapshot, aktuelle Thread-Memory-Version, Space-„aktueller Stand“, später Relevanz/Saturation als registrierte Leser |
| 2a | Context Builder wählt Layer-1- und Quell-Ausschnitte; Gateway minimiert erneut |
| 2b | Fortsetzungsvorschlag, Space-Ansicht, Aufklappen zur Quelle – keine zweite Verdichtungsformel |
Kontinuitätsarbeit ist ein **laufender Schreibpfad** auf Layer 0/1, auslösbar mitten im Dialog und am Session-Checkpoint. Sie ist unabhängig vom sichtbaren Abschluss und unabhängig davon, ob ein Handoff entsteht.
### Bewusst nicht schließen
- Thread-Zustandsliste (`Open` / `Anchored` / `Dormant` / `Resolved` sind Hinweise, kein Enum-Vertrag).
- Drift-Formel, Saturation-Score, Entry-IA (Contextual Continuation).
- Self-Model-Felder, Episodic-Schema in Kanshō (Handoff-Ziel mindnet/Obsidian).
- SQL, Sync-Engine, Offline-Store.
### Erweiterbarkeit
Neue fachliche Arten (z. B. weiteres Derived-`kind`, weiterer Handoff-Typ, feinere Space-Sicht) kommen als **registrierter Typ** plus Provenance, nicht als Sonderpfad in der Conversation-Tabelle und nicht als Prompt-Text im Code. Retrieval in den Langzeitgraphen bleibt Adapter + External ref, kein zweites mindnet in Kanshō.
Session-Ende ist ein Checkpoint, kein Zwang zu Journal/Memory/Delta/Action. Technisch heißt das: Persistenzpfade für Original und interne Kontinuität existieren unabhängig von Handoff-Tabellen oder sichtbaren Abschluss-Screens.
## 4. Offline
**Anforderung: entschieden. Ausprägung: offen.**
Leitplanken, die jede spätere Lösung erfüllen muss:
- Dialoge müssen lokal zwischenspeicherbar sein (fachliche Anforderung).
- Konfliktbehandlung und Sync sind zu definieren, bevor Multi-Gerät produktiv personenbezogene Dialoge führt.
- KI-Funktionen dürfen online bleiben; Fail Closed gilt für unsichere Provider, nicht als Ausrede, lokale Eingaben zu verwerfen.
- App-Shell-Cache (PWA) ist nicht dasselbe wie Dialog-Offline.
- Verschlüsselung at rest auf dem Gerät: offen, siehe `security.md`.
Lokale kleine Modelle: fachlich offen, nicht als Voraussetzung des Rahmens.
## 5. Sync-Hypothese
**Status: Hypothese**
Ein Gerät schreibt in eine lokale Queue, das Backend ist Source of Truth nach erfolgreichem Sync. Idempotente Message-IDs verhindern Duplikate. Konflikte an Originalnachrichten sind selten (ein Nutzer, ein aktiver Dialog); Konflikte an Summaries werden durch Neuberechnung aus der Quelle gelöst, nicht durch Merge von Verdichtungen.
Diese Hypothese ist zu verwerfen oder zu bestätigen, sobald Geräte- und Offline-Szenarien in Phase G4 entschieden sind.
## 6. Entscheidungsstand
| Thema | Stand | Status |
|---|---|---|
| Mehrere Memory-Schichten | heutiger Fachstand | nicht als Schema einfrieren |
| Original vor Summary / Re-Grounding | fachliche Invariante | bindend, sobald Memory gebaut wird |
| Objektarten und Lebenszyklus-Trennung | Verträge in §3a | entschieden als Vorsorge, kein SQL |
| mindnet nicht Working Memory | wahrscheinlich | bevorzugte Richtung |
| Offline-Fähigkeit | erforderlich | entschieden (fachlich), Ausprägung offen |
| Sync/Konflikte/lokale DB | – | offen |
| Drift-Berechnung | fachlich nötig | bevorzugte Richtung, Technik offen |
## 6.1 Implementierungsstand (Rahmen-Schnitt)
**Status: Code vorhanden, Heuristiken nicht.**
Layer-0-Tabellen `usage_sessions` (nicht Auth-`sessions`), `conversations`, `messages`, Thread-/Space-Identität, `derived_records` (append-only, Kind-Registry), Handoff-/Ref-/Re-Grounding-/Mapping-Hüllen. Continuity-Checkpoint ohne LLM. Admin trennt Original und Derived. Die Dialogseite speichert nur Originaltext.
Nicht enthalten: Entry-IA, Fadenerkennung, Thread-Enum, Summaries über das Gateway.
2026-08-25 13:57:23 +02:00
## 6.2 Implementierungsstand (MVP-Journal-Slice)
**Status: Code vorhanden für den ersten vertikalen Slice.** Technische Umsetzung: `mvp_implementation.md`. Fachhome: `../functional/mvp.md`. Foundation: `../functional/implementation_foundation.md`. Fit-Gap (Code gegen Slice und Gesamtziel): `../functional/mvp_stand_und_abgleich.md`.
Zusätzlich zu Layer 0:
- `spaces` mit `visibility='user'` ist der sichtbare Reflection Space (anlegen, umbenennen, auswählen).
- `journal_days` ist die chronologische Bezugseinheit `(space_id, calendar_date)`. Kalendertag und `messages.created` bleiben getrennt. `scratch_json` hält optionale Tagesstichpunkte (lokal, kein KI-Kontext).
- `conversations.space_id` / `journal_day_id` sind Primary Assignment, nicht Identität. Alte Conversations ohne Assignment bleiben außerhalb des Journals.
- `journal_drafts` sind Derived: neue Generierung historisiert den vorigen Draft und lässt `journal_entries.current_version_id` unangetastet.
- `journal_entries` + `journal_entry_versions` tragen Current Validity und History; Soft-Delete über `deleted_at`. Übernehmen eines Entwurfs schreibt eine neue Version des bestehenden Entry (`origin=accepted_draft`), sofern nicht ausdrücklich ein weiterer Entry angelegt wird. Die aktuelle Fassung steht in der Versionsliste ohne Restore auf sich selbst.
- `media_assets` verweisen auf lokale Dateien unter `backend/data/media/`. Einbettung und Unterschrift stehen im Entry-Body als Markdown, nicht als eigene Caption-Tabelle.
- `writing_profiles` / `writing_profile_sources` halten den Current Brief. Quellenpriorität: finale Nutzerfassungen, Importe, Dialogstil (`dialogue_style` aus `user:`-Zeilen). Quellen tragen `occurred_at` und `context_hint`. KI-Drafts sind keine Stilquelle. Der Brief ist eine abgeleitete Sicht.
- `writing_profiles.lifecycle` (`uninitialized` | `initial_pending` | `confirmed`) trennt Korpus-Sammlung vom kontinuierlichen Lernen. `writing_profile_traits` / `writing_profile_trait_refs` sind die dynamischen semantischen Merkmale inkl. Evidence und Exemplaren. `writing_profile_facets` bleiben Layer-Hüllen (Core/context/output), kein festes Stilraster.
- `writing_profiles.governance` (`learning` | `advising` | `frozen`) und Locks verhindern stilles Voll-Überschreiben. `writing_profile_suggestions` trägt advising-Vorschläge (auch `trait_slug` / `action`).
2026-08-25 17:16:35 +02:00
- `writing_profiles.version` / `review_ready` / `last_reviewed` plus `writing_profile_evidence`, `writing_profile_reviews`, `writing_profile_versions` tragen die Review-Pipeline: lokale Evidenz, gebündelte `kansho.profile_analysis_package`/`kansho.profile_analysis_result`, API- oder Paste-Kanal, Proposal vor User-Acceptance, nachvollziehbare Stände. Kein Re-Infer nach jedem Save. Der Current Brief bleibt abgeleitetes Runtime-Artefakt und wird nicht als Profil importiert.
2026-08-25 13:57:23 +02:00
- Portable JSON-Dokumente (`kansho.writing_profile`, `kansho.interaction_profile`, `kansho.profiles`) exportieren Facets/Prefs/Governance, nicht Journalquellen oder Identity-Mapping.
- `interaction_profiles` / `interaction_preferences` / `interaction_suggestions` sind getrennt vom Writing Profile. Default-Governance `advising`. Starke Quellen nur explizit/manuell/angenommener Vorschlag.
- `conversations.emotional_intensity` / `long_story` sind operative Dialogue-State-Felder, kein User-Fakt.
`derived_records` bleibt die generische Layer-0-Hülle und ist nicht der Journal-Store. `handoffs.target='journal'` ist kein Schreibpfad für Einträge.
Nicht enthalten: Threads-UI, Related Spaces, semantisches Retrieval, Session-Summaries, Voice, Space Content Memory. Der Dialogzug sieht denselben Journal Day vollständig und dazu die letzten Journal Entries des Spaces als Recency-Ausschnitte. Die Journalgenerierung bekommt denselben Tagesdialog inklusive Kanshō-Impulse als Gesprächskontext, nicht als Erlebtes.
## 7. Offene Fragen
1. IndexedDB vs. SQLite-WASM vs. nur Service-Worker-Queue?
2. Wird Audio nach Transkription gelöscht oder als Medium behalten? → `voice_and_media.md`
3. Wie greift Re-Grounding bei teilweise gesyncten Sessions?
## 8. Querverweise
- `data_architecture.md`, `frontend_pwa_shell.md`, `privacy_gateway.md`
- Fachlich: `memory_and_context.md`, `resurfacing_and_saturation.md`