Anti-money laundering

Declare the laundering rate, the typology mix and the hard negatives, then prove nothing else in the file looks like a crime.

Financial crime teams, model validators, and anyone benchmarking a detector

2M
transfers over 60,000 accounts
7.2 seconds
8,000
laundering transactions declared, and found
0 drift
1 node
largest component in the un-cased background
1,988,000 edges
0
cycles that nobody declared
proved, not sampled

The problem

Real transaction data cannot leave the bank, and the part that could would not help anyway: nobody knows which of its rows are laundering. Institutions have alerts, and alerts are a detector's opinion, not the truth.

So the number every AML programme is judged on, the false positive rate, is measured against labels that were themselves produced by a detector. The measurement and the thing being measured share an error.

Why the usual answer falls short

The established answer is simulation. AMLworld, from IBM Research and ETH Zurich (NeurIPS 2023), grows an agent-based economy and labels what its agents do. It is careful work and it produces complete labels, which is a real advance over alerts.

But a simulator measures its illicit ratio after the fact rather than accepting it as an input. That is why its public releases are bucketed into higher- and lower-illicit sets rather than parameterised: the rate is an outcome. You cannot ask for exactly 0.40% split 40/20/20/10/10 across typologies.

The deeper problem is the one nobody can see. Emergent background traffic will sometimes contain, by chance, the exact shapes a detector hunts. When the screen fires on one, there is no way to tell whether the detector erred or the simulation happened to draw a ring. The false positive rate inherits that ambiguity.

Legacy Approach (Grown, then measured)

Uncontrolled Accidental Cycles

Standard agentic or probabilistic graph generators let edges form at random. When loops inevitably close due to random chance, detection models cannot distinguish real criminal patterns from noise.

False-Alarm Background NoiseHigh (~35–50%)
Ground Truth Label QualityAmbiguous / Guessed
Oracle Proof GuaranteeNone
Misata Engine (Declared, then proved)

Strictly Acyclic Background + Explicit Motifs

The background network is enforced as a strict topologically ranked DAG where edges only flow from low to high rank. Zero accidental loops can ever close. Every ring has an explicit Case ID.

False-Alarm Background Noise0.000% (Mathematically Proved)
Ground Truth Label Quality100% Deterministic Case IDs
Oracle Proof GuaranteeSigned Cryptographic Audit

Head to head

Agent simulation

The illicit rate is whatever the agents produce. Releases ship as higher- and lower-illicit buckets because the ratio is an outcome.

Declaration

The rate is an input. 0.40% of two million rows is 8,000 transactions, and 8,000 is what comes out.

Agent simulation

The typology mix is emergent. You take the blend the model happens to generate.

Declaration

The mix is stated and allocated by largest remainder, so 40/20/20/10/10 lands as 3,200/1,600/1,600/800/800 exactly.

Agent simulation

Background traffic can grow the same shapes a detector hunts. A hit may be the detector's error or the simulation's coincidence, and nothing distinguishes them.

Declaration

The background is ranked and acyclic, so an accidental ring cannot form. Every hit sorts into a declared bucket.

Agent simulation

Confounders cannot be commissioned. You cannot request 800 innocent rings that look guilty.

Declaration

Hard negatives are declared like anything else: 4,000 rows across 872 real cycles, labeled legitimate and never flagged.

What was declared

0.40% of two million transfers are laundering, split 40% rings, 20% fan-out, 20% fan-in, 10% scatter-gather and 10% layering chains, plus 0.20% declared hard negatives: real rings that are entirely legitimate.

Primitives used: graph_motifs, dag_edges. Seed 20260905, engine 0.9.6.46.

Circular Ring

cycle

Funds traverse a closed loop of accounts, returning to source minus intermediary cuts.

100% Ground TruthCase Labeled

Fan-Out Smurfing

fan_out

One central originator splits a large aggregate sum into micro-transactions under reporting thresholds.

100% Ground TruthCase Labeled

Fan-In Layering

fan_in

Dozens of small straw-purchaser accounts aggregate balances into a single destination vault.

100% Ground TruthCase Labeled

Scatter-Gather

scatter_gather

Funds split across mule relays, layer through shell accounts, then reconverge at a clean entity.

100% Ground TruthCase Labeled

Multi-Hop Layering Chain

chain

Linear sequential hops across jurisdictions and entities to obscure provenance.

100% Ground TruthCase Labeled

