Skip to main content

Overview

The rules table stores extracted compliance rules with compound condition logic and Bayesian feedback counters for precision improvement over time.

Schema

ColumnTypeDescription
idUUID, PKUnique rule identifier
policy_idUUID, FKParent policy
rule_idtextUnique ID within policy (e.g., 'aml_rule_1')
nametextHuman-readable name
typetextExecution type (see below)
severitytext'CRITICAL', 'HIGH', 'MEDIUM'
thresholdnumericRule threshold value
time_windowintegerTime window in hours (windowed rules only)
conditionsjsonbCompound boolean logic tree (see below)
policy_excerpttextQuote from regulatory document
policy_sectiontextSection reference (e.g., “Article 5(1)(a)“)
descriptiontextJSON string with rule text + optional historical_context
is_activebooleanWhether rule fires during scans
approved_countintegerUser-confirmed true positives (Bayesian feedback)
false_positive_countintegerUser-dismissed false positives (Bayesian feedback)
created_attimestamptzTimestamp when rule was created

Rule Types

The type field determines how the rule is executed:
TypeDescription
single_transactionEvaluated per record (no aggregation)
aggregationAggregates values across multiple records
velocityDetects rate-of-change patterns
structuringDetects transaction structuring patterns
dormant_reactivationDetects dormant account reactivation
round_amountDetects suspicious round-number transactions

Conditions JSONB Structure

Rules support arbitrarily nested AND/OR logic trees. Each condition can be a logical operator (AND, OR) or a leaf condition.

Example: Compound AND Condition

{
  "AND": [
    { "field": "amount", "operator": ">=", "value": 10000 },
    { "field": "transaction_type", "operator": "IN", "value": ["DEBIT", "WIRE"] }
  ]
}

Example: Nested AND/OR Logic

{
  "AND": [
    { "field": "amount", "operator": ">=", "value": 5000 },
    {
      "OR": [
        { "field": "country", "operator": "==", "value": "US" },
        { "field": "country", "operator": "==", "value": "CA" }
      ]
    }
  ]
}

Leaf Condition Format

{
  "field": "column_name",
  "operator": ">=",
  "value": 10000,
  "value_type": "literal"  // or "field" for cross-field comparisons
}

Bayesian Feedback Loop

The approved_count and false_positive_count columns enable Bayesian precision calculation:Precision = (1 + TP) / (2 + TP + FP)Where:
  • TP = approved_count (true positives)
  • FP = false_positive_count (false positives)
When a user reviews a violation:
  • Approve → Increments approved_count
  • Dismiss as False Positive → Increments false_positive_count
Rules that consistently produce false positives lose confidence over time.

Updating Bayesian Counters

Use the increment_rule_stat RPC function to atomically increment counters:
-- Increment approved_count for a rule
SELECT increment_rule_stat(
  'policy-uuid',
  'aml_rule_1',
  'approved_count'
);

-- Increment false_positive_count for a rule
SELECT increment_rule_stat(
  'policy-uuid',
  'aml_rule_2',
  'false_positive_count'
);

Supported Operators

OperatorAliasesDescription
>=greater_than_or_equal, gteGreater than or equal
>greater_than, gtGreater than
<=less_than_or_equal, lteLess than or equal
<less_than, ltLess than
==equals, eqEquality (with type coercion)
!=not_equals, neqInequality
INSet membership
BETWEENRange check [min, max]
existsField is present and non-empty
not_existsField is missing or empty
containsincludesCase-insensitive substring match
MATCHregexRegular expression test

Relationships

  • Foreign Key to policies — Each rule belongs to a policy
  • Referenced by violations — Violations reference rule_id

Build docs developers (and LLMs) love