"""Company Intelligence (Phase 2A) — Company Capability Profile (domain objects). This is the HEAD of the spine Company -> (Operational) Capability -> Product -> Applicable Regulation -> Obligation -> Procedure -> Evidence and answers a DIFFERENT question than Regulatory Intelligence: not "which laws apply to my product" but "which capabilities does my company already have, and which regulatory obligations might they already cover". HARD RULE (structural, not convention): a capability derived from a certification is at most INFERRED — never CONFIRMED, never "erfuellt". A certification produces EVIDENCE for a capability, an inference produces a CANDIDATE, and only checked evidence produces a CONFIRMED capability. This keeps the company side inside Welt 1 (potential), mirroring `ClaimCoverage` on the obligation side; it is NOT a conformity verdict (`ComplianceStatus`, Welt 2, owned by Compliance Execution). OWNERSHIP: Reasoning OWNS this CompanyContext container + the trust-state machine. It does NOT own the Certification->Capability mapping RULES — those are the same kind of rule as Feature->Capability and belong to the Compliance Execution Capability Registry. This layer only CONSUMES `OperationalCapabilityCandidate` {capability_id, source, confidence, verification_status} via an injected mapping (see contract.py). No mapping DATA lives in product code (tests inject mocks). Application/reasoning types, NOT compliance-meta-model classes (architecture freeze v1.0 untouched). Python 3.9 compatible (no `|` unions). """ from __future__ import annotations from enum import Enum from typing import List, Optional from pydantic import BaseModel, Field from compliance.reasoning.enums import Confidence class VerificationStatus(str, Enum): """Trust state of an operational capability — a FOURTH vocabulary. Disjoint from ClaimCoverage (Welt 1, customer claim vs obligation), ComplianceStatus (Welt 2, verified conformity) and DeltaType (RCI). It says only how well-established a company CAPABILITY is, never whether an obligation is met. Progression: DECLARED (customer says) -> INFERRED (a certification implies it) -> CONFIRMED (checked against real evidence); UNKNOWN = no signal. """ DECLARED = "declared" INFERRED = "inferred" CONFIRMED = "confirmed" UNKNOWN = "unknown" # ── raw company inputs (the CompanyContext children) ────────────────────── class Certification(BaseModel): certification_id: str # e.g. "ISO27001" name: str = "" scope: str = "" # what the cert covers, customer-stated class Declaration(BaseModel): """A customer statement that they have a capability ("we do patch management").""" capability_id: str statement: str = "" class ExistingProcess(BaseModel): process_id: str name: str = "" class ExistingSystem(BaseModel): system_id: str name: str = "" class ExistingEvidence(BaseModel): """A concrete artefact the company already holds (policy, audit log, SBOM ...). `proves_capability_id` is the ONLY thing that may lift a capability to CONFIRMED — and only when a human/engine has attached real evidence. """ evidence_id: str evidence_type: str = "" # config_export/test_report/policy/audit_log/... proves_capability_id: Optional[str] = None # ── intermediate: certification -> evidence-of-capability (refinement 1) ── class CapabilityEvidence(BaseModel): """A certification does not yield a capability directly — only EVIDENCE for one. "Company holds a certified ISMS" is the evidence/claim; capabilities are then INFERRED from it via the injected (Execution-owned) mapping, never directly. """ source: str # provenance, e.g. "certification:ISO27001" claim: str = "" certification_id: str = "" # ── consumed contract type (refinement 2) ───────────────────────────────── class OperationalCapabilityCandidate(BaseModel): """The ONLY thing Reasoning consumes from Execution's capability mapping. Named "operational" (organisational ability) to stay distinct from later Product/AI/Safety capabilities. A candidate is always Welt 1 — DECLARED or INFERRED — and never CONFIRMED on its own. """ capability_id: str source: str confidence: Confidence = Confidence.MEDIUM verification_status: VerificationStatus = VerificationStatus.INFERRED class OperationalCapability(BaseModel): """A capability the company actually has, CONFIRMED against real evidence.""" capability_id: str verification_status: VerificationStatus confidence: Confidence = Confidence.MEDIUM sources: List[str] = Field(default_factory=list) # ── the container Reasoning OWNS (raw inputs) ───────────────────────────── class CompanyContext(BaseModel): company_id: str certifications: List[Certification] = Field(default_factory=list) declarations: List[Declaration] = Field(default_factory=list) processes: List[ExistingProcess] = Field(default_factory=list) systems: List[ExistingSystem] = Field(default_factory=list) evidence: List[ExistingEvidence] = Field(default_factory=list) # ── derived view (the Company Capability Profile) ───────────────────────── class CompanyCapabilityProfile(BaseModel): """Derived: capability evidence + candidates (declared/inferred) + confirmed. `candidate_capabilities` NEVER auto-promote to `confirmed_capabilities`; only explicit ExistingEvidence does that. The hard rule is enforced in engine.py. """ company_id: str capability_evidence: List[CapabilityEvidence] = Field(default_factory=list) candidate_capabilities: List[OperationalCapabilityCandidate] = Field(default_factory=list) confirmed_capabilities: List[OperationalCapability] = Field(default_factory=list)