How it is built

  1. Stage 01Pipeline Step

    Declare

    Rate, typology mix, hard negatives. Shares must sum to one or the schema is refused.

    rate: 0.004
    shares: {cycle: .4, fan_out: .2, fan_in: .2, scatter_gather: .2}
  2. Stage 02Pipeline Step

    Rank & Lay Background

    Nodes receive a strict topological rank. Every background edge runs strictly from low to high, so no cycle can close at any depth.

    dag_edges → strictly acyclic background graph
  3. Stage 03Pipeline Step

    Inject Labeled Motifs

    Targeted subgraphs are rewritten into declared laundering shapes, each tagged with an immutable case ID. Unaffected edges remain acyclic.

    graph_motifs → 8,000 edges, 1,578 certified cases
  4. Stage 04Pipeline Step

    Independent Oracle Audit

    A separate verification pass recalculates all connected components and loop structures. It throws hard errors on any unintended cycle.

    largest un-cased strongly-connected component = 1 node

What came out, and how it was checked

Transfers generated over 60,000 accounts2,000,000 in 7.2 seconds
Declared laundering transactions8,000 declared, 8,000 found
Typology mix, exact3,200 ring / 1,600 fan-out / 1,600 fan-in / 800 chain / 800 scatter-gather
Declared rings that are genuinely closed rings1,578 cases, 0 malformed
Declared hard negatives, labeled and never flagged4,000 rows across 872 real cycles, 0 flagged
Background subgraph carrying no case id1,988,000 edges over 60,000 nodes, largest strongly connected component = 1 node

The last row is the one that matters. A strongly connected component of one node means no cycle exists anywhere outside a declared case, so an accidental pattern is not unlikely, it is impossible.

Running a detector against it

A standard directed-triangle screen, the kind deployed as a first-pass graph filter, run over the same file:

Directed triangles found609
Edges flagged1,792
Flags that are a declared motif1,341
Flags that are a background edge adjacent to a declared motif451
Triangles made entirely of background edges0
Recall on the three-hop rings this screen can see1,089 / 1,089

Every false positive is attributable. Some are confounders declared on purpose, the rest are background edges pulled in by a declared structure, counted separately. None are accidents, and that is proven rather than assumed. A generator that grows its graph cannot produce this table, because it cannot separate its own noise from the detector's error.

What this does not claim

  • The acyclic background is a designed property, not a claim about banking. Real ledgers contain innocent loops. Declare hard negatives to put them back, so they stay accounted for.
  • Names and free text are structural placeholders. AML detection reads amounts, timing, counterparties and graph shape, none of which is prose, so this is not a limitation for the task. Do not use the file for anything language-shaped.
  • This does not replace AMLworld. It answers a different question. They simulate and measure, which is what you want for training on emergent realism. This declares and proves, which is what you want for measuring a detector against known conditions.
  • A certificate proves the data matches the declaration. It never proves the declaration matches reality. That judgement stays with the person writing the schema.

Questions

How is this different from AMLworld or AMLSim?
Those simulate agents and measure the illicit ratio that emerges, which is why their datasets ship as higher- and lower-illicit buckets rather than as a parameter. Misata takes the rate and the typology mix as inputs and hits them exactly, then certifies the result. Different guarantee for a different job: simulation is better for training on emergent realism, declaration is better for measuring a detector against known conditions.
What does "the background is provably acyclic" actually buy me?
It means an accidental laundering pattern cannot exist in the data. Every cycle belongs to a case that was declared, so when your detector fires, the hit sorts into a known bucket instead of an unknown one. On emergent data you can never tell a detector's mistake from a coincidence in the traffic, and that ambiguity lands directly in your false positive rate.
Can I control the typology mix precisely?
Yes, that is the point. Shares must sum to one and are hit exactly by largest-remainder allocation, so 40/20/20/10/10 over 8,000 transactions gives 3,200/1,600/1,600/800/800 and not approximately that.
What are declared hard negatives?
Real motifs of the same shapes, labeled as legitimate rather than as laundering. Without them a detector is only measured on whether it can find loops. With them it is measured on whether it can tell a laundering ring from an innocent one, which is the thing that actually drives alert volume.
Is the data reproducible?
Yes. The same schema, seed and Misata version produce byte-identical output. The seed and version for the run above are printed on this page.
Can I use this for model validation or a regulator conversation?
It is built for exactly that: measuring detector behaviour under conditions you stated in advance and can show on paper. It is not a substitute for testing against your own production data, and the honest limits are listed on this page rather than buried.

Build this yourself

Everything above is a schema and a seed. Install the engine, declare what has to be true, and check the result with whatever you trust.