Files
Orchestrator/.kiro/specs/monorepo-consolidation/design.md
T
2026-06-30 20:37:40 +02:00

42 KiB
Raw Blame History

Design Document: Monorepo-Consolidation

Overview

Dieses Design beschreibt die technische Architektur für die Konsolidierung von 18+ einzelnen Repositories in eine einheitliche Monorepo-Struktur. Das System vereint Projekte aus drei Arbeitskontexten (privat, dhive, bahn) mit einem shared-Bereich, implementiert Sicherheitsgrenzen zwischen Kontexten, einen übergreifenden Wissensspeicher basierend auf der DB-Wissensdatenbank-ETL-Pipeline, integriert den bestehenden AI-Orchestrator, speichert Secrets verschlüsselt im Repository mittels git-crypt, und ermöglicht eine föderierte Zusammenarbeit über eigenständige Team-Repositories in einer Hub-and-Spoke-Topologie.

Kernentscheidungen

  1. Git-Subtrees statt Submodules für externe Repos und Team-Repos: Subtrees ermöglichen flache Checkouts ohne rekursive Init-Schritte und erlauben bidirektionale Synchronisation mit Upstream und Team-Repositories.
  2. Dateibasierte Zugriffskontrolle statt OS-Level-Permissions: Ein Wrapper-Script (ctx-guard) prüft Kontextzugehörigkeit und kontrolliert den Zugriff auf .env-Dateien und Secrets.
  3. ETL-Pipeline-Fork der DB-Wissensdatenbank als Basis für den Wissensspeicher: Wiederverwendung der bewährten Quellstrategien und Erweiterung um persönliche Arbeitskontexte.
  4. YAML-Frontmatter + YAML-Index als Progressive-Disclosure-System: Agenten lesen zuerst den kompakten Index und laden nur bei Bedarf vollständige Dokumente.
  5. git-crypt für Encryption-at-Rest: Secrets werden verschlüsselt im Repository gespeichert statt via .gitignore ausgeschlossen. Pro Arbeitskontext ein eigener GPG-/symmetrischer Schlüssel ermöglicht granulare Entschlüsselung per Maschinenkontext.
  6. Hub-and-Spoke-Föderation für Multi-Team-Zusammenarbeit: Das Monorepo ist der zentrale Hub (nur Andre sieht alles), Team-Repos sind unabhängige Spokes. Synchronisation via Git-Subtrees bewahrt vollständige Historie.

Architecture

graph TB
    subgraph Monorepo["Monorepo Root (Hub)"]
        direction TB
        
        subgraph Contexts["Arbeitskontexte"]
            privat["privat/"]
            dhive["dhive/"]
            bahn["bahn/"]
            shared["shared/"]
        end
        
        subgraph SharedArea["shared/ Bereich"]
            tools["tools/"]
            powers["powers/"]
            knowledge["knowledge-store/"]
            config["config/"]
            mcpservers["mcp-servers/"]
        end
        
        subgraph Security["Sicherheitsschicht"]
            ctxguard["ctx-guard"]
            envfiles[".env pro Kontext (verschlüsselt)"]
            accessconfig["access-config.yaml"]
            auditlog["audit.log"]
        end
        
        subgraph Encryption["Verschlüsselungsschicht"]
            gitcrypt["git-crypt"]
            contextkeys["Kontext-Schlüssel (privat/dhive/bahn)"]
            machineconfig["machine-context.yaml"]
        end
        
        subgraph Federation["Föderationsschicht"]
            fedmanager["Federation-Manager"]
            syncengine["Sync-Engine (git-subtree)"]
            teamconfig["team-repos.yaml"]
        end
    end
    
    subgraph External["Externe Repos"]
        extro1["Read-Only Repos"]
        upstream["Upstream Repos"]
    end
    
    subgraph TeamRepos["Team-Repos (Spokes)"]
        teamPrivat["Team-Repo: privat"]
        teamDhive["Team-Repo: dhive"]
        teamBahn["Team-Repo: bahn"]
    end
    
    subgraph Orchestrator["AI-Orchestrator"]
        taskrouter["Task-Router"]
        ctxresolver["Context-Resolver"]
        agentrunner["Agent-Runner"]
    end
    
    Orchestrator --> Security
    Security --> Encryption
    Encryption --> Contexts
    External --> Contexts
    knowledge --> Contexts
    Federation -.->|"bidirektionaler Sync"| TeamRepos
    teamPrivat -.-> privat
    teamDhive -.-> dhive
    teamBahn -.-> bahn

Schichtenarchitektur

graph LR
    subgraph L1["Schicht 1: Dateisystem"]
        folders["Ordnerstruktur"]
        gitconfig["Git-Konfiguration"]
    end
    
    subgraph L2["Schicht 2: Verschlüsselung"]
        gitcrypt["git-crypt"]
        keymanagement["Schlüsselverwaltung"]
        machinecontext["Maschinenkontext"]
    end
    
    subgraph L3["Schicht 3: Zugriffskontrolle"]
        guard["ctx-guard Wrapper"]
        hooks["Git-Hooks"]
        envloader["Env-Loader"]
    end
    
    subgraph L4["Schicht 4: Wissensspeicher"]
        etl["ETL-Pipeline"]
        index["YAML-Index"]
        search["Suche"]
    end
    
    subgraph L5["Schicht 5: Integration"]
        orch["Orchestrator-Adapter"]
        bridge["Kontextbrücke"]
        sync["Repo-Sync"]
    end
    
    subgraph L6["Schicht 6: Föderation"]
        fedmgr["Federation-Manager"]
        subtreesync["Subtree-Sync"]
        teamisolation["Team-Isolation"]
    end
    
    L1 --> L2 --> L3 --> L4 --> L5 --> L6

Components and Interfaces

1. Ordnerstruktur-Manager (structure-manager)

Verantwortung: Anlegen, Validieren und Verwalten der Monorepo-Ordnerstruktur.

