4027470855
#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>
46 lines
2.1 KiB
Python
46 lines
2.1 KiB
Python
"""Stufe 4 — Validierung: belastbare Registry-Checks (kein LLM/Key).
|
|
Prüft die User-Regeln: LEGAL_MINIMUM braucht legal_basis · member_controls vollständig ·
|
|
out_of_scope separat · >8-Obligations/Review-Unit-Warnung. Exit-Code 1 bei hartem Fehler.
|
|
|
|
python3 scripts/obligation_discovery/validate_registry.py obligations/cra_authentication.json
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
|
|
from _core import validate_registry
|
|
from scope_audit import NON_MANUFACTURER_DOMAINS
|
|
|
|
|
|
def main() -> None:
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("registry")
|
|
a = ap.parse_args()
|
|
reg = json.load(open(a.registry, encoding="utf-8"))
|
|
v = validate_registry(reg)
|
|
print(f"=== validate {a.registry} ===")
|
|
print(f" obligations: {v['obligations']}")
|
|
print(f" LEGAL_MINIMUM: {v['legal_minimum']}")
|
|
print(f" LM ohne legal_basis: {v['lm_without_legal_basis'] or 'keine'}")
|
|
print(f" member_controls leer: {v['empty_member_controls'] or 'keine'}")
|
|
print(f" >8 Obligations/Review-Unit: {v['over8_per_review_unit'] or 'keine'}")
|
|
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)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|