"""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()