ctx // the memory your LLM pretends to have

Planung & offene Themen

Vollständiger Statusreport aller geplanten Erweiterungen und Änderungen — destilliert aus Architektur-Blöcken, Plan-Dateien und verifiziertem Git-Stand.

● Stand 2026-06-17 Branch feat/multi-tenant HEAD ddbfd7f Live-DB migration 57 6 Themen · 121 Arbeitspakete
Kennzahlen

Gesamtbild

Aktive Grossvorhaben3-stufigMT-Kern (Bau) → Enterprise-Aufsatz (Anforderung) → Workflow-Engine/Issues (Vision)
MT-Wellen committet / gesamt20 / 44T01–T43, T40 in T40a/b gespalten, 7 Achsen / Phasen A–G
Migrationen committet / Ziel7 (058–064) / 11 (058–068)Branch feat/multi-tenant
Live-Deploy-StatusNICHT deployedBranch lokal, HEAD ddbfd7f; echte Live-DB max(migration)=57
MT-LOC inkl. Tests~78055925 + ~1880 Achse 07; Tenant-Modell C (3-Ebenen)
Frontend-Plan41/41 Wellen (G01–G41)komplett gebaut, letzte Release v3.15.0 (2026-06-14)
Enterprise-Anforderungen~140 / 5 DimensionenPhasen 0–5, 6/6 Code-Befunde gegen HEAD verifiziert
MT-Grundsatzentscheidungen 2026-06-176u.a. Welle-0-Scope-Konsolidierung, scope-granulare Quota, Backend-Whitelist
Lage

Executive Summary

Das Projekt ctx (PostgreSQL 18 + pgvector + TimescaleDB Knowledge-Store, Go-Monolith aus ctx CLI und ctxd Daemon, llama.cpp-Inferenz, MPL-2.0, Autor GottZ) steht an einem klaren Wendepunkt: das Web-Frontend ist mit dem 41-Wellen-Plan G01–G41 vollstaendig gebaut (letzte Release v3.15.0 vom 2026-06-14, die ausserplanmaessige Graph-Landkarte F5-W6; der 41-Plan selbst geschlossen mit v3.14.0 vom 2026-06-13), und das aktive Grossvorhaben ist die Multi-Tenant-Ausarbeitung im Gold-Standard nach Tenant-Modell C (Hybrid, 3-Ebenen Tenant/Scope/Block), entschieden durch User-Praezisierung E1 am 2026-06-15. Von 44 geplanten Wellen (T01–T43, T40 in T40a/b gespalten, 7 Achsen / Phasen A–G, 11 Ziel-Migrationen 058–068, ~7805 LOC inkl. Tests) sind 20 Wellen committet und Migrationen 058–064 (7 Stueck) im Branch; der Branch feat/multi-tenant (HEAD ddbfd7f) ist jedoch lokal und NICHT deployed — die echte Live-DB steht bei max(migration)=57.

Auf den Multi-Tenant-Kern setzen zwei weitere Stufen auf: ein bereits anforderungsseitig ausgearbeiteter Enterprise-Aufsatz (Stand 2026-06-16, 5 Dimensionen — Reseller, Konzern-Hierarchie, ephemere Test-Tenants, separate Models, Lastverteilung — ~140 Anforderungen, Phasen 0–5, noch kein Bau-Plan), und danach die Workflow-Engine / das Issue-System (Vision aus 2026-06-01, 4 Schema-First-Wellen W1–W4, noch nicht gebaut). Am 2026-06-17 hat der User sechs MT-Grundsatzentscheidungen getroffen, die die naechste Bau-Phase praegen: eine destruktive Welle 0 (Scope-Konsolidierung work+shared→private, mit Backup, VOR den MT-Wellen 058+, in dieser Session nicht ausgefuehrt), gefolgt von additiv/pausierbaren Wellen (parent_tenant_id, embed_model-Provenance/Attribution T35b, metadata.ephemeral). Daneben laeuft ein operativer Backlog (Resilienz-Reste Welle G, zwei Code-Fixes, Retention/Kuration). Die Inferenz laeuft durchgaengig auf llama.cpp; Ollama ist komplett raus.

Sequenz

Roadmap

Welle 0
MT-Kern Rest
MT-Enterprise
Workflow-Engine / Issues
Fertig / laufender Backlog
01

Scope-Konsolidierung (destruktiv, pre-MT, mit Backup)

  • work + shared → private DB-weit ueber alle scope-Spalten (blocks/dream_links/blobs/sources/chat_sessions/settings) + Work-API-Key + Overview-Rebuild
  • macht E4 gegenstandslos (default-Tenant behaelt EINEN Scope)
  • erste Welle der naechsten Bau-Phase, VOR den MT-Wellen 058+; in dieser Session noch nicht ausgefuehrt
02

Multi-Tenant Modell C — Phasen A–G fertigstellen (20/44 committet)

  • Phase A abschliessen: T05 (01-T6 api-key-create tenant-gebunden, letzte offene Fundament-Welle, E4-fix → durch Welle 0 adressiert)
  • Phase B Config-Snapshot: T09→T10→T11→T12→T13 (T08 committet)
  • Phase C/D Read-Isolation + Admin-Tier: T16 Graph-Isolations-Bench; Achse 05 T18→T19→T22→T25 (05-A8 harte Vorbedingung fuer T31+T37)
  • Phase E Settings/Secrets: T28 (sofort startbar) →T29→T30→T31→T32 (Migration 065)
  • Phase F LLM-Pool/Quota: T34 (Chain tenant-gefiltert, jetzt own∪granted-Whitelist) →T35→T36→T37→T38; Migrationen 062/063 committet
  • Phase G block-level-sharing erst nach 02-V3-Bench: T39 (Migration 067)→T40a→{T41 ∥ T42}→T40b (Migration 068, nach gruener T42)→T43
  • Release-Schnitt RC-1 (Phase A+C+D = Sicherheits-Kern) vorbereiten, Versionsnummer offen
  • additiv/pausierbar vorziehbar (2026-06-17): parent_tenant_id ADD COLUMN + acyclicity-Trigger, embed_model-Provenance + Attribution (T35b), metadata.ephemeral
03

Enterprise-Aufsatz auf Modell C — Phasen 0–5 (~140 Anforderungen, 5 Dimensionen)

  • Phase 0 Doktrinen festziehen: OD-1=CoW-Embedding (context_block_embeddings), Wurzel=default-Tenant, Quota-Granularitaet (User-Revision 2026-06-17), OD-2 cosine-Proof, N>1-State
  • Phase 1 additiv/verhaltensneutral: parent_tenant_id + Trigger, embed_model-Provenance + Backfill, embed-Kosten-Attribution, metadata.ephemeral
  • Phase 2 fail-OPEN-Loecher schliessen (INV-1, 6 Stellen): Backend-WRITE-scope-Pinning, context_backend_grants-Subsystem, Chain-Scope-Whitelist (embed-Rolle als _global-Sonderzweig), embed_equivalence-Gate haerten, text_preview entfernen (DSGVO), CreateApiKey-tenant_id-Param
  • Phase 3 Autorisierung + Lifecycle: CanAdministerDescendant + ancestor_tenant_ids, denormalisiertes effective_status (Suspend-Kaskade), Re-Parent + Grant-Lifecycle, resumabler Sub-Tree-Prune leaf→root
  • Phase 4 Quota + Last-Fairness: Quota-Enforcement in Pool.Chain(), chat-Semaphore auf ar.TenantID, In-Flight-Lastverteilung, Background per-Tenant-Iteration (T38/06-C6)
  • Phase 5 Haertung + Observability: Topologie-Cap, Auto-Cleanup-Janitor (advisory-lock+Yield), Generation-Drift-Detektor, per-Tenant-Embed-Rebuild-Worker
  • geparkt: per-Tenant-HNSW-Partition (A), Self-Service-Onboarding (C), White-Label (D), N>1 SHARED Counter-Store (E), Daten-Sicht-Vererbung als Default (Anti-Feature, F)
04

Block-Types dynamisch + Issue-System (Vision, nach Frontend + MT)

  • Kern-Achse zuerst entscheiden: deklarativ-reich (empfohlen) vs. programmierbar
  • W1 dynamische Type-Registry + Default-Configs (Migration vom block_role-Enum) + ctx project Fundament
  • W2 Issue-Workflow + Forge-Sync (GitHub zuerst, 3-Wege-Content-Hash, Issue = context_block im Repo-Scope-Tenant)
  • W3 Drift/Resilienz + lokaler Fallback; W4 ctx kanban TUI
  • danach Themen-Backlog als Issues IM System dokumentieren (Webhooks, Project-Boards-Sync, Multi-User, Auth-Redesign, Admin-Oberflaeche, autonome Agenten); todos.md entfaellt
05

Web-Frontend gebaut (41-Plan) + operativer Backlog

  • Web-Frontend 41-Wellen-Plan G01–G41 komplett gebaut; 41-Plan geschlossen mit v3.14.0 (2026-06-13), letzte Release v3.15.0 (2026-06-14, Graph-Landkarte F5-W6)
  • Frontend offen: F5-W4 1M-Bench (optional), F6-C6 Write-Confirmation, Ingest-Generalisierung; F5-W7 Map-Mode verfrueht/geparkt (Korpus 691)
  • Resilienz-Reste Welle G: Watchdog + Aktivitaets-Agent als Logon-Task (llama.cpp)
  • Code-Fixes: store.StoreEmbedding ohne pgx.Tx (W49), ClassifyConfidence-Rekalibrierung unter Blend-Scores
  • Daten-Lebenszyklus: context_access_log-Retention geparkt (87k rows/18 MB), Korpus-Kuration veralteter Config-Bloecke
  • Re-Messungen: Back-off ≈2026-06-30, Temporal-Cyclic-Retrieval-Status vs. README v3.0.0 verifizieren; Infra: llama.cpp durchgaengig, Ollama raus; n8n-Service bewusst behalten
Offen

Wichtigste offene Entscheidungen

MT-Kern-Entscheidungen E2–E9 + Achse-07-Sub-Entscheidungen UB-1..UB-6

Acht User-Entscheidungen blockieren jeweils Wellen/Migrationen (E1 = Modell C ist entschieden): E2 Rollen-Wertebereich (2 vs. 3 Stufen — Anmerkung: 059/T02 bereits committet mit owner|admin|member); E3 shared-Schreibrecht (blockiert 05-Write-Gate T25/T31); E5 shared-_global-Provider-Fallback + tenant-owned OAuth (blockiert 03-W5 T31 + 04-W2 T34, plus T26); E7 HNSW-Cap/Hop-Budget/Fairness (datengetrieben, Bench T16). E4 (shared-Zuordnung der 21 kanonischen Cross-Tenant-Bloecke) ist durch die Welle-0-Entscheidung 2026-06-17 (Scope-Konsolidierung work+shared→private) gegenstandslos geworden. UB-1..UB-6 sind die offenen block-level-Freigabe-Sub-Entscheidungen der Achse 07/Phase G.

Welle 0 destruktiv ausfuehren + scope-granulare Quota-Lesart bestaetigen (2026-06-17)

Die Scope-Konsolidierung work+shared→private ist eine destruktive DB-weite Operation ueber alle scope-Spalten (blocks/dream_links/blobs/sources/chat_sessions/settings) + Work-API-Key + Overview-Rebuild, geplant als erste Welle der naechsten Bau-Phase VOR den MT-Wellen 058+, mit Backup — in dieser Session noch nicht ausgefuehrt. Parallel ist die User-Bestaetigung der scope-granularen Quota-Lesart ausstehend (Budget pro Scope, 063-Kommentar 'per tenant'→'per scope', Struktur bleibt, Tenant-Gesamtbudget = Summe der Scope-Quotas) — diese Revision vom 2026-06-17 betrifft direkt Befund 5 (063:59 falscher Kommentar) und die fruehere Enterprise-Doktrin LB-A1 (tenant_id-keyed gilt nicht mehr unveraendert).

Enterprise Phase-0-Doktrinen: OD-2 cosine-Aequivalenz-Proof + N>1 geteilter State

OD-2: Erzeugung des cosine-Aequivalenz-Proofs (heute nur nackter bool aus Client-Payload validate.go:195) — Empfehlung B (Test-Harness, cosine ≥ 0.9999) mit zwei zwingenden Haertungen (Flag server-admin-only, Gate lokalitaets-blind auf Scope!=_global statt nur LocalityExternal); C (Verbot/separate Partition) als fail-closed-Default solange B nicht gebaut. LB-OD4: aller Last-/Health-/Quota-State ist prozess-lokal (ausser ClaimTurn) — kurzfristig N==1 explizit dokumentieren; bei N>1 sind on_exceed=block (echtes Geld/Egress) und Cooldown-Verduennung bei geteilten _global-Backends die verifizierten Ausnahmen, die einen SHARED Counter-Store (geparkt) erzwingen wuerden.

Workflow-Engine Kern-Achse: deklarativ-reich vs. programmierbar

Noch nicht entschieden und Voraussetzung fuer die Workflow-Engine: deklarativ-reich (empfohlen als Fundament) — Type = Config mit Verhaltens-Feldern (retrieval_policy, guard_dedup, dream_linkable, structural_parent, is_meta-Aequivalent), kein server-seitiger User-Code, kein Sandboxing; vs. programmierbar (Hooks/Plugins/Expressions mit eingeklinkter User-Logik) — maximale Macht, aber Sandboxing/Sicherheit/Lebenszyklus als eigenes Subsystem (dokumentiertes W6d-Risiko), nur als Erweiterungspunkt wenn ein realer Workflow das deklarative Vokabular nachweislich sprengt.

Release-Schnitt RC-1 + Versionsnummer des MT-Sicherheits-Kerns

Als naechster Release-Meilenstein soll RC-1 (Tenant-Fundament + Read-Isolation = Phase A+C+D) als Sicherheits-Kern-Release vorbereitet werden; die Versionsnummer ist offen und vom User zu entscheiden. Vorgelagert bleibt der Reihenfolge-Zwang innerhalb der Phasen (Achse 05: T18→T19→T22→T25 als harte Vorbedingung fuer T31+T37; Phase G erst nach 02-V3-Bench).

Muster

Querschnitts-Themen

Scope→Tenant-Generalisierung als durchgehende Linie v2.0.0 → MT → Block-Types

Dieselbe Bewegung — Mechanismus vs. Policy trennen, ein Enum zu generischer Konfiguration aufweiten — zieht sich durch alle Stufen: v2.0.0 generalisierte scope von Enum zu VARCHAR(50) fuer Multi-Tenant; die MT-Migration 058 (scope_generalize) setzt das Altbestand-weit fort (CHECK-Drop + VARCHAR(20)→50 auf dream_links/blobs/sources/write_log); und die geplante Workflow-Engine fuehrt denselben Schritt eine Ebene tiefer durch — das hardcoded 4-Klassen-block_role-Enum (system-meta/audit-trail/reference/knowledge) wird zu dynamischer Policy-Config, sodass User eigene Workflows auf ctx bauen. Modell C haelt scope explizit als Daten-Diskriminator und legt das Tenant-Register schmal darueber.

fail-closed-Disziplin als oberste Bau-Prioritaet

Quer durch MT-Kern und Enterprise-Aufsatz dokumentiert die Quelle fail-closed als erklaerte oberste Prioritaet: RequireScopes-Kontrakt (leeres scope-Array → ErrNoScopes, unknown → [] → rrf lehnt ab, T04/T07 committet), COALESCE-Untergrenze in ctx_auth (T15), MCP-private-Default-Fix (K-SEC2, T07), Suspend-Status-Gate. Der Enterprise-Review benennt explizit sechs verifizierte fail-OPEN-Stellen (Chain filtert Backend.Scope nicht; CreateApiKey laesst tenant_id/tenant_role weg → DEFAULT default-Tenant; quota.scope ohne _-CHECK; descendant-scope-Set ohne RequireScopes u.a.), die als INV-1 geschlossen werden muessen. Die User-Entscheidung 2026-06-17, die Backend-Sicht auf Whitelist (own ∪ granted, fail-closed) statt additiv zu stellen, schliesst nach Quelle die einzige verbleibende fail-open-Luecke und macht drei Grant-Ebenen (scope/block/backend) konsistent.