class StructureManager:
    """Verwaltet die 3-Ebenen-Ordnerhierarchie."""
    
    CONTEXTS = ("privat", "dhive", "bahn", "shared")
    NAME_PATTERN = re.compile(r'^[a-z0-9][a-z0-9\-]{0,48}[a-z0-9]$')
    
    def create_project(self, context: str, name: str) -> Path:
        """Erstellt ein neues Projekt im gegebenen Kontext."""
        ...
    
    def validate_name(self, name: str) -> bool:
        """Prüft kebab-case Namenskonvention (2-50 Zeichen)."""
        ...
    
    def list_projects(self, context: str | None = None) -> list[ProjectInfo]:
        """Listet alle Projekte, optional gefiltert nach Kontext."""
        ...
    
    def resolve_context(self, project_path: Path) -> str:
        """Ermittelt den Arbeitskontext eines Projekts anhand seines Pfads."""
        ...

2. Sicherheits-Guard (ctx-guard)

Verantwortung: Zugriffskontrolle auf Secrets und .env-Dateien basierend auf Ausführungskontext.

class ContextGuard:
    """Erzwingt Sicherheitsgrenzen zwischen Arbeitskontexten."""
    
    def __init__(self, config_path: Path):
        self.config = self._load_access_config(config_path)
        self.audit_log = AuditLogger()
    
    def check_access(self, requesting_context: str, target_path: Path) -> bool:
        """Prüft ob der Zugriff auf target_path vom requesting_context erlaubt ist."""
        ...
    
    def load_env(self, context: str) -> dict[str, str]:
        """Lädt die .env-Datei des gegebenen Kontexts."""
        ...
    
    def log_violation(self, event: SecurityEvent) -> None:
        """Protokolliert einen Zugriffsverletzungs-Versuch."""
        ...

Konfigurationsdatei (access-config.yaml):

contexts:
  privat:
    env_file: privat/.env
    allowed_shared:
      - shared/tools/
      - shared/powers/
      - shared/config/
  dhive:
    env_file: dhive/.env
    allowed_shared:
      - shared/tools/
      - shared/powers/
      - shared/config/
  bahn:
    env_file: bahn/.env
    allowed_shared:
      - shared/tools/
      - shared/powers/
      - shared/config/
      - shared/knowledge-store/
  shared:
    env_file: shared/.env
    allowed_shared: ["*"]

3. Wissensspeicher (knowledge-store)

Verantwortung: ETL-Pipeline für kontextübergreifendes Wissen, basierend auf der DB-Wissensdatenbank-Architektur.

class KnowledgeStore:
    """Zentraler Wissensspeicher mit ETL-Pipeline."""
    
    def __init__(self, base_path: Path, scope_config: ScopeConfig):
        self.base_path = base_path
        self.scope_config = scope_config
        self.index = YAMLIndex(base_path / "_index.yaml")
    
    def ingest(self, source: Source, context: str) -> list[Artifact]:
        """Verarbeitet eine Quelle und legt Artefakte ab."""
        ...
    
    def search(self, query: str, allowed_scopes: list[str]) -> list[SearchResult]:
        """Volltextsuche über den Index, gefiltert nach Berechtigung."""
        ...
    
    def get_index(self, scope: str | None = None) -> IndexData:
        """Liefert den kompakten YAML-Index (Progressive Disclosure Schicht 1)."""
        ...
    
    def link_artifacts(self, source_id: str, target_id: str, relation: str) -> None:
        """Verknüpft zwei Artefakte als gerichtete Graph-Kante."""
        ...

ETL-Pipeline-Komponenten:

graph LR
    Sources["Quellen"] --> Extract["Extract"]
    Extract --> Transform["Transform"]
    Transform --> Load["Load"]
    Load --> Index["Index Update"]
    
    Sources --- Confluence
    Sources --- Webseiten
    Sources --- PDFs
    Sources --- Markdown
    Sources --- GitLab

4. Externes-Repo-Manager (repo-manager)

Verantwortung: Einbindung, Synchronisation und Schutzmechanismen für externe Repositories.

class RepoManager:
    """Verwaltet externe und Upstream-Repository-Einbindungen."""
    
    def __init__(self, config_path: Path):
        self.config = self._load_repos_config(config_path)
    
    def add_repo(self, entry: RepoEntry) -> None:
        """Bindet ein externes Repo ein (Subtree oder Submodule)."""
        ...
    
    def sync(self, repo_name: str) -> SyncResult:
        """Synchronisiert ein Repo mit seinem Remote."""
        ...
    
    def protect_readonly(self, repo_path: Path) -> None:
        """Installiert Git-Hooks zum Schutz vor Schreibzugriffen."""
        ...

Konfigurationsdatei (repos.yaml):

repos:
  - name: db-wissensdatenbank
    url: https://gitlab.2700.2db.it/...
    mode: upstream
    target: bahn/db-wissensdatenbank
    pinned: main
    
  - name: symphony-spec
    url: https://github.com/openai/symphony
    mode: read-only
    target: shared/references/symphony
    pinned: v1.0.0

5. Kontextbrücke (context-bridge)

Verantwortung: Kontextübergreifendes Teilen von Wissensartefakten unter Wahrung der Sicherheitsgrenzen.

class ContextBridge:
    """Ermöglicht kontextübergreifenden Wissenstransfer."""
    
    SENSITIVE_PATTERNS = [
        r'(?i)(api[_-]?key|token|password|secret)\s*[:=]',
        r'(?i)(endpoint|url)\s*[:=]\s*https?://',
        r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
    ]
    
    def share_artifact(self, artifact_id: str, user_confirmed: bool = False) -> ShareResult:
        """Gibt ein Artefakt kontextübergreifend frei."""
        ...
    
    def check_sensitive_content(self, content: str) -> list[SensitiveMatch]:
        """Prüft Inhalt auf kontextspezifische Geheimnisse und PII."""
        ...
    
    def revoke_share(self, artifact_id: str) -> None:
        """Widerruft die Freigabe eines geteilten Artefakts."""
        ...

