"""Cross-Regulation Capability Mapping (Regulatory Convergence) — RS-005. Answers the USP question: „Welche Capability deckt gleichzeitig mehrere Regelwerke ab?" Given, per capability, the set of target regulations it covers (`covers_targets`, curated knowledge from a Regulatory Convergence Pattern), it computes how many capabilities cover >= 2 regulations at once — the basis for the customer sentence „von N Maßnahmen decken M gleichzeitig CRA und MaschinenVO". Pure, deterministic, computed-not-stored. No new graph/base class/meta-model class (freeze v1.0 untouched). Python 3.9 compatible (no `|` unions). """ from __future__ import annotations from typing import Dict, List from pydantic import BaseModel, Field class RegulatoryConvergence(BaseModel): targets: List[str] = Field(default_factory=list) per_target_count: Dict[str, int] = Field(default_factory=dict) # capabilities each target requires multi_target_capabilities: List[str] = Field(default_factory=list) # cover >= 2 targets single_target_capabilities: List[str] = Field(default_factory=list) headline: str = "" # NO percentages def regulatory_convergence( capability_targets: Dict[str, List[str]], targets: List[str] ) -> RegulatoryConvergence: """capability_targets: capability_id -> regulations it covers. `targets`: the regulations in scope.""" target_set = set(targets) per: Dict[str, int] = {t: 0 for t in targets} multi: List[str] = [] single: List[str] = [] for cap, covers in capability_targets.items(): in_scope = [t for t in covers if t in target_set] for t in in_scope: per[t] += 1 if len(in_scope) >= 2: multi.append(cap) elif len(in_scope) == 1: single.append(cap) headline = ( "%d von %d Capabilities decken >= 2 Regelwerke gleichzeitig ab (%s)." % (len(multi), len(capability_targets), " + ".join(targets)) ) return RegulatoryConvergence( targets=list(targets), per_target_count=per, multi_target_capabilities=sorted(multi), single_target_capabilities=sorted(single), headline=headline, )