"""Regulatory Change Intelligence (RCI) — domain objects. RCI is a read-/reasoning layer ON TOP of the product-first pipeline. It answers "what changes relative to my existing Regulatory Map?" — NOT "what does the new law say in general". A RegulatoryChange is simulated/provided INPUT (no ingestion, no newsletter/mailbox, no RAG); the delta is computed against a stored ComplianceBaseline (snapshot of the map). `delta_type` is a THIRD vocabulary — distinct from `ClaimCoverage` (Welt 1, what the customer claims) and `ComplianceStatus` (Welt 2, verified evidence). The three must never be conflated. These are application/reasoning types, NOT compliance-meta-model classes (architecture freeze v1.0 untouched). """ from __future__ import annotations from enum import Enum from typing import Dict, List, Optional from pydantic import BaseModel, Field from compliance.profile.canonical import CanonicalProductRegulatoryProfile from compliance.reasoning.enums import AuthorityLevel, Confidence from compliance.regulatory_map.schemas import RegulatoryMap class DeltaType(str, Enum): NEW = "new" # obligation now applies that was not in the baseline CHANGED = "changed" # existing obligation substantively modified REMOVED = "removed" # obligation no longer applies (repeal) ALREADY_COVERED = "already_covered" # existing obligation, evidence likely suffices NEEDS_REVIEW = "needs_review" # a human must check NOT_APPLICABLE = "not_applicable" # change does not touch this product's map class ChangeType(str, Enum): NEW_REGULATION = "new_regulation" AMENDMENT = "amendment" REPEAL = "repeal" GUIDANCE_UPDATE = "guidance_update" # ── stored snapshot ────────────────────────────────────────────────────── class ComplianceBaseline(BaseModel): baseline_id: str product_profile_snapshot: CanonicalProductRegulatoryProfile regulatory_map_snapshot: RegulatoryMap applicable_obligations: List[str] = Field(default_factory=list) # registry-linked obligation_ids # required evidence per obligation (derived) — to compute missing_evidence obligation_evidence_required: Dict[str, List[str]] = Field(default_factory=dict) # evidence the customer ALREADY has, per obligation (provided) evidence_refs: Dict[str, List[str]] = Field(default_factory=dict) created_at: Optional[str] = None # ── simulated/provided change (INPUT — never ingested) ─────────────────── class RegulatoryChange(BaseModel): change_id: str source: str = "simulated" affected_regulations: List[str] = Field(default_factory=list) affected_obligations: List[str] = Field(default_factory=list) change_type: ChangeType effective_date: Optional[str] = None authority_level: AuthorityLevel = AuthorityLevel.LEGAL_TEXT summary: str = "" # ── per-obligation delta ───────────────────────────────────────────────── class ObligationDelta(BaseModel): obligation_id: str delta_type: DeltaType reason: str affected_evidence: List[str] = Field(default_factory=list) # evidence already present for it missing_evidence: List[str] = Field(default_factory=list) # required but not yet present confidence: Confidence # ── management-level summary ────────────────────────────────────────────── class ChangeImpactSummary(BaseModel): what_changed: str = "" what_matters_for_this_product: List[str] = Field(default_factory=list) # need action already_covered: List[str] = Field(default_factory=list) needs_review: List[str] = Field(default_factory=list) not_relevant: List[str] = Field(default_factory=list) unsupported_domains: List[str] = Field(default_factory=list) class ChangeAssessment(BaseModel): change_id: str affects_product: bool deltas: List[ObligationDelta] = Field(default_factory=list) summary: ChangeImpactSummary