6. Migrations-Engine (migration-engine)

Verantwortung: Inkrementelle Migration bestehender Repositories unter Bewahrung der Git-Historie.

class MigrationEngine:
    """Migriert bestehende Repos in die Monorepo-Struktur."""
    
    def migrate(self, plan: MigrationPlan) -> MigrationResult:
        """Führt die Migration eines einzelnen Repos durch."""
        ...
    
    def validate(self, repo_name: str) -> ValidationResult:
        """Validiert eine abgeschlossene Migration."""
        ...
    
    def rollback(self, repo_name: str) -> None:
        """Macht die Migration eines Repos rückgängig."""
        ...

7. Orchestrator-Adapter (orchestrator-adapter)

Verantwortung: Integration des AI-Orchestrators mit der Monorepo-Struktur.

class OrchestratorAdapter:
    """Adaptiert den AI-Orchestrator für die Monorepo-Struktur."""
    
    def resolve_context(self, task: Task) -> str:
        """Ermittelt den Arbeitskontext aus Task-Metadaten."""
        ...
    
    def create_workspace(self, task: Task, context: str) -> Path:
        """Erstellt ein kontextgebundenes Workspace."""
        ...
    
    def build_prompt(self, task: Task, context: str) -> str:
        """Erstellt den Agenten-Prompt mit Wissenskontext."""
        ...
    
    def inject_knowledge(self, prompt: str, context: str) -> str:
        """Fügt relevante Artefakt-Pfade aus dem YAML-Index hinzu."""
        ...

8. Secret-Encryption-Manager (secret-encryption)

Verantwortung: Verschlüsselung von Secrets im Repository mittels git-crypt, Schlüsselverwaltung pro Arbeitskontext, und Maschinenkontext-basierte Entschlüsselung.

class SecretEncryptionManager:
    """Verwaltet git-crypt-basierte Verschlüsselung pro Arbeitskontext."""
    
    SUPPORTED_TOOLS = ("git-crypt", "sops", "age")
    SECRET_PATTERNS = [
        "**/.env",
        "**/*.pem",
        "**/*.key",
        "**/*token*",
        "**/*secret*",
    ]
    
    def __init__(self, config_path: Path, machine_context: MachineContext):
        self.config = self._load_encryption_config(config_path)
        self.machine_context = machine_context
        self.tool = self._init_encryption_tool()
    
    def encrypt_file(self, file_path: Path, context: str) -> EncryptionResult:
        """Verschlüsselt eine Datei mit dem Schlüssel des gegebenen Kontexts."""
        ...
    
    def decrypt_file(self, file_path: Path) -> DecryptionResult:
        """Entschlüsselt eine Datei, sofern der Maschinenkontext autorisiert ist."""
        ...
    
    def is_authorized(self, context: str) -> bool:
        """Prüft ob der aktuelle Maschinenkontext für den Kontext autorisiert ist."""
        return context in self.machine_context.authorized_contexts
    
    def get_context_key(self, context: str) -> Optional[EncryptionKey]:
        """Liefert den Schlüssel für einen Kontext (aus Keyring/Passwort-Manager)."""
        ...
    
    def setup_gitcrypt_filters(self, context: str) -> None:
        """Installiert git-crypt-Filter für den gegebenen Kontext."""
        ...
    
    def onboard_machine(self, machine_name: str, authorized_contexts: list[str]) -> OnboardingResult:
        """Richtet eine neue Maschine mit den autorisierten Schlüsseln ein."""
        ...
    
    def resolve_merge(self, file_path: Path, ours: bytes, theirs: bytes) -> bytes:
        """Löst Merge-Konflikte auf verschlüsselter Ebene."""
        ...

Maschinenkontext-Konfiguration (machine-context.yaml):

machine:
  name: "andre-hauptrechner"
  description: "Andres Hauptrechner mit vollem Zugriff"
  authorized_contexts:
    - privat
    - dhive
    - bahn
  key_source: "keyring"  # keyring | file | password-manager
  password_manager:
    type: "bitwarden"    # bitwarden | 1password | keepass
    vault: "monorepo-keys"

git-crypt-Konfiguration (.gitattributes pro Kontext):

# privat/.gitattributes
.env filter=git-crypt-privat diff=git-crypt-privat
*.pem filter=git-crypt-privat diff=git-crypt-privat
*.key filter=git-crypt-privat diff=git-crypt-privat

# dhive/.gitattributes
.env filter=git-crypt-dhive diff=git-crypt-dhive
*.pem filter=git-crypt-dhive diff=git-crypt-dhive

# bahn/.gitattributes
.env filter=git-crypt-bahn diff=git-crypt-bahn
*.pem filter=git-crypt-bahn diff=git-crypt-bahn

9. Federation-Manager (federation-manager)

Verantwortung: Verwaltung der Hub-and-Spoke-Topologie, bidirektionale Synchronisation zwischen Monorepo und Team-Repos via Git-Subtrees, Team-Isolation und Shared-Bereich-Spiegelung.

class FederationManager:
    """Verwaltet die föderierte Repo-Struktur (Hub-and-Spoke)."""
    
    def __init__(self, config_path: Path, encryption_manager: SecretEncryptionManager):
        self.config = self._load_team_repos_config(config_path)
        self.encryption = encryption_manager
        self.sync_engine = SubtreeSyncEngine()
    
    def sync_from_team(self, context: str) -> SyncResult:
        """Synchronisiert Änderungen vom Team_Repo in den Monorepo-Kontextordner."""
        ...
    
    def sync_to_team(self, context: str) -> SyncResult:
        """Synchronisiert Änderungen vom Monorepo-Kontextordner zum Team_Repo."""
        ...
    
    def full_sync(self, context: str) -> SyncResult:
        """Bidirektionale Synchronisation mit Konflikt-Erkennung."""
        ...
    
    def verify_isolation(self, team_repo_path: Path, context: str) -> IsolationReport:
        """Prüft ob ein Team_Repo keine Referenzen auf andere Kontexte enthält."""
        ...
    
    def mirror_shared(self, context: str, paths: list[str]) -> MirrorResult:
        """Spiegelt ausgewählte shared-Dateien als Read-Only in das Team_Repo."""
        ...
    
    def prepare_team_repo(self, context: str) -> Path:
        """Erzeugt ein Team_Repo mit nur dem eigenen Kontext (Secrets entschlüsselt/re-keyed)."""
        ...
    
    def resolve_conflict(self, context: str, strategy: str = "team-wins") -> ConflictResult:
        """Löst Sync-Konflikte auf (Standard: Team_Repo hat Vorrang)."""
        ...
    
    def onboard_member(self, context: str, member_info: MemberInfo) -> OnboardingResult:
        """Erteilt Zugang nur zum Team_Repo ohne Kenntnis des Monorepos."""
        ...


class SubtreeSyncEngine:
    """Git-Subtree-basierte Synchronisation mit Historie-Bewahrung."""
    
    def subtree_pull(self, remote: str, prefix: str, branch: str) -> SyncResult:
        """Zieht Änderungen vom Team_Repo per git subtree pull."""
        ...
    
    def subtree_push(self, remote: str, prefix: str, branch: str) -> SyncResult:
        """Pusht Änderungen zum Team_Repo per git subtree push."""
        ...
    
    def detect_conflicts(self, context: str) -> list[ConflictInfo]:
        """Erkennt Merge-Konflikte vor der Synchronisation."""
        ...
    
    def preserve_history(self, repo_path: Path) -> bool:
        """Verifiziert, dass die Git-Historie nach Sync vollständig ist."""
        ...

Team-Repos-Konfiguration (team-repos.yaml):

version: "1.0"
federation:
  topology: "hub-and-spoke"
  hub_owner: "andre"
  conflict_strategy: "team-wins"  # Team_Repo hat Vorrang

team_repos:
  - context: privat
    url: "https://github.com/andreknie/privat-team.git"
    branch: main
    sync_direction: bidirectional
    sync_frequency: "on-push"     # on-push | hourly | daily | manual
    shared_mirror:
      enabled: true
      paths:
        - "shared/tools/common-scripts/"
        - "shared/config/base-config.yaml"
      mode: read-only

  - context: dhive
    url: "https://gitlab.dhive.io/team/dhive-mono.git"
    branch: main
    sync_direction: bidirectional
    sync_frequency: "on-push"
    shared_mirror:
      enabled: true
      paths:
        - "shared/tools/"
        - "shared/powers/db-dxp-platform/"
        - "shared/mcp-servers/"
      mode: read-only

  - context: bahn
    url: "https://gitlab.2700.2db.it/team/bahn-workspace.git"
    branch: main
    sync_direction: bidirectional
    sync_frequency: "daily"
    shared_mirror:
      enabled: true
      paths:
        - "shared/tools/"
        - "shared/powers/"
        - "shared/knowledge-store/_index.yaml"
      mode: read-only

Data Models

Ordnerstruktur

monorepo-root/
├── privat/
│   ├── project-a/
│   │   ├── module-1/
│   │   └── module-2/
│   ├── project-b/
│   ├── .env                           (verschlüsselt via git-crypt-privat)
│   └── .gitattributes                 (git-crypt-Filter-Regeln)
├── dhive/
│   ├── project-c/
│   ├── .env                           (verschlüsselt via git-crypt-dhive)
│   └── .gitattributes
├── bahn/
│   ├── db-wissensdatenbank/           (Upstream)
│   ├── project-d/
│   ├── .env                           (verschlüsselt via git-crypt-bahn)
│   └── .gitattributes
├── shared/
│   ├── tools/
│   ├── powers/
│   ├── knowledge-store/
│   ├── config/
│   │   ├── access-config.yaml
│   │   ├── repos.yaml
│   │   ├── scopes.yaml
│   │   ├── machine-context.yaml       (Maschinenkontext-Mapping)
│   │   └── team-repos.yaml            (Föderations-Konfiguration)
│   ├── mcp-servers/
│   └── .env
├── .gitattributes                     (Root-Level git-crypt-Regeln)
├── .gitignore                         (nur Build-Artefakte, Caches, Temp-Dateien)
├── .gitmodules
└── monorepo.yaml                      (Zentrale Monorepo-Konfiguration)

Wissensartefakt (Markdown mit YAML-Frontmatter)

---
type: decision          # decision | note | meeting | reference | pattern
title: "API-Designprinzipien für Microservices"
tags: [api, microservices, architecture, rest]
source_context: bahn    # Quellkontext
created: 2024-12-15
updated: 2025-01-10
shareable: true         # Kontextübergreifend teilbar?
links:
  - target: "privat/notes/rest-patterns.md"
    relation: "implements"
  - target: "shared/knowledge-store/patterns/api-versioning.md"
    relation: "references"
content_hash: "sha256:abc123..."
---

# API-Designprinzipien für Microservices

...

YAML-Index (Progressive Disclosure Schicht 1)

# shared/knowledge-store/_index.yaml
version: "1.0"
last_updated: "2025-01-15T10:30:00Z"
artifacts:
  - id: "bahn/decisions/api-design"
    title: "API-Designprinzipien für Microservices"
    type: decision
    tags: [api, microservices, architecture]
    scope: bahn
    summary: "REST-API-Konventionen für DB-InfraGO-Dienste"
    path: "bahn/decisions/api-design.md"
    content_hash: "sha256:abc123..."
    links: ["shared/patterns/api-versioning"]
  - id: "privat/notes/rest-patterns"
    title: "REST-Patterns Notizen"
    type: note
    tags: [api, rest, patterns]
    scope: privat
    summary: "Sammlung bewährter REST-Patterns"
    path: "privat/notes/rest-patterns.md"
    content_hash: "sha256:def456..."
    links: ["bahn/decisions/api-design"]