alles datengetrieben / empirisch — Caps und Strukturwechsel erst nach Bench

Skalierungs-Entscheidungen werden konsequent gemessen statt geblind gesetzt: E7 (HNSW-Filtered-Search-Cap, Graph-Hop-Budget, Background-Fairness) wird per Bench-Welle T16/02-V3 zuerst gemessen, dann max_scan_tuples-Cap; die Phase-G-Skalen-Bench T42 (OR-Kosten @1M) ist harte Vorbedingung fuer die teure RRF-OR-Welle T40b; OD-1 (geteilte vs. per-Tenant-Embedding-Generation) ist als CoW-Embedding entschieden mit Bau-Trigger 'erster inkompatibler Tenant ODER gemessener HNSW-recall-Druck'; der externe Vektor-Store (Qdrant/Milvus) wird verworfen, weil pgvector @1M gebencht ist und der Kern-Wert Hybrid-Fusion in EINER Transaktion bleibt.

Verwaltungs-Autoritaet orthogonal zur Daten-Sicht — Grant-Write als einziger Sicht-Pfad

Tragende Erkenntnis des Enterprise-Aufsatzes, von vier der fuenf Dimensionen unabhaengig getragen und gegen HEAD verifiziert: ein Reseller verwaltet seinen Sub-Tree, sieht aber NULL Block-Inhalte; eine Konzern-Mutter vererbt Verwaltung transitiv abwaerts, aber Daten-Sicht entsteht NUR ueber eine explizite context_tenant_grants-Kante. read_scopes wird ausschliesslich aus tenant_id + Grants gebaut — die Management-Hierarchie spielt keine Rolle. Der Grant-Write ist damit der einzige Pfad, der read_scopes weitet, und das hoechstwertige Eskalations-Ziel; diese Trennung soll test-gepinnt erhalten bleiben.

Gold-Standard-Bau-Methode: TDD rot→gruen + 3-Linsen-Verify + Reihenfolge-Zwaenge

Jede der 20 committeten MT-Wellen folgt laut Quelle demselben Muster (TDD rot→gruen, 3-Linsen-Verify, Nachverifikation, pre-commit 0 issues). Migrations-Nummern werden linear neu vergeben (K-M1), weil vier Achsen 058 beanspruchten und der Runner ON CONFLICT DO NOTHING still ueberspringt; Gates pruefen Artefakte/Spalten, nie Nummern. Harte Reihenfolge-Zwaenge ziehen sich durch: 05-A8 (T25) MUSS vor 03-W5 (T31) und 04-W5 (T37), sonst fail-OPEN; die teure RRF-OR-Welle T40b erst NACH gruener Skalen-Bench T42; Phase G erst nach Phase C/02-V3-Bench.

Detail

Themenbereiche

01

Multi-Tenant Kern-Architektur (Modell C, 44 Wellen)

Aktiv · In BauIn Bau — 20/44 Wellen committet, Branch feat/multi-tenant (nicht deployed)
Fertig 20Geplant 28

Das aktive Grossvorhaben: Multi-Tenant-Ausarbeitung im Gold-Standard, Tenant-Modell C (Hybrid, 3-Ebenen Tenant/Scope/Block), durch User-Praezisierung 2026-06-15 entschieden (E1). Umfang 44 Wellen (T01-T43, T40 gespalten in T40a/b) ueber 7 Achsen / Phasen A-G, 11 Migrationen 058-068, ~7805 LOC inkl. Tests. Bau-Status gegen Git verifiziert: 20 Wellen committet (jede TDD rot->gruen + 3-Linsen-Verify + Nachverifikation + pre-commit 0 issues), Migrationen 058-064 committet. Branch feat/multi-tenant ist lokal, NICHT gepusht/deployed; echte Live-DB max(migration)=57.

44 (T01-T43, T40 gespalten in T40a/b)Gesamt-Wellen20 WellenCommittet7 (058-064)Migrationen committet11 (058-068)Ziel-MigrationenNICHT deployed (Branch lokal, DB max(migration)=57)Live-Deploy-Status~7805 (5925 + ~1880 Achse 07)LOC inkl. Tests7 Achsen, Phasen A-GAchsen / PhasenC (Hybrid, 3-Ebenen Tenant/Scope/Block)Tenant-Modellddbfd7f (feat/multi-tenant)HEAD
  • T01Migration 058 scope_generalizeFertig

    01-T1, Phase A. Altbestand-Generalisierung: CHECK-Drop chk_blob_scope/chk_source_scope + VARCHAR(20)->50 auf dream_links/blobs/sources/write_log. Modellunabhaengige Vorbedingung fuer ALLES. Committet 180d894.

    Achse 01Phase AMigration 058
  • T02Migration 059 tenants_hybrid (Modell C)Fertig

    01-T2, Phase A. context_tenants (UUID-PK, slug, status-CHECK) + context_tenant_scopes (scope PK, tenant_id FK) + context_api_keys.tenant_id/tenant_role (CHECK = E2-Satz) + default-Tenant-Backfill (feste UUID, 3 scope-Zeilen, 7 Keys, idempotent). owner|admin|member RBAC-Bootstrap. Committet 0a18292.

    Achse 01Phase AMigration 059
  • T14Migration 061 context_tenant_grantsFertig

    02-V1, Phase C. Cross-tenant Read-Kanal (grantee_tenant FK->tenants, granted_scope FK->tenant_scopes, ON DELETE CASCADE, uq grantee+scope, idx). Additive Tabelle, kein Konsument (no-consumer). Committet 2b08ec3.

    Achse 02Phase CMigration 061
  • T03/T15Migration 060 ctx_auth_tenant (fusioniert)Fertig

    01-T3 + 02-V2 in EINER Migration (K-A1). ctx_auth DROP+CREATE: tenant identity (+tenant_id/tenant_role via Join) + Suspend-Status-Gate + positional read_scopes-Body (own ∪ grants, _-gefiltert, COALESCE-Untergrenze). AuthResult.TenantID/TenantRole + auth.go:48 NAMED-SELECT additiv. Committet 3bdaf30.

    Achse 01Achse 02Phase A/CMigration 060
  • T04store.TenantScopes + RequireScopesFertig

    01-T4, Phase A. Per-tenant scope foundation: TenantScopes(tenantID) Lookup + RequireScopes (fail-closed read contract: unknown -> [] -> rrf lehnt ab, leeres scope-Array -> ErrNoScopes). Committet bd6897c.

    Achse 01Phase A
  • T05aTenant-Lifecycle manage-actionsFertig

    01-T5 (Teil), Phase A. tenant-create/list/get/update Actions, admin-gated, eigene reservedSlug-Validierung. Committet 0bc2133.

    Achse 01Phase A
  • T05bTenant-delete full-pruneFertig

    01-T5 (Teil), Phase A. FK-geordneter batched DELETE (dream_links->blocks->blobs->scopes->tenant, NICHT metadata-only). Committet 9033ef5.

    Achse 01Phase A
  • T05cE6 session-suspend-cutFertig

    01-T5 (Teil), Phase A. Per-Turn owner-tenant Status-Recheck (Suspend-Snapshot-Entwertung). Setzt die in E6 offene Entscheidung um. Committet 2c2d1d9.

    Achse 01Phase AE6
  • T07Fail-closed read-path hardeningFertig

    01-T7, Phase A. RequireScopes-Wiring in SearchBlocks + Manage-Reads + Blob/Overview-Reads; MCP-private-Default -> fail-closed (L7, K-SEC2 — 05-A10 hierher fusioniert). Committet e68c391.

    Achse 01Phase AK-SEC2
  • T0806-C1 per-tenant config snapshot foundationFertig

    06-C1, Phase B. Store v2: base-Pointer + leerer Tenant-Cache (sync.Map) + SnapshotForRequest/SnapshotForTenant (faellt heute IMMER auf base zurueck), Snapshot() unveraendert, Replace wiped Cache + baseGen-Stempel, single-flight. Committet 7e45d42.

    Achse 06Phase B
  • T16a02-V3 end-to-end graph isolation probesFertig

    02-V3 (Teil), Phase C. Vier Cross-Tenant-Leak-Pfade als end-to-end Graph-Isolations-Probes verankert (negativ-geprobt, keine Produkt-Code-Aenderung). Committet 9f846ed.

    Achse 02Phase C
  • T1702-V4 cross-tenant grant managementFertig

    02-V4, Phase C. Admin-gated manage-actions tenant-grant-create/list/delete + store CRUD (Freund-Tenant-Workflow). Read wirkt sofort (naechster Auth resolved neu). Committet 563abae.

    Achse 02Phase C
  • T2005-A3 auth.Role + fail-closed IsServerAdmin/IsTenantAdminOfFertig

    05-A3, Phase D. auth.Role + reine Funktionen (fail-closed-Lattice, Leer-Guard tenant=='' -> false VOR is_admin-Kurzschluss). Admin-Tier-Foundation. Committet f93082e.

    Achse 05Phase D
  • T2105-A4 whoami tenant identityFertig

    05-A4, Phase D. whoami additiv um tenant_id + per-tenant role (admin-Feld bleibt back-compat). Committet 19110c6.

    Achse 05Phase D
  • T2305-A6 tenant-scoped + active-filtered api-key listFertig

    05-A6, Phase D. ListApiKeys(tenantFilter, activeOnly=true) WHERE tenant_id (schliesst L1-Enumeration). activeOnly=true ist benannter Verhaltens-Change fuer Operator-Tooling. Committet 8482fd4.

    Achse 05Phase D
  • T2405-A7 tenant-gated api-key deleteFertig

    05-A7, Phase D. DeleteApiKey(id, tenant, isServerAdmin) mit WHERE id=$ AND tenant=ANY($), atomar in Store-Schicht (TOCTOU-frei), 404-no-oracle. Schliesst L2-DoS. Committet ffcdce3.

    Achse 05Phase D
  • T2703-W1 settings tenant-resolution foundation (Migration 064)Fertig

    03-W1, Phase E. Migration 064 (idx_settings_scope_key/idx_secrets_scope_name, scope-leading) + store.LoadSettingOverridesMulti (zwei-Scope-Pass tenant+_global, tenant gewinnt, empty-scopes fail-closed). Kein Konsument. Committet 3f182e8.

    Achse 03Phase EMigration 064
  • T33a04-W1 context_backends scope dimension (Migration 062)Fertig

    04-W1 (Teil), Phase F. Migration 062: context_backends.scope VARCHAR(50) NOT NULL DEFAULT '_global' (K-S1) + UNIQUE-Swap name->(scope,name) + idx_backends_scope + Audit-Trigger. Backend.Scope geladen/gescannt (read path). ctxd verhaltensgleich (alle 5 Backends _global). Committet ca7c0f5.

    Achse 04Phase FMigration 062K-S1
  • T33b04-W1 per-tenant quota schema (Migration 063)Fertig

    04-W1 (Teil), Phase F. Migration 063: context_tenant_quota + trg_tenant_quota_notify (K-N1) + llmlog/access_log-Indizes. Quota leer = fail-open = heute. Committet 70d944c.

    Achse 04Phase FMigration 063K-N1
  • T35a04-W3 query-synthesis caller attribution (api_key_id)Fertig

    04-W3 (Teil), Phase F. Telemetrie-Attribution: api_key_id am query-synthesis Pfad (synthesize.go — der teuerste, heute unattribuierte LLM-Pfad). Committet ddbfd7f.

    Achse 04Phase F
  • T0501-T6 api-key-create tenant-gebundenGeplant

    01-T6, Phase A. CreateApiKey +tenantID-Param (Key erbt tenant_id des Erzeugers) + {shared}-Default tenant-bewusst (R-LEAK5, api_keys.go:67) + whoami liefert owning-tenant-Identitaet. Deps T03/T05, E4 fix. Negativ: neuer Key fuer Tenant B -> read_scopes ohne default-shared-Bloecke. ~90 LOC. (Plan-ID T06; Briefing nennt T06 nicht als committet.)

    Achse 01Phase AE4
  • T0906-C2 TenantOverlay-Typ + settings-ImplGeplant

    06-C2, Phase B. TenantOverlay-Typ + settings-Implementierung (zweiter Overlay-Pass: _global-Basis + tenant-Rows, Praezedenz tenant>global, voller config.Build mit zwei Override-Slices). Deps T08, 03-MT3-W3 (loadTenantOverrideRows-Refactor). ~120 LOC.

    Achse 06Phase B
  • T1006-C3 Store.overlay per Boot injiziertGeplant

    06-C3, Phase B. Store.overlay per Boot injiziert (main.go); SnapshotForTenant baut/cached echte Tenant-Generationen; Build-Fehler -> base (fail-safe). Deps T09. ~40 LOC.

    Achse 06Phase B
  • T1106-C4 NOTIFY-Payload-scope + Listener-DispatchGeplant

    06-C4, Phase B. NOTIFY-Payload-scope + Listener-Dispatch (InvalidateTenant bei tenant-scope, Replace+wipe bei _global); No-Notify-Loop-Invariante gewahrt. Deps T10, 03-MT3-W6 (Migration 065 + Trigger-Payload live). ~60 LOC.

    Achse 06Phase B
  • T1206-C5 ConfigStore-Interface + Request-Call-SitesGeplant

    06-C5, Phase B. ConfigStore-Interface um SnapshotForRequest; ~12 TENANT-Request-Call-Sites umstellen, tenantScope INTERN aus AuthResultFromContext (kein Scope-Param, fail-closed by construction). Deps T10, 01-T3. ~90 LOC.

    Achse 06Phase B
  • T1306-C6 Background-Tenant-IterationGeplant

    06-C6, Phase B. Scheduler/audit/classify loopen ueber Tenant-Liste, SnapshotForTenant pro Iteration (round-robin, E7-Fairness offen). Vorbedingung K-SNAP1: tenant-loser Pfad SnapshotForTenant(_global) muss existieren. Deps T10, 01, E7. ~110 LOC.

    Achse 06Phase BE7
  • T1602-V3 Graph-Isolations-Bench + MutationsprobenGeplant

    02-V3 (Rest), Phase C. Vier Leak-Pfade als Mutationstests + scope-Selektivitaets-Bench (R-SCALE1/2/3, E7): 1M-x-N-Korpus mit scope-Selektivitaet als Achse, EXPLAIN ANALYZE small-tenant-Query. Deps T15. ~260 LOC. (T16a end-to-end-Probes bereits committet.)

    Achse 02Phase CE7
  • T1805-A1 Konsum-Welle (0 Migration)Geplant

    05-A1, Phase D. Konsum-Welle: tenant_role/tenant_id + ctx_auth 6->8 sind Achse-01-Artefakte (060); verifiziert nur den Konsum-Kontrakt. Deps T03. ~0 LOC.

    Achse 05Phase D
  • T1905-A2 AuthResult + Authenticate Scan-AnschlussGeplant

    05-A2, Phase D. AuthResult + Authenticate Scan um TenantID/TenantRole (reiner Daten-Transport; Felder gehoeren Achse 01, Scan-Anschluss hier verifiziert). Deps T18. ~15 LOC.

    Achse 05Phase D
  • T2205-A5 Key-Minting tenant-gatedGeplant

    05-A5, Phase D. non-server-admin home_scope MUSS == eigener Tenant (schliesst L3-Escalation). Negativ: non-server-admin mint fremder Tenant -> 403. Deps T20. ~40 LOC.

    Achse 05Phase D
  • T2505-A8 actionTier + requireTenantAdmin verdrahtenGeplant

    05-A8, Phase D. actionRequiresAdmin -> actionTier + requireTenantAdmin(targetTenant): tenant-admin darf key/mcp/backend/audit, NICHT gaming/dream/Status/llmlog/events (server-admin). Verallgemeinert K-SEC1 Write-Gate. HARTE Vorbedingung fuer 03-W5 (T31) + 04-W5 (T37), sonst fail-OPEN (R-LEAK8). Deps T22/T23/T24. ~50 LOC.

    Achse 05Phase DK-SEC1R-LEAK8
  • T2605-A9 Migration 066 OAuth-Client-Tenant-BindungGeplant

    05-A9 (optional, E5), Phase D. Migration 066: context_oauth_clients.tenant_id + Backfill aus created_by.home_scope (Modell-C-UUID) + _orphan-Sentinel (server-admin-only) + MCP-Client tenant-owned (schliesst L6). Nur falls E5=ja. Deps T25. ~50 LOC.

    Achse 05Phase DMigration 066E5optional
  • T2803-W2 Registry-tenancy-Tag-AchseGeplant

    03-W2, Phase E. tenancy-Tag (tenant-overridable|global-only, untagged Leaf -> Boot-Panic) + admitOverride-Gate. gaming.active + 4 embed-Keys (embed.host/protocol, dream_embed.host/protocol) = global-only. R-SCALE6-Gate: Spy auf embedcache.Flush. Cross-achsen-frei, sofort startbar. ~230 LOC.

    Achse 03Phase ER-SCALE6
  • T2903-W3 loadTenantOverrideRows + tenant-gewinnt-MergeGeplant

    03-W3, Phase E. loadTenantOverrideRows(tenant) + Merge im Build-Pfad (tenant>global>env>default). Bootstrap bleibt _global-only. Liefert den Refactor, den 06-C2 (T09) konsumiert. Deps T28, 01-T3. ~260 LOC.

    Achse 03Phase E
  • T3003-W4 Per-Tenant-Snapshot-KonsumGeplant

    03-W4, Phase E. cfg.SnapshotForRequest/SnapshotForTenant liefert tenant-aufgeloeste Config gegen 06-Halterung. EIN Snapshot pro Operation pro Tenant (kein torn read). Vorbedingung K-SNAP1: tenant-loser Pfad fuer Scheduler. Deps T29, 06-C3. ~280 LOC.

    Achse 03Phase EK-SNAP1
  • T3103-W5 Settings/Secrets-API tenant-scopedGeplant

    03-W5, Phase E. 12 Handler-Stellen tenant-scoped + tenant-Secret-Resolver + Zwei-Schreib-Welten (IsOperator schreibt _global, tenant-admin nur TenantOf(ar), R-LEAK8) + resolveGlobalFallback gegated auf tenant.allow_shared_secrets (default false, E5-D2) + referencedBy folgt resolveScopes-Kette. Reihenfolge-Zwang: 05-A8 (T25) VOR W5, sonst fail-OPEN. Deps T29, 05-A8, E5. ~380 LOC.

    Achse 03Phase ER-LEAK8E5
  • T3203-W6 Migration 065 NOTIFY-scope-PayloadGeplant

    03-W6, Phase E. Migration 065: notify_settings_write CREATE OR REPLACE, scope im NOTIFY-Payload (K-N1) + scope-getragene Cache-Invalidierung. Optimierung; ohne W6 invalidiert jeder Write alle Tenants. 063-Quota-Trigger erbt scope-Payload automatisch nach 065. Deps T30, T27, 06-C4 (soft). ~220 LOC.

    Achse 03Phase EMigration 065K-N1
  • T3404-W2 Chain() tenant-gefiltertGeplant

    04-W2, Phase F. visibleTo als ERSTE Filter-Case (_global OR caller-Tenant, _-Praefix-Guard K-SEC3) + Caller-Tenant durch 5 Request-Pfad-Call-Sites (synthesize.go:398, query.go:432/661/905, engine.go:569). Egress-Isolation (R-LEAK7). Negativ: fremdes tenant-private prio-1000-Backend NICHT in Chain(...tenantA). Deps T33, 01-T3. ~350 LOC.

    Achse 04Phase FK-SEC3R-LEAK7
  • T3504-W3 Telemetrie-Attribution (Rest)Geplant

    04-W3 (Rest), Phase F. Entry.APIKeyID an allen Caller-getragenen WIRE-Calls: chain.go:307-328 (translate/temporal), chain.go:198-217 (embed). Dream bleibt NULL (Background). Optional scope-Denormalisierung (R-ATTR1, E8). Deps T33. ~200 LOC. (query-synthesis-Teil T35a bereits committet.)

    Achse 04Phase FE8
  • T3604-W4 Quota-DurchsetzungGeplant

    04-W4, Phase F. TenantQuota-Typ + QuotaAccountant (lock-frei atomic.Pointer+CAS, TTL) + QuotaGate vor Locality=='external' (Kosten-Gate) + daily_calls vor jedem Versuch + pool.default_tenant_quota + manage-Action tenant-quota-set/get + CLI ctx quota. Lokal IMMER erreichbar. Deps T34+T35, 02/03-Settings-Overlay. ~450 LOC.

    Achse 04Phase F
  • T3704-W5 Per-Tenant-Admin Backend + llmlogGeplant

    04-W5, Phase F. backend-create erzwingt scope=ar.HomeScope (tenant-admin)/erlaubt _global (server-admin); update/delete 404 fuer fremde/_global; backend-list=Status(tenant); GET /api/llmlog + 24h-Rollup per-Tenant-Filter + sum(cost_usd). SSE-Re-Auth (events.go:469-471) + Pull-Filter MUESSEN zusammen deployen (K-T1). Deps T34+T35, 05-A8. ~400 LOC.

    Achse 04Phase FK-T1
  • T3804-W6 Background-Pfad tenant-iteriertGeplant

    04-W6, Phase F. Dream/Digest pro Tenant (DISTINCT home_scope aktiver Keys) mit tenant-sichtbarem Chain (router.go:44/56/75) + per-Tenant-ScopeSensitivityFloor. Kein tenant-privates Backend im Background fremd-genutzt. Deps T34, 01, 02/06. ~400 LOC.

    Achse 04Phase F
  • T3907-W1 Migration 067 context_block_grantsGeplant

    07-W1, Phase G (NEU 2026-06-15). Migration 067: context_block_grants (block_id FK CASCADE + grantee_tenant FK + granted_by + uq + idx; KEINE permission-Spalte), backfill-frei/idempotent, kein Konsument. T07-Count 28->29. Deps T02. ~150 LOC.

    Achse 07Phase GMigration 067
  • T40a07-W2 Abruf-OR (skalen-unkritisch)Geplant

    07-W2, Phase G. VisibilityPredicate zentral +Grant-Set-Param (Pflicht-Klammer) + GetBlock/ResolveBlockID/SearchBlocks/Browse/GraphExpand-inline + 3 MCP-Handler. Orakel-Fix (Log hinter GetBlock, Full-UUID nicht ungated). KEIN ctx_rrf. Deps T39, 01-T4, 01-T7. ~290 LOC.

    Achse 07Phase G
  • T4107-W3 Graph-Bruecken-Blatt-SchutzGeplant

    07-W3, Phase G. Grant-Block = Blatt (sichtbar, nicht traversierbar) in ALLEN 3 Seed-Quellen (frontier / Hop-0-Focus / GraphExpand-Seed). G4 dreigleisig negativ-geprobt. Deps T40a (+T40b fuer RRF-Arm). ~260 LOC.

    Achse 07Phase G
  • T4207-W4 Skalen-Bench (Aufsatz auf 02-V3)Geplant

    07-W4, Phase G. OR-Kosten @ 1M (scope x Grant x Array-Groesse), EXPLAIN ANALYZE BitmapOr/Seq-Scan-Kipp, Strategie-A-Schwelle + U-E7-Cap. Reiner Bench, kein Produkt-Code-Delta. HART abhaengig von 02-V3. Deps 02-V3 (HART), T40a. ~390 LOC.

    Achse 07Phase GBench
  • T40b07-W5 RRF-OR (teuer, Migration 068)Geplant

    07-W5, Phase G. ctx_rrf DROP+CREATE (Migration 068) +p_granted_block_ids UUID[] DEFAULT NULL sechsfach, innere Klammer ERZEUGT; rrf.Search +$13. Bestand byte-identisch bei leerem Set. Reihenfolge: erst NACH gruener T42 (sonst W8-Verstoss, R-SCALE8). Deps T40a, gruene T42. ~270 LOC.

    Achse 07Phase GMigration 068R-SCALE8
  • T4307-W6 Grant-VerwaltungGeplant

    07-W6, Phase G. block-grant-create/list/revoke admin-gated + Eigentums-Pruefung (block.scope ∈ TenantScopes, Unaufloesbarkeit->DENY) + cross-tenant-opt-in (default AUS) + grant-fester Egress-Floor (annotateSensitivities-Signaturaenderung, max(owner,grantee,GRANT_FLOOR_DEFAULT,block.sens)). Deps T40a (+T40b RRF-Arm); per-Tenant-Admin spaeter 05-A8. ~440 LOC.

    Achse 07Phase G

