kings-guard/tests/test_completeness.py
tegwick 9daea96c43 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
2026-09-02 00:11:57 +02:00

111 lines
4.3 KiB
Python

from kings_guard.cadence import load_qonto_assistant_cadence
from kings_guard.contracts import (
PostureAssessment,
PostureLevel,
ReconciliationView,
StreamCompleteness,
StreamHeartbeat,
assessment_trust_key,
)
from kings_guard.posture import PostureEvaluator
from helpers import load_pilot, observation_from_fixture
def _healthy_assessment(*, completeness: StreamCompleteness, confidence: int) -> PostureAssessment:
return PostureAssessment(
posture=PostureLevel.HEALTHY,
risk_score=5,
confidence_score=confidence,
stream_completeness=completeness,
completeness_reason="test",
findings=(),
tolerated_findings=(),
rationale="test",
)
def test_completeness_is_separated_from_record_richness() -> None:
fixture = load_pilot()
observation = observation_from_fixture(fixture)
evaluation = PostureEvaluator().evaluate(fixture.genome, observation)
assert evaluation.assessment.confidence_score >= 85
assert evaluation.assessment.stream_completeness is StreamCompleteness.UNKNOWN
assert "record" in evaluation.assessment.completeness_reason
assert "cannot vouch" in evaluation.assessment.rationale or "unknown" in evaluation.assessment.rationale
def test_unmet_cadence_degrades_completeness_and_says_so_in_words() -> None:
fixture = load_pilot()
observation = observation_from_fixture(fixture)
cadence = load_qonto_assistant_cadence()
evaluation = PostureEvaluator().evaluate_with_stream(
fixture.genome,
observation,
cadence,
now="2026-07-24T10:10:00Z",
watching_since="2026-07-22T09:10:00Z",
heartbeats=(),
reconciliation=ReconciliationView(source_counts={"audit.deny": 1}, evidence_counts={"audit.deny": 1}),
)
assert evaluation.assessment.stream_completeness is StreamCompleteness.DEGRADED
assert evaluation.assessment.confidence_score >= 85
assert "cannot vouch" in evaluation.assessment.rationale
def test_incomplete_stream_is_never_more_trustworthy_than_a_complete_one() -> None:
rich_incomplete = _healthy_assessment(
completeness=StreamCompleteness.DEGRADED, confidence=95
)
sparse_complete = _healthy_assessment(
completeness=StreamCompleteness.COMPLETE, confidence=70
)
unknown = _healthy_assessment(completeness=StreamCompleteness.UNKNOWN, confidence=95)
assert assessment_trust_key(rich_incomplete) < assessment_trust_key(sparse_complete)
assert assessment_trust_key(unknown) < assessment_trust_key(sparse_complete)
assert assessment_trust_key(unknown) < assessment_trust_key(rich_incomplete)
def test_complete_stream_keeps_richness_and_states_completeness() -> None:
fixture = load_pilot()
observation = observation_from_fixture(fixture)
cadence = load_qonto_assistant_cadence()
allow_event = dict(fixture.audit_event)
allow_event["decision"] = "allow"
allow_event["deny_reason"] = None
allow_event["request_id"] = "req-allow-volume"
from kings_guard.adapters import observation_from_audit_event
allow = observation_from_audit_event(
allow_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,
)
evaluation = PostureEvaluator().evaluate_with_stream(
fixture.genome,
observation,
cadence,
now="2026-07-24T09:10:00Z",
observations=(observation, allow),
watching_since="2026-07-22T09:10:00Z",
heartbeats=(
StreamHeartbeat(
source_system="qonto-assistant",
timestamp="2026-07-24T09:00:00Z",
event_class="audit.heartbeat",
assertion="nothing-to-report",
counts={"audit.deny": 1},
),
),
reconciliation=ReconciliationView(source_counts={"audit.deny": 1}, evidence_counts={"audit.deny": 1}),
)
assert evaluation.assessment.stream_completeness is StreamCompleteness.COMPLETE
assert "Stream completeness is complete." in evaluation.assessment.rationale
assert evaluation.assessment.confidence_score >= 85