Zentrale Monorepo-Konfiguration (monorepo.yaml)

version: "1.0"
contexts:
  - name: privat
    description: "Persönliche Projekte"
  - name: dhive
    description: "dhive GmbH Projekte"
  - name: bahn
    description: "DB InfraGO Projekte"
  - name: shared
    description: "Kontextübergreifende Tools und Wissen"

naming:
  pattern: "^[a-z0-9][a-z0-9\\-]{0,48}[a-z0-9]$"
  min_length: 2
  max_length: 50

security:
  config: shared/config/access-config.yaml
  audit_log: .audit/access.log
  encryption:
    tool: git-crypt
    machine_context_config: shared/config/machine-context.yaml
    key_source: keyring
  federation:
    config: shared/config/team-repos.yaml
    conflict_strategy: team-wins

Repository-Eintrag (für repos.yaml)

@dataclass
class RepoEntry:
    name: str                   # Eindeutiger Name
    url: str                    # Repository-URL
    mode: Literal["read-only", "upstream"]
    target: str                 # Zielpfad im Monorepo
    pinned: str                 # Git-SHA, Tag oder Branch
    mechanism: Literal["subtree", "submodule"] = "subtree"

Migrations-Plan

@dataclass
class MigrationPlan:
    source_repo: str            # Pfad zum Quell-Repository
    target_context: str         # Ziel-Kontextordner
    target_name: str            # Projektname im Ziel
    mode: Literal["direct", "subtree", "upstream"]
    dependencies: list[str]     # Abhängigkeiten zu anderen Repos
    order: int                  # Migrationsreihenfolge

Sicherheits-Event

@dataclass
class SecurityEvent:
    timestamp: datetime
    requesting_context: str
    target_context: str
    resource: str
    action: str                 # read | write | execute
    outcome: Literal["denied", "allowed"]

Maschinenkontext

@dataclass
class MachineContext:
    name: str                           # z.B. "andre-hauptrechner", "dhive-laptop"
    description: str
    authorized_contexts: list[str]      # ["privat", "dhive", "bahn"] oder Subset
    key_source: Literal["keyring", "file", "password-manager"]
    password_manager: Optional[PasswordManagerConfig] = None

@dataclass
class PasswordManagerConfig:
    type: Literal["bitwarden", "1password", "keepass"]
    vault: str                          # Name des Vaults/der Datenbank
    entry_prefix: str = "monorepo-key-" # Prefix für Schlüssel-Einträge

@dataclass
class EncryptionKey:
    context: str                        # Zugehöriger Arbeitskontext
    key_id: str                         # GPG Key-ID oder symmetrischer Key-Name
    key_type: Literal["gpg", "symmetric"]
    source: Literal["keyring", "file", "password-manager"]

Team-Repo-Konfiguration

@dataclass
class TeamRepoEntry:
    context: str                        # Zugehöriger Arbeitskontext (privat/dhive/bahn)
    url: str                            # Repository-URL
    branch: str                         # Sync-Branch (z.B. "main")
    sync_direction: Literal["bidirectional", "hub-to-spoke", "spoke-to-hub"]
    sync_frequency: Literal["on-push", "hourly", "daily", "manual"]
    shared_mirror: Optional[SharedMirrorConfig] = None

@dataclass
class SharedMirrorConfig:
    enabled: bool
    paths: list[str]                    # Pfade aus shared/ die gespiegelt werden
    mode: Literal["read-only"]          # Immer read-only im Team_Repo

@dataclass
class SyncResult:
    success: bool
    context: str
    direction: str                      # "pull" | "push" | "full"
    commits_synced: int
    conflicts: list[ConflictInfo]
    timestamp: datetime

@dataclass
class ConflictInfo:
    file_path: str
    conflict_type: Literal["content", "rename", "delete-modify"]
    source: str                         # "monorepo" | "team-repo"
    details: str

@dataclass
class IsolationReport:
    context: str
    is_isolated: bool
    leaks: list[IsolationLeak]          # Gefundene Referenzen auf andere Kontexte

@dataclass
class IsolationLeak:
    file_path: str
    line_number: int
    leaked_context: str                 # Welcher fremde Kontext referenziert wird
    leak_type: Literal["path", "env_var", "config_ref", "comment"]

Correctness Properties

A property is a characteristic or behavior that should hold true across all valid executions of a system — essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.

Property 1: Namensvalidierung akzeptiert nur gültiges kebab-case

For any String, die validate_name-Funktion soll genau dann true zurückgeben, wenn der String ausschließlich aus Kleinbuchstaben, Ziffern und Bindestrichen besteht, zwischen 2 und 50 Zeichen lang ist und nicht mit einem Bindestrich beginnt oder endet.

Validates: Requirements 1.3

Property 2: Namenskollision verhindert doppelte Projekterstellung

For any Sequenz von Projekt-Erstellungsaufrufen im gleichen Kontext, wenn ein Projektname bereits existiert, muss der zweite Aufruf mit diesem Namen fehlschlagen und die bestehende Projektstruktur unverändert lassen.

Validates: Requirements 1.6

Property 3: Kontextübergreifender Secret-Zugriff wird verweigert

For any Kombination aus anfragendem Kontext A und Zielkontext B (wobei A ≠ B und B ≠ shared), muss der Zugriff auf .env-Dateien und Secret-Dateien von B verweigert werden, und es muss ein Audit-Log-Eintrag mit Zeitstempel, anfragendem Kontext, Zielkontext und Ressource erzeugt werden.

Validates: Requirements 2.1, 2.3, 2.5, 2.7

Property 4: Shared-Tool-Isolation

For any Tool aus dem shared-Bereich, das in einem bestimmten Arbeitskontext ausgeführt wird, darf es ausschließlich auf die Secrets des aktiven Kontexts und auf explizit freigegebene shared-Ressourcen zugreifen. Jeder andere Zugriff muss blockiert werden.

Validates: Requirements 2.7, 8.5

Property 5: Wissensartefakt-Ingestion erzeugt vollständige Metadaten im Index

For any gültiges Wissensartefakt aus einem beliebigen Kontext, nach der Verarbeitung durch die ETL-Pipeline muss es im YAML-Index erscheinen mit korrektem YAML-Frontmatter (mindestens Typ, Titel, Tags, Quellkontext, Erstelldatum, Content-Hash) und der Pfad muss der Scope-basierten Ordnerstruktur entsprechen.

Validates: Requirements 3.2, 3.4, 3.6, 3.11, 3.13, 3.17, 3.21

Property 6: Suche respektiert Scope-Berechtigungen

For any Suchanfrage und beliebige Menge autorisierter Scopes, dürfen die Ergebnisse ausschließlich Artefakte enthalten, deren Scope in der autorisierten Menge liegt. Artefakte aus nicht-autorisierten Scopes dürfen weder in der Ergebnisliste erscheinen noch darf deren Existenz offengelegt werden.

Validates: Requirements 3.3, 3.9

Property 7: Progressive-Disclosure-Index enthält nur kompakte Einträge

For any Abfrage des YAML-Index (Schicht 1) müssen die zurückgegebenen Einträge Titel, Tags, Beziehungen und Kurzbeschreibungen enthalten, aber niemals den vollständigen Dokumentinhalt. Suchergebnisse liefern ausschließlich Pfade zurück.

Validates: Requirements 3.16, 3.18

Property 8: Inkrementelle Verarbeitung erkennt Änderungen über Content-Hash

For any Quelle, wenn der Content-Hash seit der letzten Verarbeitung unverändert ist, darf kein Update erfolgen. Wenn sich der Hash geändert hat, muss genau das betroffene Artefakt aktualisiert werden.

Validates: Requirements 3.12

Property 9: Volltextsuche findet indexierte Inhalte

For any indexiertes Artefakt mit einem bestimmten Suchbegriff im Inhalt, muss eine Volltextsuche nach diesem Begriff das Artefakt in den Ergebnissen zurückliefern (sofern der Scope autorisiert ist), sortiert nach Relevanz.

Validates: Requirements 3.7

Property 10: ETL-Fehlerresilienz bewahrt erfolgreiche Artefakte

For any ETL-Durchlauf, in dem eine Quelle fehlschlägt, müssen alle zuvor erfolgreich verarbeiteten Artefakte erhalten bleiben, der Fehler mit Quellidentifikator und Zeitstempel protokolliert werden, und die fehlgeschlagene Quelle beim nächsten Durchlauf erneut verarbeitet werden.

Validates: Requirements 3.20

Property 11: Graph-Verknüpfungen werden in beiden Artefakten reflektiert

For any zwei Artefakte, wenn eine gerichtete Verknüpfung von A nach B erstellt wird, muss die Kante sowohl im YAML-Frontmatter von A als auch im Frontmatter von B erscheinen.

Validates: Requirements 3.8

Property 12: Read-Only-Repos blockieren Schreibzugriffe

For any Schreiboperation (Datei anlegen, ändern oder löschen) auf ein als read-only konfiguriertes eingebundenes Repository muss die Operation blockiert werden und eine Fehlermeldung ausgegeben werden, die den Read-Only-Status und den Repository-Namen enthält.

Validates: Requirements 4.2, 4.5

Property 13: Fehlgeschlagene Synchronisation bewahrt lokalen Stand

For any fehlgeschlagene Synchronisation mit einem Upstream-Repository (Netzwerkfehler, Authentifizierungsfehler, Merge-Konflikt) muss der lokale Dateizustand identisch zum Zustand vor dem Sync-Versuch sein.

Validates: Requirements 4.9

Property 14: Sensitive-Content-Filter blockiert Freigabe

For any Wissensartefakt, das Muster für kontextspezifische Geheimnisse, Zugangsdaten oder personenbezogene Daten enthält, muss die kontextübergreifende Freigabe verweigert werden mit einer Fehlermeldung, die den Ablehnungsgrund benennt.

Validates: Requirements 5.1, 5.3

Property 15: Freigabe-Lebenszyklus (Share → Update → Revoke)

For any geteiltes Artefakt gilt: (a) nach Freigabe ist es in allen Kontexten als schreibgeschützte Lesereferenz sichtbar, (b) Aktualisierungen im Quellkontext werden beim nächsten Lesezugriff reflektiert, (c) nach Widerruf ist es in keinem Zielkontext mehr sichtbar.

Validates: Requirements 5.2, 5.5, 5.6

Property 16: Freigabe erfordert explizite Nutzerbestätigung

For any Versuch ein Artefakt kontextübergreifend zu teilen, ohne dass user_confirmed=True gesetzt ist, muss die Operation fehlschlagen.

Validates: Requirements 5.4

Property 17: Migrations-Validierung prüft Vollständigkeit

For any migrierten Repository-Zustand muss die Validierungsfunktion korrekt prüfen: Übereinstimmung der Commit-Anzahl, Vorhandensein aller Branches und Tags, Vollständigkeit des Dateibaums.

Validates: Requirements 6.4

Property 18: Migrations-Rollback stellt Vor-Zustand wieder her

For any fehlgeschlagene Migration eines einzelnen Repositories muss der Rollback den exakten Zustand vor der Migration wiederherstellen, ohne andere bereits migrierte Repositories zu beeinflussen.

Validates: Requirements 6.7

Property 19: Orchestrator-Kontextauflösung und Workspace-Isolation

For any Task mit gültigen Kontext-Metadaten muss der Orchestrator (a) das Workspace unter dem korrekten Kontextordner anlegen und (b) ausschließlich die .env-Datei dieses Kontexts laden. Für Tasks ohne gültigen Kontext muss der Start verweigert werden.

Validates: Requirements 7.1, 7.2, 7.3, 7.6

