Skip to main content
Audience: engineers at banks, payment firms, or fintechs building an anti-money-laundering (AML) case workflow who need to prove, after the fact, that each transaction was screened, reviewed by a named analyst, and dispositioned under the policy that was live at the time. This recipe is a concrete instance of the patterns in Integration Patterns and Decision Chains. Read those for the general mechanics; this page shows how they fit together for an AML case.

The scenario

A counterparty initiates a transaction. Your AML pipeline runs three steps:
  1. Automated screening — match the entity against sanctions and PEP lists, country risk, and a reporting threshold. Most cases clear here.
  2. Analyst review — when screening flags something (or for a sampled subset), a human analyst attests a risk assessment, evidence summary, and recommendation.
  3. Final disposition — a compliance officer (e.g. an MLRO) records the clearance basis and final action: cleared, blocked, or escalated.
Each step is recorded as a step in one decision chain, parent-linked in causal order. When the case closes you seal the chain — proving it is complete and no step was added or removed afterwards — and any regulator can later verify every receipt offline.
Mental model: MeshQu does not run your AML pipeline. Your system orchestrates the three steps and decides what to do at each verdict. MeshQu governs each decision against your policy and binds the sequence into a tamper-evident, replayable chain.
MeshQu is advisory. It returns a verdict per step — your system blocks, queues, or releases the transaction. A DENY on the screening step does not stop the money on its own; your payment rail does, after reading the verdict.

Decision boundary

Your code owns every box that acts — release, queue, escalate, block. MeshQu owns the MeshQu evaluates boxes and the seal/verify proof.

Step 1 — Automated screening

Record the screening decision as step 1 of a new chain. Generate a chain_id (any UUID) for the case and reuse it across all three steps.
A clean screening returns decision: "ALLOW" with an empty violations array. A sanctions or PEP hit returns DENY (critical severity); a high-value transaction over the reporting threshold returns REVIEW. The full response carries the integrity_hash, Ed25519 signature, and chain_step — see Decision Assurance for what each proves.

Step 2 — Analyst review

When step 1 routes to a human, the analyst submits their attestation. Record it as step 2, linking back to step 1 with parent_decision_id. The review policy enforces that the attestation is complete — a too-short risk assessment or a missing recommendation is a violation, so an analyst cannot wave a case through with an empty form.
The analyst’s recommendation drives the verdict via conditional rules: approveALLOW, escalateREVIEW, rejectDENY. Naming the human in actor binds who reviewed the case into the receipt — see Actor Attribution.

Step 3 — Final disposition

The MLRO records the disposition. The policy requires a disposition reason and a clearance basis, and forces DENY whenever the final action is blocked or escalated — so a blocked transaction can never be recorded as a clean clearance.
TypeScript

Seal and verify

When the case closes, seal the chain. A seal is only accepted when the last step is terminal (ALLOW, DENY, or ALERT) — a chain whose last step is still a held REVIEW returns 422 CHAIN_SEAL_NOT_TERMINAL. After sealing, no further steps can be added.
verify returns valid, a per-step sequence, chain_sealed, and a chain_proof status. List the whole case at any time with GET /v1/decisions?chain_id=CHAIN_ID.

Operational notes

  • Idempotency — every record carries an idempotency_key. A retried screening call returns the original receipt with is_new: false rather than recording a duplicate step. See Idempotency.
  • Rolling out a tightened screening rule — put the new policy in shadow_mode first so its DENY is reported as ALERT and never blocks a real transaction while you tune it. See Shadow Mode.
  • Real-time SAR triggers — subscribe a webhook filtered to aml_screening / aml_disposition at severity_min: critical to page your on-call when a critical violation fires.

Concept references