1607c89459
Deterministic reasoning layer ON TOP of the Legal Knowledge Graph (obligation
registry) and the Compliance Execution Graph (control mapping/evidence). Answers
which regulations apply to a concrete product, which obligations follow, whether
the customer's implementation covers them, and whether a customer interpretation
is too narrow/broad/plausible.
- ProductProfile with tri-state facts (Optional[bool]=None => uncertain, never
false security); safe predicate evaluator (no eval).
- 6 regulation triggers (CRA/MaschinenVO/RED/EMV/DataAct/NIS2) with missing-fact
prompts; 24 obligation scope rules.
- CRA obligation_ids RE-USED verbatim from the registry (93 ids) — never re-minted
(control_uuid trap); Machine/Data-Act flagged proposed=True.
- required_evidence constrained to the framework-agnostic shared evidence catalog;
capabilities echo the planned Obligation->Capability layer.
- Overlap groups (CRA<->MaschinenVO cyber-safety) + evidence-for-multiple (USP).
- 4 endpoints POST /reasoning/{scope,obligations,implementation-assessment,
interpretation-assessment}; thin handlers, registered in api/__init__.py.
- 22 tests (5 machine-builder scenarios + 10 acceptance questions). No DB
migration, no RAG, no new controls.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
161 lines
6.7 KiB
Python
161 lines
6.7 KiB
Python
"""Regulation-level applicability trigger rules (scope discovery, spec Modus 1).
|
|
|
|
Each rule is pure data consumed by `scope_engine`. Triggers reference
|
|
`ProductProfile` fields through the safe predicate evaluator. `required_facts`
|
|
that are unknown turn the verdict *uncertain* and surface `fact_prompts`.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Dict, List, Optional
|
|
|
|
from .enums import Confidence
|
|
from .predicates import Condition
|
|
|
|
# Positive, human-readable label per profile fact (for trigger_facts output).
|
|
FIELD_LABELS: Dict[str, str] = {
|
|
"has_software": "Produkt enthält Software / digitale Elemente",
|
|
"has_embedded_software": "Produkt enthält eingebettete Software",
|
|
"has_remote_access": "Produkt besitzt Fernzugriff / Fernwartung",
|
|
"has_cloud_connection": "Produkt ist mit einer Cloud verbunden",
|
|
"has_radio_module": "Produkt enthält ein Funkmodul",
|
|
"has_safety_function": "Produkt erfüllt eine Sicherheitsfunktion",
|
|
"generates_usage_data": "Vernetztes Produkt erzeugt nutzbare Produktdaten",
|
|
"is_machine": "Produkt ist eine Maschine",
|
|
"is_component": "Produkt ist ein (Sicherheits-)Bauteil",
|
|
"eu_market": "Produkt wird auf dem EU-Markt bereitgestellt",
|
|
"is_essential_or_important_entity": "Unternehmen ist wesentliche/wichtige Einrichtung",
|
|
"manufacturer_role": "Wirtschaftsakteur-Rolle (Hersteller/Importeur/Händler)",
|
|
}
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class RegulationRule:
|
|
regulation_id: str
|
|
name: str
|
|
trigger: Condition
|
|
required_facts: List[str]
|
|
fact_prompts: Dict[str, str]
|
|
legal_basis_refs: List[str]
|
|
summary: str
|
|
confidence_when_applicable: Confidence = Confidence.HIGH
|
|
exclusion: Optional[Condition] = None
|
|
# Status is downgraded to PARTIALLY_APPLICABLE / MEDIUM when the trigger
|
|
# fires only via inference rather than a directly stated fact.
|
|
inferred: bool = False
|
|
excludable_roles: List[str] = field(default_factory=list)
|
|
|
|
|
|
_ECONOMIC_ROLES = ["manufacturer", "importer", "distributor"]
|
|
|
|
REGULATION_RULES: List[RegulationRule] = [
|
|
RegulationRule(
|
|
regulation_id="CRA",
|
|
name="Cyber Resilience Act (EU) 2024/2847",
|
|
trigger={
|
|
"all": [
|
|
{"any": [("has_software", "eq", True), ("has_embedded_software", "eq", True)]},
|
|
("eu_market", "eq", True),
|
|
]
|
|
},
|
|
required_facts=["has_software", "eu_market", "manufacturer_role"],
|
|
fact_prompts={
|
|
"has_software": "Enthält das Produkt Software / digitale Elemente?",
|
|
"eu_market": "Wird das Produkt auf dem EU-Markt bereitgestellt oder in Verkehr gebracht?",
|
|
"manufacturer_role": "Welche Rolle nehmen Sie ein (Hersteller / Importeur / Händler)?",
|
|
},
|
|
legal_basis_refs=["CRA Art. 2(1)", "CRA Art. 3(1)"],
|
|
summary="Produkte mit digitalen Elementen, die auf dem EU-Markt bereitgestellt werden.",
|
|
confidence_when_applicable=Confidence.HIGH,
|
|
excludable_roles=["operator"],
|
|
),
|
|
RegulationRule(
|
|
regulation_id="MaschinenVO",
|
|
name="Maschinenverordnung (EU) 2023/1230",
|
|
trigger={
|
|
"any": [
|
|
("is_machine", "eq", True),
|
|
{"all": [("is_component", "eq", True), ("has_safety_function", "eq", True)]},
|
|
]
|
|
},
|
|
required_facts=["is_machine", "eu_market"],
|
|
fact_prompts={
|
|
"is_machine": "Ist das Produkt eine Maschine oder ein Sicherheitsbauteil?",
|
|
"has_safety_function": "Erfüllt das Bauteil eine Sicherheitsfunktion?",
|
|
},
|
|
legal_basis_refs=["MaschinenVO (EU) 2023/1230 Art. 2", "Anhang III"],
|
|
summary="Maschinen oder Sicherheitsbauteile, ggf. mit sicherheitsrelevanter Steuerung.",
|
|
confidence_when_applicable=Confidence.MEDIUM,
|
|
),
|
|
RegulationRule(
|
|
regulation_id="RED",
|
|
name="Radio Equipment Directive 2014/53/EU",
|
|
trigger=("has_radio_module", "eq", True),
|
|
required_facts=["has_radio_module"],
|
|
fact_prompts={
|
|
"has_radio_module": "Besitzt das Produkt ein Funkmodul (WLAN, Bluetooth, Mobilfunk)?",
|
|
},
|
|
legal_basis_refs=["RED 2014/53/EU Art. 1", "Art. 3(3)(d-f)"],
|
|
summary="Funkanlagen; Art. 3(3) deckt zusätzlich Cybersecurity-Anforderungen ab.",
|
|
confidence_when_applicable=Confidence.HIGH,
|
|
),
|
|
RegulationRule(
|
|
regulation_id="EMV",
|
|
name="EMV-Richtlinie 2014/30/EU",
|
|
trigger={
|
|
"any": [
|
|
("has_software", "eq", True),
|
|
("has_embedded_software", "eq", True),
|
|
("has_radio_module", "eq", True),
|
|
]
|
|
},
|
|
required_facts=[],
|
|
fact_prompts={
|
|
"is_electrical": "Ist das Produkt ein elektrisches / elektronisches Betriebsmittel?",
|
|
},
|
|
legal_basis_refs=["EMV-RL 2014/30/EU Art. 2"],
|
|
summary="Elektrische/elektronische Betriebsmittel (hier aus den digitalen Elementen abgeleitet).",
|
|
confidence_when_applicable=Confidence.MEDIUM,
|
|
inferred=True,
|
|
),
|
|
RegulationRule(
|
|
regulation_id="DataAct",
|
|
name="Data Act (EU) 2023/2854",
|
|
trigger={
|
|
"all": [
|
|
{"any": [("has_cloud_connection", "eq", True), ("has_remote_access", "eq", True)]},
|
|
("generates_usage_data", "eq", True),
|
|
]
|
|
},
|
|
required_facts=["generates_usage_data"],
|
|
fact_prompts={
|
|
"generates_usage_data": "Erzeugt das vernetzte Produkt nutzbare Produkt-/Nutzungsdaten?",
|
|
},
|
|
legal_basis_refs=["Data Act (EU) 2023/2854 Art. 2(5)", "Art. 3-5"],
|
|
summary="Vernetzte Produkte, die Nutzungsdaten erzeugen und zugänglich machen.",
|
|
confidence_when_applicable=Confidence.HIGH,
|
|
),
|
|
RegulationRule(
|
|
regulation_id="NIS2",
|
|
name="NIS2-Richtlinie (EU) 2022/2555",
|
|
trigger=("is_essential_or_important_entity", "eq", True),
|
|
required_facts=["company_size", "sector", "is_essential_or_important_entity"],
|
|
fact_prompts={
|
|
"company_size": "Unternehmensgröße (Mitarbeiterzahl / Umsatz)?",
|
|
"sector": "In welchem Sektor ist das Unternehmen tätig (Anhang I/II)?",
|
|
"is_essential_or_important_entity": "Fällt das Unternehmen als wesentliche/wichtige Einrichtung unter NIS2?",
|
|
},
|
|
legal_basis_refs=["NIS2-RL (EU) 2022/2555 Art. 2", "Art. 3"],
|
|
summary="Adressiert die ORGANISATION (Größe/Sektor/Rolle), nicht das Produkt.",
|
|
confidence_when_applicable=Confidence.MEDIUM,
|
|
),
|
|
]
|
|
|
|
|
|
def regulation_rule(regulation_id: str) -> Optional[RegulationRule]:
|
|
for rule in REGULATION_RULES:
|
|
if rule.regulation_id == regulation_id:
|
|
return rule
|
|
return None
|