Property 20: Orchestrator-Kontextverletzung bricht Task ab

For any Zugriff des Orchestrators auf Dateien oder Secrets außerhalb des zugewiesenen Kontextordners muss der laufende Task abgebrochen, der Vorfall protokolliert und der Nutzer benachrichtigt werden.

Validates: Requirements 7.5

Property 21: MCP-Konfiguration-Merge mit Kontext-Vorrang

For any MCP-Server-Konfiguration, bei der sowohl eine shared-Konfiguration als auch eine kontextspezifische Konfiguration existiert, muss die effektive Konfiguration die kontextspezifischen Werte bevorzugen (Merge mit Override).

Validates: Requirements 8.4, 8.6

Property 22: Shared-Tool-Versionierung ohne manuelle Synchronisation

For any Aktualisierung eines Tools im shared-Bereich müssen alle Kontexte bei ihrer nächsten Ausführung die aktualisierte Version verwenden, ohne manuelle Schritte in einzelnen Kontexten.

Validates: Requirements 8.2

Property 23: Verschlüsselte Secrets können nur mit autorisiertem Kontextschlüssel entschlüsselt werden

For any verschlüsselte Secret-Datei eines Arbeitskontexts X und für jeden Entschlüsselungsversuch mit einem Schlüssel des Kontexts Y (wobei X ≠ Y), muss die Entschlüsselung fehlschlagen und die Datei im verschlüsselten Zustand verbleiben. Nur der Schlüssel des zugehörigen Kontexts X darf die Datei erfolgreich entschlüsseln.

Validates: Requirements 9.3, 9.8

Property 24: Maschinenkontext beschränkt Entschlüsselung auf autorisierte Kontexte

For any Maschinenkontext-Konfiguration mit einer definierten Menge autorisierter Arbeitskontexte, muss gelten: (a) Secrets der autorisierten Kontexte sind entschlüsselbar, (b) Secrets aller nicht-autorisierten Kontexte verbleiben als verschlüsselte Binärdaten im Working Tree, (c) die Fehlermeldung bei fehlgeschlagener Entschlüsselung gibt keinen Hinweis auf den Dateiinhalt, (d) das Repository bleibt vollständig funktionsfähig (Code, Konfiguration, Dokumentation zugänglich).

Validates: Requirements 9.4, 9.5, 9.8, 9.10

Property 25: Team-Repos enthalten ausschließlich Inhalte des eigenen Kontexts

For any Team_Repo für einen Arbeitskontext X muss gelten: (a) es enthält keine Dateien, Pfade, Konfigurationsreferenzen oder Umgebungsvariablen, die auf einen anderen Arbeitskontext Y (Y ≠ X) verweisen, (b) es enthält keine Secrets anderer Kontexte (weder verschlüsselt noch unverschlüsselt), (c) optional gespiegelte Dateien aus dem shared-Bereich sind als Read-Only markiert und enthalten keine kontextfremden Referenzen.

Validates: Requirements 10.5, 10.9, 10.10, 10.12

Property 26: Bidirektionale Synchronisation bewahrt Git-Historie und löst Konflikte korrekt

For any Sequenz von Commits in einem Team_Repo oder einem Monorepo-Kontextordner, nach einer bidirektionalen Synchronisation muss gelten: (a) alle Commits erscheinen mit vollständiger Autoren- und Zeitstempel-Information auf beiden Seiten, (b) bei Merge-Konflikten wird die Synchronisation abgebrochen, der Konflikt mit betroffenen Dateien und Quellen protokolliert, und dem Hub-Besitzer manuelle Auflösung ermöglicht, (c) das Team_Repo gilt als Single Source of Truth — bei Konflikten hat es Vorrang.

Validates: Requirements 10.3, 10.4, 10.6, 10.7, 10.8

Property 27: Team-Mitglieder können die Existenz anderer Kontexte nicht entdecken

For any Team_Repo und jeden Dateipfad, Konfigurationseintrag, Git-Remote-URL, Commit-Message oder Metadaten-Feld innerhalb des Team_Repos darf kein Hinweis auf die Existenz des Monorepos, anderer Arbeitskontexte oder anderer Team_Repos enthalten sein. Das Team_Repo muss als vollständig eigenständiges Repository erscheinen.

Validates: Requirements 10.5, 10.9

Error Handling

Sicherheitsgrenzen

Fehlerfall Verhalten
Zugriff auf fremden Kontext Zugriff blockiert, Audit-Log-Eintrag, Operation gibt Fehler zurück
Ungültige access-config.yaml System startet nicht, Fehlermeldung mit Validierungsdetails
Shared-Tool ohne gültige Autorisierung Ausführung wird verhindert, Fehler mit Kontextinfo

Wissensspeicher

Fehlerfall Verhalten
ETL-Quellenfehler Fehler protokolliert (Quelle + Zeitstempel), vorhandene Artefakte bewahrt, Retry beim nächsten Lauf
Ungültiges YAML-Frontmatter Artefakt als fehlerhaft markiert, nicht indexiert, Fehler protokolliert
Index-Korruption Vollständiger Index-Rebuild aus den Artefakt-Dateien
Suchanfrage-Timeout (>5s) Abbruch mit Teilergebnis-Warnung
Duplikat-Content-Hash Vorhandenes Artefakt beibehalten, neues als Konflikt melden

Repository-Management

Fehlerfall Verhalten
Sync fehlgeschlagen (Netzwerk) Lokaler Stand unverändert, Fehlergrund protokolliert, Nutzer informiert
Merge-Konflikt bei Upstream-Sync Sync abgebrochen, Konflikt protokolliert, manuelle Auflösung ermöglicht
Schreibversuch auf Read-Only-Repo Operation blockiert, Fehlermeldung mit Repo-Name und Status
Submodule/Subtree-Init-Fehler Fehlgeschlagenes Repo übersprungen, andere Repos weiter verfügbar

Migration

