payops_env / tasks.py
padmapriyagosakan's picture
fix: add enabled:true to PayOpsTask.grader Python property for platform compatibility
d7aea6e
"""
Task bank for the PayOps environment — 30 tasks across 4 difficulty tiers.
Difficulty tiers
----------------
easy – single clear signal; one-hop decision (6 tasks)
medium – ambiguous or competing signals; reasoning required (8 tasks)
hard – adversarial, conflicting, or edge-case patterns (10 tasks)
critical – multi-step investigation chains; regulatory compliance stakes (6 tasks)
Multi-step chains
-----------------
Tasks with chain_total > 1 require the agent to issue investigation sub-actions
(inspect / request_docs / verify_kyc / contact_sender) before a terminal decision.
Each chain step reveals progressively more context via the appropriate _reveal field.
The terminal decision is only scored on the final chain step.
Action costs
------------
Each investigation sub-action incurs a budget cost. If the agent exhausts the
budget (spend > budget_limit), a cumulative cost penalty is applied to the reward.
inspect → cost 0.1
request_docs → cost 0.2
verify_kyc → cost 0.2
contact_sender → cost 0.3
file_sar → cost 0.1 (required for structuring/AML — free if correct)
Reward structure per task
-------------------------
Each task defines:
correct_action – ground-truth terminal decision
partial_credit_actions – {action: fraction_of_full_credit}
requires_investigation – set of sub-actions ideally used before deciding
regulatory_action – if True, file_sar is a required prerequisite for full credit
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Set
@dataclass
class PayOpsTask:
# --- identity ---
task_id: str
difficulty: str # easy | medium | hard | critical
description: str
# --- transaction fields ---
transaction_id: str
amount: float
currency: str
sender: str
receiver: str
transaction_type: str # transfer | payment | withdrawal | refund | internal | loan_repayment | payroll
# --- primary risk signals ---
risk_score: float # 0.0–1.0
ml_confidence: float = 0.90 # model's confidence in its own risk_score
flags: List[str] = field(default_factory=list)
# --- sender behaviour ---
velocity_1h: Optional[int] = None
velocity_24h: Optional[int] = None
avg_transaction_amount: Optional[float] = None
account_age_days: Optional[int] = None
# --- counterparty / geo ---
country_risk: Optional[str] = None # low | medium | high | sanctioned
kyc_status: Optional[str] = None # verified | pending | failed | none | expired
kyc_expiry_days: Optional[int] = None
previous_violations: Optional[int] = None
previous_sars: Optional[int] = None
counterparty_risk: Optional[str] = None # clean | unknown | watchlist | blacklist
# --- grading ---
correct_action: str = "approve"
partial_credit_actions: Dict[str, float] = field(default_factory=dict)
requires_investigation: Set[str] = field(default_factory=set)
# Set of sub-actions the agent SHOULD use for best score.
# Using them before the terminal decision grants a bonus (applied in grader).
regulatory_action: bool = False
# If True, filing a SAR is required to get full credit.
# --- investigation reveals (each unlocked by the matching sub-action) ---
inspect_reveal: Optional[str] = None
docs_reveal: Optional[str] = None
kyc_reveal: Optional[str] = None
contact_reveal: Optional[str] = None
# --- key diagnostic flags (used for flag-identification reward shaping) ---
key_flags: List[str] = field(default_factory=list)
# Subset of flags that are causally decisive for the correct_action.
# An agent that calls inspect AND those flags are in the observation
# receives an additional flag_identification bonus in the grader.
# --- network graph (mule chain / correspondent bank relationships) ---
network_graph: Optional[Dict[str, str]] = None
# Optional dict mapping roles to entity IDs, e.g.:
# {"sender": "acc_123", "mule": "acc_456", "offshore": "bank_789"}
# Exposed in observation so agents can reason about chains.
# --- multi-step chain metadata ---
chain_total: int = 1
# chain_total > 1 means the task spans multiple investigation steps.
# The grader only scores the terminal decision on the last chain step.
@property
def grader(self) -> dict:
"""Grader configuration for this task.
Exposed as a computed property so platform validators that import
``TASKS`` from tasks.py can discover grader configs via ``task.grader``.
"""
return {
"enabled": True,
"type": "action_match",
"correct_action": self.correct_action,
"partial_credit": dict(self.partial_credit_actions),
"requires_investigation": list(self.requires_investigation),
"regulatory_action": self.regulatory_action,
"key_flags": list(self.key_flags),
}
# =============================================================================
# EASY (4 tasks — single clear signal)
# =============================================================================
EASY_TASKS: List[PayOpsTask] = [
PayOpsTask(
task_id="EASY-001",
difficulty="easy",
description="Low-value domestic transfer between two long-standing verified users. No flags.",
transaction_id="TXN-E001",
amount=47.50,
currency="USD",
sender="alice@example.com",
receiver="bob@example.com",
transaction_type="transfer",
risk_score=0.05,
ml_confidence=0.97,
flags=[],
velocity_1h=1, velocity_24h=3,
avg_transaction_amount=55.0,
account_age_days=1_095,
country_risk="low", kyc_status="verified", kyc_expiry_days=320,
previous_violations=0, previous_sars=0, counterparty_risk="clean",
correct_action="approve",
partial_credit_actions={}, # no partial credit — clear approve, wrong actions penalised
inspect_reveal="Sender account 3 yrs old. Consistent transaction history. KYC fully verified.",
key_flags=[],
),
PayOpsTask(
task_id="EASY-002",
difficulty="easy",
description="Textbook fraud: unknown sender, offshore, sanctioned country, risk=0.97.",
transaction_id="TXN-E002",
amount=9_800.00,
currency="USD",
sender="unknown_user_x99",
receiver="offshore_acct_442",
transaction_type="transfer",
risk_score=0.97,
ml_confidence=0.95,
flags=["high_value", "unknown_sender", "offshore_receiver", "sanctioned_country"],
velocity_1h=12, velocity_24h=28,
avg_transaction_amount=None,
account_age_days=2,
country_risk="sanctioned", kyc_status="none", kyc_expiry_days=None,
previous_violations=3, previous_sars=1, counterparty_risk="blacklist",
correct_action="reject",
partial_credit_actions={"escalate": 0.4}, # flag removed — textbook fraud needs decisive action
inspect_reveal="Receiver linked to 3 prior rejected transactions. IP on threat-intel blocklist.",
key_flags=["sanctioned_country", "unknown_sender"],
network_graph={"sender": "unknown_user_x99", "offshore": "offshore_acct_442"},
),
PayOpsTask(
task_id="EASY-003",
difficulty="easy",
description="Standard refund to a verified customer. Tiny amount, no flags.",
transaction_id="TXN-E003",
amount=12.99,
currency="USD",
sender="shop@retailer.com",
receiver="carol@customer.com",
transaction_type="refund",
risk_score=0.03,
ml_confidence=0.98,
flags=[],
velocity_1h=1, velocity_24h=5,
avg_transaction_amount=14.0,
account_age_days=730,
country_risk="low", kyc_status="verified", kyc_expiry_days=180,
previous_violations=0, previous_sars=0, counterparty_risk="clean",
correct_action="approve",
partial_credit_actions={}, # no partial credit — tiny refund, no flags, flagging is wrong
inspect_reveal="Standard return via web checkout. Matching order ID on file. No anomalies.",
key_flags=[],
),
PayOpsTask(
task_id="EASY-004",
difficulty="easy",
description="ATM withdrawal burst — 15 withdrawals in 58 minutes across 4 ATMs. Velocity violation.",
transaction_id="TXN-E004",
amount=200.00,
currency="USD",
sender="david@accounts.com",
receiver="atm_node_77",
transaction_type="withdrawal",
risk_score=0.78,
ml_confidence=0.89,
flags=["velocity_breach", "atm_burst"],
velocity_1h=15, velocity_24h=17,
avg_transaction_amount=80.0,
account_age_days=540,
country_risk="medium", kyc_status="verified", kyc_expiry_days=90,
previous_violations=0, previous_sars=0, counterparty_risk="unknown",
correct_action="flag",
partial_credit_actions={"escalate": 0.6, "hold": 0.5},
inspect_reveal="15 ATM withdrawals in 58 min across 4 ATMs. Pattern consistent with card clone.",
key_flags=["velocity_breach"],
),
PayOpsTask(
task_id="EASY-005",
difficulty="easy",
description="Scheduled monthly mortgage repayment. Regular amount, verified on-time borrower, no flags.",
transaction_id="TXN-E005",
amount=1_247.00,
currency="USD",
sender="john.doe@homeowner.com",
receiver="mortgages@national-bank.com",
transaction_type="loan_repayment",
risk_score=0.03,
ml_confidence=0.99,
flags=[],
velocity_1h=1, velocity_24h=1,
avg_transaction_amount=1_247.00,
account_age_days=1_825,
country_risk="low", kyc_status="verified", kyc_expiry_days=280,
previous_violations=0, previous_sars=0, counterparty_risk="clean",
correct_action="approve",
partial_credit_actions={},
inspect_reveal="Loan account in good standing. Payment 22 of 360. Amount matches amortization schedule exactly.",
key_flags=[],
),
PayOpsTask(
task_id="EASY-006",
difficulty="easy",
description="Suspected duplicate payment: same sender, receiver, and amount submitted twice within 4 minutes.",
transaction_id="TXN-E006",
amount=523.50,
currency="USD",
sender="vendor@supplies-ltd.com",
receiver="buyer@procurement.com",
transaction_type="payment",
risk_score=0.55,
ml_confidence=0.91,
flags=["duplicate_transaction", "velocity_breach"],
velocity_1h=2, velocity_24h=3,
avg_transaction_amount=520.0,
account_age_days=980,
country_risk="low", kyc_status="verified", kyc_expiry_days=150,
previous_violations=0, previous_sars=0, counterparty_risk="clean",
correct_action="flag",
partial_credit_actions={"hold": 0.6},
inspect_reveal="TXN-E006-prev processed 4 min ago for identical amount and beneficiary. Duplicate submission detected — flag for double-charge review before releasing.",
key_flags=["duplicate_transaction"],
),
]
# =============================================================================
# MEDIUM (8 tasks — ambiguous, multi-signal)
# =============================================================================
MEDIUM_TASKS: List[PayOpsTask] = [
PayOpsTask(
task_id="MED-001",
difficulty="medium",
description="Large B2B wire. Verified CFO. Cross-border to medium-risk EU jurisdiction.",
transaction_id="TXN-M001",
amount=85_000.00,
currency="EUR",
sender="cfo@globalcorp.com",
receiver="vendor@eu-supplier.de",
transaction_type="transfer",
risk_score=0.52,
ml_confidence=0.72,
flags=["high_value", "cross_border"],
velocity_1h=2, velocity_24h=4,
avg_transaction_amount=45_000.0,
account_age_days=2_190,
country_risk="medium", kyc_status="verified", kyc_expiry_days=200,
previous_violations=0, previous_sars=0, counterparty_risk="clean",
correct_action="escalate",
partial_credit_actions={"flag": 0.5, "hold": 0.4},
requires_investigation={"inspect"},
inspect_reveal="Contract on file for €85k milestone. Receiver is licensed EU entity. Quarterly vendor pattern.",
key_flags=["cross_border", "high_value"],
),
PayOpsTask(
task_id="MED-002",
difficulty="medium",
description="Internal treasury transfer. Large amount. KYC pending renewal — risk is procedural, not fraud.",
transaction_id="TXN-M002",
amount=250_000.00,
currency="USD",
sender="treasury@holdco.com",
receiver="subsidiary@holdco-us.com",
transaction_type="internal",
risk_score=0.41,
ml_confidence=0.78,
flags=["high_value", "kyc_expiry_90d"],
velocity_1h=1, velocity_24h=2,
avg_transaction_amount=200_000.0,
account_age_days=3_650,
country_risk="low", kyc_status="pending", kyc_expiry_days=5,
previous_violations=0, previous_sars=0, counterparty_risk="clean",
correct_action="hold",
partial_credit_actions={"escalate": 0.6, "flag": 0.4},
requires_investigation={"verify_kyc"},
kyc_reveal="KYC renewal submitted 10 days ago. Both accounts share same UBO. Transfer aligns with Q1 plan.",
key_flags=["kyc_expiry_90d"],
),
PayOpsTask(
task_id="MED-003",
difficulty="medium",
description="Subscription payment 3× historical average. Possible upgrade billing or card compromise.",
transaction_id="TXN-M003",
amount=449.97,
currency="USD",
sender="eve@subscriber.com",
receiver="billing@saas-platform.com",
transaction_type="payment",
risk_score=0.44,
ml_confidence=0.68,
flags=["amount_spike", "pattern_deviation"],
velocity_1h=1, velocity_24h=1,
avg_transaction_amount=149.99,
account_age_days=820,
country_risk="low", kyc_status="verified", kyc_expiry_days=150,
previous_violations=0, previous_sars=0, counterparty_risk="clean",
correct_action="flag",
partial_credit_actions={"hold": 0.5, "escalate": 0.3},
inspect_reveal="Historical monthly charge $149.99. This charge = 3-month annual upgrade. Merchant confirmation pending.",
key_flags=["amount_spike", "pattern_deviation"],
),
PayOpsTask(
task_id="MED-004",
difficulty="medium",
description="Payment to regulated crypto exchange. Moderate risk. Sender has clean history.",
transaction_id="TXN-M004",
amount=5_000.00,
currency="USD",
sender="frank@personal.com",
receiver="exchange@cryptovault.io",
transaction_type="payment",
risk_score=0.58,
ml_confidence=0.74,
flags=["crypto_exchange", "high_value"],
velocity_1h=1, velocity_24h=2,
avg_transaction_amount=2_000.0,
account_age_days=1_460,
country_risk="medium", kyc_status="verified", kyc_expiry_days=270,
previous_violations=0, previous_sars=0, counterparty_risk="unknown",
correct_action="flag",
partial_credit_actions={"escalate": 0.5, "hold": 0.4},
inspect_reveal="Exchange licensed in sender's jurisdiction. Sender made 4 similar payments over 6 months. Within limits.",
key_flags=["crypto_exchange"],
),
PayOpsTask(
task_id="MED-005",
difficulty="medium",
description="Expired KYC on a high-frequency corporate account. Routine transactions continue but KYC lapsed 12 days ago.",
transaction_id="TXN-M005",
amount=28_000.00,
currency="GBP",
sender="payments@logistics-uk.com",
receiver="driver-pool@payroll.co.uk",
transaction_type="payroll",
risk_score=0.38,
ml_confidence=0.82,
flags=["kyc_expired", "high_value"],
velocity_1h=1, velocity_24h=6,
avg_transaction_amount=26_000.0,
account_age_days=1_800,
country_risk="low", kyc_status="expired", kyc_expiry_days=-12,
previous_violations=0, previous_sars=0, counterparty_risk="clean",
correct_action="hold",
partial_credit_actions={"flag": 0.5, "escalate": 0.4},
requires_investigation={"verify_kyc"},
kyc_reveal="KYC expired 12 days ago due to administrative oversight. Re-submission in progress. No fraud indicators.",
key_flags=["kyc_expired"],
),
PayOpsTask(
task_id="MED-006",
difficulty="medium",
description="Real estate advance payment. Large amount. First payment to this receiver but contract exists.",
transaction_id="TXN-M006",
amount=120_000.00,
currency="USD",
sender="buyer@realestate-client.com",
receiver="escrow@property-agent.co",
transaction_type="transfer",
risk_score=0.56,
ml_confidence=0.65,
flags=["high_value", "first_time_payee", "large_first_transfer"],
velocity_1h=1, velocity_24h=1,
avg_transaction_amount=5_000.0,
account_age_days=2_555,
country_risk="medium", kyc_status="verified", kyc_expiry_days=90,
previous_violations=0, previous_sars=0, counterparty_risk="unknown",
correct_action="escalate",
partial_credit_actions={"flag": 0.4, "hold": 0.5},
requires_investigation={"request_docs"},
docs_reveal="Signed purchase agreement found. Escrow agent licensed and registered. Standard conveyancing practice.",
key_flags=["first_time_payee", "large_first_transfer"],
),
PayOpsTask(
task_id="MED-007",
difficulty="medium",
description=(
"Supplier emails to say bank details have changed; first payment to the "
"new account matches a large outstanding invoice. Classic BEC indicator."
),
transaction_id="TXN-M007",
amount=43_800.00,
currency="EUR",
sender="accounts@client-corp.de",
receiver="supplier-newacct@euro-clearing.eu",
transaction_type="payment",
risk_score=0.63,
ml_confidence=0.67,
flags=["bank_detail_change", "first_time_payee", "high_value"],
velocity_1h=1, velocity_24h=1,
avg_transaction_amount=44_000.0,
account_age_days=1_200,
country_risk="medium", kyc_status="verified", kyc_expiry_days=130,
previous_violations=0, previous_sars=0, counterparty_risk="unknown",
correct_action="hold",
partial_credit_actions={"escalate": 0.6, "flag": 0.4},
requires_investigation={"request_docs", "contact_sender"},
docs_reveal="Email requesting bank change was sent from supplier-noreply@euro-cIearing.eu (capital I, not l). No signed bank-change authorisation on file. Possible BEC.",
contact_reveal="Called original supplier contact number on record. They confirmed they did NOT send a bank-change notice. BEC fraud confirmed — hold and alert client.",
key_flags=["bank_detail_change", "first_time_payee"],
),
PayOpsTask(
task_id="MED-008",
difficulty="medium",
description=(
"Buy Now Pay Later purchase: high-value electronics order, account opened "
"3 weeks ago, thin credit file, elevated risk signals."
),
transaction_id="TXN-M008",
amount=2_899.00,
currency="USD",
sender="bnpl-platform@payin4.io",
receiver="electronics@megastore.com",
transaction_type="payment",
risk_score=0.60,
ml_confidence=0.71,
flags=["thin_credit_file", "high_value_bnpl", "new_account"],
velocity_1h=1, velocity_24h=2,
avg_transaction_amount=None,
account_age_days=21,
country_risk="low", kyc_status="pending", kyc_expiry_days=None,
previous_violations=0, previous_sars=0, counterparty_risk="clean",
correct_action="flag",
partial_credit_actions={"hold": 0.6, "escalate": 0.4},
requires_investigation={"verify_kyc"},
kyc_reveal="KYC check: identity document submitted but address verification failed — billing address does not match ID. BNPL fraud profile. Flag for manual identity review before releasing funds.",
key_flags=["thin_credit_file", "new_account"],
),
]
# =============================================================================
# HARD (10 tasks — adversarial, conflicting, edge-cases)
# =============================================================================
HARD_TASKS: List[PayOpsTask] = [
PayOpsTask(
task_id="HARD-001",
difficulty="hard",
description="ML model poisoning: risk_score=0.18 but manual flags scream fraud. Agent must override the model.",
transaction_id="TXN-H001",
amount=47_000.00,
currency="GBP",
sender="grace@newaccount.co.uk",
receiver="payee@solicitor-uk.com",
transaction_type="transfer",
risk_score=0.18, # poisoned — deliberately underscored
ml_confidence=0.31, # low confidence signals model uncertainty
flags=["new_account_7d", "large_first_transfer", "solicitor_mule_pattern"],
velocity_1h=1, velocity_24h=1,
avg_transaction_amount=None,
account_age_days=7,
country_risk="low", kyc_status="pending", kyc_expiry_days=None,
previous_violations=0, previous_sars=0, counterparty_risk="watchlist",
correct_action="escalate",
partial_credit_actions={"flag": 0.6, "hold": 0.5, "reject": 0.3},
requires_investigation={"inspect"},
inspect_reveal=(
"Account 7 days old. First outbound transfer. Receiver matches solicitor-impersonation "
"mule pattern from last month's intelligence bulletin. ML underscored — new clean account."
),
key_flags=["solicitor_mule_pattern"],
),
PayOpsTask(
task_id="HARD-002",
difficulty="hard",
description="APP scam: victim willingly sending money but has been social-engineered. Receiver is a mule.",
transaction_id="TXN-H002",
amount=12_500.00,
currency="GBP",
sender="henry@victim-bank.co.uk",
receiver="mule_relay_2287@fastpay.io",
transaction_type="transfer",
risk_score=0.61,
ml_confidence=0.77,
flags=["app_scam_indicator", "mule_account_pattern", "first_time_payee"],
velocity_1h=1, velocity_24h=1,
avg_transaction_amount=300.0,
account_age_days=3_285,
country_risk="medium", kyc_status="verified", kyc_expiry_days=180,
previous_violations=0, previous_sars=0, counterparty_risk="blacklist",
correct_action="reject",
partial_credit_actions={"escalate": 0.6, "hold": 0.5, "flag": 0.3},
requires_investigation={"contact_sender"},
contact_reveal=(
"Sender says they were called by someone claiming to be their bank. "
"Instructed to move savings to a 'safe account'. Classic APP scam confirmed."
),
key_flags=["app_scam_indicator", "mule_account_pattern"],
network_graph={"victim": "henry@victim-bank.co.uk", "mule": "mule_relay_2287@fastpay.io"},
),
PayOpsTask(
task_id="HARD-003",
difficulty="hard",
description="Structuring/smurfing: just-below-CTR-threshold payments from same beneficial owner across accounts.",
transaction_id="TXN-H003",
amount=9_450.00, # just below $10k CTR threshold
currency="USD",
sender="irene_acct_A@shadow.net",
receiver="irene_acct_B@shadow.net",
transaction_type="transfer",
risk_score=0.71,
ml_confidence=0.83,
flags=["structuring_pattern", "same_ubo", "ctr_threshold_avoidance", "high_value"],
velocity_1h=3, velocity_24h=9,
avg_transaction_amount=9_200.0,
account_age_days=120,
country_risk="high", kyc_status="failed", kyc_expiry_days=None,
previous_violations=2, previous_sars=1, counterparty_risk="watchlist",
correct_action="reject",
partial_credit_actions={"escalate": 0.5, "flag": 0.2},
requires_investigation={"inspect"},
regulatory_action=True,
inspect_reveal=(
"3 transactions in 24h: $9,450 + $9,200 + $9,100 from related accounts. "
"Same UBO. KYC failed on inconsistent ID docs. Classic CTR structuring."
),
key_flags=["structuring_pattern", "ctr_threshold_avoidance"],
network_graph={"node_a": "irene_acct_A@shadow.net", "node_b": "irene_acct_B@shadow.net", "ubo": "irene_ubo"},
),
PayOpsTask(
task_id="HARD-004",
difficulty="hard",
description="Legitimate FX settlement: huge amount, looks alarming — is a standard correspondent banking transfer.",
transaction_id="TXN-H004",
amount=4_200_000.00,
currency="USD",
sender="nostro@bank-a-swift.com",
receiver="vostro@bank-b-swift.com",
transaction_type="internal",
risk_score=0.67,
ml_confidence=0.58, # model uncertain on legitimate large transfers
flags=["high_value", "cross_border", "fx_settlement"],
velocity_1h=8, velocity_24h=24,
avg_transaction_amount=3_900_000.0,
account_age_days=7_300,
country_risk="medium", kyc_status="verified", kyc_expiry_days=400,
previous_violations=0, previous_sars=0, counterparty_risk="clean",
correct_action="approve",
partial_credit_actions={"escalate": 0.5, "hold": 0.4, "flag": 0.3},
requires_investigation={"inspect"},
inspect_reveal=(
"Both SWIFT BIC-verified. Part of daily USD/EUR FX settlement cycle. "
"8 similar settlements this month, all cleared. Nostro/vostro agreement on file."
),
key_flags=["fx_settlement"],
network_graph={"correspondent": "nostro@bank-a-swift.com", "settlement": "vostro@bank-b-swift.com"},
),
PayOpsTask(
task_id="HARD-005",
difficulty="hard",
description=(
"Insider threat: employee of the bank initiating an unauthorised wire "
"to their personal account, disguised as a vendor payment."
),
transaction_id="TXN-H005",
amount=22_000.00,
currency="USD",
sender="staff_ops@bank-internal.com",
receiver="jake.smith.personal@gmail.com",
transaction_type="payment",
risk_score=0.54,
ml_confidence=0.61,
flags=["internal_to_personal", "unusual_beneficiary", "after_hours"],
velocity_1h=1, velocity_24h=1,
avg_transaction_amount=75_000.0,
account_age_days=2_000,
country_risk="low", kyc_status="verified", kyc_expiry_days=240,
previous_violations=0, previous_sars=0, counterparty_risk="unknown",
correct_action="escalate",
partial_credit_actions={"flag": 0.5, "hold": 0.4, "reject": 0.3},
requires_investigation={"inspect", "contact_sender"},
inspect_reveal=(
"Initiation time: 11:47 PM. No vendor contract matches this beneficiary. "
"Staff member placed on PIP last week. Receiver email matches staff home address."
),
contact_reveal=(
"Staff member claims it is a legitimate vendor. Unable to provide contract reference. "
"Story changes on follow-up. Escalate to HR and Fraud immediately."
),
key_flags=["internal_to_personal", "unusual_beneficiary"],
),
PayOpsTask(
task_id="HARD-006",
difficulty="hard",
description=(
"Ghost account: receiver account was dormant for 5 years and suddenly "
"received 20 inbound transfers this week. Possible account takeover."
),
transaction_id="TXN-H006",
amount=3_200.00,
currency="EUR",
sender="layla@verified-sender.eu",
receiver="old_dormant_acct_889@bank.eu",
transaction_type="transfer",
risk_score=0.63,
ml_confidence=0.69,
flags=["dormant_receiver", "sudden_activity", "high_inbound_velocity"],
velocity_1h=1, velocity_24h=3,
avg_transaction_amount=800.0,
account_age_days=890,
country_risk="medium", kyc_status="verified", kyc_expiry_days=60,
previous_violations=0, previous_sars=0, counterparty_risk="unknown",
correct_action="flag",
partial_credit_actions={"hold": 0.6, "escalate": 0.5},
requires_investigation={"inspect"},
inspect_reveal=(
"Receiver dormant 5 years. 20 inbound transfers this week totalling €64k. "
"All immediately forwarded offshore. Classic money-mule account reactivation."
),
key_flags=["dormant_receiver", "sudden_activity"],
),
PayOpsTask(
task_id="HARD-007",
difficulty="hard",
description=(
"SIM-swap attack: account holder's phone number was ported to a new SIM "
"6 hours ago; account now requesting a large crypto withdrawal to a new address."
),
transaction_id="TXN-H007",
amount=14_200.00,
currency="USD",
sender="crypto-user@exchange.io",
receiver="external-wallet-9f3a@coldwallet.net",
transaction_type="withdrawal",
risk_score=0.74,
ml_confidence=0.78,
flags=["sim_swap_detected", "new_withdrawal_address", "high_value"],
velocity_1h=1, velocity_24h=1,
avg_transaction_amount=500.0,
account_age_days=620,
country_risk="low", kyc_status="verified", kyc_expiry_days=195,
previous_violations=0, previous_sars=0, counterparty_risk="unknown",
correct_action="reject",
partial_credit_actions={"hold": 0.5, "escalate": 0.4, "flag": 0.3},
requires_investigation={"inspect", "contact_sender"},
inspect_reveal=(
"Telecom provider confirmed: SIM swap on this account's registered phone "
"completed 6 h 12 min ago. External wallet address first appeared in this "
"session only. IP geolocation mismatch vs prior 90-day baseline."
),
contact_reveal=(
"Attempted call to registered phone: intercepted by new SIM holder, "
"who provided all correct security answers (likely obtained via social "
"engineering). Account holder unreachable on backup email. SIM-swap "
"takeover confirmed — reject and lock account."
),
key_flags=["sim_swap_detected", "new_withdrawal_address"],
),
PayOpsTask(
task_id="HARD-008",
difficulty="hard",
description=(
"Romance scam / pig butchering: customer making 4th escalating transfer "
"to an overseas 'romantic partner' met on a dating app 7 weeks ago. "
"Amounts have doubled each time."
),
transaction_id="TXN-H008",
amount=8_000.00,
currency="USD",
sender="victim@personal-bank.com",
receiver="crypto-invest@hongkong-fund.net",
transaction_type="transfer",
risk_score=0.66,
ml_confidence=0.73,
flags=["romance_scam_indicator", "escalating_transfers", "offshore_receiver"],
velocity_1h=1, velocity_24h=1,
avg_transaction_amount=1_200.0,
account_age_days=4_015,
country_risk="high", kyc_status="verified", kyc_expiry_days=220,
previous_violations=0, previous_sars=0, counterparty_risk="blacklist",
correct_action="reject",
partial_credit_actions={"hold": 0.5, "escalate": 0.4, "flag": 0.3},
requires_investigation={"contact_sender", "inspect"},
contact_reveal=(
"Spoke with account holder. They believe they are investing with a "
"partner they met on a dating app. Prior transfers: $500, $1,000, $4,000. "
"Receiver domain registered 3 months ago. Pig-butchering romance scam confirmed."
),
inspect_reveal=(
"Transfer history: $500 → $1,000 → $4,000 → $8,000 over 7 weeks. "
"Receiver account linked to 23 other inbound romance-scam reports in the "
"financial intelligence database. All prior transfers drained offshore within hours."
),
key_flags=["romance_scam_indicator", "escalating_transfers"],
network_graph={"victim": "victim@personal-bank.com", "scammer_fund": "crypto-invest@hongkong-fund.net"},
),
PayOpsTask(
task_id="HARD-009",
difficulty="hard",
description=(
"Synthetic identity fraud: new business account with a flawless-looking "
"profile (perfect score, clean history) requests a large first outbound "
"wire within 10 days of opening."
),
transaction_id="TXN-H009",
amount=19_500.00,
currency="USD",
sender="newco-llc@startup-bank.com",
receiver="vendor@offshore-services.biz",
transaction_type="transfer",
risk_score=0.35,
ml_confidence=0.40, # low confidence: model flagging identity inconsistency
flags=["new_account_10d", "perfect_score_anomaly", "large_first_wire"],
velocity_1h=1, velocity_24h=1,
avg_transaction_amount=None,
account_age_days=10,
country_risk="medium", kyc_status="verified", kyc_expiry_days=360,
previous_violations=0, previous_sars=0, counterparty_risk="unknown",
correct_action="escalate",
partial_credit_actions={"hold": 0.5, "flag": 0.4, "reject": 0.3},
requires_investigation={"verify_kyc", "inspect"},
kyc_reveal=(
"KYC documents re-examined: EIN was issued 11 days ago but the 'years "
"in business' field on the application states 4 years. Registered address "
"is a UPS store mailbox. Director SSN belongs to a real person with no "
"knowledge of this LLC. Synthetic identity confirmed."
),
inspect_reveal=(
"Account ML confidence flagged as low: identity features are statistically "
"perfect (no noise in credit history, address, DOB fields) — consistent "
"with synthetically generated identity. Escalate for manual identity verification."
),
key_flags=["new_account_10d", "perfect_score_anomaly"],
),
PayOpsTask(
task_id="HARD-010",
difficulty="hard",
description=(
"Payroll diversion: HR system breach rerouted an employee's salary to "
"a newly added bank account 2 days ago. Employee has not been notified."
),
transaction_id="TXN-H010",
amount=5_640.00,
currency="USD",
sender="payroll@employer-corp.com",
receiver="new-acct-redirect@routing-bank.com",
transaction_type="payroll",
risk_score=0.58,
ml_confidence=0.63,
flags=["direct_deposit_changed", "recent_account_change", "payroll_diversion_indicator"],
velocity_1h=1, velocity_24h=1,
avg_transaction_amount=5_640.0,
account_age_days=2_920,
country_risk="low", kyc_status="verified", kyc_expiry_days=180,
previous_violations=0, previous_sars=0, counterparty_risk="unknown",
correct_action="reject",
partial_credit_actions={"hold": 0.5, "escalate": 0.4, "flag": 0.3},
requires_investigation={"inspect", "contact_sender"},
inspect_reveal=(
"HR system audit: direct deposit account changed 2 days ago via an "
"unrecognized IP at 2:14 AM. Employee's primary device was offline at the "
"time. No 2FA challenge was issued. Account change was unauthorized."
),
contact_reveal=(
"Reached employee by mobile: they confirm they did NOT change their "
"direct deposit account. Did not receive any email or SMS about the "
"change. HR system credentials were likely phished. Reject this payroll "
"disbursement and revert to prior account."
),
key_flags=["direct_deposit_changed", "payroll_diversion_indicator"],
),
]
# =============================================================================
# CRITICAL (6 tasks — multi-step chains, regulatory stakes)
# =============================================================================
CRITICAL_TASKS: List[PayOpsTask] = [
PayOpsTask(
task_id="CRIT-001",
difficulty="critical",
description=(
"Multi-step investigation: large wire to a new counterparty. "
"Agent must inspect logs, then request supporting documents, "
"then make a final decision. Chain of 3 steps."
),
transaction_id="TXN-C001",
amount=375_000.00,
currency="USD",
sender="deal-team@pe-firm.com",
receiver="newco@acquisition-target.io",
transaction_type="transfer",
risk_score=0.59,
ml_confidence=0.55,
flags=["high_value", "first_time_payee", "cross_border", "new_counterparty"],
velocity_1h=1, velocity_24h=2,
avg_transaction_amount=50_000.0,
account_age_days=3_000,
country_risk="medium", kyc_status="verified", kyc_expiry_days=120,
previous_violations=0, previous_sars=0, counterparty_risk="unknown",
correct_action="approve",
partial_credit_actions={"escalate": 0.5, "hold": 0.4, "flag": 0.3},
requires_investigation={"inspect", "request_docs"},
chain_total=3,
inspect_reveal="PE firm confirmed. Series B investment round. Deal announced in press last week.",
docs_reveal="Signed SPA (Share Purchase Agreement) on file. Notarised. Receiver is the acquisition target.",
key_flags=["first_time_payee", "new_counterparty"],
),
PayOpsTask(
task_id="CRIT-002",
difficulty="critical",
description=(
"Fraud ring: three related accounts sending coordinated small payments "
"that aggregate above the reporting threshold. Requires SAR filing."
),
transaction_id="TXN-C002",
amount=4_900.00,
currency="USD",
sender="ring_node_1@tempmail.com",
receiver="collector_hub@offshore.net",
transaction_type="transfer",
risk_score=0.76,
ml_confidence=0.80,
flags=["fraud_ring_indicator", "coordinated_transfers", "threshold_avoidance", "high_value"],
velocity_1h=5, velocity_24h=18,
avg_transaction_amount=4_800.0,
account_age_days=45,
country_risk="high", kyc_status="failed", kyc_expiry_days=None,
previous_violations=1, previous_sars=0, counterparty_risk="blacklist",
correct_action="reject",
partial_credit_actions={"escalate": 0.4, "flag": 0.2},
requires_investigation={"inspect"},
regulatory_action=True,
chain_total=2,
inspect_reveal=(
"3 accounts (ring_node_1/2/3) sending $4,900 / $4,850 / $4,750 simultaneously. "
"All created same day. Receiver account drained offshore within minutes. "
"SAR filing required under BSA §5318(g)."
), key_flags=["fraud_ring_indicator", "coordinated_transfers"],
network_graph={"ring_1": "ring_node_1@tempmail.com", "ring_2": "ring_node_2", "collector": "collector_hub@offshore.net"}, ),
PayOpsTask(
task_id="CRIT-003",
difficulty="critical",
description=(
"Trade-based money laundering: over- and under-invoiced international trade payments. "
"Documents don't match transfer amounts. Regulatory escalation required."
),
transaction_id="TXN-C003",
amount=680_000.00,
currency="USD",
sender="importer@trade-co.hk",
receiver="exporter@goods-supplier.cn",
transaction_type="payment",
risk_score=0.72,
ml_confidence=0.67,
flags=["trade_finance", "invoice_mismatch", "cross_border", "high_value"],
velocity_1h=1, velocity_24h=3,
avg_transaction_amount=120_000.0,
account_age_days=730,
country_risk="high", kyc_status="verified", kyc_expiry_days=30,
previous_violations=1, previous_sars=0, counterparty_risk="watchlist",
correct_action="escalate",
partial_credit_actions={"flag": 0.4, "hold": 0.35, "reject": 0.3},
requires_investigation={"request_docs", "inspect"},
regulatory_action=True,
chain_total=3,
docs_reveal="Invoice declares 500 units @ $1,360 each = $680k. Market price is $320/unit. 4× over-invoiced.",
inspect_reveal="Shipping records show only 200 units dispatched. Payment/goods ratio 3.4× above market norm.",
key_flags=["invoice_mismatch", "trade_finance"],
network_graph={"importer": "importer@trade-co.hk", "exporter": "exporter@goods-supplier.cn"},
),
PayOpsTask(
task_id="CRIT-004",
difficulty="critical",
description=(
"Compromised corporate account: valid credentials but geo-impossible login. "
"Someone in Nigeria logged into a US-only account 8 minutes after the CEO logged out in NY."
),
transaction_id="TXN-C004",
amount=198_000.00,
currency="USD",
sender="ceo@target-corp.com",
receiver="urgent-wire@third-party-finance.com",
transaction_type="transfer",
risk_score=0.81,
ml_confidence=0.85,
flags=["geo_impossible_login", "account_takeover_indicator", "high_value", "urgency_flag"],
velocity_1h=1, velocity_24h=1,
avg_transaction_amount=15_000.0,
account_age_days=4_380,
country_risk="high", kyc_status="verified", kyc_expiry_days=365,
previous_violations=0, previous_sars=0, counterparty_risk="unknown",
correct_action="reject",
partial_credit_actions={"escalate": 0.5, "hold": 0.4},
requires_investigation={"inspect", "contact_sender"},
chain_total=2,
inspect_reveal=(
"Last login: NY (US) at 14:23. This session: Lagos (NG) at 14:31. "
"Physical travel impossible in 8 minutes. Likely credential compromise."
),
contact_reveal="CEO confirms they did NOT initiate this transfer. Account takeover confirmed.",
key_flags=["geo_impossible_login", "account_takeover_indicator"],
),
PayOpsTask(
task_id="CRIT-005",
difficulty="critical",
description=(
"OFAC sanctions evasion: large USD payment routed through a UAE shell "
"company chain. Investigation reveals the ultimate beneficial owner is "
"on the OFAC Specially Designated Nationals (SDN) list."
),
transaction_id="TXN-C005",
amount=490_000.00,
currency="USD",
sender="uae-trading@al-rashid-fze.ae",
receiver="intermediary@gulf-clearing-bv.nl",
transaction_type="transfer",
risk_score=0.69,
ml_confidence=0.60,
flags=["high_value", "cross_border", "shell_company_indicator", "sanctions_adjacent"],
velocity_1h=1, velocity_24h=2,
avg_transaction_amount=380_000.0,
account_age_days=180,
country_risk="high", kyc_status="verified", kyc_expiry_days=45,
previous_violations=0, previous_sars=0, counterparty_risk="watchlist",
correct_action="reject",
partial_credit_actions={"escalate": 0.5, "hold": 0.4},
requires_investigation={"inspect", "verify_kyc", "request_docs"},
regulatory_action=True,
chain_total=3,
inspect_reveal=(
"Corporate registry search: al-rashid-fze.ae incorporated 6 months ago. "
"Sole director: a nominee agent used by 47 other FZE shells. Beneficial "
"ownership records absent. Payment routed via 3 intermediate entities "
"before reaching the UAE sender — classic sanctions-evasion layering."
),
kyc_reveal=(
"UBO lookup via SWIFT KYC Registry and Refinitiv: ultimate beneficial "
"owner resolves to Tariq Al-Mansouri, listed on OFAC SDN list since 2021 "
"(Ref: SDN-2021-04-19-TM). Transacting with this UBO violates 31 C.F.R. "
"§ 594. Reject immediately and file SAR."
),
docs_reveal=(
"Provided trade invoice shows goods described as 'industrial equipment'. "
"HS code used (8479.89) does not match the attached packing list. "
"Likely misclassification to obscure dual-use goods export controls."
),
key_flags=["shell_company_indicator", "sanctions_adjacent"],
network_graph={
"sender_shell": "al-rashid-fze.ae",
"intermediary": "gulf-clearing-bv.nl",
"ubo_sdn": "Tariq Al-Mansouri",
},
),
PayOpsTask(
task_id="CRIT-006",
difficulty="critical",
description=(
"Correspondent banking alert: a downstream correspondent partner bank "
"was added to FinCEN's 311 Special Measures list yesterday. Payments "
"routed through them are now legally restricted."
),
transaction_id="TXN-C006",
amount=215_000.00,
currency="USD",
sender="trade-desk@our-bank.com",
receiver="correspondent@partner-bank-latam.bz",
transaction_type="transfer",
risk_score=0.71,
ml_confidence=0.65,
flags=["fincen_311_alert", "correspondent_risk", "high_value", "cross_border"],
velocity_1h=3, velocity_24h=12,
avg_transaction_amount=200_000.0,
account_age_days=2_100,
country_risk="high", kyc_status="verified", kyc_expiry_days=20,
previous_violations=0, previous_sars=0, counterparty_risk="watchlist",
correct_action="escalate",
partial_credit_actions={"hold": 0.5, "reject": 0.4},
requires_investigation={"inspect", "request_docs"},
regulatory_action=True,
chain_total=2,
inspect_reveal=(
"FinCEN Section 311 Special Measure imposed 2024-04-01 on partner-bank-latam.bz "
"for 'primary money laundering concern'. Special Measure 5 prohibits US "
"correspondent accounts and payable-through accounts. All in-flight wires "
"must be escalated to Compliance before release — unilateral rejection "
"also requires Compliance sign-off (may breach existing agreements)."
),
docs_reveal=(
"Correspondent agreement review: clause 12.3 requires 90-day wind-down "
"notice before terminating the relationship. Legal and Compliance must "
"jointly approve next steps. Escalate immediately — do not reject or "
"approve without written senior Compliance authorisation."
),
key_flags=["fincen_311_alert", "correspondent_risk"],
network_graph={
"our_bank": "trade-desk@our-bank.com",
"correspondent": "partner-bank-latam.bz",
},
),
]
# =============================================================================
# Combine all tasks
# =============================================================================
TASKS: List[PayOpsTask] = EASY_TASKS + MEDIUM_TASKS + HARD_TASKS + CRITICAL_TASKS
TASKS_BY_ID: Dict[str, PayOpsTask] = {t.task_id: t for t in TASKS}
# ---------------------------------------------------------------------------
# Action cost table (investigation sub-actions consume budget)
# ---------------------------------------------------------------------------
ACTION_COSTS: Dict[str, float] = {
"approve": 0.0,
"reject": 0.0,
"flag": 0.0,
"escalate": 0.0,
"hold": 0.0,
"inspect": 0.10,
"request_docs": 0.20,
"verify_kyc": 0.20,
"contact_sender": 0.30,
"file_sar": 0.05, # intentionally cheap — incentivise regulatory compliance
}
# ---------------------------------------------------------------------------
# Task variant pools — anti-memorisation & investigation-gating
# ---------------------------------------------------------------------------
# Each entry is a list of override dicts for alternative scenarios of that task.
# Variant index 0 always means "use base task" (no overrides applied).
# Variants 1..N override the fields listed, so the correct_action is only
# determinable after performing the required investigation sub-actions.
# The variant is selected deterministically from the episode seed in environment.py.
#
# Key design constraint: the BASE observation (pre-investigation) must be
# genuinely ambiguous — investigation reveals ARE the decisive evidence.
# ---------------------------------------------------------------------------
TASK_VARIANTS: Dict[str, List[Dict]] = {
# ── EASY ──────────────────────────────────────────────────────────────
"EASY-001": [
# v1: account accessed from unknown device just before transfer → hold
{
"correct_action": "hold",
"partial_credit_actions": {"flag": 0.6, "escalate": 0.3},
"flags": ["unusual_login_location", "device_change"],
"risk_score": 0.61,
"inspect_reveal": (
"Sender logged in from an unrecognized device in a different country "
"18 minutes ago. Possible account takeover. All signals otherwise "
"identical. Hold pending confirmation with account holder."
),
},
# v2: amount exceeds sender's daily limit for new payee → flag
{
"correct_action": "flag",
"partial_credit_actions": {"hold": 0.6, "approve": 0.2},
"flags": ["first_time_payee", "amount_spike"],
"risk_score": 0.44,
"inspect_reveal": (
"Bob is a new payee — first time ever on this account. System "
"limit for first-time payees is $25. Transfer amount $47.50 exceeds "
"new-payee daily cap. Flag for standard new-payee challenge-and-confirm."
),
},
],
"EASY-002": [
# v1: signals are real but entity is a licensed MSB with OFAC authorisation → escalate
{
"correct_action": "escalate",
"partial_credit_actions": {"reject": 0.4, "hold": 0.3},
"inspect_reveal": (
"Sender is a licensed Money Service Business (MSB) with a FinCEN "
"registration number and a current OFAC sanctions-compliance programme. "
"The 'sanctioned country' flag was triggered by destination country "
"of receiver's beneficial owner, but this MSB holds a specific OFAC "
"licence for this corridor. Escalate for senior review rather than "
"unilateral reject."
),
},
# v2: additional money mule node detected → reject + SAR
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.5},
"regulatory_action": True,
"inspect_reveal": (
"Receiver account linked to 6 prior confirmed fraud rejections this "
"quarter, totalling $58k. New network node in a known mule ring. "
"All prior transfers drained offshore within 30 minutes. Reject "
"immediately and file SAR."
),
},
],
"EASY-003": [
# v1: refund issued to a different card than the original purchase → flag
{
"correct_action": "flag",
"partial_credit_actions": {"hold": 0.5, "escalate": 0.3},
"flags": ["refund_mismatch", "different_card"],
"risk_score": 0.52,
"inspect_reveal": (
"Original purchase was made on Visa ending 4412. Refund is being "
"issued to Mastercard ending 7891 — a different card not on file for "
"this order. Possible refund fraud. Flag for merchant verification "
"before processing."
),
},
# v2: refund claimed on a fraudulent chargeback dispute → reject
{
"correct_action": "reject",
"partial_credit_actions": {"flag": 0.5, "escalate": 0.3},
"flags": ["chargeback_fraud", "dispute_open"],
"risk_score": 0.68,
"inspect_reveal": (
"Customer filed a chargeback claiming non-receipt. Courier tracking "
"shows package delivered and signed for 3 days ago. Customer's "
"claimed delivery address matches the signature. Friendly fraud — "
"reject refund and respond to chargeback with delivery evidence."
),
},
],
"EASY-004": [
# v1: card-cloning confirmed by bank intelligence → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.5, "flag": 0.4},
"inspect_reveal": (
"Cross-check with card-fraud intelligence feed: the card number "
"involved in this ATM burst matches a batch of 340 card numbers "
"from a point-of-sale skimming incident reported yesterday. Confirmed "
"card-clone attack. Reject all withdrawals and block card immediately."
),
},
# v2: legitimate end-of-month cash distribution for a small cash-and-carry → approve
{
"correct_action": "approve",
"partial_credit_actions": {"flag": 0.3},
"inspect_reveal": (
"Account holder is a licensed cash-and-carry wholesaler. Same "
"end-of-month ATM burst pattern appears in 11 of the last 12 months — "
"consistent with weekly cash float replenishment for their 4 shop "
"locations. No fraud intelligence matches. Approve."
),
},
],
"EASY-005": [
# v1: loan account in arrears, payment covers only partial balance → flag
{
"correct_action": "flag",
"partial_credit_actions": {"hold": 0.5, "approve": 0.3},
"amount": 650.00,
"flags": ["partial_payment", "loan_arrears"],
"risk_score": 0.38,
"inspect_reveal": (
"Loan account 2 months in arrears. Required minimum payment is "
"$1,247 but sender submitted $650. Partial payment does not clear "
"the overdue balance. Flag for borrower contact and payment plan "
"communication before crediting."
),
},
# v2: overpayment submitted — process normally but note discrepancy → approve
{
"correct_action": "approve",
"partial_credit_actions": {"flag": 0.3},
"amount": 2_500.00,
"flags": ["overpayment"],
"risk_score": 0.08,
"inspect_reveal": (
"Borrower submitted $2,500 vs scheduled $1,247. Overpayments are "
"permitted under the loan agreement (clause 8.2) and reduce principal "
"balance. No fraud indicators. Approve and apply excess to principal."
),
},
],
"EASY-006": [
# v1: genuine re-submission after first instance failed → approve
{
"correct_action": "approve",
"partial_credit_actions": {"flag": 0.4},
"flags": ["resubmission"],
"risk_score": 0.18,
"inspect_reveal": (
"First submission (4 min ago) failed with a bank routing error "
"(error code: ROUTE-001 — invalid sort code format). This is a valid "
"resubmission with corrected routing. No double-charge risk. Approve."
),
},
# v2: vendor-side system error caused 8 duplicate submissions → hold
{
"correct_action": "hold",
"partial_credit_actions": {"flag": 0.6},
"velocity_1h": 8,
"flags": ["duplicate_transaction", "velocity_breach", "api_error_burst"],
"risk_score": 0.72,
"inspect_reveal": (
"Vendor payment API experienced a timeout loop at 14:02. 8 identical "
"payment submissions in 5 minutes from the same API key. Only 1 "
"should be processed. Hold all 8; contact vendor to identify the "
"canonical intended payment before releasing any."
),
},
],
# ── MEDIUM ────────────────────────────────────────────────────────────
"MED-001": [
# v1: CEO impersonation (BEC) — fraudulent wire instruction → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.5, "hold": 0.4},
"flags": ["high_value", "cross_border", "bec_indicator"],
"risk_score": 0.74,
"inspect_reveal": (
"The CFO's email domain in the wire instructions is globalcorp.co "
"(note: .co not .com). CFO's actual domain is globalcorp.com. "
"Phone verification: real CFO is on holiday and did NOT authorise "
"this transfer. Business Email Compromise confirmed — reject."
),
},
# v2: contract and counterparty fully verified → approve
{
"correct_action": "approve",
"partial_credit_actions": {"escalate": 0.3, "flag": 0.2},
"inspect_reveal": (
"Vendor contract on file, signed 3 months ago (ref VC-EUR-0712). "
"Receiver is an EU-licensed entity (UID DE315441892). Payment matches "
"milestone 2 of 4. CFO confirmed by phone. Cross-border and amount "
"are within normal operating parameters. Approve."
),
},
],
"MED-002": [
# v1: KYC re-check reveals UBO mismatch → escalate
{
"correct_action": "escalate",
"partial_credit_actions": {"hold": 0.5, "flag": 0.3},
"kyc_reveal": (
"KYC renewal triggered a UBO re-check. Companies House filing shows "
"the ultimate beneficial owner changed 3 months ago to a holding "
"company domiciled in a secrecy jurisdiction, without bank "
"notification. Material KYC change — escalate for enhanced due "
"diligence before releasing any treasury transfers."
),
},
# v2: board resolution authorises emergency liquidity transfer → approve
{
"correct_action": "approve",
"partial_credit_actions": {"hold": 0.4},
"kyc_reveal": (
"KYC renewal: both entities share the same UBO (verified). Pending "
"status is purely administrative — renewal submitted 6 days ago, "
"no change of ownership. Board resolution ref BR-2024-Q1-08 "
"authorises this emergency liquidity transfer. Approve."
),
},
],
"MED-003": [
# v1: unauthorised recurring billing → hold
{
"correct_action": "hold",
"partial_credit_actions": {"flag": 0.5, "escalate": 0.3},
"inspect_reveal": (
"Merchant billing records show 3 prior declined charges this month "
"from different cards linked to the same subscriber IP. Pattern is "
"consistent with credential stuffing / unauthorised recurring charge. "
"Freeze payment and contact customer before releasing."
),
},
# v2: confirmed annual plan upgrade → approve
{
"correct_action": "approve",
"partial_credit_actions": {"flag": 0.3},
"inspect_reveal": (
"Customer service log: subscriber upgraded to annual plan via phone "
"this morning. $449.97 = 3 × monthly fee (annual discount applied). "
"Merchant has confirmed the charge. Safe to approve."
),
},
],
"MED-004": [
# v1: structuring pattern across exchanges → escalate
{
"correct_action": "escalate",
"partial_credit_actions": {"flag": 0.5, "hold": 0.3},
"inspect_reveal": (
"Sender has made 7 crypto exchange payments in 5 days totalling $28k "
"across 3 different platforms. Amounts stay just below exchange "
"reporting limits. Pattern matches structuring. Escalate for AML review."
),
},
# v2: clean recurring investment → approve
{
"correct_action": "approve",
"partial_credit_actions": {"flag": 0.3},
"inspect_reveal": (
"Sender's 3-year payment history shows consistent quarterly crypto "
"purchases of similar size. Exchange is fully regulated and KYC-verified. "
"Amount within personal investment limits. No structuring indicators. Approve."
),
},
],
"MED-005": [
# v1: KYC discrepancy found → escalate
{
"correct_action": "escalate",
"partial_credit_actions": {"flag": 0.5, "hold": 0.3},
"kyc_reveal": (
"KYC expired because the compliance team found discrepancies between "
"the business registration address and Companies House records. The "
"case has been flagged for investigation by the KYC team. Escalate — "
"do not approve or hold without senior sign-off."
),
},
# v2: KYC renewed, routine payroll → approve
{
"correct_action": "approve",
"partial_credit_actions": {"hold": 0.4},
"kyc_reveal": (
"KYC renewal was submitted 10 days ago and completed processing "
"yesterday. All checks passed. The lapse was an administrative "
"oversight only. Payroll has an 18-month history with no anomalies. "
"Approve and process."
),
},
],
"MED-006": [
# v1: forged purchase agreement → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.4, "flag": 0.3},
"docs_reveal": (
"Purchase agreement is a forgery: the notary seal serial number "
"does not exist in the notary registry; the property title number "
"returns no match in Land Registry; the 'escrow agent' is not "
"registered with the Council for Licensed Conveyancers. "
"Classic conveyancing fraud — reject immediately."
),
},
# v2: title dispute — hold pending resolution
{
"correct_action": "hold",
"partial_credit_actions": {"escalate": 0.5, "flag": 0.3},
"docs_reveal": (
"SPA is authentic and escrow agent is licensed. However, a co-owner "
"has filed a title dispute on the property. The buyer's solicitor "
"advises funds should be held in escrow until the dispute is resolved "
"(expected 3–4 weeks). Hold pending legal clearance."
),
},
],
"MED-007": [
# v1: genuine bank account change, properly authorised → approve
{
"correct_action": "approve",
"partial_credit_actions": {"hold": 0.5, "flag": 0.3},
"docs_reveal": (
"Signed bank-change authorisation letter provided on supplier "
"letterhead, with notarised director signature matching KYC records. "
"Called supplier finance director on known contact number — confirmed "
"the account change. New account is registered to the same company. "
"Approve."
),
"contact_reveal": (
"Original supplier contact verified the bank change was genuine — "
"they switched banks last month due to a merger. Reference number "
"SBC-2024-0312 matches their internal change management log."
),
},
# v2: multiple lookalike invoice redirect emails sent to same client → escalate
{
"correct_action": "escalate",
"partial_credit_actions": {"hold": 0.5, "reject": 0.4},
"docs_reveal": (
"Client reports receiving 3 lookalike invoice redirect emails in 2 "
"weeks from slightly different supplier domains. Two payments to "
"prior redirect accounts were already processed (total €87k). This "
"is a systematic BEC campaign targeting this client relationship. "
"Escalate to fraud and financial crime team immediately."
),
"contact_reveal": (
"Genuine supplier finance director: they have sent zero bank-change "
"notices this year. The lookalike domain was registered 3 weeks ago. "
"Client's email system has been compromised. Escalate."
),
},
],
"MED-008": [
# v1: KYC passes, address verified — legitimate BNPL purchase → approve
{
"correct_action": "approve",
"partial_credit_actions": {"flag": 0.4},
"kyc_reveal": (
"KYC recheck: address verification passed on second attempt — "
"customer had entered a unit number incorrectly. Identity document "
"authentic. Credit bureau confirms thin file is consistent with "
"a first-time credit applicant (age 22). No fraud indicators. "
"Approve BNPL transaction."
),
},
# v2: device fingerprint linked to BNPL fraud network → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.5, "hold": 0.4},
"kyc_reveal": (
"Device fingerprint matches 14 prior BNPL fraud applications across "
"3 platforms in the last 6 weeks. All 14 prior accounts defaulted on "
"first instalment. Identity documents were synthetically generated. "
"Reject and blacklist device fingerprint."
),
},
],
# ── HARD ──────────────────────────────────────────────────────────────
"HARD-001": [
# v1: deeper forensics confirm active fraud ring → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.5, "flag": 0.3},
"inspect_reveal": (
"Cross-database query: same receiver account (payee@solicitor-uk.com) "
"appeared in 4 prior rejected fraud wires this quarter, total £190k. "
"Funds clear to offshore within 45 min each time. ML score was "
"deliberately poisoned via clean-account seeding. Reject immediately."
),
},
# v2: flags are false positives, ML score correct → approve
{
"correct_action": "approve",
"partial_credit_actions": {"escalate": 0.4, "flag": 0.3},
"inspect_reveal": (
"Manual flag investigation: 'solicitor_mule_pattern' rule mis-fired "
"on a legitimate SRA-registered firm (reg. SRA-443210) that rebranded "
"last month, causing a new account. 'New_account_7d' flag triggered "
"by the rebrand. ALL flags are false positives. ML risk score 0.18 is "
"accurate. Safe to approve."
),
},
],
"HARD-002": [
# v1: new legitimate supplier, flags were incorrect → approve
{
"correct_action": "approve",
"partial_credit_actions": {"flag": 0.4, "hold": 0.3},
"contact_reveal": (
"Sender confirmed: mule_relay_2287@fastpay.io is their new supplier "
"in Singapore. The VPN flagged by geo-risk monitoring is the company's "
"standard corporate security policy. Purchase order #PO-44821 is on "
"file matching the amount. Safe to approve."
),
},
# v2: inconsistent story, AML review needed → escalate
{
"correct_action": "escalate",
"partial_credit_actions": {"reject": 0.4, "flag": 0.3},
"contact_reveal": (
"Contacted sender: story is vague and inconsistent across two "
"follow-up calls. Cannot confirm supplier identity. No purchase order "
"provided. The receiver's business registration cannot be located. "
"Cannot approve or reject — escalate to AML for investigation."
),
},
],
"HARD-003": [
# v1: confirmed structuring but scale needs MLRO → escalate
{
"correct_action": "escalate",
"partial_credit_actions": {"reject": 0.5, "flag": 0.3},
"inspect_reveal": (
"Pattern strongly resembles CTR structuring. However, the total "
"aggregate ($27,750) and the involvement of 3 related entities "
"means this crosses the threshold for mandatory MLRO referral under "
"internal policy. Escalate rather than unilaterally reject."
),
},
# v2: same UBO transfers are authorised corporate restructuring → hold
{
"correct_action": "hold",
"partial_credit_actions": {"reject": 0.4, "escalate": 0.5},
"inspect_reveal": (
"Same-UBO transfers are documented in a board resolution dated last "
"week authorising an internal corporate restructuring. KYC failure "
"was due to an ID document resubmission still in queue. Structuring "
"indicators are coincidental. Hold pending KYC re-verification."
),
},
],
"HARD-004": [
# v1: unrecognised SWIFT BIC, potential impersonation → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.5, "flag": 0.3},
"inspect_reveal": (
"SWIFT BIC vostro@bank-b-swift.com resolved to a bank that does NOT "
"appear in the correspondent banking agreement registry. The BIC is "
"visually similar to a legitimate bank (one character substituted). "
"Likely impersonation of a correspondent partner — reject and alert."
),
},
# v2: ghost employees detected → flag for payroll audit
{
"correct_action": "flag",
"partial_credit_actions": {"approve": 0.5, "hold": 0.4},
"inspect_reveal": (
"FX settlement accounts are SWIFT-verified and legitimate. However, "
"the initiating staff workflow shows this $4.2M wire was split from "
"a larger batch that included 2 non-existent internal accounts. "
"Flag for payroll/treasury audit before releasing."
),
},
],
"HARD-005": [
# v1: confirmed insider fraud, no response from staff → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.5, "flag": 0.3},
"contact_reveal": (
"Staff member's phone is disconnected; email bounced. HR confirms "
"the employee was placed on garden leave 2 days ago pending "
"investigation. Receiver account drained offshore within hours of "
"prior similar payments. Insider fraud confirmed — reject and freeze."
),
},
# v2: authorized vendor payment, staff working late → approve
{
"correct_action": "approve",
"partial_credit_actions": {"escalate": 0.4, "flag": 0.3},
"contact_reveal": (
"Staff member confirmed: personal Gmail was added as a forwarding "
"alias last month when the vendor switched to a personal invoicing "
"service. Contract reference VC-2024-189 verified by procurement. "
"After-hours initiation matches remote work schedule. Approve."
),
},
],
"HARD-006": [
# v1: confirmed active mule network → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.5, "flag": 0.4},
"inspect_reveal": (
"Receiver account confirmed to be receiving from 12 other dormant "
"accounts this week (total €78k). All funds exit to the same offshore "
"cluster within 2 hours. Active money-mule aggregation network. "
"Reject and file SAR immediately."
),
},
# v2: estate probate settlement, legitimate reactivation → escalate
{
"correct_action": "escalate",
"partial_credit_actions": {"flag": 0.6, "hold": 0.4},
"inspect_reveal": (
"Account was frozen under a probate order that was lifted 3 days ago. "
"Estate settlement documentation is on file. Amount (€3,200) is "
"consistent with a partial distribution from the estate. Legitimate "
"reactivation — escalate for senior approval given the reactivation flag."
),
},
],
"HARD-007": [
# v1: SIM was ported by legitimate account holder (travelling) → hold
{
"correct_action": "hold",
"partial_credit_actions": {"escalate": 0.5, "reject": 0.4},
"inspect_reveal": (
"Telecom records: SIM swap was initiated via the carrier's verified "
"app using biometric authentication. Account holder is overseas and "
"replaced a broken SIM abroad. No third-party involvement detected. "
"New withdrawal address is a cold storage wallet previously linked "
"to the account. Hold briefly for confirmation call."
),
"contact_reveal": (
"Reached account holder on a backup email. They confirm the SIM swap "
"and the withdrawal are legitimate. They are in Japan and broke their "
"phone. Hold approved — confirm by secure callback before releasing."
),
},
# v2: no response from account holder, third-party SIM swap confirmed → reject
{
"correct_action": "reject",
"partial_credit_actions": {"hold": 0.4, "escalate": 0.5},
"contact_reveal": (
"Account holder unreachable on all registered contact methods. "
"Carrier fraud team confirmed: SIM swap was initiated via a social "
"engineering call to a customer service agent — not by the account "
"holder. No biometric authentication used. Third-party SIM swap "
"confirmed. Reject and lock account."
),
},
],
"HARD-008": [
# v1: customer is aware it's high-risk investment but not a scam → escalate
{
"correct_action": "escalate",
"partial_credit_actions": {"reject": 0.4, "hold": 0.4},
"contact_reveal": (
"Customer is fully aware of the risk and has a history of crypto "
"investing. The 'romantic partner' is actually a friend from a "
"verified online investment forum. Prior transfers were legitimate "
"investments that returned profit. However, the escalating pattern "
"and offshore destination warrant senior review. Escalate."
),
"inspect_reveal": (
"Transaction history: prior 3 payments were invested and partially "
"returned. Receiver fund has a verifiable online presence (2 years). "
"However, the most recent dormancy of returns and amount escalation "
"match late-stage pig-butchering conversion. Escalate for human review."
),
},
# v2: scam confirmed, customer is distressed victim → reject
{
"correct_action": "reject",
"partial_credit_actions": {"hold": 0.4, "escalate": 0.3},
"contact_reveal": (
"Customer broke down on the call. They have now been blocked by the "
"'romantic partner' and cannot reach them. They realise they have been "
"scammed. All prior funds ($5,500) are lost. Reject this transfer, "
"file SAR, and refer customer to scam recovery support."
),
},
],
"HARD-009": [
# v1: new tech entrepreneur, thin file is legitimate → approve
{
"correct_action": "approve",
"partial_credit_actions": {"hold": 0.5, "escalate": 0.4},
"kyc_reveal": (
"KYC deep-dive: EIN issued 11 days ago but LLC was pre-registered "
"90 days ago (formation date vs EIN issuance differ — normal for new "
"companies). Registered address is a co-working space (common for "
"startups). Director SSN cross-check passsed. Wire is to a verified "
"software vendor (AWS partner). Thin file is genuine, not synthetic. "
"Approve."
),
"inspect_reveal": (
"ML confidence flag was fired due to thin data, not anomalous data. "
"No features match synthetic identity profile (all values have "
"natural variance). The 'perfect score anomaly' flag was a false "
"positive from the rule engine. Safe to approve."
),
},
# v2: identity confirmed as synthetic via government database check → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.4, "hold": 0.3},
"kyc_reveal": (
"IRS TIN matching service: EIN does not match the business name in "
"the IRS database. SSN belongs to a deceased individual. Address is "
"a virtual office with no physical occupancy. Synthetic identity "
"confirmed. Reject all transactions and report to FinCEN."
),
},
],
"HARD-010": [
# v1: employee did change their account (legitimate, notified HR verbally) → approve
{
"correct_action": "approve",
"partial_credit_actions": {"hold": 0.5, "flag": 0.4},
"inspect_reveal": (
"HR audit: account change was requested by the employee at HR's "
"'walk-in' desk 3 days ago. The change was logged manually by an "
"HR admin and entered into the system at 2:10 AM during the overnight "
"batch. Unusual timestamp is from the batch processor, not an "
"attacker. Legitimate change confirmed."
),
"contact_reveal": (
"Employee confirms: they switched to a new bank and submitted the "
"form in person. Was not aware any notification would be sent. "
"Batch processing time was confusing but legitimate. Approve."
),
},
# v2: HR credentials were phished, second employee already victimised → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.5, "hold": 0.4},
"inspect_reveal": (
"HR system audit: same rogue IP (185.220.101.x — known Tor exit node) "
"changed direct deposit accounts for 3 employees overnight. Two "
"employees have already confirmed they did not make changes. Payroll "
"diversion campaign in progress. Reject all affected disbursements "
"and freeze HR system access."
),
},
],
# ── CRITICAL ──────────────────────────────────────────────────────────
"CRIT-001": [
# v1: deepfake deal, BEC fraud → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.4, "hold": 0.35, "flag": 0.3},
"inspect_reveal": (
"PE firm name verified but domain is a typo-squatting lookalike "
"(pe-flrm.com vs pe-firm.com). No SEC filing exists for this deal. "
"The 'press announcement' URL leads to a page created 6 days ago. "
"Classic BEC / CEO impersonation fraud."
),
"docs_reveal": (
"'Signed SPA' is a doctored template — notarization certificate "
"serial number LN-2024-00512 does not exist in the notary registry. "
"Acquisition is fabricated. Reject and alert security team."
),
},
# v2: legitimate deal, wrong destination account → hold
{
"correct_action": "hold",
"partial_credit_actions": {"approve": 0.4, "escalate": 0.5},
"inspect_reveal": (
"PE firm and deal confirmed as genuine (SEC filing #0001234567). "
"Press announcement verified with three external sources. Acquisition "
"is legitimate. However, the destination account does not match the "
"independent escrow account specified in clause 7.3 of the SPA."
),
"docs_reveal": (
"SPA authenticated by legal team. Per clause 7.3, all milestone "
"payments must route to independent escrow account "
"escrow@trustco-escrow.com, not directly to the acquisition target. "
"Hold and redirect to the correct escrow account."
),
},
],
"CRIT-002": [
# v1: same SME multiple business accounts — coincidental threshold → hold
{
"correct_action": "hold",
"partial_credit_actions": {"reject": 0.5, "escalate": 0.4},
"inspect_reveal": (
"The 3 flagged accounts all belong to the same registered SME "
"(Companies House reg. 09876543) using separate business accounts "
"for different cost centres. The $4,900 pattern matches their "
"internal expense approval limit — not structuring intent. "
"KYC re-verification recommended before releasing. Hold."
),
},
# v2: ring is larger (9 accounts), MLRO escalation needed → escalate
{
"correct_action": "escalate",
"partial_credit_actions": {"reject": 0.5, "flag": 0.3},
"inspect_reveal": (
"Network analysis reveals the ring involves 9 accounts total (not 3), "
"all created on the same day, all funnelling to the same offshore "
"collector. Aggregate total is $42k. Volume and complexity require "
"MLRO involvement and a formal SAR — escalate rather than unilaterally reject."
),
},
],
"CRIT-003": [
# v1: legitimate specialized goods, market price correct → approve
{
"correct_action": "approve",
"partial_credit_actions": {"escalate": 0.5, "hold": 0.3},
"docs_reveal": (
"Independent commodity valuation confirms: these are custom precision "
"industrial components for semiconductor manufacturing. Verified market "
"price: $1,310–1,420 per unit. Invoice price of $1,360 is within "
"normal range. No mismatch. Documentation is clean."
),
"inspect_reveal": (
"Full shipping manifest verified: 500 units dispatched per bill of "
"lading BoL-HK-2024-8821. Customs clearance certified in both "
"Hong Kong and the destination country. No discrepancies."
),
},
# v2: criminal-scale TBML → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.5, "flag": 0.3},
"docs_reveal": (
"Invoice declares 500 units @ $1,360 = $680k. Independent valuation: "
"market price is $250/unit. Over-invoiced by 5.4×. Matches a "
"trade-based money laundering typology filed with FATF last year. "
"Criminal-level TBML — reject and file SAR immediately."
),
"inspect_reveal": (
"Shipping records show only 100 units dispatched vs 500 invoiced. "
"Invoice-to-goods ratio 5.4× above market. Direct evidence of false "
"customs declarations. Reject immediately."
),
},
],
"CRIT-004": [
# v1: CEO delegated to CFO who was in Lagos → hold for confirmation
{
"correct_action": "hold",
"partial_credit_actions": {"escalate": 0.5, "reject": 0.4},
"inspect_reveal": (
"Geo-impossible login flagged. However, a delegation email from the "
"CEO was sent 2 hours ago via their verified corporate account granting "
"the CFO emergency signing authority for this exact transfer. "
"CFO was in Lagos for a board meeting (flight records available). "
),
"contact_reveal": (
"CEO confirmed via secure callback: CFO had full authority to initiate "
"this transfer. Delegation is documented in the board minutes. "
"Hold briefly to verify the papertrail, then release."
),
},
# v2: CEO unreachable, audit trail ambiguous → escalate
{
"correct_action": "escalate",
"partial_credit_actions": {"reject": 0.5, "hold": 0.4},
"inspect_reveal": (
"Account takeover strongly suspected. CEO's registered number is "
"unreachable (OOO message). However, the transfer went through the "
"standard dual-approval workflow with two internal approvers (both "
"records look genuine). Outcome ambiguous — escalate to Fraud "
"Operations for emergency investigation."
),
"contact_reveal": (
"Cannot reach CEO. Deputy CFO states they approved the transfer but "
"cannot confirm whether the CEO or an impersonator initiated it. "
"Escalate immediately to Fraud Ops and place a temporary hold."
),
},
],
"CRIT-005": [
# v1: shell layers cleared, legitimate commodity trade → approve
{
"correct_action": "approve",
"partial_credit_actions": {"escalate": 0.5, "hold": 0.4},
"inspect_reveal": (
"UAE FZE registration traced through 3 layers: ultimate beneficial "
"owner is a listed European industrial group (Frankfurt Stock Exchange: "
"DXI.DE). No SDN or PEP matches. Shell structure is standard for "
"legitimate UAE free-zone trading entities. All FATF risk factors "
"cleared by AML team. Approve."
),
"kyc_reveal": (
"UBO lookup: al-Rashid FZE is a subsidiary of Deutsche Xport Industries "
"AG, a publicly listed entity. No sanctions exposure. KYC pack complete "
"and verified. Trade invoice amount matches published commodity prices."
),
"docs_reveal": (
"Trade invoice and shipping manifest verified. HS code 8479.89 matches "
"industrial mixing equipment — no dual-use export restrictions apply. "
"All documentation clean. Approve."
),
},
# v2: SDN match confirmed at deeper UBO level → reject
{
"correct_action": "reject",
"partial_credit_actions": {"escalate": 0.4, "hold": 0.3},
"inspect_reveal": (
"Shell chain traced: al-rashid-fze.ae → Gibraltar holding → BVI "
"nominee → Tariq Al-Mansouri (OFAC SDN since 2021, Ref SDN-2021-04-19). "
"3-layer obfuscation structure is classic sanctions evasion. Reject "
"and report to OFAC within 10 business days."
),
"kyc_reveal": (
"UBO confirmed as Tariq Al-Mansouri via FinScan premium SDN database "
"cross-reference. Transacting with this UBO violates 31 C.F.R. § 594. "
"Reject immediately and file SAR with FinCEN."
),
},
],
"CRIT-006": [
# v1: FinCEN notice is a false positive — different bank with same name → approve
{
"correct_action": "approve",
"partial_credit_actions": {"hold": 0.5, "escalate": 0.4},
"inspect_reveal": (
"FinCEN 311 action reviewed: the targeted bank is 'Global Partner Bank "
"of Belize', ABA 082901987. Our correspondent is 'Partner Bank of Latin "
"America, Belize', ABA 082901462 — a distinct entity. The alert was "
"triggered by a partial name match. Our correspondent is not subject "
"to the 311 measure. Approve with a compliance memo on file."
),
"docs_reveal": (
"SWIFT BIC PTBZBZBZ confirmed as Partner Bank of Latin America — "
"no sanctions linkage. Legal confirmed no restriction applies to "
"this specific correspondent relationship. Approve this payment and "
"update the name-match rule to prevent future false positives."
),
},
# v2: FinCEN 311 applies, must cease all correspondent transactions → escalate
{
"correct_action": "escalate",
"partial_credit_actions": {"hold": 0.5, "reject": 0.4},
"inspect_reveal": (
"FinCEN 311 Special Measure 5 confirmed as applicable to our "
"correspondent (partner-bank-latam.bz, SWIFT PTBZBZBZ). All US "
"dollar correspondent and payable-through accounts must be closed "
"within 30 days. In-flight transactions require Compliance authorisation. "
"Escalate immediately — unilateral rejection may breach our "
"contractual wind-down obligations."
),
"docs_reveal": (
"Correspondent agreement clause 12.3 requires 90-day written wind-down "
"notice. FinCEN has set a 30-day compliance deadline creating a "
"legal conflict. Legal and Compliance must jointly manage the "
"resolution. Escalate with full documentation."
),
},
],
}