mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-18 23:39:34 +00:00
199 lines
6.4 KiB
Python
199 lines
6.4 KiB
Python
"""Tests for Dealix contracts — DecisionOutput, classifications, validators."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from dealix.classifications import (
|
|
NEVER_AUTO_EXECUTE,
|
|
ApprovalClass,
|
|
ReversibilityClass,
|
|
SensitivityClass,
|
|
classify,
|
|
)
|
|
from dealix.contracts.audit_log import AuditAction, AuditEntry
|
|
from dealix.contracts.decision import (
|
|
DecisionOutput,
|
|
Evidence,
|
|
NextAction,
|
|
)
|
|
from dealix.contracts.event_envelope import EventEnvelope
|
|
|
|
|
|
# ── Classifications ────────────────────────────────────────────
|
|
def test_classify_known_action():
|
|
a, r, s = classify("proposal_send")
|
|
assert a == ApprovalClass.A2
|
|
assert r == ReversibilityClass.R2
|
|
assert s == SensitivityClass.S2
|
|
|
|
|
|
def test_classify_unknown_defaults_conservative():
|
|
a, r, s = classify("some_brand_new_action_xyz")
|
|
# Conservative default
|
|
assert a == ApprovalClass.A2
|
|
assert r == ReversibilityClass.R2
|
|
assert s == SensitivityClass.S2
|
|
|
|
|
|
def test_never_auto_execute_includes_expected_actions():
|
|
for critical in (
|
|
"pricing_offer_commit",
|
|
"contract_change",
|
|
"nda_send",
|
|
"payment_terms_change",
|
|
"regulator_communication",
|
|
"sensitive_data_export",
|
|
):
|
|
assert critical in NEVER_AUTO_EXECUTE
|
|
|
|
|
|
def test_approval_class_properties():
|
|
assert not ApprovalClass.A0.requires_approval
|
|
assert ApprovalClass.A1.requires_approval
|
|
assert ApprovalClass.A3.minimum_approvers == 2
|
|
|
|
|
|
def test_reversibility_class_r3_blocks():
|
|
assert ReversibilityClass.R3.blocks_auto_execution
|
|
assert not ReversibilityClass.R0.blocks_auto_execution
|
|
|
|
|
|
def test_sensitivity_s3_is_pdpl():
|
|
assert SensitivityClass.S3.is_pdpl_scope
|
|
assert not SensitivityClass.S1.is_pdpl_scope
|
|
|
|
|
|
# ── DecisionOutput validation ──────────────────────────────────
|
|
def test_decision_low_stakes_works_without_evidence():
|
|
d = DecisionOutput(
|
|
entity_id="lead_1",
|
|
objective="qualify_lead",
|
|
agent_name="icp_matcher",
|
|
recommendation={"tier": "A"},
|
|
confidence=0.9,
|
|
rationale="test",
|
|
approval_class=ApprovalClass.A0,
|
|
reversibility_class=ReversibilityClass.R0,
|
|
sensitivity_class=SensitivityClass.S1,
|
|
)
|
|
assert not d.is_high_stakes
|
|
assert not d.requires_human_approval
|
|
|
|
|
|
def test_decision_high_stakes_requires_evidence():
|
|
with pytest.raises(ValueError, match="Evidence"):
|
|
DecisionOutput(
|
|
entity_id="lead_1",
|
|
objective="recommend_proposal",
|
|
agent_name="proposal",
|
|
recommendation={"send": True},
|
|
confidence=0.9,
|
|
rationale="test",
|
|
approval_class=ApprovalClass.A2,
|
|
reversibility_class=ReversibilityClass.R2,
|
|
sensitivity_class=SensitivityClass.S2,
|
|
evidence=[], # missing!
|
|
)
|
|
|
|
|
|
def test_decision_high_stakes_with_evidence_ok():
|
|
d = DecisionOutput(
|
|
entity_id="lead_1",
|
|
objective="recommend_proposal",
|
|
agent_name="proposal",
|
|
recommendation={"send": True},
|
|
confidence=0.9,
|
|
rationale="test",
|
|
approval_class=ApprovalClass.A2,
|
|
reversibility_class=ReversibilityClass.R2,
|
|
sensitivity_class=SensitivityClass.S2,
|
|
evidence=[Evidence(source="test", excerpt="evidence here")],
|
|
)
|
|
assert d.is_high_stakes
|
|
assert d.requires_human_approval
|
|
|
|
|
|
def test_decision_r3_is_high_stakes_even_with_a0():
|
|
# R3 alone is enough to be high-stakes
|
|
with pytest.raises(ValueError, match="Evidence"):
|
|
DecisionOutput(
|
|
entity_id="deal_1",
|
|
objective="irreversible_commit",
|
|
agent_name="test",
|
|
recommendation={"commit": True},
|
|
confidence=0.9,
|
|
rationale="test",
|
|
approval_class=ApprovalClass.A0,
|
|
reversibility_class=ReversibilityClass.R3,
|
|
sensitivity_class=SensitivityClass.S1,
|
|
evidence=[],
|
|
)
|
|
|
|
|
|
def test_decision_has_auto_generated_ids():
|
|
d = DecisionOutput(
|
|
entity_id="x",
|
|
objective="test",
|
|
agent_name="test",
|
|
recommendation={},
|
|
confidence=0.5,
|
|
rationale="r",
|
|
approval_class=ApprovalClass.A0,
|
|
reversibility_class=ReversibilityClass.R0,
|
|
sensitivity_class=SensitivityClass.S0,
|
|
)
|
|
assert d.decision_id.startswith("dec_")
|
|
assert d.schema_version == "1.0"
|
|
assert d.created_at # ISO string
|
|
|
|
|
|
# ── NextAction ─────────────────────────────────────────────────
|
|
def test_next_action_fields():
|
|
na = NextAction(
|
|
action_type="proposal_send",
|
|
description="send proposal",
|
|
approval_class=ApprovalClass.A2,
|
|
reversibility_class=ReversibilityClass.R2,
|
|
sensitivity_class=SensitivityClass.S2,
|
|
payload={"proposal_id": "p1"},
|
|
)
|
|
assert na.action_type == "proposal_send"
|
|
assert na.payload["proposal_id"] == "p1"
|
|
|
|
|
|
# ── EventEnvelope ──────────────────────────────────────────────
|
|
def test_event_envelope_cloudevents_required():
|
|
ev = EventEnvelope(
|
|
source="dealix/test",
|
|
type="dealix.test.emitted",
|
|
)
|
|
assert ev.specversion == "1.0"
|
|
assert ev.id.startswith("evt_")
|
|
assert ev.time # ISO string
|
|
|
|
|
|
def test_event_envelope_carries_classification():
|
|
ev = EventEnvelope(
|
|
source="dealix/phase8",
|
|
type="dealix.lead.intaken",
|
|
approval_class=ApprovalClass.A0,
|
|
reversibility_class=ReversibilityClass.R0,
|
|
sensitivity_class=SensitivityClass.S2,
|
|
)
|
|
assert ev.sensitivity_class == SensitivityClass.S2
|
|
|
|
|
|
# ── AuditEntry ─────────────────────────────────────────────────
|
|
def test_audit_entry_minimal():
|
|
entry = AuditEntry(action=AuditAction.DECISION_EMITTED)
|
|
assert entry.audit_id.startswith("aud_")
|
|
assert entry.outcome == "ok"
|
|
assert entry.schema_version == "1.0"
|
|
|
|
|
|
def test_audit_action_enum_values():
|
|
assert AuditAction.POLICY_ESCALATED.value == "policy.escalated"
|
|
assert AuditAction.TOOL_CONTRADICTED.value == "tool.contradicted"
|
|
assert AuditAction.WORKFLOW_COMPENSATED.value == "workflow.compensated"
|