Entscheidungen

  • E1 — Tenant-Modell = Modell C 2026-06-15Entschieden durch User-Praezisierung 2026-06-15 (addendum-2026-06-15.md §1). 3-Ebenen-Architektur verbindlich: Tenant = Projekt/Firma inkl. Test-Tenants, scope = Abteilung/Arbeitsbereich, Block = Freigabe. Begruendung: scope steckt bereits im Unique-Key (Befund D); Modell A redundant + teuer (5 Constraint-Swaps + 6 SET-NOT-NULL ACCESS-EXCLUSIVE-Locks ueber 1M+), Modell B fehlt das Owner-Register fuer Status/Suspend bei oeffentlichem Deployment.
  • Tenant ist schmales Owner-Register, KEIN tenant_id auf Daten-TabellenVerbindliche Invariante (conflicts.md §0): context_tenants (UUID-PK, status active|suspended|offboarding). scope (VARCHAR(50)) bleibt der Daten-Diskriminator auf allen datentragenden Tabellen. Bruecke = Partitions-Map context_tenant_scopes(scope PK, tenant_id UUID FK CASCADE). shared ist ein Grant, keine unbedingte Auto-Sicht (fail-closed). System-scopes (_-Praefix, insb. _global) gehoeren KEINEM Tenant.
  • K-M1 — lineare Migrations-Neuvergabe 058-066Vier Achsen beanspruchten 058 (Runner ON CONFLICT DO NOTHING -> stiller Schema-Verlust). Aufgeloest: 058 scope_generalize, 059 tenants_hybrid, 060 ctx_auth_tenant (01+02 fusioniert, K-A1), 061 tenant_grants, 062 backend_pool_tenant, 063 tenant_quota, 064 settings_secrets_index, 065 settings_notify_scope, 066 oauth_client_tenant (optional). Phase G ergaenzt 067/068. Gates pruefen Artefakte/Spalten, nie Nummern.
  • K-A1 — ctx_auth als EINE kombinierte Migration 060ctx_auth dreifach umgebaut -> fusioniert: Struktur+Status-Gate (Achse 01) + tenant-aufgeloester read_scopes-Body (Achse 02) in EINER Datei (DROP+CREATE, M052-Muster). 060 setzt 061 voraus (read_scopes-Body filtert grantee_tenant).
  • K-S1 — shared-Backend-Marker = scope='_global' NOT NULL04s Wahl verbindlich (nicht NULL). Konsistent mit context_settings/context_secrets-Konvention; _-Praefix system-reserviert -> kollisionsfrei; metadata-only Backfill ohne NULL-Sonderpfad. Achse 01 zieht die NULL-Skizze zurueck. Vereinheitlichung VOR Migration 062.
  • K-SEC2 — MCP-private-Default-Fix gehoert Achse 01 (T7)ar==nil -> private an 4 MCP-Stellen ersetzt durch errResult/401. Achse 05-A10 (MCP-Haertung) ist redundant und wurde zu 01-T7 zusammengefuehrt. Bereits committet in T07 (e68c391).
  • E6 — Suspend-Snapshot-Entwertung umgesetzt 2026-06-15Per-Turn-Status-Gate (Variante a, chirurgischer Schnitt) wurde in T05c committet (2c2d1d9). Die Entscheidung war als E6 offen markiert; der Bau hat den per-Turn owner-tenant Status-Recheck gewaehlt.
  • Audit-Amendments 2026-06-15 2026-06-15(1) read_scopes POSITIONAL in 060 — KEIN array_agg(DISTINCT) (bricht home_scope=read_scopes[0]); (2) Achse 08 Graph-Overview-Tenant-Isolation neu (Read schon doppelt-gegatet/sicher laut Quelle, offen nur optionale Rebuild-Isolation); (3) api-key-list activeOnly=true-Default = benannter Verhaltens-Change; (4) Full-Prune FK-geordnet + E6 Session-Suspend-Cut entschieden; (5) 066-Backfill auf Modell-C-UUID korrigiert.

Offene Fragen

  • E2 — Rollen-Wertebereich (2 vs. 3 Stufen)member|tenant-admin (2 Stufen, Empfehlung, minimaler Schnitt analog M052) vs. owner|admin|member (3 Stufen). Muss byte-identisch in DB-CHECK (059) + Go-Role (T20) + whoami-Wire. Anmerkung: 059 (T02) ist bereits committet mit owner|admin|member RBAC-Bootstrap laut Briefing.
  • E3 — shared-Schreibrecht fuer Friend-Tenantsread-only via Grant (Empfehlung; nur default-Tenant schreibt shared) vs. echtes Schreibrecht (K-SEC1). Blockiert 05-Write-Gate (T25/T31).
  • E4 — shared-Zuordnung der 21 kanonischen Cross-Tenant-BloeckeWeg a: bleibt default-Tenant-Scope (Empfehlung, kleinste revidierbare Aenderung) vs. Weg b: System-uebergreifender Scope wie _global. Der {shared}-Default-Fix (R-LEAK5, api_keys.go:67) ist davon unabhaengig Pflicht in T06 (=Plan-Welle T05 hier).
  • E5 — shared-_global-Provider-Key/Backend-Fallback + tenant-owned OAuth-ClientsEIN gemeinsamer Opt-in-Schalter tenant.allow_shared_secrets (global-only, default false = strikte Isolation, Empfehlung) fuer Backend UND Secret. OAuth-tenant-owned (066/T26) nur falls oeffentliche N-Tenant-MCP-Registrierung gewuenscht. Blockiert 03-W5 (T31) + 04-W2 (T34); T26.
  • E7 — HNSW-Filtered-Search-Cap + Graph-Hop-Budget + Background-FairnessDatengetrieben: zuerst messen (T16 / 02-V3-Bench), dann max_scan_tuples-Cap. Round-robin-Fairness als Tag-1-Strategie. Eigene Bench-Welle (T16).
  • E8 — Kosten-Attribution Key-Lifecycle(a) scope-Denormalisierung in context_llm_log (Empfehlung, mutations-unabhaengig) vs. (b) home_scope immutabel deklarieren (R-ATTR1). Optionaler Migrations-Schritt in 04-W3 (T35).
  • E9 — Default-Tenant-slugdefault (Empfehlung, kosmetisch) vs. Betreiber-Name (gottz). Triviale Backfill-Konstante in 059 (T02). Anmerkung: 059 ist bereits committet.
  • UB-1..UB-6 — Achse-07-Sub-Entscheidungen (block-level)grain-of-salt-Marker fuer die block-level-Freigabe (Achse 07/Phase G), dokumentiert in addendum-2026-06-15.md §6.3. Offen seit der E1-Praezisierung 2026-06-15. Volltext-Gate-Texte in design/07-block-level-sharing.md + addendum §4.

Risiken

  • HochR1 — Cross-Tenant-Daten-Leak ueber empty/NULL/Sentinel-ScopeNur rrf/search.go:65-67 hat heute den Empty-Scope-Reject. SearchBlocks/Manage-Reads/Blob/Overview-Reads ueberleben nur durch das PG-ANY('{}')-Artefakt. Unter per-Tenant-Resolution wird der NULL/empty-Pfad real. Adressiert in 01-T7 (RequireScopes-Helper, committet T07) + 02-V2 (COALESCE-Untergrenze in ctx_auth, committet T15) + 01-T4 (TenantScopes, committet T04). Quelle nennt fail-closed-Disziplin als oberste Prioritaet.
  • HochR2 — Egress-Leak: Tenant A nutzt Bs external Backend/KeyChain() kennt heute keinen Caller. Adressiert in 04-W2 (T34, visibleTo-Filter, geplant) + tenant-aware SecretResolver + 03-W5/05-A8 (Zwei-Schreib-Welten). Reihenfolge-Zwang: 05-A8 (T25) VOR 03-W5 (T31).
  • HochR3 — Settings/Secrets cross-tenant-Enumeration / DELETE-fail-open + embed-cache-Sturm_global-Secret-DELETE prueft Refs heute nur in _global. Die 4 embed-Keys tragen mut:coupled:embed-cache; ein per-Tenant-Override wuerde embedcache.Flush ueber den prozessweit geteilten Cache (keine scope-Spalte) ausloesen -> leert Cache ALLER Tenants. Adressiert in 03-W2 (T28, embed-Keys global-only + Flush-Spy-Gate) + 03-W5 (T31, caller-scope-Resolution + resolveGlobalFallback gegated).
  • HochR4 — HNSW-Vektor-Post-Filter-Amplifikation + Overview O(node_limit^2) + Hop-Budget-StarvationDer semantic-CTE in ctx_rrf filtert scope als POST-FILTER auf scope-blindem HNSW-Index; iterative_scan='relaxed_order' OHNE max_scan_tuples/ef_search-Cap. Bei 1M x N zwingt ein Friend-Tenant mit kleiner Selektivitaet den Scan beliebig tief. Adressiert in 02-§6.2a/E7 (datengetrieben, NICHT geblind geloest, bench-pflichtig T16) + node_limit per-Tenant cappen.
  • MittelR5 — Stiller Schema-Verlust durch doppelte Migrations-Nummer + ACCESS-EXCLUSIVE-Lock-DauerVier Achsen wollten 058; ON CONFLICT (version) DO NOTHING ueberspringt die zweite Datei STILL. migrations.go:88-110 haelt jede Datei in EINER Tx -> CREATE INDEX CONCURRENTLY verboten. Adressiert in K-M1 (lineare Neuvergabe 058-066) + K-C1 (Achse 01 alleiniger Erzeuger) + R-MIG2-Mitigation (lock_timeout-Header 058; access_log-Index Out-of-Band CONCURRENTLY VOR Deploy).

Nächste Schritte

  • Neun User-Entscheidungen einholen — E2-E9 + UB-1..UB-6 (E1 bereits entschieden = Modell C). Ohne E-Entscheidungen bleiben die jeweiligen Wellen/Migrationen blockiert.
  • Phase B parallel weiterfuehren: T09 (06-C2 TenantOverlay) -> T10 -> T11 -> T12 -> T13 (T08 bereits committet).
  • Phase A abschliessen: T05 (=Plan-Welle 01-T6, api-key-create tenant-gebunden) — letzte offene Fundament-Welle (E4 fix noetig).
  • Achse 05 fortsetzen: T18 (Konsum) -> T19 -> T22 -> T25 (05-A8, harte Vorbedingung fuer T31+T37).
  • Achse 03 fortsetzen: T28 (cross-achsen-frei, sofort startbar) + T29 -> T30 -> T31 -> T32.
  • Achse 04 fortsetzen: T34 (Chain tenant-gefiltert) -> T35 (Rest-Attribution) -> T36 -> T37 -> T38.
  • Phase G erst nach Phase C/02-V3-Bench: T39 -> T40a -> {T41 ∥ T42} -> T40b (nach gruener T42) -> T43.
  • Release-Schnitt RC-1 (Tenant-Fundament + Read-Isolation = Phase A+C+D) als Sicherheits-Kern-Release vorbereiten; Versionsnummer offen (User entscheidet).
02

MT Enterprise-Erweiterung (Aufsatz auf Modell C)

GeplantAnforderungs-Wahrheit erstellt — 5 Dimensionen, ~140 Anforderungen, kein Bau-Plan
Entschieden 4Geplant 27

Enterprise-Aufsatz auf die abgeschlossene Multi-Tenant-Planung (Modell C, 44 Wellen T01-T43, Migrationen 058-068): Reseller/Mandanten-Verwaltung, Konzern-Hierarchie (Mutter/Tochter), ephemere Test-Tenants, separate Models (Embedding+Inference) und Lastverteilung. Das Anforderungs-Dokument (Stand 2026-06-16, ~140 Anforderungen ueber 5 Dimensionen) ist die Anforderungs-Wahrheit fuer die naechste Planungsstufe — es legt fest WAS verlangt wird und WO es den Code beruehrt, NICHT die Bau-Wellen-Reihenfolge. Alle IST-Stellen gegen HEAD feat/multi-tenant (ddbfd7f) re-verifiziert. Tragende Erkenntnis (von vier der fuenf Dimensionen unabhaengig getragen): Verwaltungs-Autoritaet ist orthogonal zur Daten-Sicht — der context_tenant_grants-Write ist der einzige Pfad, der read_scopes weitet.

