Finish KG-WP-0003: stream completeness and live qonto observation
Classify evidence as load-bearing or attributive, draft the emission-cadence declaration for Taxonomy, treat silence as a stream finding, keep completeness separate from record richness, forbid immune memory as a state plane, and make containment proposals reconstructable to their origin. Observe real qonto-assistant audit events; deny-class completeness stays unknown until the source publishes a heartbeat. Assistant: grok Assistant-Session: 01a05ef1-9e5a-70f2-b0ff-0b05d6b38ae9
This commit is contained in:
parent
c85646dc3c
commit
9daea96c43
35 changed files with 2023 additions and 138 deletions
91
tests/test_evidence_class.py
Normal file
91
tests/test_evidence_class.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
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,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue