feat(pipeline): Scope-Audit als fester Review-Step (flag-only, non-blocking)
#3 (User): Scope-Audit in den Cut-Prozess aufnehmen — nicht-invasiv, nur flaggen, Reklassifizierung bleibt menschlich/koordiniert (betrifft join_keys + Compliance Execution). - validate_registry.py surfaced jetzt pro Cut authority-/institution-adressierte Obligations OHNE scope-Klassifikation als non-fatal Warnung (ändert Exit-Code NICHT, mutiert NICHT; importiert NON_MANUFACTURER_DOMAINS aus scope_audit.py, DRY). Verifiziert: clean-Fall (cra_machinery, 3 klassifiziert) still, Negativtest (sanctions ohne scope) feuert Warnung. - obligation_registry_v1.md: neuer Abschnitt "Scope-Audit (Review-Step, PFLICHT je Cut)" mit scope-Achse (in_scope/out_of_scope/derived_obligation), Gate-Regel verbatim und Werkzeug-Trennung FLAG (scope_audit.py) ⊥ MUTATE (apply_scope_classification.py, nur Review-Go). Gate: jeder neue Cut läuft durch Scope-Audit; Findings werden dokumentiert; automatische Reclassification verboten ohne explizites Review-Go. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -128,3 +128,31 @@ SBOM ✓ → Vuln ✓ → Registry v1 (DIESE Spec) → Ontologie/Beziehung
|
||||
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).
|
||||
|
||||
@@ -11,6 +11,7 @@ import json
|
||||
import sys
|
||||
|
||||
from _core import validate_registry
|
||||
from scope_audit import NON_MANUFACTURER_DOMAINS
|
||||
|
||||
|
||||
def main() -> None:
|
||||
@@ -28,6 +29,15 @@ def main() -> None:
|
||||
print(f" out_of_scope: {v['out_of_scope']}")
|
||||
print(f" semantische Kanten: {v['semantic_edges']}")
|
||||
print(f" PASSED: {v['passed']}")
|
||||
# Scope-Audit (Review-Step, FLAG-ONLY — mutiert nie, blockt nie, ändert Exit-Code nicht):
|
||||
unclassified = [o.get("id") or o.get("obligation_id") for o in reg.get("obligations", [])
|
||||
if (o.get("applicability") or "").strip() in NON_MANUFACTURER_DOMAINS and not o.get("scope")]
|
||||
if unclassified:
|
||||
print(f" ⚠ SCOPE-AUDIT: {len(unclassified)} authority-/institution-adressierte Obligation(s) OHNE scope:")
|
||||
print(f" {', '.join(str(x) for x in unclassified)}")
|
||||
print(" → Review-Pflicht: scope=out_of_scope|derived_obligation (apply_scope_classification.py, NUR mit Review-Go). Auto-Reclassification VERBOTEN.")
|
||||
else:
|
||||
print(" Scope-Audit: keine unklassifizierten authority-/institution-Obligations")
|
||||
sys.exit(0 if v["passed"] else 1)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user