"""Tests for Company Intelligence (Phase 2A) — Company Capability Profile. Acceptance: from a CompanyContext (certifications, declarations, evidence) the engine derives operational capabilities with a four-state trust model and a HARD RULE: a certification is NEVER auto-treated as "erfuellt" — at most INFERRED. The Certification->Capability mapping is Execution's domain. It is injected here as a MOCK (the yaml-like dict below lives ONLY in tests); product code ships no table. """ from __future__ import annotations from compliance.company import ( CapabilityMappingEntry, Certification, CompanyContext, Declaration, ExistingEvidence, VerificationStatus, build_company_profile, ) from compliance.reasoning.enums import Confidence # --- MOCK mapping (Execution-owned in reality; here only for the tests) ------- # mapping: # ISO27001 -> [cap_patch_management, cap_supplier_management] MOCK_MAPPING = { "ISO27001": CapabilityMappingEntry( capability_ids=["cap_patch_management", "cap_supplier_management"], confidence=Confidence.MEDIUM, ) } def _candidate(profile, capability_id): return [c for c in profile.candidate_capabilities if c.capability_id == capability_id] def _confirmed_ids(profile): return {c.capability_id for c in profile.confirmed_capabilities} # A certification yields INFERRED candidates via the injected mapping. def test_certification_infers_candidates_via_injected_mapping(): ctx = CompanyContext(company_id="acme", certifications=[Certification(certification_id="ISO27001")]) profile = build_company_profile(ctx, MOCK_MAPPING) ids = {c.capability_id for c in profile.candidate_capabilities} assert ids == {"cap_patch_management", "cap_supplier_management"} for c in profile.candidate_capabilities: assert c.verification_status == VerificationStatus.INFERRED assert c.source == "certification:ISO27001" # Without an injected mapping there are NO inferred capabilities — only the claim. # This is the architectural guarantee that the table lives only in Execution. def test_no_mapping_no_inferred_capabilities(): ctx = CompanyContext(company_id="acme", certifications=[Certification(certification_id="ISO27001")]) profile = build_company_profile(ctx) # default EMPTY mapping assert profile.candidate_capabilities == [] # the certification still produced evidence-of-claim (refinement 1) assert len(profile.capability_evidence) == 1 assert profile.capability_evidence[0].source == "certification:ISO27001" assert profile.capability_evidence[0].certification_id == "ISO27001" # A customer declaration yields a DECLARED candidate. def test_declaration_yields_declared_candidate(): ctx = CompanyContext(company_id="acme", declarations=[Declaration(capability_id="cap_patch_management")]) profile = build_company_profile(ctx, MOCK_MAPPING) cands = _candidate(profile, "cap_patch_management") assert len(cands) == 1 assert cands[0].verification_status == VerificationStatus.DECLARED # declared + inferred coexist as distinct signals for the same capability. def test_declared_and_inferred_coexist(): ctx = CompanyContext( company_id="acme", certifications=[Certification(certification_id="ISO27001")], declarations=[Declaration(capability_id="cap_patch_management")], ) profile = build_company_profile(ctx, MOCK_MAPPING) statuses = {c.verification_status for c in _candidate(profile, "cap_patch_management")} assert statuses == {VerificationStatus.DECLARED, VerificationStatus.INFERRED} # HARD RULE: a certification alone NEVER yields a confirmed capability. def test_hard_rule_certification_never_confirmed(): ctx = CompanyContext(company_id="acme", certifications=[Certification(certification_id="ISO27001")]) profile = build_company_profile(ctx, MOCK_MAPPING) assert _confirmed_ids(profile) == set() for c in profile.candidate_capabilities: assert c.verification_status != VerificationStatus.CONFIRMED # Only real evidence confirms a capability — and it leaves the candidate list. def test_evidence_confirms_capability(): ctx = CompanyContext( company_id="acme", certifications=[Certification(certification_id="ISO27001")], evidence=[ExistingEvidence(evidence_id="pol-1", evidence_type="policy", proves_capability_id="cap_patch_management")], ) profile = build_company_profile(ctx, MOCK_MAPPING) assert "cap_patch_management" in _confirmed_ids(profile) confirmed = [c for c in profile.confirmed_capabilities if c.capability_id == "cap_patch_management"][0] assert confirmed.verification_status == VerificationStatus.CONFIRMED assert confirmed.confidence == Confidence.HIGH assert confirmed.sources == ["pol-1"] # a confirmed capability is no longer a mere candidate assert _candidate(profile, "cap_patch_management") == [] # the un-proven capability stays an inferred candidate assert _candidate(profile, "cap_supplier_management")[0].verification_status == VerificationStatus.INFERRED # The four-state vocabulary exists and is ordered declared->inferred->confirmed (+unknown). def test_four_states_present(): assert {s.value for s in VerificationStatus} == {"declared", "inferred", "confirmed", "unknown"} # verification_status is a FOURTH vocabulary, disjoint from ClaimCoverage and DeltaType. def test_verification_status_distinct_vocabulary(): from compliance.rci.schemas import DeltaType from compliance.reasoning.enums import ClaimCoverage verif = {s.value for s in VerificationStatus} assert verif.isdisjoint({c.value for c in ClaimCoverage}) assert verif.isdisjoint({d.value for d in DeltaType})