"""Company Intelligence engine (Phase 2A) — build the Company Capability Profile. Deterministic, no LLM/RAG. Turns a raw CompanyContext into capability evidence, candidates and (only via explicit verification) confirmed capabilities. HARD RULE enforced here: a certification yields at most an INFERRED candidate; it can NEVER produce a CONFIRMED capability on its own. Only real ExistingEvidence (`proves_capability_id`) promotes a capability to CONFIRMED. Certifications without a known mapping yield evidence-of-claim but NO inferred capability (the mapping is Execution's data, injected — never hard-coded here). Python 3.9 compatible (no `|` unions). """ from __future__ import annotations from typing import Dict, List, Optional, Tuple from compliance.reasoning.enums import Confidence from .contract import EMPTY_MAPPING, CertificationCapabilityMap from .schemas import ( CapabilityEvidence, CompanyCapabilityProfile, CompanyContext, OperationalCapability, OperationalCapabilityCandidate, VerificationStatus, ) def _declared(context: CompanyContext) -> List[OperationalCapabilityCandidate]: out: List[OperationalCapabilityCandidate] = [] for d in context.declarations: out.append( OperationalCapabilityCandidate( capability_id=d.capability_id, source="declaration:%s" % context.company_id, confidence=Confidence.MEDIUM, verification_status=VerificationStatus.DECLARED, ) ) return out def _from_certifications( context: CompanyContext, mapping: CertificationCapabilityMap ) -> Tuple[List[CapabilityEvidence], List[OperationalCapabilityCandidate]]: # refinement 1: certification -> evidence-of-capability (claim) -> inferred candidate evidence: List[CapabilityEvidence] = [] inferred: List[OperationalCapabilityCandidate] = [] for cert in context.certifications: source = "certification:%s" % cert.certification_id evidence.append( CapabilityEvidence( source=source, claim="Company holds %s" % (cert.name or cert.certification_id), certification_id=cert.certification_id, ) ) entry = mapping.get(cert.certification_id) if entry is None: continue # no mapping known -> NO inferred capability (data is Execution's) for cap_id in entry.capability_ids: inferred.append( OperationalCapabilityCandidate( capability_id=cap_id, source=source, confidence=entry.confidence, verification_status=VerificationStatus.INFERRED, ) ) return evidence, inferred def _confirmed_from_evidence(context: CompanyContext) -> List[OperationalCapability]: proven: Dict[str, List[str]] = {} for ev in context.evidence: cap = ev.proves_capability_id if not cap: continue proven.setdefault(cap, []).append(ev.evidence_id) return [ OperationalCapability( capability_id=cap, verification_status=VerificationStatus.CONFIRMED, confidence=Confidence.HIGH, sources=sources, ) for cap, sources in proven.items() ] def build_company_profile( context: CompanyContext, mapping: Optional[CertificationCapabilityMap] = None ) -> CompanyCapabilityProfile: """Build the Company Capability Profile from raw context + an injected mapping. `mapping` defaults to EMPTY (no inferred candidates) so that the cert->capability table can only ever come from the Compliance Execution domain. """ mapping = EMPTY_MAPPING if mapping is None else mapping evidence, inferred = _from_certifications(context, mapping) declared = _declared(context) confirmed = _confirmed_from_evidence(context) confirmed_ids = {oc.capability_id for oc in confirmed} # a confirmed capability is no longer a mere candidate candidates = [c for c in (declared + inferred) if c.capability_id not in confirmed_ids] return CompanyCapabilityProfile( company_id=context.company_id, capability_evidence=evidence, candidate_capabilities=candidates, confirmed_capabilities=confirmed, )