Files
breakpilot-compliance/scripts/obligation_discovery/apply_scope_classification.py
T
Benjamin Admin 6523286af6 feat(registry-quality): scope-Achse — 2 out_of_scope + derived_obligation (User Option 2)
User-Entscheidung 2026-07-01 zum Scope-Audit: Adressat der Norm != Handlungspflicht des
Herstellers. Neue `scope`-Attribut-Achse (Enum, KEINE neue Objektklasse -> Freeze v1.0
unberuehrt): in_scope (default) / out_of_scope / derived_obligation.

- sanctions + market_surveillance_safeguard -> out_of_scope (reine Staats-/Durchsetzungs-
  bestimmungen; Praezedenz CSIRT/ENISA im CRA-Vuln-Cut). Aus join_keys gefiltert.
- notified_body_requirements -> derived_obligation (Norm adressiert primaer die notifizierte
  Stelle, erzeugt aber mittelbare Herstellerpflichten: NB einbeziehen + Unterlagen +
  Konformitaetsbewertung) + scope_split_candidate (spaetere Aufspaltung Normadressat <->
  abgeleitete Herstellerpflicht). BLEIBT im Set (Prinzip: Wissen nicht zu frueh verwerfen).
- export_join_keys.py filtert scope==out_of_scope + fuehrt scope je Eintrag -> join_keys
  126->124 (MaschVO 31->29; 123 in_scope + 1 derived_obligation).
- scope_audit.py jetzt 3-Wege-klassifikations-bewusst (0 unklassifizierte Reste) +
  apply_scope_classification.py (deterministisch). Fuer jeden kuenftigen Cut mitlaufen.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-01 13:22:38 +02:00

54 lines
2.5 KiB
Python

"""Scope-Klassifikation anwenden (User-Entscheidung 2026-07-01, Option 2 + derived_obligation).
Neue `scope`-Attribut-Achse (KEINE neue Objektklasse — Enum-Wert, freeze-safe):
in_scope (default/implizit) · out_of_scope · derived_obligation
Prinzip (User): Adressat der Norm ⊥ Handlungspflicht des Herstellers. Reine Staats-/
Durchsetzungs-/Institutions-Bestimmungen = out_of_scope. Norm, die primär eine andere Rolle
adressiert ABER mittelbar eine Hersteller-Handlungspflicht erzeugt = derived_obligation
(bleibt im Hersteller-Set, wird NICHT verworfen — 'im Zweifel nicht zu früh Wissen verwerfen').
"""
from __future__ import annotations
import glob
import json
SCOPE = {
"sanctions": {
"scope": "out_of_scope",
"scope_reason": "Adressat = Mitgliedstaaten (legen Sanktionen fest); keine Hersteller-Handlungspflicht. Präzedenz CSIRT/ENISA (CRA-Vuln-Cut).",
},
"market_surveillance_safeguard": {
"scope": "out_of_scope",
"scope_reason": "Adressat = Marktüberwachungsbehörden/Kommission (Schutzmaßnahmen, Schutzklauselverfahren); keine Hersteller-Handlungspflicht. Präzedenz CSIRT/ENISA.",
},
"notified_body_requirements": {
"scope": "derived_obligation",
"scope_reason": "Norm adressiert primär die notifizierte Stelle (Unabhängigkeit/Kompetenz/Unparteilichkeit), erzeugt aber mittelbare Hersteller-Pflichten: notifizierte Stelle einbeziehen, erforderliche Unterlagen bereitstellen, Konformitätsbewertung korrekt durchführen.",
"scope_split_candidate": True,
"scope_split_note": "Kandidat für spätere Aufspaltung: 'Normadressat' (Anforderungen AN die notifizierte Stelle = institutional/out_of_scope) ↔ 'abgeleitete Herstellerpflicht' (NB einbeziehen + Unterlagen + Konformitätsbewertung = in_scope). NICHT vorzeitig festziehen.",
},
}
def main() -> None:
applied = []
for f in sorted(glob.glob("obligations/cra*.json")):
d = json.load(open(f, encoding="utf-8"))
changed = False
for o in d.get("obligations", []):
spec = SCOPE.get(o.get("id"))
if spec:
o.update(spec)
applied.append((o["id"], spec["scope"]))
changed = True
if changed:
json.dump(d, open(f, "w", encoding="utf-8"), ensure_ascii=False, indent=1)
for oid, sc in applied:
print(f" {oid:32} scope={sc}")
print(f"angewendet: {len(applied)} (erwartet 3)")
if __name__ == "__main__":
main()