feat(core): define sanctions screening gate contract

This commit is contained in:
2026-07-30 01:54:58 +02:00
parent f3b388fe7e
commit ca8a8c5111
2 changed files with 323 additions and 1 deletions

View File

@@ -6,9 +6,19 @@ import unittest
from govoplan_core.core.sanctions import (
CAPABILITY_CONNECTORS_SANCTIONS_SNAPSHOTS,
CAPABILITY_RISK_COMPLIANCE_SANCTIONS_SCREENING,
SanctionsScreeningEvidence,
SanctionsScreeningFreshness,
SanctionsScreeningFreshnessRequest,
SanctionsScreeningPolicy,
SanctionsScreeningProvider,
SanctionsScreeningRequest,
SanctionsScreeningResult,
SanctionsScreeningSubject,
SanctionsSnapshotPayload,
SanctionsSnapshotProvider,
SanctionsSnapshotReference,
sanctions_screening_provider,
sanctions_snapshot_provider,
)
@@ -38,6 +48,27 @@ class _Registry:
return self.provider if self.has_capability(name) else None
class _ScreeningProvider:
def request_screening(self, session, principal, request):
del session, principal, request
raise NotImplementedError
def check_freshness(self, session, principal, request):
del session, principal, request
raise NotImplementedError
class _ScreeningRegistry:
def __init__(self, provider):
self.provider = provider
def has_capability(self, name):
return name == CAPABILITY_RISK_COMPLIANCE_SANCTIONS_SCREENING
def capability(self, name):
return self.provider if self.has_capability(name) else None
class SanctionsContractTests(unittest.TestCase):
def test_snapshot_evidence_is_versioned_and_bounded(self) -> None:
content = b"<CONSOLIDATED_LIST/>"
@@ -74,6 +105,66 @@ class SanctionsContractTests(unittest.TestCase):
sanctions_snapshot_provider(_Registry(provider)),
)
def test_screening_evidence_and_freshness_are_versioned(self) -> None:
subject = SanctionsScreeningSubject(
subject_type="person",
primary_name="Example Person",
)
policy = SanctionsScreeningPolicy(failure_policy="review")
request = SanctionsScreeningRequest(
list_snapshot_id="snapshot-1",
idempotency_key="request-1",
subject=subject,
policy=policy,
)
evidence = SanctionsScreeningEvidence(
ref="risk-screening:run-1",
run_id="run-1",
outcome="clear",
candidate_count=0,
list_snapshot_id=request.list_snapshot_id,
source_version="2026-07-30",
subject_fingerprint="a" * 64,
matcher_version="matcher-v1",
normalization_version="normalization-v1",
policy_version="policy-v1",
completed_at=datetime.now(timezone.utc),
)
freshness_request = SanctionsScreeningFreshnessRequest(
evidence_ref=evidence.ref,
current_subject=subject,
policy=policy,
)
freshness = SanctionsScreeningFreshness(
evidence=evidence,
fresh=True,
reasons=(),
checked_at=datetime.now(timezone.utc),
current_list_snapshot_id=request.list_snapshot_id,
gate_decision="allow",
gate_reasons=("screening_clear",),
)
result = SanctionsScreeningResult(
evidence=evidence,
freshness=freshness,
created=True,
)
provider = _ScreeningProvider()
self.assertEqual(evidence.ref, freshness_request.evidence_ref)
self.assertTrue(result.freshness.fresh)
self.assertIsInstance(provider, SanctionsScreeningProvider)
self.assertIs(
provider,
sanctions_screening_provider(
_ScreeningRegistry(provider)
),
)
def test_screening_contract_rejects_ambiguous_subjects(self) -> None:
with self.assertRaises(ValueError):
SanctionsScreeningSubject(subject_type="entity")
if __name__ == "__main__":
unittest.main()