bank-fraud / fraud-example.md
root
init
942b115
|
Raw
History Blame Contribute Delete
3.92 kB

Triggering a fraud alert (demo/test guide)

The model learned one dominant signature from PaySim: a TRANSFER or CASH_OUT that drains an account to exactly zero β€” amount == old balance and new balance == 0. That pattern alone (regardless of the actual amount, RWF 181 or RWF 275,000) is what pushes the fraud probability toward 1.0 and the risk tier to high. PAYMENT, CASH_IN, and DEBIT transactions, and any partial (non-draining) transfer, score low almost every time β€” those are the two fraud-prone types identified in reports/EDA_REPORT.md.

1. Trigger it through the client UI (easiest, no raw PaySim fields needed)

The client-facing form (/client/transactions/new) only asks for type, amount, destination account, and date β€” balances are derived server-side from the account's real running balance. To reproduce the fraud pattern:

  1. Log in as a client (or have an officer create one via /officer/clients first).
  2. Note the account's current balance shown on /client (e.g. RWF 5,000).
  3. Go to /client/transactions/new.
  4. Type: Transfer (or Cash out)
  5. Amount: the exact current balance (e.g. 5000.00) β€” this drains the account to zero, the same signature real PaySim fraud rows have.
  6. Destination: anything, e.g. C_MULE_1
  7. Submit.

Expected result: risk_tier: "high", and the UI shows "This transaction is being reviewed for your security." An alert appears immediately on /officer/alerts and on the client's own /client/alerts.

A partial transfer (e.g. RWF 2,000 out of a RWF 5,000 balance) stays low-risk β€” it's the full drain to zero, not the size of the transaction, that the model keys on.

2. Trigger it directly against /api/predict (officer-only, raw PaySim fields)

Useful for testing the model in isolation without going through the account-balance flow. Requires an officer session.

curl -X POST http://127.0.0.1:8811/api/predict \
  -H "Content-Type: application/json" \
  -b "session_token=<officer session cookie>" \
  -d '{
    "step": 5,
    "type": "TRANSFER",
    "amount": 181.0,
    "nameOrig": "CFXFRAUD000A",
    "oldbalanceOrg": 181.0,
    "newbalanceOrig": 0.0,
    "nameDest": "CFXFRAUD000B",
    "oldbalanceDest": 0.0,
    "newbalanceDest": 0.0
  }'

Expect "risk_tier": "high" with probability close to 1.0, and the top SHAP features dominated by the balance-drain signal.

More fraud-triggering examples (any amount works, as long as it fully drains)

type amount oldbalanceOrg newbalanceOrig oldbalanceDest newbalanceDest
TRANSFER 181.00 181.00 0.00 0.00 0.00
TRANSFER 2,500.00 2,500.00 0.00 0.00 0.00
TRANSFER 50,000.00 50,000.00 0.00 0.00 0.00
TRANSFER 275,000.50 275,000.50 0.00 0.00 0.00
CASH_OUT 300.00 300.00 0.00 0.00 0.00
CASH_OUT 15,000.00 15,000.00 0.00 0.00 0.00

These are drawn straight from tests/fixtures/labeled_transactions.json (28 hand-labeled fraud fixtures in total β€” search for "expected_label": "fraud").

3. What does not trigger fraud (for contrast)

type amount oldbalanceOrg newbalanceOrig Expected
PAYMENT 45.00 5,000.00 4,955.00 low
TRANSFER 2,000.00 5,000.00 3,000.00 low (partial, not a drain)
CASH_IN 1,000.00 3,000.00 4,000.00 low
DEBIT 60.00 1,200.00 1,140.00 low

Reference

  • Alert threshold: FRAUD_ALERT_THRESHOLD=0.5 (probability above this becomes an alert)
  • Display risk tiers (independent of the alert threshold): low < 0.30, medium 0.30–0.70, high β‰₯ 0.70
  • Full model methodology: reports/MODEL_COMPARISON_conservative.md, reports/EDA_REPORT.md
  • Regenerate/inspect the full fixture set: python -m scripts.generate_fixtures, then tests/fixtures/labeled_transactions.json