5Dimensionen~140Anforderungen6/6 gegen HEADVerifizierte Code-Befunde0-5Phasen (Sequenzierung)feat/multi-tenant (ddbfd7f)Branch058-064Migrationen (HEAD)
  • Dim 1Reseller / Mandanten-VerwaltungGeplant

    Ein Tenant-Key (Reseller) provisioniert + verwaltet Tenants INNERHALB seines eigenen Sub-Trees (Keys/Quotas/Grants), sieht aber NIE deren Daten. Mehrstufig (Reseller-of-Reseller). 23 Anforderungen R-RES-01..R-RES-23. Braucht das fehlende Hierarchie-Primitiv parent_tenant_id, einen sub-tree-bewussten Admin-Praedikat-Satz, hierarchische Quota mit Usage-Rollup und einen resumablen Sub-Tree-Prune. Heute der EINZIGE Akteur mit Tenant-Management ist server-admin (is_admin); kein Reseller/per-tenant-admin erreicht irgendeine Tenant-Management-Action (actionRequiresAdmin context_manage.go:206-207). Modell C bleibt: scope ist Daten-Diskriminator, der Baum lebt auf context_tenants.

    resellerhierarchieprovisioning
  • R-RES-02parent_tenant_id-Kante als Fundament (neue-achse)Geplant

    context_tenants erhaelt parent_tenant_id UUID NULL REFERENCES context_tenants(id) ON DELETE RESTRICT + btree-Index + PRAEVENTIVER acyclicity-Trigger. default-Tenant = Wurzel (parent NULL). Repo-weiter grep fuer parent_tenant|ancestor|reseller|RECURSIVE|closure|subtree ueber internal/+migrations/ = NULL Treffer (context_tenants flach 059:55-65). Empfehlung D-RES-01: self-FK + recursive CTE pro Query + Constraint-Trigger; Closure-Table premature bei diesem Row-Count. Tenant struct/tenantCols/scanTenant (tenant.go:103-130) erweitern.

    schemahierarchiemigration
  • R-RES-03Sub-tree-bewusste Autorisierung CanAdministerDescendant (umbau)Geplant

    Tenant-Management-Authz vom binaeren server-admin-Gate auf Praedikat-SATZ: (a) IsTenantAdminOf self bleibt; (b) NEU CanAdministerDescendant = STRIKTER Descendant + NICHT self; (c) server-admin global. IsTenantAdminOf (role.go:47-61) ist heute STRIKT ar.TenantID==tenant, kann descendant nicht ausdruecken. Vermischtes OR self oeffnet Self-Promotion. EXPLIZIT: default/root-owner ist NIE impliziter Reseller-ueber-alle (braucht weiterhin is_admin). BEHAVIORLOS bis 05/T25 das Gate von is_admin auf IsTenantAdminOf flippt.

    securityauthz
  • R-RES-09Resumable leaf-to-root Sub-Tree-Prune mit offboarding-FreezeGeplant

    Tenant-Deletion durch Reseller auf Sub-Tree beschraenkt; Tenant mit Descendants verweigern ODER als EXPLIZITE geordnete RESUMABLE Kaskade leaf->root. PruneTenant (tenant.go:277-313) ist autocommit-batched (kein Tx-Wrapper) -> passt bei 1M+ NICHT in eine Tx. Zuerst status=offboarding auf GANZEN Sub-Tree (friert create ein), dann leaf-zuerst prunen (Crash-Resume = no-op). default-Wurzel-Delete bleibt verweigert. VORBEDINGUNG: context_dream_links scope-Index CONCURRENTLY out-of-band VOR Auslieferung.

    lifecycleprune
  • R-RES-22Konsistenz bei horizontaler Skalierung (N>1 Prozesse)Geplant

    Bei >1 ctx-Prozess driften prozess-lokale Counter (pool.go:259 atomic.Pointer); ancestor charge-up zaehlt N-fach NICHT (fail-OPEN auf Geld) -> SHARED Counter-Store (PG atomic UPSERT) ODER single-process-Constraint. Plus Invalidierungs-Kanal bei parent-Aenderung (sonst staler Cache = ge-reparenteter Tenant beim alten Reseller). Background-Kost GEBLOCKT auf T38/06-C6 (Dream/Digest global = dominanter nicht-attributierter Block).

    scalequotanon-functional
  • Dim 2Konzern-Hierarchie (Mutter/Tochter)Geplant

    Derselbe Baum (parent_tenant_id), andere Geschaeftslogik: transitive Verwaltungs-Vererbung abwaerts (Owner verwaltet alle Nachkommen), Chinese Walls zwischen Schwester-Toechtern, zentrales inhaltsfreies Compliance-Audit, Suspend-Kaskade auf den Sub-Baum. KH-F1..KH-L1 (functional/non-functional/security/data-isolation/lifecycle). Drei harte Vorbedingungen: (a) ungecappter HNSW-Post-Filter ist der @1M-mal-N-Killer; (b) transitive Verwaltung behaviorlos bis 05/T25; (c) Background-Suspend-Stop existiert nicht ohne 06-C6/04-W6 (Scheduler tenant-blind scheduler.go:700/724). Reseller = strikter Descendant + NICHT self; Konzern = transitive Verwaltung abwaerts.

    konzernhierarchiesuspend-kaskade
  • KH-F6Suspend-Kaskade in DREI getrennten MechanismenGeplant

    (1) ctx_auth-Auth-Zeit-Gate (060:146-147) von Single-PK-Lookup auf bounded recursive ancestor-Walk — kein Vorfahre != active, NULL/unaufloesbar -> __UNAUTHORIZED__ (fail-closed-Arm erhalten). (2) Per-Turn-Engine-Cut: ownerActive (engine.go:271) -> TenantStatusForScope (scope-keyed) muss sess.Scope->tenant->ancestor-walken (NEUE store-Fn), Turn abgelehnt (kein Sentinel). (3) Background-Stop: scheduler.go:700/724 muss suspendierte UND ancestor-suspendierte ueberspringen — existiert NICHT, HARTE Abhaengigkeit auf 06-C6/04-W6 (BLOCKER).

    securitysuspend
  • KH-S1Chinese Wall zwischen Schwester-ToechternGeplant

    Gleiches parent_tenant_id -> WEDER gegenseitige Sicht NOCH Verwaltung. Vertikal-only. Mutationstest BEIDE Richtungen: (a) lateral (B1 sieht B2-scopes NICHT, B1-Admin verwaltet B2 NICHT); (b) aufwaerts (A verwaltet B1+B2, B1 verwaltet B2 false, B1 verwaltet A false). role.go:60 ancestor-Check false fuer Geschwister UND aufwaerts.

    securityisolation
  • KH-NF2Denormalisiertes effective_status als Primaer-Design (nicht Reserve)Geplant

    ancestor-Status-Walk auf den ctx_auth-Hot-Path, der bereits WRITE-bound ist (last_used_at write-on-read 060:111-122, R-SCALE7 offen). Daher denormalisiertes effective_status/root_tenant_id (Trigger-gepflegt) als PRIMAER-DESIGN — ein indexed Lookup statt recursive CTE pro Request. recursive CTE mit variabler Tiefe ist plpgsql-generic-plan-Verlierer (060:90 cached generic plan nach ~5 Calls). ancestor_tenant_ids + Status-Gate in EINE Resolution fusionieren (kein N+1). Tiefen-Cap KONSTANTE (Vorschlag 16).

    non-functionalperformance
  • KH-S8Default-Tenant-Re-Parenting-VerbotGeplant

    handleTenantUpdate lehnt default-Tenant als Re-Parent-SUBJEKT ab (darf nie Kind werden) UND verhindert, dass ein anderer Tenant ihn via transitive Verwaltung uebernimmt. Wuerde default Kind, koennte dessen Owner via KH-F3 den Bestands-Korpus (private/work/shared) verwalten/suspendieren. KH-S10 ergaenzt: voll-transitive Owner-Vererbung macht den default-Owner zum De-facto-zweiten-Server-Admin OHNE is_admin-Bit, sobald andere Tenants unter default haengen — default kinderlos halten ODER transitive Verwaltung an der Wurzel begrenzen.

    securitydefault-tenant
  • Dim 3Testbereiche / ephemere TenantsGeplant

    Korpus-Test-Tenants als first-class Use-Case: billiger Create (Modell C), korrektheits-sicherer Teardown, additive Test-Markierung, Ausschluss aus ALLEN Background-Konsumenten (Overview/Louvain, Dream, Daily-Synthesis), Quota-Befreiung, Auto-Cleanup-Janitor, strikte Isolation gegen Prod, Embedding-/Vektorraum-Hygiene. F-ETT/NF-ETT/S-ETT/DI-ETT. ZENTRALE W3-Korrektur: der Background-Ausschluss-Filter gehoert an context_blocks.scope (loadNodes cluster.go:164 + aggSQL), NICHT an context_dream_links.scope (057:20-21 + visibility.go:20-21 verbieten l.scope als Diskriminator HART; loadEdges hat keine scope-Spalte).

    test-tenantsephemeralteardown
  • F-ETT-01 / S-ETT-03Markierung ueber metadata.ephemeral, NICHT status-WertEntschieden

    Test-Tenant als markierter context_tenants-Eintrag, additiv ueber metadata.ephemeral=true (059:63 JSONB), NICHT ueber neuen status-Wert. Begruendung (S-ETT-03): ctx_auth (060:32-36 v_status IS NULL OR <> active -> __UNAUTHORIZED__) wuerde status=ephemeral jeden Test-Request fail-closed abweisen (401, Test unbenutzbar). ephemeral orthogonal zum Lifecycle, ohne Auth-Tabellen-Lock. Plus redundante slug-Konvention (test- Praefix, NICHT _) als zweite Erkennungs-Achse (Defense-in-Depth).

    test-tenantsmarkierung
  • F-ETT-09b / S-ETT-04default-Tenant-Garde STRUKTURELL im Prune-MechanismusGeplant

    defaultTenantID nach internal/store exportieren (store.DefaultTenantID) und entweder PruneTenant um Default-Reject ODER separate store.PruneEphemeralTenant(id) die VOR dem Prune (a) id<>Default UND (b) metadata.ephemeral==true prueft. Handler-Pfad UND Janitor erben dieselbe Garde by-construction (doppelt fail-closed). Heute ist defaultTenantID UNEXPORTIERTE handler-lokale Konstante (tenant_manage.go:146); Janitor (internal/events) kann die handler-const NICHT importieren. Janitor-WHERE doppelt fail-closed; Cast-Fehler schliesst Zeile AUS.

    securityjanitor
  • F-ETT-10 / X5Daily-Synthesis Test-zu-Prod-Leak (einziger echter Daten-Leak)Geplant

    fetchDailyDreamLinks (synthesize_report.go:223-244) liest ALLE context_dream_links GLOBAL ohne scope-Param; GenerateDailyReport schreibt via UpsertBlock in cfg.Scheduler.HomeScope (Default private) -> Test-Aktivitaet im Klartext in einem PROD-retrieval-sichtbaren Synthese-Block. EINZIGER echter Test->Prod-DATEN-Leak (dream-links sind by-construction same-scope dream.go:672, computeClustering skippt dangling). F-ETT-05/06 sind am HEAD nahezu NO-OP (cfg.Scheduler.ReadScopes nur default-Tenant), Nutzen GEBLOCKT auf per-Tenant-Iteration 06-C6.

    data-isolationleak
  • NF-ETT-06Janitor-Prune mit advisory-lock + Yield + pro-Tick-BudgetGeplant

    Auto-Cleanup-Janitor erbt NICHT das gutartige Profil von rebuildOverviewOnce/EvictBodies. MUSS: (1) eigenen pg_try_advisory_xact_lock (Muster overviewLockKey cluster.go:34/268), damit bei horizontaler Skalierung nur EINE Instanz prunt; (2) activeQueries-Yield (scheduler.go:545/592/714), damit 1M-Teardown nicht in Prod-Last faellt; (3) PRO TICK nur EINEN Tenant (oder Batch-Budget). Janitor friert ablaufenden Test-Tenant VOR dem Prune atomar ein (UpdateTenant status=offboarding, F-ETT-08b).

    non-functionaljanitor
  • Dim 4Separate Models (Embedding + Inference)Geplant

    Per-Tenant Embedding-Provider mit Vektorraum-Isolation, embed-Provenance, scope-selektiver Rebuild-Job (inkl. zwei Embed-Rollen + drei Write-Pfade); per-Tenant Inference-Whitelist via NOCH-NICHT-EXISTENTES context_backend_grants. SM-F/SM-N/SM-S/SM-DI/SM-O/SM-Q. Die teuerste und gefaehrlichste Dimension, weil alle Tenants HEUTE EINEN HNSW-Vektorraum teilen (001:250) und gemischte Generationen darin NACHWEISLICH (cosine 0.997, embedcache.go:174) verboten sind. Dimension hart auf 1024 (vector(1024), embed.go:30 TargetDims=1024).

    embeddinginferencevektorraum
  • SM-F4 / SM-S0Chain-Scope-Whitelist + context_backend_grants-Subsystem (umbau)Geplant

    Per-Tenant Inference ueber Whitelist visible(tenant)=own (scope=tenant) UNION granted UNION _global. DREI Voraussetzungen, Fundament FEHLT: (a) context_backend_grants EXISTIERT NICHT (Migrationen enden 064; context_tenant_grants 061 ist BLOCK-READ, KEINE Backend-Sicht) — komplettes Subsystem (Tabelle+CRUD+NOTIFY+Handler) bauen; (b) Chain (pool.go:258-301) MUSS Scope-Filter bekommen, Backend.Scope (backend.go:132) heute NICHT ausgewertet (fail-OPEN: jeder Tenant bekommt VOLLE _global-Chain), Signatur-Bruch an ALLEN 9 Call-Sites; (c) visible()-Join im Pool-Snapshot vor atomic swap. Scope-Filter MUSS deployt sein BEVOR der erste Nicht-_global-Backend existiert (SM-S0).

    securitybackendfail-open
  • SM-F5embed-Rolle HART als _global-Sonderzweig im Chain-Scope-FilterGeplant

    embed-Role-Routing HART entkoppelt vom Inference-Whitelist (SM-F4) + BEIDE Embed-Rollen (RoleEmbed UND RoleDreamEmbed, backend.go:49): role in embedRoles bekommt einen Sonderzweig, der NUR scope=_global aufloest. embed darf NIE tenant-scoped Backend ziehen — sonst gewinnt nach SM-F4-Nachruestung ein tenant-scoped embed-Backend mit hoeherer Priority die scope-blinde Sortierung (pool.go:289-299) und uebernimmt query-embed eines ANDEREN Tenants. Plus: embed-Chains NIE mehr als EINE Generation (Pool-Invariant-Check beim Reload, embed-Failover auf anderes Modell VERBOTEN).

    embeddingrouting
  • SM-F2 / SM-F3Per-Tenant-Embed-Rebuild-Job via embed_status-Stale (neue-achse)Geplant

    Bei Modellwechsel ALLE Bloecke des Scopes stale markieren + neu einbetten, scope-gefiltert. Stale-Marker MUSS bestehende Infra nutzen — embed_status (001:43, 002:14) mit partiellem Index idx_embed_pending (001:206) statt embedding=NULL (verliert alten Vektor + scope-weites Sichtbarkeitsloch = Denial-Vektor). ALLE DREI Pick-Queries (scheduler.go:762, query.go:898, Rebuild) auf embed_status umstellen (heute liest KEINE den Index = toter Index). Idempotent, crash-resume, suspend-resume (Tenant-SUSPEND waehrend Rebuild MUSS pausieren, nicht abbrechen), ratenbegrenzt. Edit-vs-Rebuild-Race deterministisch.

    embeddingrebuild
  • SM-S2 / SM-S5embed-Cache Cross-Tenant-Klartext-Leak + DSGVO (text_preview)Geplant

    context_embed_cache global (kein scope, PK (text_hash, model)), text_preview (200 chars Klartext, embedcache.go:27/75-78/144-145). Bei geteiltem Modell liegen ALLE Cache-Eintraege ALLER Tenants im selben model-Bucket — ein DB-Leser/break-glass/SQL-Injection-Fund sieht 200-Zeichen-Fragmente JEDES Texts JEDES Tenants. Plus: PruneTenant loescht den scope-losen Cache NICHT -> text_preview ueberlebt Tenant-Delete (DSGVO-Loeschpflicht verletzt). Fix: text_preview im MT-Betrieb GANZ entfernen (loest SM-S2+SM-S5 gemeinsam); text_hash genuegt zur Identifikation.

    securitydsgvocache
  • SM-DI3 / INV-3Single Switch Point — scope=ANY-Filter in EINE wiederverwendbare CTEEntschieden

    Bei echter per-Tenant-Generation braeuchte ein Tenant eine SEPARATE Index-Partition + ZWEITE ctx_rrf-Funktion. Jede Kopie der scope=ANY-Postfilter-Logik (ctx_rrf an mehreren CTE-Stellen 018:71/91/118/139) ist eine NEUE scope-Leak-Stelle. visibility.go self-dokumentiert sich als designated single switch point. Aufloesung (VERBINDLICH): die scope=ANY-Sicht-Filter-Logik MUSS in EINE wiederverwendbare SQL-Funktion/CTE extrahiert werden, die JEDE ctx_rrf-Variante teilt, BEVOR eine zweite Partition-Variante entsteht — STARKES Argument fuer OD-1=A. read_scopes-Build bleibt FLACH (Gleichheit scope=ANY, kein Praefix/Rekursion in ctx_auth 060).

    data-isolationretrievalinvariante
  • Dim 5Lastverteilung / Load-BalancingGeplant

    Backend-Pool, Per-Tenant-Fairness, Quota als Lastschutz, Health/Failover, Background-Fairness, horizontale Skalierung. LB-A1/LB-F/LB-N/LB-S/LB-D/LB-L/LB-OBS. Zentrale Korrektur (von allen drei Linsen als critical markiert): scope == Last-Einheit ist die Wurzel-Fehlannahme — der default-Tenant hat DREI scopes (059:83-87), die Last-/Quota-/Fairness-Einheit ist ar.TenantID, NICHT die scope-Partition. Pool.Chain() hat genau 9 produktive Call-Sites; 6 von 9 umgehen ChainCall.Do -> Enforcement MUSS in Pool.Chain() selbst (LB-F5).

    load-balancingfairnessquota
  • LB-A1scope-vs-tenant aufgeloest VOR jedem Enforcement (Doktrin)Entschieden

    JEDE Achse schluesselt auf die ueber api_key->tenant_id aufgeloeste TENANT-Identitaet (ar.TenantID), NICHT die scope-Partition. (a) Quota 063 von uq_tenant_quota_scope UNIQUE(scope) auf UNIQUE(tenant_id) (063:42-43/59), Rollup ueber alle scopes UND Keys; (b) chat.go:112 inflight map auf tenant_id; (c) Background-Round-Robin iteriert context_tenants, nicht scopes. ar.TenantID verfuegbar (auth.go:24, populiert aus 060). HINWEIS: durch User-Entscheidung 2026-06-17 ist die Quota-Granularitaet revidiert (siehe offene Frage).

    data-isolationquotafundament
  • LB-F1 / LB-F1bChain-Scope-Whitelist als zweiter reason-loser Switch-CaseGeplant

    Chain MUSS Scope-Whitelist anwenden BEVOR Last verteilt wird: visible(tenant)=eigene UNION granted (context_backend_grants ~069) UNION _global-Pool. Tenant ohne Grant/Backend sieht nur _global; _global-loser grant-loser Tenant -> LEERE Chain (fail-closed). Scope-Filter als ZWEITER reason-loser Switch-Case NACH HasRole + VOR Enabled/Trust (sonst leaken fremde Backend-Namen in die admin-Surface). context_backend_grants (~069, LB-F1b) als eigenes Schema mit fail-closed-FK (ON DELETE CASCADE, uq(grantee_tenant, granted_backend)); _global einziger System-Sonderfall (additiv per Default, NICHT ueber Grant).

    securityfail-closed
  • LB-F3 / LB-F3bBackground-Fairness + per-Tenant activeQueries (neue-achse)Geplant

    Background-Pfad MUSS (a) fair ueber AKTIVE Tenants iterieren (status=active, suspended/offboarding HART uebersprungen) statt global aeltesten Block, und (b) FOR-UPDATE-SKIP-LOCKED race-frei ueber DreamParallelism>1. KEIN geteilter Cursor — pro Worker-Pick aktiven Tenant gewichtet-zufaellig ziehen (Backlog als Gewicht, Round-Robin-Floor). LB-F3b (logisch PRIOR): activeQueries (scheduler.go:104) DARF NICHT EIN globaler Counter bleiben, der den GESAMTEN Background suspendiert, sobald IRGENDEIN Tenant querying ist. Yield-Entscheidung pro bearbeitetem Tenant-Scope. Einhaengen in T38/06-C6.

    fairnessbackgroundscale
  • LB-F6KeysForTenantRollup ueber ALLE (auch deaktivierte) KeysGeplant

    Quota-Rollup-Abfrage MUSS api_key_id auf tenant_id aufloesen und ALLE jemals zum Tenant gehoerenden Keys summieren — auch DEAKTIVIERTE, deren Calls noch im Fenster liegen. NEUE Store-Fn KeysForTenantRollup(tenantID) []uuid.UUID (NICHT activeOnly); ListApiKeys(activeOnly=true) UNGEEIGNET (Tenant unterlaeuft Budget per Key-Rotation). context_llm_log.api_key_id ist FK-LOS (054:23) — nach Key-HARD-Delete zeigen Zeilen auf geloeschte Keys.

    quotarollup
  • LB-N5 / LB-F2In-Flight-Lastverteilung statt name-ASC-MonopolGeplant

    Innerhalb der gegateten+trust-gefilterten+nicht-cooled Menge MUSS ein Lastverteiler streuen statt deterministisch das namens-kleinste (pool.go:289-300 cooldown ASC, priority DESC, name ASC). Neuer Sort: (cooled ASC, priority DESC, in_flight ASC, name ASC) — In-Flight rankt NUR im (cooled, priority)-Plateau. In-Flight als eigener Lebenszyklus (LB-N5): neues inFlight int im prozess-lokalen healthState (NICHT im by-value-Snapshot), Inc/Dec an der Wire-Grenze (chain.go:94, embedcache.go:136), Dec per defer auch im Panik-/Cancel-Pfad. Round-Robin als einfacherer erster Schritt (LB-OD2).

    fairnessload-balancing
  • LB-D3 / LB-D4Chat-Semaphore auf ar.TenantID + _global-opt-outGeplant

    Chat-Semaphore (chat.go:112/228 acquire(sess.Scope)) ist HEUTE per-SCOPE und damit KEINE Per-Tenant-Drossel — MUSS auf ar.TenantID umgeschluesselt werden, sonst multipliziert ein Multi-Scope-Tenant die ConcurrentTurns-Decke ueber seine N Scopes/Sessions. config.go ConcurrentTurns kommentiert als per-tenant, Implementierung per-scope. LB-D4: ein neuer Tenant (insb. Test/Staging) DARF NICHT per Default auf das _global-Prod-Backend last-verteilt werden — explizites opt-out am Tenant, sodass die Whitelist nicht jedem grant-/backend-losen Tenant automatisch die geteilte Prod-Ressource gibt.

    fairnessisolation
  • X1-X7Wechselwirkungs-Matrix — 8 Szenarien, mehrere Dimensionen an EINER Code-StelleGeplant

    Acht Szenarien (X1-X7 plus Reseller-Skeleton-Key), in denen mehrere Dimensionen an EINER Code-Stelle kollidieren, jedes gegen HEAD verifiziert mit verbindlicher Aufloesung. X1: Reseller-Kunde mit LAN-Ollama-embed + Test-Sub-Tenant + Last-Isolation (vier Seams an einer Stelle). X2: Suspend-Kaskade trifft geliehene-Scope-Session + Background-Kosten (drei Lecks). X3: Quota trifft Multi-Scope-Tenant + Embed-Last + Rebuild. X4: Sub-Tree-Prune mit ephemeren Toechtern + 2M dream_links + Rebuild. X5: Test-Cross-Tenant-Grant + Synthese-Leak. X6: Reseller-Key-Kompromiss als Skeleton-Key + Topologie-DoS. X7: Horizontale Skalierung trifft prozess-lokalen State.

    cross-cuttingverifiziert
  • INV-1..INV-5Fuenf tragende Invarianten unter Druck (verbindliche Aufloesung)Entschieden

    INV-1 fail-closed durchgaengig (6 verifizierte fail-OPEN-Stellen, siehe Risiken). INV-2 _-Praefix = system, gehoert keinem Tenant (hart an DREI Stellen; _global wird NIEMALS Tenant/Parent/Root, Wurzel ist realer default-Tenant). INV-3 Single Switch Point (scope=ANY in EINE wiederverwendbare CTE, read_scopes bleibt FLACH). INV-4 Modell C = scope-Diskriminator, KEIN tenant_id auf Daten-Tabellen (parent_tenant_id + Quota-Umschluesselung betreffen nur MANAGEMENT-Tabellen). INV-5 Pausierbarkeit (drei Wellen NICHT additiv: CreateApiKey DROP DEFAULT, Chain-Signatur-Wechsel an 9 Sites, context_blocks-Partitionierung).

    invariantecross-cutting
  • Markergrain-of-salt-Marker als verhaltensneutrale Code-KommentareGeplant

    Naht-Marker als reiner Kommentar an die genannte file:line, damit der naechste Implementierer die Enterprise-Anforderung am Beruehrungspunkt sieht. // TENANT-DECISION(id) = HEUTE relevante Entscheidung/Luecke; // TENANT-FUTURE(id) = bewusst spaetere Welle. 16 Marker u.a. tenant.go:103 (parent-Kante), role.go:60 (CanAdministerDescendant), api_keys.go:36 (CreateApiKey), 060:146 (Status-Gate), pool.go:264 (Chain switch), validate.go:194 (embed-Gate), chain.go:198 (LogEmbedWire), 063:59 (uq_tenant_quota_scope falscher Kommentar).

    dokumentationseams

