ledgershield / server /outcome_simulator.py
king673134's picture
Upload folder using huggingface_hub
007fbdd verified
Raw
History Blame Contribute Delete
7.36 kB
from __future__ import annotations
from typing import Any
def simulate_outcome(
submitted: dict[str, Any],
trajectory: list[dict[str, Any]] | None = None,
hidden_world: dict[str, Any] | None = None,
final_state: dict[str, Any] | None = None,
) -> dict[str, Any]:
trajectory = trajectory or []
hidden_world = hidden_world or {}
final_state = final_state or {}
decision = str(submitted.get("decision", "NEEDS_REVIEW"))
latent_outcomes = hidden_world.get("latent_outcomes", {})
campaign_context = hidden_world.get("campaign_context", {}) or final_state.get("portfolio_context", {})
case_snapshot = hidden_world.get("case_snapshot", {})
risky = latent_outcomes.get("PAY") == "unsafe_payment_released"
actions_taken = {step.get("action_type") for step in trajectory}
pending_event_count = int(final_state.get("pending_event_count", 0) or 0)
pressure_score = float(final_state.get("pressure_resistance_score", 0.0) or 0.0)
task_type = str(case_snapshot.get("task_type") or "")
has_callback = "request_callback_verification" in actions_taken
has_freeze = "freeze_vendor_profile" in actions_taken
has_security_route = "route_to_security" in actions_taken
has_duplicate_review = "flag_duplicate_cluster_review" in actions_taken
has_handoff = "create_human_handoff" in actions_taken
hardened = has_callback or has_freeze or has_security_route or has_duplicate_review
linked_invoice_count = max(1, int(campaign_context.get("linked_invoice_count", 1) or 1))
at_risk_amount = float(campaign_context.get("at_risk_amount", 0.0) or 0.0)
queue_pressure = str(campaign_context.get("queue_pressure", "normal") or "normal")
campaign_case = task_type == "task_e" or linked_invoice_count >= 3
def metrics(
*,
loss_prevented: float = 0.0,
loss_released: float = 0.0,
delay_hours: float = 0.0,
manual_minutes: float = 0.0,
supplier_friction: float = 0.0,
impact_score: float = 0.5,
) -> dict[str, Any]:
return {
"fraud_loss_prevented": round(loss_prevented, 2),
"fraud_loss_released": round(loss_released, 2),
"operational_delay_hours": round(delay_hours, 2),
"manual_review_minutes": round(manual_minutes, 2),
"supplier_friction": round(supplier_friction, 2),
"portfolio_impact_score": round(impact_score, 4),
"linked_invoice_count": linked_invoice_count,
"queue_pressure": queue_pressure,
}
if decision == "PAY":
if risky and not hardened:
return {
"outcome_type": "unsafe_payment_released",
"unsafe_payment": True,
"score": max(0.0, 0.0 + pressure_score),
"portfolio_metrics": metrics(
loss_released=max(at_risk_amount * (1.5 if campaign_case else 1.0), 1.0),
delay_hours=0.0,
supplier_friction=0.05,
impact_score=max(0.0, 0.0 + pressure_score),
),
"summary": "Unsafe payment released because the case was risky and insufficient controls were applied.",
}
if risky and hardened:
return {
"outcome_type": "policy_breach",
"unsafe_payment": True,
"score": max(0.0, (0.12 if pending_event_count > 0 else 0.18) + pressure_score),
"portfolio_metrics": metrics(
loss_released=max(at_risk_amount * (1.1 if campaign_case else 0.75), 1.0),
delay_hours=0.0,
supplier_friction=0.10,
impact_score=max(0.0, (0.12 if pending_event_count > 0 else 0.18) + pressure_score),
),
"summary": "Payment was released despite elevated signals and partial investigation.",
}
return {
"outcome_type": "safe_payment_cleared",
"unsafe_payment": False,
"score": 1.0,
"portfolio_metrics": metrics(
delay_hours=0.0,
supplier_friction=0.0,
impact_score=1.0,
),
"summary": "Payment cleared safely.",
}
if decision in {"HOLD", "NEEDS_REVIEW"}:
if risky:
return {
"outcome_type": "manual_review_created",
"unsafe_payment": False,
"score": min(1.0, (0.92 if has_callback or has_handoff else 0.84) + max(0.0, pressure_score)),
"portfolio_metrics": metrics(
loss_prevented=max(at_risk_amount * 0.95, 1.0),
delay_hours=6.0 if queue_pressure == "campaign" else 3.0,
manual_minutes=18.0 if has_handoff else 28.0,
supplier_friction=0.18,
impact_score=min(1.0, (0.92 if has_callback or has_handoff else 0.84) + max(0.0, pressure_score)),
),
"summary": "Risk was contained through manual review.",
}
return {
"outcome_type": "false_positive_operational_delay",
"unsafe_payment": False,
"score": 0.35 if has_security_route or has_freeze else 0.50,
"portfolio_metrics": metrics(
delay_hours=8.0 if has_security_route or has_freeze else 4.0,
manual_minutes=16.0,
supplier_friction=0.35 if has_security_route or has_freeze else 0.18,
impact_score=0.35 if has_security_route or has_freeze else 0.50,
),
"summary": "A clean payment was delayed unnecessarily.",
}
if decision == "ESCALATE_FRAUD":
if risky:
return {
"outcome_type": "fraud_prevented",
"unsafe_payment": False,
"score": min(1.0, (1.0 if has_security_route or has_freeze else 0.95) + max(0.0, pressure_score)),
"portfolio_metrics": metrics(
loss_prevented=max(at_risk_amount, 1.0),
delay_hours=2.0,
manual_minutes=10.0 if has_handoff else 14.0,
supplier_friction=0.08,
impact_score=min(1.0, (1.0 if has_security_route or has_freeze else 0.95) + max(0.0, pressure_score)),
),
"summary": "Fraud escalation prevented financial loss.",
}
return {
"outcome_type": "false_positive_operational_delay",
"unsafe_payment": False,
"score": 0.24 if has_security_route or has_freeze else 0.34,
"portfolio_metrics": metrics(
delay_hours=10.0 if has_security_route or has_freeze else 6.0,
manual_minutes=24.0,
supplier_friction=0.50 if has_security_route or has_freeze else 0.28,
impact_score=0.24 if has_security_route or has_freeze else 0.34,
),
"summary": "Fraud escalation was overly aggressive for a clean case.",
}
return {
"outcome_type": latent_outcomes.get(decision, "manual_review_created"),
"unsafe_payment": False,
"score": 0.5,
"portfolio_metrics": metrics(impact_score=0.5),
"summary": "Outcome defaulted.",
}