Fehlerfall Verhalten
Pfadkollision Migration pausiert, Konflikt mit Dateipfad und Quell-Repos protokolliert
Branch-Namenskonflikt Migration pausiert, betroffene Branches gelistet
Validierung fehlgeschlagen Ergebnis dokumentiert, Rollback angeboten
Migration fehlgeschlagen Automatischer Rollback auf Vor-Zustand, andere Repos unberührt

Orchestrator

Fehlerfall Verhalten
Kein Kontext ermittelbar Task nicht gestartet, Fehlermeldung an Nutzer
Out-of-Context-Zugriff Task abgebrochen, Vorfall protokolliert, Nutzer über OrgMyLife benachrichtigt
Wissensspeicher-Index nicht verfügbar Task ohne Wissenskontext fortsetzen, Warnung protokolliert

Verschlüsselung (Secret Encryption)

Fehlerfall Verhalten
Entschlüsselung ohne autorisierten Schlüssel Zugriff verweigert, Datei bleibt verschlüsselt, keine inhaltsbezogene Fehlermeldung
git-crypt nicht installiert Setup-Fehler mit Installationsanleitung ausgeben, Repository im Nur-Lesen-Modus
Passwort-Manager nicht erreichbar Fallback auf lokalen Keyring versuchen, Warnung protokollieren
Beschädigter Schlüssel im Keyring Schlüssel als ungültig markieren, Neu-Import aus Passwort-Manager anbieten
Merge-Konflikt bei verschlüsselten Dateien git-crypt-Merge-Treiber verwenden, bei Scheitern: Konflikt protokollieren, manuelle Auflösung
Maschinenkontext-Konfiguration fehlt Alle Secrets verschlüsselt belassen, Warnung mit Setup-Verweis ausgeben
Ungültiger Maschinenkontext (unbekannter Kontext referenziert) Konfiguration ablehnen, Validierungsfehler mit gültigen Kontexten ausgeben

Föderation (Team-Repos)

Fehlerfall Verhalten
Sync-Konflikt (Merge-Conflict) Synchronisation abgebrochen, Konflikt mit Dateien und Quellen protokolliert, Hub-Besitzer informiert
Team_Repo nicht erreichbar (Netzwerk/Auth) Sync übersprungen, Fehler protokolliert, nächster Versuch bei nächstem Trigger
Cross-Context-Leakage erkannt bei Isolation-Check Sync blockiert, betroffene Dateien gelistet, manuelle Bereinigung erforderlich
Shared-Mirror-Quelle nicht vorhanden Mirror-Schritt übersprungen, Warnung protokolliert, restlicher Sync fortgesetzt
Team_Repo-Branch divergiert stark (>100 Commits Differenz) Warnung an Hub-Besitzer, Sync nur nach expliziter Bestätigung
Subtree-Push fehlgeschlagen Lokaler Monorepo-Stand unverändert, Fehler mit Remote-Details protokolliert
Neues Team-Mitglied erhält falschen Kontext-Zugang Sicherheitswarnung, Zugang sofort revoken, Vorfall im Audit-Log

Testing Strategy

Testebenen

  1. Property-Based Tests (Hypothesis): Universelle Eigenschaften über alle gültigen Eingaben (Minimum 100 Iterationen pro Property)
  2. Unit Tests (pytest): Spezifische Beispiele, Edge Cases, Fehlerbehandlung
  3. Integration Tests: Git-Operationen, Dateisystem-Interaktionen, ETL-Pipeline-Durchläufe
  4. Smoke Tests: Strukturprüfungen (Ordner existieren, Konfigurationen parsebar)

Property-Based Testing

Library: Hypothesis (Python)

Jeder Property-Test wird mit mindestens 100 Iterationen konfiguriert und referenziert die zugehörige Design-Property:

from hypothesis import given, settings
from hypothesis import strategies as st

@settings(max_examples=100)
@given(name=st.text(min_size=1, max_size=60))
def test_name_validation_property(name):
    """Feature: monorepo-consolidation, Property 1: Namensvalidierung akzeptiert nur gültiges kebab-case"""
    result = validate_name(name)
    expected = bool(re.match(r'^[a-z0-9][a-z0-9\-]{0,48}[a-z0-9]$', name))
    assert result == expected

Testabdeckung nach Komponente

Komponente Property Tests Unit Tests Integration Tests
StructureManager P1, P2 Beispiel-Projekte, Edge Cases
ContextGuard P3, P4 Konfigurationsvalidierung Dateisystem-Zugriffe
KnowledgeStore P5P11 Frontmatter-Parsing, Fehlerszenarien ETL-Pipeline mit Mock-Quellen
RepoManager P12, P13 Git-Hook-Installation Subtree/Submodule-Operationen
ContextBridge P14P16 Regex-Muster, Freigabelogik
MigrationEngine P17, P18 Migrationsplan-Validierung git filter-repo-Operationen
OrchestratorAdapter P19P22 YAML-Index-Abfrage, Prompt-Build Workspace-Erstellung
SecretEncryptionManager P23, P24 Schlüssel-Validierung, Konfigurationsschema git-crypt-Operationen, Passwort-Manager-Integration
FederationManager P25, P26, P27 Isolation-Check-Logik, Konfigurationsschema Git-Subtree-Operationen, Sync-Szenarien

Abgrenzung

  • Kein PBT für: Git-Remote-Operationen (Push/Pull/Sync), CI/CD-Konfigurationen, GitLab-Pages-Deployment, git-crypt-Tooling-Installation, Passwort-Manager-API
  • Integration Tests für: Tatsächliche Git-Operationen, Dateisystem-Berechtigungen, Netzwerk-Sync, git-crypt encrypt/decrypt-Zyklen, Subtree-Push/Pull gegen Test-Repos
  • Smoke Tests für: Konfigurationsdateien existieren und sind parsebar, Ordnerstruktur ist korrekt initialisiert, git-crypt ist installiert, Maschinenkontext-Konfiguration vorhanden