Entscheidungen

  • Phase-0 (a): OD-1 = A (eine geteilte Embedding-Generation als hartes Default) 2026-06-16Eine Embedding-Generation / ein geteilter HNSW als HARTES Default; per-Tenant-embed nur seltene server-admin-gegatete Ausnahme mit eigener Partition. Begruendung (von den Reviews verstaerkt): (1) separate Partition dupliziert den scope=ANY-Postfilter = zweite ctx_rrf = neue Leak-Stelle (Single-Switch-Point-Bruch, SM-DI3); (2) cross-scope-Grants + per-Tenant-Generation fundamental inkompatibel ohne Grant-Generation-Match-Gate (SM-DI2); (3) Single-GPU parallelisiert den Partition-Rebuild nicht (SM-N1); (4) context_blocks-Partitionierung sprengt die Pausierbarkeit (SM-N3). Diese eine Entscheidung entschaerft SM-DI3/SM-N1/SM-N3/SM-DI2 auf einmal. C (verified-equivalent) als Sub-Pfad, setzt OD-2=B zwingend voraus.
  • Phase-0 (c): Baum-Wurzel = realer default-Tenant (parent NULL), _global wird NIE Tenant 2026-06-16Der Super-Tenant ist der REALE default-Tenant (00000000-0000-0000-0000-0000000d3fa0, parent NULL), NICHT _global. Der default-Tenant traegt den Legacy-Korpus und ist die natuerliche Baum-Wurzel. _global zum Tenant/Root zu machen wuerde den '_'-Hart-Filter (060:178 LIKE '\_%') brechen, der an drei Stellen erzwungen ist (api_keys.go:46, reservedSlug tenant_manage.go:28, FK granted_scope->context_tenant_scopes). _global bleibt der system-reservierte Namespace OHNE context_tenants-Zeile (INV-2, R-RES-02/KH-F1).
  • Kern-Erkenntnis: Verwaltungs-Autoritaet ORTHOGONAL zur Daten-Sicht 2026-06-16Von vier der fuenf Dimensionen unabhaengig getragen: ein Reseller verwaltet seinen Sub-Tree, sieht aber NULL Block-Inhalte; eine Konzern-Mutter vererbt Verwaltung transitiv abwaerts, aber Daten-Sicht entsteht NUR ueber eine explizite context_tenant_grants-Kante (060:170-173 — read_scopes wird AUSSCHLIESSLICH aus tenant_id + Grants gebaut, die Management-Hierarchie spielt keine Rolle). Der Grant-Write ist der EINZIGE Pfad, der read_scopes weitet, und damit das hoechstwertige Eskalations-Ziel. Diese Trennung MUSS test-gepinnt erhalten bleiben; Daten-Sicht-Vererbung als Default waere ein bewusstes Anti-Feature (macht zentrales inhaltsfreies Audit unmoeglich). KEIN Management-Pfad schreibt Grants implizit fuer sich selbst (R-RES-01/KH-S3).

Offene Fragen

  • Phase-0 (b): Quota/Last tenant- vs scope-granular — durch User-Entscheidung 2026-06-17 REVIDIERTDas Anforderungs-Dokument (2026-06-16) empfahl als Phase-0-Doktrin (b), JEDE Last-/Quota-/Fairness-Achse auf ar.TenantID statt scope zu schluesseln und 063 von uq_tenant_quota_scope UNIQUE(scope) auf UNIQUE(tenant_id) umzustellen (LB-A1). ACHTUNG: durch eine User-Entscheidung vom 2026-06-17 ist dies zu scope-granular revidiert worden (siehe Briefing 03). Querverweis: der Befund 5 (063:59 falscher Kommentar 'one quota row per tenant') und LB-A1 sind von dieser Revision direkt betroffen — die Aufloesungs-Richtung im Dokument (tenant-keyed) gilt nicht mehr unveraendert.
  • OD-2: Erzeugung des cosine-Aequivalenz-Proofs (heute nur bool)Empfehlung B (automatischer Test-Harness: N Referenz-Texte alt+neu embedden, cosine >= 0.9999) fuer den 'gleicher-Raum'-Anspruch, C (Verbot, immer separate Partition) als fail-closed-Default solange B nicht gebaut. Zwei Haertungen zwingend: (1) das Flag server-admin-only (heute nackter bool aus Client-Payload validate.go:195); (2) das Gate lokalitaets-blind auf 'Scope != _global' (heute nur LocalityExternal). Ein bool-Flag genuegt nie (SM-S1).
  • OD-6 / SM-Q1: Rebuild-GPU-Kosten gegen das eigene Quota-GateRebuild von 1M (nach SM-F7-Attribution) erzeugt 1M attributierte embed-Calls -> sprengt jedes daily_calls-Budget (063:47) sofort + on_exceed (063:49-53) legt den Tenant MITTEN im Rebuild lahm. Konflikt SM-F7 (attribuieren) vs SM-S3 (durchsetzen). Empfehlung OD-6: Rebuild MUSS eigene Kostenklasse 'rebuild' sein, die fuer Telemetrie/Abrechnung zaehlt, aber NICHT gegen das daily_calls-Drossel-Gate; Unterscheidung am Ausloeser (A tenant-initiiert, B server-initiiert).
  • D-ETT-08: Auto-Cleanup-Janitor Default-AN vs Default-AUSSPANNUNG: Default-AUS folgt der Pausierbarkeit (NF-ETT-04), ist aber widerspruechlich (Auto-Cleanup wirkungslos bis manuell aktiviert, stiller Storage-Leak). Default-AN verletzt Pausierbarkeit. Empfehlung-Kompromiss: Default-AUS BEHALTEN, aber Bestands-Cap (NF-ETT-05) als harte Bremse + Aggregat-Signal (NF-ETT-07) als Sichtbarkeit, sodass der Operator den Janitor bewusst aktiviert. Umentscheidbar pro Deployment.
  • LB-OD4: Geteilter State bei mehreren ctxd-Instanzen (N>1)Aller Last-/Health-/Quota-State ist prozess-lokal (pool.go atomic.Pointer + Mutex-Health, chat.go inflight map) AUSSER ClaimTurn (DB-backed). Empfehlung: kurzfristig N==1 EXPLIZIT dokumentieren. Zwei verifizierte Ausnahmen bei N>1: (a) on_exceed=block (echtes Geld/Egress) DARF nicht per-prozess approximiert werden (K Prozesse -> bis K-faches cost-Budget vor dem ersten Block) -> verteilter Token-Bucket/DB-CAS; (b) Cooldown-Verduennung bei geteilten _global-Backends -> Sticky-Routing ODER 429-als-globales-Signal. SHARED Counter-Store als geparkte Naht (E).

Risiken

  • MittelBefund 1: offboarding ist toter Statusctx_auth 060:147 'v_status IS NULL OR <> active' -> suspended UND offboarding werden beide __UNAUTHORIZED__. offboarding ist damit ein toter dritter Status (einzige Code-Erwaehnung tenant.go:108). Fuer das Reseller-Geschaeft braucht es eigene mehrstufige Semantik (Grace-Period, read-only Export-Fenster, Rechnungsabschluss, DANN Prune) ODER explizite Dokumentation als redundant zu suspended. Bei read-only-Pfad MUSS ctx_auth-Gate suspended vs offboarding unterscheiden (R-RES-17, D-RES-06).
  • MittelBefund 2: status=ephemeral wuerde jeden Test-Request fail-closed abweisenctx_auth (060:32-36) wuerde einen status-Wert ephemeral genau wie suspended fail-closed abweisen (401, Test unbenutzbar). Daher gehoert die Test-Markierung in context_tenants.metadata (metadata.ephemeral=true), NICHT in status. ephemeral ist orthogonal zum Lifecycle und KEIN read_scopes-Input (S-ETT-03, D-ETT-01).
  • MittelBefund 3: stale Quota-Zeile ueberlebt Prune (scope-Reuse erbt sie)PruneTenant (tenant.go:277-309) loescht context_tenant_quota NICHT. Da die Quota-Zeile SCOPE-keyed ist (063:59) und auf einen now-unmapped scope zeigt, erbt bei Scope-String-Reuse der neue Tenant still die alte Quota. PruneTenant MUSS die Quota-Zeile (und jede scope-keyed per-Tenant-Config) mit-loeschen. Grants sind bereits grantee-UUID-keyed (D-RES-10).
  • HochBefund 4: embed_equivalence_verified umgehbar (LAN-Ollama)validate.go:194-195 gated das embed-Aequivalenz-Flag NUR fuer hasEmbedRole && b.Locality == LocalityExternal. Ein embed-Backend mit Locality=local/lan (LAN-Ollama, haeufigster MT-Fall) umgeht das Gate KOMPLETT. Zudem ist das Flag ein nackter bool aus Client-metadata (applySpec 1:1), ohne server-admin-Gate. Fremde Generation im geteilten HNSW (001:250) -> 0.997-cosine-Degradation fuer ALLE. Fix: Bedingung auf 'External ODER Scope != _global' erweitern + Flag server-admin-only. Eskalation PROSPEKTIV, real ab T37 (SM-S1, OD-2).
  • MittelBefund 5: uq_tenant_quota_scope UNIQUE(scope) mit falschem KommentarMigration 063:59 traegt UNIQUE(scope) mit dem Kommentar 'one quota row per tenant' — der ist FALSCH: ein Tenant hat N scopes (default-Tenant 3), die Tabelle ist scope-keyed, nicht tenant-keyed. Ein 3-scope-Tenant bekaeme 3 Quota-Zeilen = 3x Budget ODER der pro-tenant-Rollup findet keine eindeutige Zeile. Vor T36-Enforcement zu klaeren; 063 hat heute keinen Konsument. HINWEIS: die Aufloesungs-Richtung (tenant- vs scope-keyed) ist durch User-Entscheidung 2026-06-17 revidiert (siehe offene Frage).
  • HochBefund 6: Suspend-Kaskade fehlt (ctx_auth Status-Gate nur direkter Tenant)ctx_auth Status-Gate (060:146) prueft nur den direkten v_tenant_id, kein Ancestor-Walk. Suspend eines Reseller-/Mutter-Knotens schaltet die Descendants NICHT ab. Plus: ownerActive (engine.go:271) -> TenantStatusForScope prueft nur den direkten scope-Owner, found=false -> aktiv (engine.go:276-277) = fail-OPEN fuer unmapped scope mid-session. Fix: ancestor-bewusstes denormalisiertes effective_status (KH-NF2), found=false -> fail-CLOSED im MT-Pfad (R-RES-14/R-RES-15/KH-F6).
  • HochINV-1 fail-OPEN-Stelle (1/6): Chain filtert Backend.Scope nichtChain (pool.go:264-281) filtert Backend.Scope NICHT -> jeder Tenant bekommt die volle _global-Chain (inkl. evtl. external/full-trust). Sobald ein scope!=_global-Backend mit passender Rolle existiert, routet Fremd-Last ueber ein privates Backend = Cross-Tenant-Routing-Leck (LB-S0/SM-S0). Aufloesung: Scope-Filter als ZWEITER reason-loser Switch-Case NACH HasRole, VOR Enabled (LB-F1); leere Chain fuer _global-/grant-losen Tenant; MUSS deployt sein BEVOR der erste Nicht-_global-Backend existiert.
  • HochINV-1 fail-OPEN-Stelle (2/6): CreateApiKey laesst tenant_id/tenant_role wegCreateApiKey (api_keys.go:36-78) hat KEINEN tenant_id/tenant_role-Param, INSERT laesst beide Spalten weg -> jeder Key erbt DEFAULT default-Tenant (059:111-112) + DEFAULT member (059:118). Vergisst der Handler den Sub-Tree-validierten tenant_id, landet der Fremd-Key STILL im default-Tenant = Fremd-Key mit voller Legacy-Sicht (R-RES-05). Aufloesung: tenant_id Pflicht-Param + Sub-Tree-Validierung VOR Store-Call; DROP DEFAULT erst in EIGENER Migration NACH Caller-Umstellung (sonst 23502; nicht-pausierbar markiert).
  • MittelINV-1 fail-OPEN-Stelle (3/6): quota.scope ohne _-CHECKcontext_tenant_quota.scope (063:42) hat heute KEINEN _-CHECK. Ein Reseller koennte (kuenftig) _global/_-Praefix-scopes konfigurieren. Aufloesung: expliziter _-Reject auf JEDEM Reseller-scope-Param (R-RES-12), analog dem _-Hart-Filter, der an drei anderen Stellen erzwungen ist (api_keys.go:46, reservedSlug tenant_manage.go:28, FK granted_scope).
  • HochINV-1 fail-OPEN-Stelle (4/6): descendant-scope-Set ohne RequireScopesJeder descendant-scope-Set MUSS durch RequireScopes (tenant.go:19-30) — ein leeres Set kollabiert sonst zu scope=ANY('{}') = KEIN Filter = fail-OPEN (Rollup sieht ALLE / Prune global). TenantScopes liefert bei leer/unbekannt ein LEERES slice ohne Error (tenant.go:42-53); das fail-open-Artefakt ist dort dokumentiert. Aufloesung: RequireScopes PFLICHT vor jedem descendant scope=ANY (KH-D1).

Nächste Schritte

  • PHASE 1 (additiv, verhaltensneutral): 1. parent_tenant_id ADD COLUMN NULL + idx_tenants_parent + acyclicity-Trigger OHNE Konsument (KH-NF3).
  • PHASE 1: 2. embed_model-Provenance in alle 3 Write-Pfade schreiben + einmaliger verifizierter Backfill der Bestands-Bloecke (SM-F1/F1b, reines UPDATE single-Tx) — VORBEDINGUNG fuer jeden selektiven Rebuild.
  • PHASE 1: 3. embed-Kosten-Attribution (api_key_id durch EmbedChain/LogEmbedWire/beide Vordergrund-Sites, SM-F7/LB-N3) — VORBEDINGUNG fuer jedes Quota-Budget.
  • PHASE 1: 4. metadata.ephemeral-Markierung + gezielte tenantCols-Projektion (F-ETT-01/09, additive Wire-Aenderung mit omitempty).
  • PHASE 2 (fail-OPEN-Loecher schliessen): 5. Backend-WRITE-Pfad scope-Pinning auf ar.TenantID (SM-F4b). 6. context_backend_grants-Subsystem bauen (LB-F1b). 7. Chain-Scope-Whitelist-Filter (LB-F1/SM-F4) als zweiter reason-loser Switch-Case, embed-Rolle als _global-Sonderzweig (SM-F5).
  • PHASE 2: 8. embed_equivalence-Gate auf Scope!=_global erweitern + Flag server-admin-only (SM-S1). 9. text_preview im MT-Betrieb entfernen (SM-S2+SM-S5 DSGVO). 10. CreateApiKey-tenant_id-Param + Sub-Tree-Validierung + is_admin/role-Reject (R-RES-05/19), DROP DEFAULT als eigene spaetere Migration.
  • PHASE 3 (Autorisierung + Lifecycle): 11. CanAdministerDescendant + ancestor_tenant_ids als ctx_auth-Spalte (KH-F3/R-RES-03; Gate-Flip ist Achse 05/T25). 12. denormalisiertes effective_status fuer ancestor-bewussten Suspend-Gate + per-Turn-Cut schneidet sess.ReadScopes neu + found=false->fail-CLOSED (R-RES-15).
  • PHASE 3: 13. Re-Parent-Action + Grant-Lifecycle-Kopplung (TenantForScope-Resolver, grantor_tenant, Auto-Widerruf). 14. Sub-Tree-Prune resumable leaf->root mit offboarding-Freeze + Block-Membership-dream_links-DELETE + DDL/Cache-Cleanup (VORBEDINGUNG: dream_links scope-Index CONCURRENTLY out-of-band).
  • PHASE 4 (Quota + Last-Fairness): 15. Quota-Enforcement in Pool.Chain() mit prozess-lokalem Counter + Reconcile + Bootstrap-Load (Granularitaet beachtet User-Revision 2026-06-17). 16. chat-Semaphore auf ar.TenantID. 17. In-Flight-Lastverteilung/Round-Robin im Chain-Sort. 18. Background per-Tenant-Iteration (T38/06-C6, status-gefiltert).
  • PHASE 5 (Haertung + Observability): 19. Topologie-Kardinalitaets-Cap + Quota-Write-Rate-Limit. 20. Auto-Cleanup-Janitor mit advisory-lock+Yield+Einfrier-vor-Prune, Default-AUS + Aggregat-Alert. 21. Generation-Drift-Detektor + %-stale-pro-Scope + Fairness-Metriken. 22. per-Tenant-Embed-Rebuild-Worker (embed_status-Stale) + abgeleitete Strukturen invalidieren.
  • PARKEN (Anti-Feature/Naht): per-Tenant-embed mit eigener HNSW-Partition (A), recall-Kollaps des geteilten HNSW bei grossem N (B), Self-Service-Onboarding (C), White-Label/Branding (D), N>1 SHARED Counter-Store (E), Daten-Sicht-Vererbung als Default (F), parent-scoped slug-Uniqueness (G).
