62da36872f
User-Ergänzung: norm_ids sind nur die erste Rechtsreferenz-Art. Runtime-Vertrag (Phase B)
soll eine erweiterbare Hülle tragen (legal_reference: {norm_ids, citation_units, recital_ids,
guidance_ids, case_law_ids, interpretation_ids}), damit neue Referenz-Arten additiv als
optionale Keys landen ohne erneuten Vertrags-/Go-Struct-Umbau. Naming-Hinweis: NICHT
"legal_basis" (kollidiert mit dem Obligation-Array). Bindend ⊥ Guidance bleibt erhalten.
Phase B baut NUR norm_ids; Rest = reservierter Platz, kein Bauauftrag. Nur Spec, kein Code.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
202 lines
11 KiB
Markdown
202 lines
11 KiB
Markdown
# Obligation Registry v1 — Schema, Zitierfähigkeit, Zwei-Graphen-Architektur
|
||
|
||
Status: **Spec festgeschrieben (2026-06-24)**. Baut auf
|
||
[legal_obligation_layer_v1.md](legal_obligation_layer_v1.md) +
|
||
[obligation_aggregation_validation.md](obligation_aggregation_validation.md).
|
||
Die Obligation Discovery Pipeline v1 ist gegen Ground Truth validiert
|
||
(SBOM 12 vs 10, Vuln 8 vs 7, out_of_scope + conditional Applicability korrekt).
|
||
|
||
## Leitsatz
|
||
|
||
**Die Legal Obligation ist das fachliche Wissensobjekt der Plattform** — nicht der Master
|
||
Control. Controls sind Prüfstrategien / Erkennungsmuster / Evidenzsammler FÜR eine Obligation.
|
||
Ohne Zitierfähigkeit ist die Registry fachlich nicht belastbar: die erste Kundenfrage ist
|
||
immer „**Wo steht das?**".
|
||
|
||
## Zwei Assets, zwei Graphen, EIN Join (nicht verschmelzen, verbinden)
|
||
|
||
- **Asset 1 — Compliance Knowledge** (bereits gebaut): 313k atomare Controls, 33k Master
|
||
Controls, ~14k use-case-gemappt, Dedup, Obligation Layer, Applicability, Tiering, G/C/E.
|
||
- **Asset 2 — Zitierfähige Wissensbasis** (entsteht in anderer Session): Dokument → Chunk →
|
||
Paragraph → Span → Zitat.
|
||
|
||
Die beiden werden **NICHT verschmolzen** (das wäre wie eine normalisierte DB nach CSV zu
|
||
exportieren und neu zu importieren). Sie werden über die **Obligation gekoppelt**:
|
||
|
||
```
|
||
GRAPH 1 — Legal Knowledge Graph (Chat/Advisor) GRAPH 2 — Compliance Execution Graph (Engine)
|
||
Regulation → Annex/Artikel → Paragraph → Span Obligation → Control → Criterion → Evidence → Finding
|
||
\ /
|
||
\____ LEGAL OBLIGATION ______/ ← gemeinsame Sprache (der Join)
|
||
```
|
||
Chat: „diese Aussage stammt aus Absatz X." · Engine: „diese Obligation ist nicht erfüllt." →
|
||
beide meinen DIESELBE `obligation_id`.
|
||
|
||
## Registry-Schema v1
|
||
|
||
```yaml
|
||
id: # snake_case, regulierungs-agnostisch (z.B. sbom_complete)
|
||
name: # kurz
|
||
description: # 1 Satz
|
||
tier: # LEGAL_MINIMUM | BEST_PRACTICE | IMPLEMENTATION_GUIDANCE | EVIDENCE
|
||
family: # Organisationshilfe (z.B. sbom, vulnerability_handling)
|
||
applicability: # universal | conditional:<pred> | domain:<x>
|
||
facets: # welche Evidenz-Facetten die Pflicht belegt
|
||
governance: bool
|
||
capability: bool
|
||
evidence: bool
|
||
legal_basis: # PRIMÄRRECHT — Pflicht zwingend (mind. 1 Anker für LEGAL_MINIMUM)
|
||
- source: CRA
|
||
regulation_code: eu_2024_2847
|
||
article: "" # falls zutreffend
|
||
annex: "Annex I, Part II"
|
||
section: ""
|
||
paragraph: ""
|
||
span_id: "" # harter Anker in die zitierfähige Wissensbasis (Asset 2)
|
||
document_version: ""
|
||
citation: "" # menschenlesbar
|
||
guidance_basis: # SEKUNDÄR — Umsetzung/Best Practice, NICHT Pflicht
|
||
- source: NIST SSDF
|
||
anchor: ""
|
||
role: best_practice # implementation_guidance | best_practice
|
||
member_controls: # control_uuids (Prüflogik aus Asset 1)
|
||
citation_anchor_ids: # span/paragraph-Anker (Asset 2) — auf der OBLIGATION, NICHT auf Controls
|
||
relationships: # siehe Beziehungsgraph
|
||
decision_method: # CONTENT/LLM | CONTENT/EMBEDDING | FIELD/REGEX | BEHAVIOR/PLAYWRIGHT ...
|
||
out_of_scope: [] # ausgeschlossene Cluster + Begründung
|
||
```
|
||
|
||
## Zitierfähigkeit hängt an der OBLIGATION (nicht an Controls)
|
||
|
||
258 SBOM-Controls → 11 Obligations: nur die **Obligation** speichert
|
||
`CRA / Annex I / Paragraph X / chunk_id / span_id / document_version`. Die 258 Controls zeigen
|
||
nur auf die `obligation_id`. Folge: **Regulierungsänderung (CRA v1→v2) = `citation_anchor`
|
||
tauschen, Controls bleiben identisch.** Massive Pflegeersparnis + Versionsstabilität.
|
||
|
||
## `legal_basis` vs `guidance_basis` + `source_role`
|
||
|
||
Damit beim Verschmelzen von CRA + NIST + OWASP zu einer Obligation NICHT verloren geht, was
|
||
Pflicht / Best Practice / Evidenz / Umsetzung ist, klassifiziert die Discovery-Pipeline jeden
|
||
Member/Cluster mit einer **`source_role`**:
|
||
|
||
```
|
||
LEGAL_BASIS → Primärrecht (begründet die Pflicht)
|
||
GUIDANCE → NIST/OWASP/ENISA/BSI/ISO (Umsetzung/Best Practice)
|
||
EVIDENCE → Nachweis/Bericht/Audit
|
||
IMPLEMENTATION → technische Umsetzungsanweisung
|
||
OUT_OF_SCOPE → gehört nicht zur Obligation (andere Regulierung/Domäne)
|
||
```
|
||
|
||
## HARTE Tier-Regel
|
||
|
||
Eine Obligation wird **`LEGAL_MINIMUM` nur mit mindestens einem Primärrechts-Anker**
|
||
(`legal_basis` nicht leer). Ohne Primärrechts-Anker:
|
||
`BEST_PRACTICE | IMPLEMENTATION_GUIDANCE | EVIDENCE` — **aber niemals Pflicht.**
|
||
|
||
## Beziehungsgraph (Ontologie)
|
||
|
||
**Strukturell** (bereits in der Pipeline): `same_obligation`, `sub_obligation`,
|
||
`applicability_variant`, `evidence_for`, `governance_for`, `out_of_scope`.
|
||
|
||
**Semantisch (NEU, P2-Ergänzung):** `requires`, `implements`, `supports`,
|
||
`produces_evidence_for`, `depends_on`, `derived_from`. Beispiele:
|
||
```
|
||
sbom_established --supports--> vulnerability_handling --supports--> incident_reporting
|
||
authentication --requires--> credential_management
|
||
```
|
||
→ für den Compliance Advisor extrem wertvoll (er kann Pflicht-Ketten erklären).
|
||
|
||
## Citation-Anchor-Pipeline (Document → Obligation, NICHT Document → Control)
|
||
|
||
Der neue Ingest erzeugt zusätzlich zu Chunk/Embedding: `paragraph_uuid`, `span_uuid`,
|
||
`document_version`, `legal_citation`, `referenced_articles`, `referenced_regulations`.
|
||
**Erst danach** läuft Obligation Discovery, sodass jede neu entdeckte Obligation sofort ihre
|
||
Primärquelle bekommt:
|
||
```
|
||
Neue Dokumente → Chunking → Span IDs → LLM („welche Obligation(en)?") → Confidence
|
||
→ Review → obligation.citation_anchor_ids[]
|
||
```
|
||
Die alten Controls werden wiederverwendet; die Pipeline erzeugt zusätzlich Obligation→Evidence
|
||
und Obligation→Citation-Anchors. **Kein Re-Ingest zum Neubau von Controls.**
|
||
|
||
## Sequenz (geändert — Registry vor weiteren Cuts)
|
||
|
||
```
|
||
SBOM ✓ → Vuln ✓ → Registry v1 (DIESE Spec) → Ontologie/Beziehungsgraph ergänzen
|
||
→ Authentication → Remote Access → Logging → Updates
|
||
```
|
||
Begründung: Schema jetzt billig änderbar; bei 300–1000 Obligations wird jede Schemaänderung
|
||
teuer. Fortschritt wird daran gemessen, ob jede neue Obligation die Registry besser macht —
|
||
nicht an neuen Controls.
|
||
|
||
## Scope-Audit (Review-Step, PFLICHT je Cut)
|
||
|
||
Die Registry modelliert **Hersteller-Pflichten**. Bestimmungen, die an Behörden / notifizierte
|
||
Stellen / Mitgliedstaaten adressiert sind (Sanktionen, Marktüberwachung, Anforderungen an
|
||
Konformitätsbewertungsstellen), sind Enforcement-/Institutions-Recht. **Prinzip: Adressat der Norm
|
||
⊥ Handlungspflicht des Herstellers.** `scope`-Attribut-Achse (Enum, KEINE neue Objektklasse):
|
||
|
||
- `in_scope` — Norm adressiert direkt den Hersteller (Default).
|
||
- `out_of_scope` — reines Staats-/Durchsetzungs-/Institutions-Recht (Adressat ≠ Hersteller, KEINE
|
||
mittelbare Herstellerpflicht). Aus `obligation_join_keys.json` gefiltert. Präzedenz CSIRT/ENISA.
|
||
- `derived_obligation` — Norm adressiert primär eine andere Rolle, erzeugt aber MITTELBAR eine
|
||
Hersteller-Handlungspflicht → **bleibt im Set** (`scope_split_candidate` markiert spätere
|
||
Aufspaltung Normadressat ↔ abgeleitete Pflicht; nicht vorzeitig festziehen).
|
||
|
||
**Gate-Regel:**
|
||
```
|
||
Jeder neue Obligation-Cut muss durch Scope-Audit laufen.
|
||
Findings mit authority-/institution-addressed obligations werden dokumentiert.
|
||
Automatische Reclassification ist verboten, solange kein explizites Review-Go vorliegt.
|
||
```
|
||
|
||
**Werkzeug-Trennung (FLAG ⊥ MUTATE):**
|
||
- `scope_audit.py` — **flaggt nur** (scannt alle Registries → `scope_audit_findings.json`; mutiert nie).
|
||
- `validate_registry.py` — surfaced pro Cut unklassifizierte authority-/institution-Obligations als
|
||
**non-fatal Warnung** (blockt nicht, mutiert nicht).
|
||
- `apply_scope_classification.py` — **mutiert** (setzt `scope`), läuft NUR nach explizitem Review-Go
|
||
(ändert `join_keys` + Compliance-Execution-Sync → menschlich/koordiniert).
|
||
|
||
## Weg 1 — Obligation→Norm-Zitierfähigkeit (Datenbereitschaft; UI deferred)
|
||
|
||
**Zwei Zitierebenen — NICHT verwechseln (beide langfristig nötig):**
|
||
- **RAG-Evidence-Zitat** (heute im Advisor sichtbar): `Frage/Antwort → Evidence-Chunk`
|
||
(KB-v2 `article_label`/`source_url`, `[n]`-Citations). Quelle = Compliance/KB-Session `/retrieve`.
|
||
- **Obligation→Norm-Zitat** (der `norm_id`-Join): `Pflicht → konkrete Rechtsgrundlage` (KB-v2-Unit).
|
||
Quelle = diese Registry. **Weg 1** = dieses Zitat sichtbar machen.
|
||
|
||
**Datenbereitschaft (Stand 2026-07-01):**
|
||
|
||
| Baustein | Status |
|
||
|---|---|
|
||
| `obligations/*.json` → `legal_basis.norm_ids` | ✅ 62/64 joinbar (53 annex + 16 article, KB-v2-verifiziert) |
|
||
| KB-v2-Join-Ziele (CRA Art1-71 · MaschVO Art1-54 · Annexe) | ✅ bestätigt |
|
||
| `obligation-status`-Endpoint + Traversal (`obligation_id→citation_unit→Controls→Evidence`) | ✅ vorhanden; exponiert `LegalBasis = citation_units` |
|
||
| Runtime-Vertrag `obligation_join_keys.json` trägt `norm_ids` | ❌ nur `citation_units` (Anker-Strings), KEINE `norm_ids` |
|
||
| Go `ObligationKey`-Struct / `CitationSpans` | ❌ kein `NormIDs`-Feld; `AssessObligationStatus` setzt `CitationSpans:"pending"` hart (compliance_status.go) |
|
||
|
||
**Deferred-Sequenz (UI zuletzt) — bewusst NICHT gebaut:**
|
||
1. **Data-Prep** (nicht-UI, Domäne 2): `norm_ids` in `export_join_keys.py` → `obligation_join_keys.json` exportieren.
|
||
2. **Build** (ai-sdk, koordiniert): `NormIDs` in `ObligationKey`; `AssessObligationStatus` füllt `CitationSpans` aus `norm_ids` statt `"pending"`.
|
||
3. **UI** (später): „Diese Pflicht beruht auf **CRA Anhang I / Art. 13**".
|
||
|
||
**Design-Vorgabe für Phase B (Runtime-Vertrag): generische Legal-Reference-Hülle statt flachem
|
||
`norm_ids`.** `norm_ids` sind nur die ERSTE Rechtsreferenz-Art. Damit der Runtime-Vertrag
|
||
(`obligation_join_keys.json` + Go `ObligationKey`) bei neuen Referenz-Arten NICHT erneut geändert
|
||
werden muss, trägt jeder Eintrag eine **erweiterbare Hülle** (optionale Keys, additiv):
|
||
```json
|
||
"legal_reference": { // Hülle — NICHT "legal_basis" (kollidiert mit dem Obligation-Array)
|
||
"norm_ids": [...], // bindendes Primärrecht (Artikel/Anhang) ← Phase B baut nur DAS
|
||
"citation_units": [...], // menschliche Anker-Strings (Interim-Brücke)
|
||
"recital_ids": [...], // Erwägungsgründe (später, additiv)
|
||
"guidance_ids": [...], // Leitlinien EDPB/DSK (später, additiv)
|
||
"case_law_ids": [...], // Gerichtsurteile (später, additiv)
|
||
"interpretation_ids": [...] // Interpretationshilfen (später, additiv)
|
||
}
|
||
```
|
||
Prinzip: neue Referenz-**Art** = neuer optionaler Key in der Hülle → Vertrag/Go-Struct bleiben
|
||
stabil (wie die `scope`-Achse: erweitern über Attribute, nicht über Strukturumbau). **Bindend ⊥
|
||
Guidance-Trennung bleibt erhalten** (`norm_ids`/`case_law` = bindend · `guidance_ids` = Soft-Law) —
|
||
konsistent mit `legal_basis` ⊥ `guidance_basis` und dem Authority-Router. In Phase B wird NUR
|
||
`norm_ids` befüllt; die übrigen Keys sind reservierter Platz, kein Bauauftrag.
|