feat(reasoning): Regulatory Reasoning Engine MVP (scope/obligations/implementation/interpretation)

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>
This commit is contained in:
Benjamin Admin
2026-06-25 19:30:53 +02:00
parent e46e74ddbb
commit 1607c89459
20 changed files with 2270 additions and 0 deletions
@@ -0,0 +1,91 @@
"""Obligation overlap groups (spec §4.5 / Modus 2).
Overlaps are emitted only for the members that are actually applicable to the
product. `canonical_obligation_id` points at the strongest / most specific
obligation in the group (preferring a registry-anchored CRA id).
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import List
from .enums import OverlapType
@dataclass(frozen=True)
class OverlapGroup:
overlap_group_id: str
members: List[str]
overlap_type: OverlapType
canonical_obligation_id: str
explanation: str
OVERLAP_GROUPS: List[OverlapGroup] = [
OverlapGroup(
overlap_group_id="VULNERABILITY_HANDLING",
members=[
"vuln_handling_process",
"coordinated_vulnerability_disclosure",
"machine_protection_against_corruption",
],
overlap_type=OverlapType.COMPLEMENTARY,
canonical_obligation_id="vuln_handling_process",
explanation=(
"CRA adressiert die Schwachstellenbehandlung des Produkts. Die MaschinenVO wird "
"komplementär relevant, sobald eine Cyber-Schwachstelle eine Sicherheitsfunktion "
"beeinflussen kann (Anhang III 1.1.9). Nicht identisch, aber gemeinsam zu erfüllen."
),
),
OverlapGroup(
overlap_group_id="SECURITY_UPDATES",
members=["provide_security_updates", "signed_update_integrity"],
overlap_type=OverlapType.COMPLEMENTARY,
canonical_obligation_id="provide_security_updates",
explanation=(
"Updates bereitstellen und ihre Integrität sichern sind zwei Seiten desselben "
"Update-Prozesses; ein Nachweis (Update-Policy, Release Notes) deckt teils beide ab."
),
),
OverlapGroup(
overlap_group_id="RISK_ASSESSMENT",
members=["cra_risk_assessment", "machine_risk_assessment"],
overlap_type=OverlapType.DIFFERENT_SCOPE,
canonical_obligation_id="cra_risk_assessment",
explanation=(
"Zwei getrennte Risikobetrachtungen: CRA = Cybersicherheits-Risiko, MaschinenVO = "
"Sicherheits-/Gefährdungsbeurteilung. Methodisch verwandt, inhaltlich unterschiedlich."
),
),
OverlapGroup(
overlap_group_id="TECHNICAL_DOCUMENTATION",
members=["cra_technical_documentation", "machine_risk_assessment"],
overlap_type=OverlapType.SIMILAR,
canonical_obligation_id="cra_technical_documentation",
explanation=(
"Beide Regime verlangen eine technische Dokumentation; Teile (Risikobetrachtung, "
"Konstruktionsunterlagen) lassen sich in einem konsolidierten technischen Dossier führen."
),
),
OverlapGroup(
overlap_group_id="CE_CONFORMITY",
members=["cra_ce_conformity_assessment", "machine_ce_conformity"],
overlap_type=OverlapType.COMPLEMENTARY,
canonical_obligation_id="machine_ce_conformity",
explanation=(
"Ein Produkt kann zwei CE-Regime gleichzeitig erfüllen müssen (MaschinenVO + CRA). "
"Eine gemeinsame CE-Kennzeichnung, aber getrennte Konformitätsbewertungen."
),
),
OverlapGroup(
overlap_group_id="INSTRUCTIONS_FOR_USE",
members=["cra_instructions_for_use", "machine_instructions_for_use"],
overlap_type=OverlapType.SIMILAR,
canonical_obligation_id="machine_instructions_for_use",
explanation=(
"Betriebsanleitung (MaschinenVO) und Sicherheitsinformationen (CRA) überschneiden sich; "
"ein integriertes Anleitungsdokument kann beide Pflichten bedienen."
),
),
]