03

MT-Entscheidungen 2026-06-17 + nächste Wellen-Sequenz

Aktiv · In BauIn Bau — Wellen-Sequenz festgelegt, Welle 0 destruktiv vor MT-Wellen 058+
Fertig 1Entschieden 3Geplant 6

Am 2026-06-17 hat der User sechs Multi-Tenant-Grundsatzentscheidungen getroffen: Scope-Konsolidierung work+shared→private (macht E4 gegenstandslos), scope-granulare Quota statt tenant_id-Umbau, OD-1 als CoW-Embedding, Cross-Vektorraum-Grant per Re-Embed statt Abruf-only, Wurzel = default-Tenant und Backend-Sicht als Whitelist (fail-closed, ändert T34). Das Embedding-Storage-Layout ist live als TOAST-EXTERNAL gemessen; die separate Tabelle context_block_embeddings ist identisch mit der OD-1-Form. Die nächste Bau-Phase startet mit der destruktiven Welle 0 (mit Backup), gefolgt von additiv/pausierbaren Wellen (parent_tenant_id, embed_model-Provenance, embed-Attribution T35b, metadata.ephemeral). Inferenz läuft durchgängig auf llama.cpp, Ollama ist komplett raus.

6MT-Entscheidungen am 2026-06-171024d Matryoshka von nativ 4096dEmbedding-Dimension (fix)3 (blocks.go:248, scheduler.go:803, query.go:927)embed_model-Provenance-Pfadeqwen3.6:27b @96k-contextChat-Modell1× Quadro RTX 6000 (24 GB), ~21 GB belegtherbert GPU
  • Welle 0Scope-Konsolidierung work+shared → private (destruktiv, mit Backup)Geplant

    pre-MT, DB-weit über alle scope-Spalten (blocks/dream_links/blobs/sources/chat_sessions/settings) + Work-Key + Overview-Rebuild. Erste Welle der nächsten Bau-Phase, VOR den MT-Wellen 058+. Destruktive DB-weite Operation, mit Backup.

    welle-0destruktivscopepre-mt
  • parent_tenant_idparent_tenant_id ADD COLUMN NULL + idx + acyclicity-TriggerGeplant

    Danach additiv/pausierbar: ADD COLUMN NULL + idx + acyclicity-Trigger, ohne Konsument. Hierarchie-Fundament.

    hierarchieadditivschema
  • T35b (Provenance)embed_model-Provenance schreiben (3 Pfade) + einmaliger BackfillGeplant

    embed_model-Provenance schreiben über 3 Pfade (blocks.go:248, scheduler.go:803, query.go:927) + einmaliger Backfill → Voraussetzung für selektiven Rebuild. Teil von T35b. Billige Versicherung Phase 1, inkl. ctx_rrf-Lesepfad kapseln.

    embedprovenancet35brebuild
  • T35b (Attribution)embed-Kosten-Attribution (api_key_id durch EmbedChain/LogEmbedWire)Geplant

    api_key_id durch EmbedChain/LogEmbedWire = Rest von T35b.

    embedattributiont35bkosten
  • metadata.ephemeralmetadata.ephemeral (Test-Tenant-Marker) + tenantCols-ProjektionGeplant

    metadata.ephemeral als Test-Tenant-Marker + gezielte tenantCols-Projektion.

    metadatatest-tenantprojektion
  • T34Backend-Chain own∪granted + Grant-Subsystem (~069)Entschieden

    T34 als Whitelist: Chain wird own∪granted statt _global∪own; context_backend_grants (künftig ~069), Tabelle + CRUD + NOTIFY + Handler ist neu, fail-closed. T34 risikoarm baubar, keine weitere Entscheidung nötig.

    backendwhitelistgrantt34
  • OD-1context_block_embeddings — separate Tabelle für Multi-VektorraumEntschieden

    Multi-Vektorraum (Generationen/per-Tenant-Modell/Blue-Green-Rebuild) → separate Tabelle context_block_embeddings(block_id FK, generation, embedding, PK(block_id,generation)) ist die richtige FORM, IDENTISCH mit OD-1. Bau-Trigger: erster inkompatibler Tenant ODER gemessener HNSW-recall-Druck bei wachsendem N — datengetrieben. Externer Store (Qdrant/Milvus): NEIN — Kern-Wert = Hybrid-Fusion in EINER Transaktion (RRF+FTS+Graph+temporal+scope, alles SQL); pgvector @1M ist gebencht.

    od-1embeddingmulti-vektorraumcow
  • T28 / T34 / T35brisikoarm baubar, keine Entscheidung nötigEntschieden

    T28 / T34 / T35b sind risikoarm baubar; keine Entscheidung nötig (T34 als Whitelist).

    t28t34t35b
  • GPU-EmbedGPU-Embed-Beschleunigung (Idle-Voll-Swap, validiert)Geplant

    User-Idee, validiert: Idle-Voll-Swap (Chat-Server raus, Embed auf GPU, bei Query zurück). Page-Cache-Backoff (mmap, herbert 128 GB RAM / ~76 frei) macht Reload RAM→VRAM (~1–2 s) statt Disk. Offen: Warm-Restart-Messung (braucht Chat-Server-Bounce, Idle-Fenster).

    gpuembedidle-swap
  • InfraAktive Modelle — llama.cpp durchgängig, Ollama rausFertig

    Inferenz-Engine llama.cpp DURCHGÄNGIG, Ollama KOMPLETT RAUS (war Stack bis ~April 2026). Alle Backends sprechen OpenAI-Wire-Protokoll, Routing via context_backends. CHAT/SYNTHESE/DREAM/DIGEST/CLASSIFY/TRANSLATE: qwen3.6:27b (think:false) — Backend 'herbert-chat' (10.13.37.11:8089) @96k-context. RERANK: bge-reranker-v2-m3 — 'herbert-rerank' (10.13.37.11:8082), dediziert. EMBEDDING: qwen3-embedding-8b — 'llama-embed' (Docker, CPU am ctx-Host, getrennt von GPU), 1024d Matryoshka von nativ 4096d. Fallbacks: 'openrouter' (extern, prio 50), 'llama-cpu' (Docker CPU, prio 10). Hardware: herbert = Windows-Box, EINE Quadro RTX 6000 (24 GB), fährt 2× llama-server (Chat 27b @96k + Rerank), ~21 GB belegt; ctx-Host (Docker) hat KEINE GPU → Embedding CPU-only; KEIN GPU-Swap Embed↔Chat. CPU-Embedding = Durchsatz-Engpass bei Bulk-Rebuild, nicht Live-Query-Latenz.

    modellellama-cppollama-rausinfra

Entscheidungen

  • Scope-Konsolidierung work+shared → private (pre-MT cleanup) 2026-06-17work + shared werden komplett zu private; der default-Tenant behält EINEN Scope. Macht E4 gegenstandslos. Destruktive DB-weite Operation (scope-Spalten blocks/dream_links/blobs/sources/chat_sessions/settings + Work-API-Key + Overview-Rebuild) → erste Welle der nächsten Bau-Phase, VOR den MT-Wellen 058+, mit Backup. In dieser Session NICHT ausgeführt.
  • Quota = scope-granular 2026-06-17Budget pro Abteilung/Scope, Verwaltung via Preset-Editor; 063-Kommentar von 'per tenant' → 'per scope', Struktur bleibt (KEIN tenant_id-Umbau). Tenant-Gesamtbudget = Summe der Scope-Quotas. User-Bestätigung der Lesart ausstehend.
  • OD-1 = CoW-Embedding 2026-06-17Bestätigt: geteilte Embedding-Generation als Default (ghost vom Pool/Parent), Divergenz (anderes Modell/Dimension) materialisiert lazy in separate Ablage, Refcount-GC. Dimension fix 1024 (embed.go:30 TargetDims + Quality-Gate). Pool trägt Generation (RoleEmbed) = eine Achse.
  • Cross-Vektorraum-Grant = re-embed (ersetzt Abruf-only) 2026-06-17Gegranteter Block wird mit Grantee-Modell neu embedded → zweite Generations-Zeile → voll im semantischen Retrieval bei B, nicht nur Abruf. Kosten: 1 Embed-Call/Grant + Speicher; Revoke → Refcount-GC.
  • Wurzel = default-Tenant 2026-06-17Bestätigt. owner('_global') := default-Tenant.
  • Backend-Sicht = Whitelist 2026-06-17WHITELIST statt additiv: visible(tenant) = own ∪ granted (context_backend_grants, künftig ~069), fail-closed; owner('_global') := default-Tenant; neuer Tenant ohne Grant/eigenes Backend → leere Chain. Schließt die einzige fail-open-Lücke (drei Grant-Ebenen konsistent: scope/block/backend). Ändert T34: Chain wird own∪granted statt _global∪own; das Grant-Subsystem (Tabelle + CRUD + NOTIFY + Handler) ist neu.

Offene Fragen

  • User-Bestätigung Quota-Lesart ausstehendQuota = scope-granular (Budget pro Abteilung/Scope, 063-Kommentar 'per tenant' → 'per scope', Struktur bleibt, Tenant-Gesamtbudget = Summe der Scope-Quotas). Die Lesart ist noch nicht durch den User bestätigt.
  • Warm-Restart-Messung GPU-Embed offenDie Warm-Restart-Messung für die GPU-Embed-Beschleunigung (Idle-Voll-Swap) ist offen — braucht Chat-Server-Bounce und ein Idle-Fenster.

Risiken

  • HochWelle 0 ist destruktiv (DB-weit)Die Scope-Konsolidierung work+shared → private ist eine destruktive DB-weite Operation über alle scope-Spalten (blocks/dream_links/blobs/sources/chat_sessions/settings) + Work-API-Key + Overview-Rebuild. Mitigation: Backup dokumentieren (Quelle nennt 'mit Backup').

Nächste Schritte

  • Welle 0 mit Backup ausführen (Scope-Konsolidierung work+shared → private, DB-weit), VOR den MT-Wellen 058+
  • User-Bestätigung der scope-granularen Quota-Lesart einholen
  • parent_tenant_id ADD COLUMN NULL + idx + acyclicity-Trigger (additiv, ohne Konsument)
  • embed_model-Provenance über 3 Pfade schreiben + Backfill (T35b)
  • embed-Kosten-Attribution (api_key_id durch EmbedChain/LogEmbedWire, Rest T35b)
  • metadata.ephemeral + tenantCols-Projektion
  • Warm-Restart-Messung für GPU-Embed-Idle-Swap durchführen
04

Workflow-Engine / Issue-System

VisionVision — noch nicht gebaut, nach Web-Frontend und Multi-Tenant
Geplant 10

Vision/Anker aus Session 2026-06-01 (NOCH NICHT GEBAUT, Reihenfolge: nach Web-Frontend, nach Multi-Tenant). Kern-Richtungsentscheidung: das hardcoded 4-Klassen-block_role-Enum (system-meta / audit-trail / reference / knowledge) wird zu dynamischer Policy-Config, sodass User eigene Workflows auf ctx bauen koennen. Erster Workflow darauf: Issues als isolierter Tenant-Korpus, der die ctx-Maschine (Guard, RRF, Dream, Scope) gratis erbt, plus GitHub-Forge-Sync. Roadmap in 4 Schema-First-Wellen (W1-W4) plus ein offener Themen-Backlog (Webhooks, Project-Boards-Sync, Multi-User, Auth-Redesign, Admin-Oberflaeche, autonome Agenten).

W1-W4 (je 1 Welle, Schema-First)Roadmap-Wellen6Backlog-Vision-PunkteNoch nicht gebaut (Vision/Anker)Statusnach Web-Frontend, nach Multi-TenantReihenfolge2026-06-01Session
  • W1Dynamische Type-Registry + Default-Configs + ctx project FundamentGeplant

    Schema-First, 1 Welle. Dynamische Type-Registry plus mitgelieferte Default-Type-Configs (Migration vom hardcoded block_role-Enum) und das Fundament der CLI-Familie ctx project (detect/init/show). Projekt-Identitaet, die Klone/Umzuege ueberlebt: github:owner/repo | git-root:<root-commit-sha> | manual:slug.

    RoadmapType-RegistrySchema-First
  • W2Issue-Workflow + Forge-SyncGeplant

    Schema-First, 1 Welle. Issue = context_block in repo-spezifischem Scope-Tenant; erbt Guard (Duplikat-Erkennung via HNSW-Similarity), RRF (related-issues, semantisch), Dream (autonomes Cross-Linking) und Scope-Modell (home_scope, v2.0.0) als Repo-Isolation. Repo-Agent = MCP-Key mit home_scope=repo-tenant, sieht nur sein Repo. Forge-Sync GitHub zuerst (Forge-Abstraktion; GitLab/BitBucket/self-hosted als Erweiterungspunkt), externer Spiegel via 3-Wege-Content-Hash (NICHT Timestamp — W16): github-ahead (pull) / ctx-ahead (push) / beide=Konflikt (anzeigen, kein Auto-Merge). CLI: ctx project issues (list/create/sync/status). Comments = eigene embedded Bloecke, Parent via Metadata-Pointer; RRF aggregiert Comment-Treffer auf ihr Issue. Neue strukturelle Link-Klasse (deterministisch aus Forge, conf 1.0): comment->issue belongs-to; erweiterbar issue->PR/milestone/sub-issue; strukturelle Links NICHT in den Dream-Graph mischen.

    RoadmapIssuesForge-SyncGitHubSchema-First
  • W3Drift/Resilienz + lokaler FallbackGeplant

    Schema-First, 1 Welle. Drift-Behandlung und Resilienz: bei GitHub-Ausfall in ctx weiterarbeiten (lokaler Fallback).

    RoadmapResilienzDriftSchema-First
  • W4ctx kanban TUIGeplant

    Schema-First, 1 Welle. ctx kanban: interaktive TUI bei TTY, strukturierte Ausgabe bei Pipe.

    RoadmapTUIkanbanSchema-First
  • BL-WebhooksWebhooks (eingehend + ausgeloest)Geplant

    Offener Themen-Backlog (User-Vision 2026-06-01, zu dokumentieren sobald Basis steht). Webhooks eingehend und ausgeloest. Im Kern-Redesign als Beispiel fuer den programmierbaren Pfad (event-driven Webhooks) genannt.

    Vision
  • BL-ProjectBoardsGitHub Project Boards <-> kanban-SyncGeplant

    Offener Themen-Backlog (User-Vision 2026-06-01). GitHub Project Boards <-> kanban-Sync via Projects-v2 GraphQL (spaet).

    Vision
  • BL-MultiUserMulti-User / Freund bekommt eigenen ctx-TenantGeplant

    Offener Themen-Backlog (User-Vision 2026-06-01). Multi-User: ein Freund bekommt einen eigenen ctx-Tenant.

    Vision
  • BL-AuthAuth-Architektur Kern-RedesignGeplant

    Offener Themen-Backlog (User-Vision 2026-06-01). Auth-Architektur Kern-Redesign: funktioniert fuer Einzelperson, braucht mehr.

    Vision
  • BL-AdminAdmin-Oberflaeche fuer User/Tenants/Access-Keys/API-TokenGeplant

    Offener Themen-Backlog (User-Vision 2026-06-01). Admin-Oberflaeche fuer User/Tenants/Access-Keys/API-Token.

    Vision
  • BL-AgentsAutonome Agenten arbeiten eigene Issues abGeplant

    Offener Themen-Backlog (User-Vision 2026-06-01). Autonome Agenten arbeiten eigene Issues ab. Uebergeordnetes Ziel: sobald die Basis steht, dokumentiert der User (und Agenten) den Rest als Issues IM System selbst; dann entfaellt .project/todos.md ganz.

    Vision

