Skip to content

Tuning and calibration

A rule is only as good as its numbers. Set a threshold too low and your analysts drown in alerts about ordinary customers; set it too high and real money laundering goes through unnoticed. This page explains how to find the right numbers and how to change them safely.

Problem What it looks like Cost
Too many false positives (rule too sensitive) Hundreds of alerts a day, almost all closed as “false positive” Analysts stop reading alerts properly; real cases get lost in the noise; SLAs are breached
Too many false negatives (rule too loose) Very few alerts; suspicious activity found later by other means Regulatory findings, unreported suspicious transactions, financial loss

Calibration is about finding the point where the rule catches what matters and your team can still work every alert properly.

  1. Start from what is normal for your customers. Look at the distribution of transaction amounts (or counts) for the segment the rule applies to. A threshold is usually set somewhere well above typical behaviour — for example around the top 1% of values — not at a round number picked from the air.
  2. Split by segment. Retail customers, small businesses, agents and corporates behave very differently. Most library rules take a segments[] parameter so you can apply them only to the group the threshold was designed for. Where segments need different numbers, create one rule per segment rather than one compromise number that suits nobody.
  3. Respect regulatory thresholds exactly. Where a number comes from regulation (for example the cash reporting threshold behind A2) take it from current FIC guidance, confirmed by your compliance officer — not from these docs.
  4. Write down why. Use the version’s change note to record where the number came from (“99th percentile of retail cash-in, Jan–Jun 2026”). Examiners ask, and you will forget.

Shadow mode: proving a change on live traffic

Section titled “Shadow mode: proving a change on live traffic”

Every rule can have two versions running at the same time:

  • the active version, which creates alerts as normal, and
  • a shadow version, which is checked against exactly the same live transactions and records what it would have flagged — but never creates alerts.

This lets you answer “what happens if I lower this threshold from GHS 50,000 to GHS 30,000?” with real data, without your analysts seeing a single extra alert.

Shadow hits are stored and marked as shadow, so you can compare them with the active version’s hits: how many more (or fewer) hits, on which customers, and whether the extra ones look genuinely suspicious. The rule’s page shows the live and shadow hit counts for the last 30 days side by side; a list of individual shadow hits isn’t on screen yet. The step-by-step guide is Shadow mode.

A shadow version only runs while its rule is running (switched on).

Backtesting: proving a change on past data

Section titled “Backtesting: proving a change on past data”

A backtest runs a rule version over up to 180 days of your own history and compares it with the live version: “this version would have produced 312 alerts last quarter instead of 540, on these customers, and these 41 alerts would no longer fire”. It works on drafts, on versions awaiting approval, on other parameter values and on unsaved rules in the builder, and it answers in minutes. Nothing goes live and no alert is raised.

Use backtests to choose a version, and shadow mode to confirm it on live traffic. A backtest can’t know everything live monitoring knows (for example when your analysts would have closed each alert); each result says exactly how it was computed. See Backtesting.

How to roll out a new rule or a change safely

Section titled “How to roll out a new rule or a change safely”

This is the process for both a brand-new rule and a change to an existing one. Editing a rule always creates a new version; the version that is running stays untouched until you replace it. The exact API calls for each step are in Tuning a rule and Shadow mode. For a brand-new custom rule, see Writing a custom rule, because a rule needs an active version before its shadow can run.

  1. Create a draft version. A rule author sets the parameters (or edits the CEL for a custom rule) and writes a change note explaining what changed and why.
  2. Check required fields. Confirm your integration sends every field the rule needs.
  3. Backtest it. Replay the last 90 to 180 days through the draft and compare it with the live version: the alert volume, the alerts that would no longer fire, and a sample of the new hits. Try other values if the result isn’t right. See Backtesting.
  4. Submit for approval. The version moves to pending approval. Mention the backtest in the change note; the approver can open it on the rule’s page.
  5. A second person approves it (4-eyes). Someone with the rule-approver permission — and who is not the person who created the version — reviews and approves or rejects it. SpeculaPro enforces this; you cannot approve your own version.
  6. Run it in shadow. Deploy the approved version to the rule’s shadow slot (the rule must be enabled). Leave it long enough to cover your business cycle.
  7. Compare. Look at shadow hits against the active version (or, for a new rule, simply at the shadow hits). Ask an experienced analyst to review a sample: would these have been worth investigating?
  8. Promote. Select Make live on the shadow version (it deploys it to the active slot). The shadow slot empties, and from now on its hits create alerts. Changes reach the running system within about 15 seconds.
  9. Watch the first weeks. Track alert volume and how alerts are closed. If most are closed as false positives, go back to step 1.

Every case is closed with a disposition. Cases closed as false_positive feed back into tuning statistics per rule. Look at them regularly:

What you see What it usually means What to try
One rule produces most of the false positives Threshold too low, or applied to the wrong segment Raise the threshold, or narrow the rule (for example channels on core.large_transaction)
False positives concentrated on a few known customers Their behaviour is legitimate but unusual (payroll, a wholesaler) A time-boxed suppression for that customer and rule, with a reason
A rule never fires Threshold too high, or missing data Check required fields first, then backtest a lower threshold, and confirm it in shadow
Many alerts but true positives are also high The rule is working; your team may be under-resourced Do not loosen a rule just to cut workload — talk to your MLRO

Where your workspace uses the AI assistant, a rule author can ask it to read these figures for one rule and suggest values worth testing. It suggests and changes nothing, and it sees only what analysts decided. See Suggestions from the AI assistant.

High-risk customers: lower thresholds everywhere (F3)

Section titled “High-risk customers: lower thresholds everywhere (F3)”

The library describes rule F3 as a multiplier on other rules’ parameters for customers rated high-risk: with a multiplier of 0.5, a customer rated high would trip a GHS 50,000 threshold at GHS 25,000. That design is planned.

The F3 that ships today, core.high_risk_customer, is simpler: it raises its own alert when a high-risk customer makes a transaction at or above its threshold. Until the multiplier arrives, you can get a similar effect by writing high-risk checks into a rule’s own expression, for example a lower threshold when customer.risk_rating == 'high'. See the CEL reference.

Using suppressions instead of loosening a rule

Section titled “Using suppressions instead of loosening a rule”

When a rule is right for almost everyone but wrong for a specific, understood case, do not change the rule — add a suppression. Suppressions are scoped (one rule, one customer, one customer + rule, or one customer–counterparty pair), always expire, need a reason and a second approver, and suppressed hits are still recorded for audit.

  • Leaving defaults in place. Covered above — every default is a placeholder.
  • One threshold for all segments. A wallet holder and a corporate customer should not share a “large transaction” threshold.
  • Skipping shadow because the change “is small”. Halving a window or changing a list can multiply alert volume.
  • Permanent suppressions in disguise. Renewing the same suppression every month for a year is a sign the rule’s segmentation is wrong.
  • Ignoring silent rules. A rule that has not fired in months is either perfectly tuned or broken. Check its required fields and test it in shadow with a lower threshold.
  • Not recording why. Every version has a change note. Use it.