# SPEC-ontology: Ontologie der Datenhaltung Paket: `knaster.ontology`. Quelle: `ontology/know.yaml`. CLI: `knaster ontology …`. Die Ontologie beschreibt, *was* in der Datenhaltung steht (Projekt, Kontakt, Ankaufsfall, Mail …) und wie die Begriffe zusammenhängen. Tabellen sind nur die Ablage dahinter. Sie ist die eine Quelle der Wahrheit; Turtle, Graph und Ansicht werden daraus erzeugt, nie von Hand gepflegt. ## 1. Drei Ebenen, drei Pflegeregeln | Ebene | Inhalt in `know.yaml` | Wie sie sich ändert | |---|---|---| | Kern | `classes`, `relations`, `modules` | bewusst, per Commit (Review wie Code) | | Vokabulare | `vocabularies.*.concepts`, `alt`, `rejected` | wachsen über Vorschläge der Service-Routine → Freigabe → `knaster ontology apply` | | Instanzen | – (stehen in den Daten) | automatisch; unsichere Verknüpfungen später ebenfalls über Vorschläge | Ohne diese Regeln zerfällt ein Vokabular wieder in mehrere Listen (KNOW-Befund B20). Deshalb legt nie ein Werkzeug oder LLM selbstständig Klassen oder Konzepte an; es schlägt sie vor. ## 2. Modell (`know.yaml`) ```yaml id: know version: 3 # steigt bei jeder Übernahme von Entscheidungen namespace: urn:mygodel:know# modules: {mail: Mail & Absender, …} classes: Mail: label: Mail module: mail table: mail_events # fehlt = implizite Klasse (nur Wert in Spalten) oder externes System key: message_id definition: … sensitive: … # steuert Datenschutz-Regeln (geplant: PSE/lokal) subclass_of: Dokument # optional attributes: {message_id: TEXT, …} # Spalten der Tabelle, Abbild des KNOW-Schemas relations: - {source: Mail, name: zugeordnetZu, target: Projekt, via: mail_events.assigned_project_key, kind: key} # kind: key (gemeinsamer Schlüssel) | soft (Wertabgleich) | external (ID in KanBau/SharePoint/M365) vocabularies: MailKategorie: label: Mail-Kategorie class: MailKategorie # optional: Konzepte sind Ausprägungen dieser Klasse columns: [mail_events.category, workflow_hints.hint_type, workflow_hint_config.config_key] concepts: buchhaltung: {label: Rechnungen, alt: [Buchhaltung]} default: {label: Standard, technical: true} rejected: [MPA] # bewusst kein Konzept ignore: [sql:ASP - Absender-Report:…] # bewusst hingenommene Befunde ``` `Ontology.validate_model()` prüft: Module, Oberklassen und Beziehungsenden existieren; jede Tabelle gehört zu höchstens einer Klasse; Vokabel-Spalten existieren als Attribut; kein Name zeigt auf zwei Konzepte; kein verworfener Wert ist zugleich Konzept. `knaster validate` prüft das in der CI und warnt, wenn `know.ttl` nicht zur YAML passt. ## 3. Abgleich mit n8n (`check`) Eingabe ist eine Momentaufnahme der n8n-Workflows (`build_snapshot`, nur GET `/api/v1/workflows` bzw. eine JSON-Datei): - **KNOW-Spezifikation** aus dem Code des KNOW-Workflows: erlaubte Operationen (`const allowed`), Schema (`CREATE TABLE`, `ALTER … ADD COLUMN`), pro Operation geschriebene Spalten und dabei gesetzte Literale, Seeds (reine Literal-INSERTs). - **Aufrufe** von KNOW mit Operation und Payload-Ausdruck. Wird die Operation erst zur Laufzeit gesetzt, werden Kandidaten aus den Literalen des Workflows abgeleitet (`inferred`). - **Direktes SQL**: Postgres-Knoten außerhalb von KNOW, die das Schema `knowledge` ansprechen. Ergebnisse (`OntologyFinding`, sortiert nach Schwere): | Art | Schwere | Vorschlag? | |---|---|---| | `unmapped_table` – Tabelle ohne Klasse | medium | ja: `add_class` | | `unmapped_column` – Spalte ohne Attribut | low | ja: `add_attribute` | | `vocab_value` – Wert in einer Vokabel-Spalte, der kein Konzept ist | medium (low, wenn nur aus inaktiven Workflows) | ja: aufnehmen, zuordnen oder verwerfen | | `unknown_operation` – Aufruf einer Operation, die KNOW nicht kennt | high (aktiv) / low | nein, Befund | | `direct_sql` – SQL an KNOW vorbei | medium (schreibend) / low | nein | | `missing_table` / `missing_column` – Ontologie verweist auf etwas, das KNOW nicht anlegt | medium / low | nein | | `concept_without_producer` – Konzept, das keine *feste* Zuordnung erzeugt | info | nein | | `no_write_operation` / `no_active_writer` – Klasse ohne Schreibweg | info | nein | Werte werden nur aus Schlüsseln der obersten Payload-Ebene gelesen (verschachtelte JSON-Felder gehören zu einer JSON-Spalte). „Fest“ heißt: Literal oder Zuordnungstabelle mit Literal-Rückfall; bei freien Werten (LLM-Ausgabe) trifft die Prüfung keine Aussage. Entschiedene Schlüssel (Tabelle `ontology_decisions`) und `ignore` werden übersprungen. ## 4. Service-Routine und Freigabe Schritt 8 der Routine (`MaintenanceAgent.run_routine`) ruft den Abgleich auf, wenn `ontology_path` existiert und eine Quelle konfiguriert ist (`KNASTER_ONTOLOGY_SNAPSHOT` oder `N8N_HOST` + `N8N_API_KEY`): - Befunde ohne Vorschlag erscheinen als Zeilen „Ontologie [schwere]: …“ (höchstens `ontology_max_findings`, Standard 15). - Befunde mit Vorschlag werden zu Vorschlägen der Art `ontology_change` (Richtlinie: immer Freigabe, Risiko niedrig), dedupliziert über `ontology:`. - `genehmige P-x` → Entscheidung `accept`; `ordne P-x zu` → `map` (Wert wird alternative Schreibweise des Konzepts); `lehne P-x ab: …` → `reject` (Wert landet in `rejected` bzw. der Schlüssel in `ignore`). - Entscheidungen liegen in `ontology_decisions`; ein entschiedener Schlüssel wird nicht erneut vorgeschlagen. - `knaster ontology apply` schreibt offene Entscheidungen in `know.yaml`, erhöht `version`, prüft das Ergebnis und markiert die Entscheidungen als übernommen. Danach `knaster ontology export --ttl ontology/know.ttl` und committen. Fällt n8n aus, meldet die Routine „Ontologie-Abgleich nicht möglich“ und läuft weiter. ## 5. CLI | Befehl | Zweck | |---|---| | `knaster ontology validate` | Modell prüfen | | `knaster ontology export --ttl F --graph F --html F` | Turtle (OWL + SKOS), Graph-JSON, eigenständige Ansicht (`ontology/viewer.html.tmpl`) | | `knaster ontology snapshot --out F` | Workflows lesen und speichern (enthält Workflow-Code, nicht committen) | | `knaster ontology check [--snapshot F] [--json]` | Abgleich; Exit 1 bei Befunden der Schwere high | | `knaster ontology apply [--dry-run]` | freigegebene Entscheidungen übernehmen | ## 6. Grenzen und nächste Schritte - Die Prüfung liest Code, keine Daten: ob Tabellen tatsächlich leer sind, zeigt erst eine Zählung in der Datenbank. - Weiche Bezüge (z. B. Absender ↔ Kontakt) werden noch nicht automatisch als Verknüpfungsvorschläge erzeugt; geplant über Embeddings mit Schwelle (Instanz-Ebene). - Aus der Ontologie sollen erzeugt werden: Sichten pro Klasse („Projekt 360°“), JSON-Schemas für Skill-Ausgaben, Werkzeugkatalog für Hermes/NEX, Datenschutz-Regeln aus `sensitive`.