Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.finwatch.finance/llms.txt

Use this file to discover all available pages before exploring further.

A FinWatch rule is a self-contained unit of logic defined in a single .ws file. It evaluates incoming transaction data against a set of conditions and, if those conditions are met, produces a verdict. A verdict is an actionable decision about the transaction’s risk. Every rule is composed of four structural components: rule, description, when, and then.

1.1 The Complete Structure

rule HighValueTransactionCheck {
    description "Flags any single transaction exceeding $10,000 for manual review."

    when amount > 10000

    then review
         score  0.7
         reason "Transaction amount exceeds $10,000 high-value threshold"
}

1.2 The rule Block

Purpose: The top-level declaration that names the rule and acts as the container for all its logic. Syntax:
rule <RuleName> { ... }
Key Facts:
  • The rule keyword is optional but strongly recommended for readability. The parser will accept an identifier followed by { as a valid rule start.
  • <RuleName> is an identifier, not a string. It must start with a letter or underscore, and can contain letters, digits, and underscores.
  • There is one rule per .ws file. The parser reads a single rule from the input.
  • The entire body of the rule is enclosed in curly braces { }.
Naming Conventions:
  • Use PascalCase or PascalCase_With_Underscores.
  • The name should describe the fraud pattern or policy it enforces.
  • Good: HighValueTransactionCheck, SanctionedCountryCheck, BlockIfPreviousFailed
  • Bad: rule1, test, myRule

1.3 The description Clause

Purpose: A human-readable explanation of the rule’s intent. This is your audit trail. When a regulator asks “why was this transaction blocked?”, the description is your first line of defense. Syntax:
description "<text>"
Key Facts:
  • The value must be a double-quoted string.
  • It is optional in the parser, but mandatory in practice. A rule without a description is a rule that will be misunderstood.
  • Write for a non-technical audience: compliance officers, auditors, and future teammates.
Examples:
// Good: Explains the what, and implies the why.
description "Blocks transactions to countries on the OFAC sanctions list."

// Good: Specific about the threshold and the regulatory driver.
description "Flags any single transaction over $10,000 for AML reporting (BSA/CTR requirement)."

// Bad: Too vague to be useful.
description "Checks amount."

1.4 The when Clause

Purpose: The logical heart of the rule. It defines the conditions that must evaluate to true for the rule to fire. Syntax:
when <condition>
 and <condition>
 or  <condition>
Key Facts:
  • Contains one or more conditional expressions.
  • Multiple conditions are joined by and or or logical operators.
  • If the entire when clause evaluates to true, the then clause executes.
  • If it evaluates to false, the rule silently passes — no verdict is produced.
  • A rule MUST have a when clause. The parser will reject a rule without one.

1.5 The then Clause

Purpose: Defines the action taken when the when clause is satisfied. Syntax:
then <verdict>
     score  <number>
     reason "<text>"
Key Facts:
  • A rule MUST have a then clause. The parser will reject a rule without one.
  • score and reason are optional. If omitted, score defaults to 0.0 and reason defaults to "No reason provided".
  • score and reason can appear in any order after the verdict.

1.6 Fully Annotated “Hello World” Example

rule DormantAccountActivity {
    // ─── DESCRIPTION ───────────────────────────────────────────────────────
    // Provides context for analysts and auditors.
    description "Unusual activity after long period of account dormancy."

    // ─── WHEN ──────────────────────────────────────────────────────────────
    // Two conditions joined by 'and'. BOTH must be true.
    // Condition 1: Access nested metadata via dot notation.
    // Condition 2: A simple numeric comparison on a top-level field.
    when metadata.days_since_last_transaction > 90
     and amount > 1000

    // ─── THEN ──────────────────────────────────────────────────────────────
    // Verdict: 'review' (send to a human analyst queue).
    // Score: 0.7 (high confidence this is suspicious).
    // Reason: A clear explanation for the analyst.
    then review
         score   0.7
         reason  "High-value transaction after extended account inactivity"
}