import pytest from kings_guard.adapters import observation_from_audit_event from kings_guard.contracts import DeclaredEvidenceSource, EvidenceClass from helpers import load_pilot, observation_from_fixture def test_genome_declares_both_evidence_classes() -> None: genome = load_pilot().genome classes = {source.event_class: source.evidence_class for source in genome.evidence_sources} assert classes["audit.deny"] is EvidenceClass.LOAD_BEARING assert classes["audit.allow"] is EvidenceClass.ATTRIBUTIVE assert classes["audit.heartbeat"] is EvidenceClass.LOAD_BEARING def test_observation_copies_declared_class_and_does_not_infer_it() -> None: fixture = load_pilot() observation = observation_from_fixture(fixture) declared = fixture.genome.source_for("audit.deny") assert declared is not None assert observation.evidence_class is declared.evidence_class assert observation.evidence_class is EvidenceClass.LOAD_BEARING joined = " ".join(fixture.evidence_class_reasoning) assert "source declares" in joined assert "does not infer" in joined assert all(source.reasoning for source in fixture.genome.evidence_sources) def test_allow_event_is_attributive_because_the_source_said_so() -> None: fixture = load_pilot() event = dict(fixture.audit_event) event["decision"] = "allow" event["deny_reason"] = None event["request_id"] = "req-allow" observation = observation_from_audit_event( event, subject_id=fixture.normalization_hints["subject_id"], capability_scope=fixture.normalization_hints["capability_scope"], identity_binding=fixture.normalization_hints["identity_binding"], egress_destination=fixture.normalization_hints["egress_destination"], genome=fixture.genome, ) assert observation.event_class == "audit.allow" assert observation.evidence_class is EvidenceClass.ATTRIBUTIVE def test_class_mismatch_with_source_declaration_is_rejected() -> None: fixture = load_pilot() with pytest.raises(ValueError, match="does not match source declaration"): observation_from_audit_event( fixture.audit_event, subject_id=fixture.normalization_hints["subject_id"], capability_scope=fixture.normalization_hints["capability_scope"], identity_binding=fixture.normalization_hints["identity_binding"], egress_destination=fixture.normalization_hints["egress_destination"], genome=fixture.genome, evidence_class=EvidenceClass.ATTRIBUTIVE, ) def test_class_cannot_be_inferred_from_event_contents() -> None: fixture = load_pilot() with pytest.raises(ValueError, match="does not infer"): observation_from_audit_event( fixture.audit_event, subject_id=fixture.normalization_hints["subject_id"], capability_scope=fixture.normalization_hints["capability_scope"], identity_binding=fixture.normalization_hints["identity_binding"], egress_destination=fixture.normalization_hints["egress_destination"], ) def test_declared_source_is_expressible_on_genome_and_observation() -> None: source = DeclaredEvidenceSource( source_id="example.audit.deny", source_system="example", event_class="audit.deny", evidence_class=EvidenceClass.LOAD_BEARING, reasoning="denials are load-bearing by statute ยง9.6", cadence_form="heartbeat-or-reconciliation", ) assert source.evidence_class is EvidenceClass.LOAD_BEARING assert observation_from_fixture().evidence_class in { EvidenceClass.LOAD_BEARING, EvidenceClass.ATTRIBUTIVE, }