Entscheidungen

  • Block-Types: hardcoded Enum -> dynamische Policy-Config 2026-06-01Architektur-Richtungsentscheidung 2026-06-01 (019e83df-3787). Ausgeloest durch verrottete todos.md + fragmentierten Backlog -> grundlegendes Redesign statt Flicken. KERN: Mechanismus vs. Policy trennen — Block-Type-VERHALTEN wird Daten/Config statt hardcoded. Das 4-Klassen-block_role-Enum (system-meta / audit-trail / reference / knowledge) wird zu mitgelieferten Default-Type-Configs. Mechanismus (Embedding, RRF-Fusion, Guard-Similarity, Dream-Loop, Link-Graph) bleibt Code; Policy (wie ein Type in RRF/Guard/Dream behandelt wird) wird konfigurierbar. Ziel: User bauen eigene Workflows auf ctx. Kontinuitaet: Fortsetzung der v2.0.0-Generalisierung (scope von Enum -> VARCHAR(50) fuer Multi-Tenant); block_role ist derselbe Schritt eine Ebene tiefer.

Offene Fragen

  • Kern-Achse: deklarativ-reich (empfohlen) vs. programmierbarNoch NICHT entschieden. deklarativ-reich (EMPFOHLEN als Fundament): Type = Config mit Verhaltens-Feldern — retrieval_policy (full-pass / excluded / damped(f) / aggregate-to-parent), guard_dedup (threshold|off), dream_linkable + erlaubte Link-Klassen, structural_parent, is_meta-Aequivalent. Kein server-seitiger User-Code -> kein Sandboxing, testbar, deckt fast alle Workflows. programmierbar: Hooks/Plugins/Expressions, User-Logik eingeklinkt (z.B. event-driven Webhooks). Maximale Macht, aber Sandboxing/Sicherheit/Lebenszyklus = eigenes Subsystem (konkretes W6d-Risiko). Als Erweiterungspunkt, wenn ein realer Workflow das deklarative Vokabular nachweislich sprengt.

Risiken

  • MittelProgrammierbarer Pfad: Sandboxing/Sicherheit/Lebenszyklus als eigenes SubsystemQuelle dokumentiert dies als konkretes W6d-Risiko fuer die programmierbare Option (Hooks/Plugins/Expressions mit eingeklinkter User-Logik): maximale Macht, aber Sandboxing/Sicherheit/Lebenszyklus werden ein eigenes Subsystem. Daher nur als Erweiterungspunkt, wenn ein realer Workflow das deklarative Vokabular nachweislich sprengt.

Nächste Schritte

  • W1: dynamische Type-Registry + Default-Configs (Migration vom Enum) + ctx project Fundament
  • W2: Issue-Workflow + Forge-Sync (GitHub zuerst)
  • W3: Drift/Resilienz + lokaler Fallback
  • W4: ctx kanban TUI
  • Offene Kern-Achse entscheiden: deklarativ-reich (empfohlen) vs. programmierbar
  • Sobald Basis steht: restlichen Themen-Backlog als Issues IM System dokumentieren, todos.md entfaellt
05

Web-Frontend Reststand (41-Wellen-Plan G01–G41 komplett gebaut)

FertigKomplett — 41-Wellen-Plan G01–G41 gebaut, letzte Release v3.15.0
Fertig 9In Arbeit 1Geplant 3Geparkt 1

Der 41-Wellen-Masterplan G01–G41 für das Web-Frontend ist komplett gebaut. Die Release-Kette reicht von F1 (G09–G14/G15/G20) bis G39 Graph-Bench + G32 Pool-/Vault-Editor (v3.14.0, 2026-06-13), die den 41-Plan schließt. Zusätzlich wurde die außerhalb des Plans benannte F5-W6 Graph-Landkarte (W1/W2/W3) entworfen und mit v3.15.0 (2026-06-14) released. Offen bleiben W4 1M-Bench (optional), F6-C6 Write-Confirmation, Ingest-Generalisierung sowie F5-W7 Map-Mode (verfrüht).

41 (G01–G41)Wellen-Plankomplett gebautStatusv3.15.0 (2026-06-14)Letzte Releasev3.14.0 (2026-06-13)41-Plan geschlossen mitclusters=70 nodes=669 edge_rows=58 modularity=0.857 elapsed=45msGraph-Landkarte live
  • F1F1 — Release-Block G09–G14/G15/G20Fertig

    Erster Release-Block des 41-Wellen-Plans, umfasst die Wellen G09–G14 sowie G15 und G20.

    releasef1
  • F2F2 — Release-Block G16–G19 (v3.3.0 = RC-1)Fertig

    Wellen G16–G19, released als v3.3.0, markiert als RC-1.

    releasef2v3.3.0rc-1
  • Phase 3Phase 3 — G21–G24 (v3.4.0)Fertig

    Wellen G21–G24, released als v3.4.0.

    releasephase3v3.4.0
  • F3F3-Kette — G25–G31 + G40 + G41 (v3.5.0–v3.10.0 = RC-2)Fertig

    Wellen G25–G31 plus G40 und G41, released über die Versionsspanne v3.5.0 bis v3.10.0, markiert als RC-2.

    releasef3v3.5.0v3.10.0rc-2
  • v3.9.0llmlog-Retention (v3.9.0)Fertig

    llmlog-Retention released als v3.9.0 (Teil der F3-Versionsspanne).

    releasellmlogretentionv3.9.0
  • F4F4-Dashboard — G33 (v3.11.0) / G34 (v3.12.0)Fertig

    Dashboard-Block: G33 released als v3.11.0, G34 released als v3.12.0.

    releasef4dashboardv3.11.0v3.12.0
  • F6F6-Chat-Kette — G35–G38 (v3.13.0 = RC-3)Fertig

    Chat-Kette mit Wellen G35–G38, released als v3.13.0, markiert als RC-3.

    releasef6chatv3.13.0rc-3
  • v3.14.0G39 Graph-Bench + G32 Pool-/Vault-Editor (v3.14.0) — schließt 41-PlanFertig

    G39 Graph-Bench und G32 Pool-/Vault-Editor released als v3.14.0 (2026-06-13). Dieser Release schließt den 41-Wellen-Plan.

    releaseg39g32graph-benchvault-editorv3.14.0
  • F5-W6F5-W6 Graph-Landkarte (Overview-Map) — Design fertig, W1/W2/W3 done (v3.15.0)Fertig

    Außerhalb des 41-Plans benannt. Design fertig 2026-06-14 (Doc design/07-graph-overview.md, kanonisch ctx projects 019ec337, via 21-Agent-Workflow wf_4970eccf). Scope-Count-Leak gelöst über scope-partitionierte Vor-Aggregate (Migration 057 = 3 normale Tabellen graph_cluster_member/_node/_edge, keine MView; Request summiert nur scope=ANY(readScopes)); gonum-Louvain-Daemon-Job (raw_confidence-Gewicht, min-UUID-cluster_id, advisory-lock); cluster_id nie roh raus, per-Request-Ordinal. Verworfen: A3 k-Anon (fatal), A1 globale-MView, A4 per-sig (K-Explosion). W1 gebaut 2026-06-14 (Migration 057 + internal/overview/cluster.go + config.GraphOverviewConfig + scheduler.runOverviewRebuild, Determinismus 250x verifiziert). W2 gebaut 2026-06-14 (store/overview.go GraphOverview + handler/overview.go HandleOverview; enabled=false→404; per-Request-Ordinal; Integration scope-Negativ-Proben). Live deployed + enabled 2026-06-13/14: clusters=70 nodes=669 edge_rows=58 modularity=0.857 elapsed=45ms. W3 Client code-complete 2026-06-14 (lib/graph/api.ts fetchOverview + overview-map.ts buildOverviewGraph + OverviewMap.svelte + GraphPage Landkarte; svelte-check 0/0, vitest 141). Released v3.15.0 2026-06-14.

    releasef5graphoverview-mapmigration-057v3.15.0
  • F5-W4F5-W4 1M-Bench (optional) — offenGeplant

    Offener Rest der Graph-Landkarte-Wellen: 1M-Bench, als optional gekennzeichnet.

    f5bench1moptional
  • F6-C6F6-C6 Write-Confirmation — offenGeplant

    Außerhalb des 41-Plans benannt, keine fixe Reihenfolge. ctx_store/update als Tools mit Confirm-Card + payload_hash, zuzüglich Migration.

    f6write-confirmationtoolsmigration
  • IngestIngest-Generalisierung — offenGeplant

    Außerhalb des 41-Plans benanntes offenes Frontend-Item, keine fixe Reihenfolge.

    ingestgeneralisierung
  • F5-W7F5-W7 Map-Mode — verfrüht (geparkt)Geparkt

    Map-Mode für >50k Knoten; Korpus aktuell 691 — als verfrüht eingestuft.

    f5map-modeverfrueht
  • MT-FEMulti-Tenant-Ausarbeitung (Frontend-Seite)In Arbeit

    Außerhalb des 41-Plans benannt. grep TODO(multi-tenant) war 9 Marker, jetzt 0 im Code — durch feat/multi-tenant-Arbeit ersetzt/abgelöst.

    multi-tenantfrontendtodo

Entscheidungen

  • Scope-Count-Leak per scope-partitionierte Vor-Aggregate gelöst 2026-06-14Migration 057 = 3 normale Tabellen (graph_cluster_member/_node/_edge), keine MView; Request summiert nur scope=ANY(readScopes). gonum-Louvain-Daemon-Job mit raw_confidence-Gewicht, min-UUID-cluster_id, advisory-lock; cluster_id nie roh raus, per-Request-Ordinal.
  • Verworfene Design-Alternativen Graph-Landkarte 2026-06-14Verworfen: A3 k-Anon (fatal), A1 globale-MView, A4 per-sig (K-Explosion).
  • F5-W7 Map-Mode als verfrüht eingestuft 2026-06-17Map-Mode zielt auf >50k Knoten; Korpus aktuell 691, daher verfrüht.

Nächste Schritte

  • W4 1M-Bench durchführen (optional)
  • F6-C6 Write-Confirmation umsetzen: ctx_store/update als Tools mit Confirm-Card + payload_hash + Migration
  • Ingest-Generalisierung angehen
  • F5-W7 Map-Mode zurückgestellt bis Korpus >50k Knoten (aktuell 691)
06

Operativer Backlog, Resilienz & Quirks

GeplantBacklog — Resilienz-Reste offen, Re-Messungen terminiert
Entschieden 1Offene Frage 6Geparkt 1

Sammlung offener operativer Arbeit aus MEMORY.md ("Offene Arbeit" Rest + "Operative Quirks"): Resilienz-Reste der Welle G (Watchdog, Aktivitäts-Agent als Logon-Task), zwei offene Code-Fixes (StoreEmbedding ohne pgx.Tx, ClassifyConfidence-Rekalibrierung), Daten-Lebenszyklus-Themen (context_access_log-Retention geparkt, Korpus-Kuration) sowie ein Sammelposten Niedrig-Prio-Punkte. Der n8n-Service bleibt bewusst erhalten und ist nicht zu entfernen.

87k rows / 18 MB (db.md:105)context_access_log2 (StoreEmbedding-pgx.Tx, ClassifyConfidence)Offene Code-Fixes≈2026-06-30Back-off Re-Messung
  • Welle G RestWatchdog (llama.cpp-Resilienz, offen)Offene Frage

    Welle G Rest (llama.cpp-Resilienz): Gaming-Toggle erledigt (G30/v3.8.0). OFFEN: Watchdog. Infra-Referenz ctx 019eaf18.

    resilienzinfrastrukturwelle-gllama.cpp
  • Welle G RestAktivitäts-Agent als Logon-Task (offen)Offene Frage

    Welle G Rest (llama.cpp-Resilienz): OFFEN neben dem Watchdog der Aktivitäts-Agent als Logon-Task. Infra-Referenz ctx 019eaf18.

    resilienzinfrastrukturwelle-glogon-task
  • W49Code-Fix: store.StoreEmbedding ohne pgx.TxOffene Frage

    1 Code-Fix (W49, ungefixt): store.StoreEmbedding ohne pgx.Tx. Der dream.chatJSON-DreamProtocol-Fix war a137ee0, done.

    code-fixw49storepgx
  • ClassifyConfidenceClassifyConfidence-Rekalibrierung unter Blend-ScoresOffene Frage

    ClassifyConfidence-Rekalibrierung unter Blend-Scores — N01-05 + T01-Klasse (Blend hebt No-Hit knapp über ScoreThreshold → low_confidence statt none); eigene Welle, falls Confidence je als Gate dient.

    code-fixclassify-confidenceblend-scores
  • Retentioncontext_access_log-Retention (geparkt)Geparkt

    context_access_log-Retention (geparkt — Review nach allen Phasen, User-Entscheidung 2026-06-13): Tabelle wächst unbegrenzt (87k rows / 18 MB, db.md:105), keine Hypertable/keine Retention. Weniger dringlich als llmlog (v3.9.0 via Body-NULLing abgedeckt). Kandidat bei 1M-Scale: Hypertable + zeitbasierte Retention analog llmlog.EvictBodies / embed_cache-Janitor.

    daten-lebenszyklusretentioncontext_access_logskalierung
  • Korpus-KurationKorpus-Kuration veralteter Config-BlöckeOffene Frage

    Korpus-Kuration — veraltete Config-Blöcke (CPU-Antwort zitierte alten "aktuelles Modell"-Block).

    daten-lebenszykluskorpus-kurationconfig
  • Niedrig-PrioNiedrig-Priorität (Sammelposten)Offene Frage

    Sammelposten Niedrig-Priorität: Session-10-Todos P2; ctx dream --dry-run; FTS OR-Matching (M018); PromoteToCanonical Unit-Tests; Shared-Scope-Migration Warnings (→ /ctx-init); go test -short im pre-commit; OLLAMA_EMBED_DIMS-Echos in test/eval/state.sh (display-only tot — Altlast aus Ollama-Ära); TestResolveProject-Mini-Fix; test.sh-exit-0-Kosmetik.

    niedrig-priosammelpostenquirks
  • n8n-Servicen8n-Service bewusst behalten (nicht entfernen)Entschieden

    Bewusst KEINE Altlast: n8n-Service läuft bewusst weiter (override.yml, SMS-Webhook); NICHT als Altlast entfernen.

    nicht entfernenn8nbewusst-behalten

Entscheidungen

  • n8n-Service bleibt erhaltenn8n-Service läuft bewusst weiter (override.yml, SMS-Webhook) und ist nicht als Altlast zu entfernen.
  • context_access_log-Retention geparkt 2026-06-13Review nach allen Phasen, User-Entscheidung; weniger dringlich als llmlog (v3.9.0 via Body-NULLing abgedeckt).

Offene Fragen

  • Temporal Cyclic Retrieval — Status-WiderspruchStatus vs. README v3.0.0 verifizieren: "65% offen" widerspricht README v3.0.0.
  • ClassifyConfidence als GateRekalibrierung unter Blend-Scores als eigene Welle, falls Confidence je als Gate dient (N01-05 + T01-Klasse).

Risiken

  • Niedrigcontext_access_log wächst unbegrenztTabelle wächst unbegrenzt (87k rows / 18 MB, db.md:105), keine Hypertable/keine Retention. Retention-Entscheidung geparkt bis Review nach allen Phasen (User-Entscheidung 2026-06-13); Kandidat bei 1M-Scale.

Nächste Schritte

  • Back-off Re-Messung ≈2026-06-30 — User setzt Kalendereintrag, Prozedur .project/bench-session-w49c/HISTORY-SPLIT.md
  • Temporal Cyclic Retrieval — Status vs. README v3.0.0 verifizieren ("65% offen" widerspricht README v3.0.0)