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
111
tests/test_completeness.py
Normal file
111
tests/test_completeness.py
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue