"""Consumption contract for the Certification -> Capability mapping. OWNERSHIP BOUNDARY (hard): the Capability Registry, CapabilityDefinition and the Certification->Capability / Feature->Capability mapping RULES live in the Compliance Execution domain. This Reasoning layer defines ONLY the shape it consumes and never ships mapping DATA in product code — tests inject mocks, so the real table can only ever live in Execution. Execution will eventually provide CapabilityRegistry / CapabilityMapping / CapabilityDefinition; Reasoning consumes exactly `OperationalCapabilityCandidate` {capability_id, source, confidence, verification_status} (see schemas.py) and the minimal mapping SHAPE below — nothing more. Python 3.9 compatible (no `|` unions). """ from __future__ import annotations from typing import Dict, List from pydantic import BaseModel, Field from compliance.reasoning.enums import Confidence class CapabilityMappingEntry(BaseModel): """One mapping rule SHAPE: a certification implies candidate capabilities. Contract type only. The actual table (which capabilities ISO27001 implies) is Execution's DATA and MUST NOT be hard-coded here or anywhere in product code. """ capability_ids: List[str] = Field(default_factory=list) confidence: Confidence = Confidence.MEDIUM # certification_id -> entry. Injected at call time; product code holds NO entries. CertificationCapabilityMap = Dict[str, CapabilityMappingEntry] # Intentionally empty: without an injected mapping there are zero inferred # candidates. This is the architectural guarantee that the registry lives only in # the Compliance Execution domain. EMPTY_MAPPING: CertificationCapabilityMap = {}