"""Read-model for the Regulatory Map (step 4). A customer-readable view that COMPOSES what the engine already computed (scope + obligations + overlaps). It adds no scope/obligation logic. All fields are application-level presentation types — NOT compliance-meta-model classes (architecture freeze v1.0 untouched). """ from __future__ import annotations from typing import Dict, List from pydantic import BaseModel, Field from compliance.product_scope.schemas import UnsupportedDomain from compliance.profile.canonical import CanonicalProductRegulatoryProfile from compliance.reasoning.enums import AuthorityLevel, Confidence class RegulatoryMapRequest(BaseModel): product_profile: CanonicalProductRegulatoryProfile class ObligationRef(BaseModel): obligation_id: str title: str legal_basis_refs: List[str] = Field(default_factory=list) authority_level: AuthorityLevel class ApplicableRegulationView(BaseModel): regulation_id: str name: str why_applicable: str triggered_by: List[str] = Field(default_factory=list) obligations: List[ObligationRef] = Field(default_factory=list) obligations_note: str = "" # set when obligations are not yet registry-linkable confidence: Confidence class UncertainRegulationView(BaseModel): regulation_id: str name: str missing_facts: List[str] = Field(default_factory=list) question_refs: List[str] = Field(default_factory=list) class ExcludedRegulationView(BaseModel): regulation_id: str name: str exclusion_reason: str class OverlapView(BaseModel): overlap_group_id: str shared_obligations: List[str] = Field(default_factory=list) explanation: str = "" class RegulatoryMap(BaseModel): scope_resolved: bool product_summary: str trigger_facts: List[str] = Field(default_factory=list) applicable_regulations: List[ApplicableRegulationView] = Field(default_factory=list) uncertain_regulations: List[UncertainRegulationView] = Field(default_factory=list) excluded_regulations: List[ExcludedRegulationView] = Field(default_factory=list) unsupported_domains: List[UnsupportedDomain] = Field(default_factory=list) overlaps: List[OverlapView] = Field(default_factory=list) shared_evidence: Dict[str, List[str]] = Field(default_factory=dict) executive_summary: str = ""