> ## 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.

# The when Clause: Conditional Logic

This section provides a deep dive into every mechanism available for constructing conditions.

### 2.1 Accessing Transaction Data

Transaction data is represented as a flat or nested JSON object. You access fields using **dot notation**.

**Top-level fields:** These are the standard fields on the `transactions` table:

| Field            | Type             | Description                              |
| ---------------- | ---------------- | ---------------------------------------- |
| `transaction_id` | string           | Unique transaction identifier            |
| `amount`         | number           | Transaction amount                       |
| `currency`       | string           | Currency code (e.g., "USD")              |
| `source`         | string           | Source account/entity                    |
| `destination`    | string           | Destination account/entity               |
| `timestamp`      | string (RFC3339) | When the transaction occurred            |
| `description`    | string           | Free-text description of the transaction |
| `metadata`       | object           | Arbitrary JSON metadata                  |

**Accessing nested metadata:** The `metadata` field is a JSON object that can contain any custom data your system sends. You access its properties with dot notation:

```go theme={null}
// Access a top-level field
when amount > 10000

// Access a nested metadata field
when metadata.destination_country == "IR"

// Access deeply nested metadata
when metadata.device.fingerprint == "abc123"
```

**How it works internally:** The interpreter uses a `dig()` function that splits the path by `.` and traverses the JSON tree. If any part of the path does not exist, the condition evaluates to `false` (it does **not** throw an error).

**Pitfall:** If a field is missing from the transaction data, the condition silently fails. This is by design — it prevents rules from crashing on incomplete data. But it means a typo in a field name (e.g., `ammount` instead of `amount`) will cause a rule to **never trigger** without any error message.

### 2.2 Comparison Operators

These operators form the backbone of simple conditions. Each compares a field's value against a target value.

| Operator              | DSL Syntax | Internal Name | Description                                    |
| --------------------- | ---------- | ------------- | ---------------------------------------------- |
| Equal                 | `==`       | `eq`          | True if left equals right                      |
| Not Equal             | `!=`       | `ne`          | True if left does not equal right              |
| Greater Than          | `>`        | `gt`          | True if left is greater than right             |
| Greater Than or Equal | `>=`       | `gte`         | True if left is greater than or equal to right |
| Less Than             | `<`        | `lt`          | True if left is less than right                |
| Less Than or Equal    | `<=`       | `lte`         | True if left is less than or equal to right    |

**Type Coercion Rules:** The interpreter attempts to compare values numerically first. If both sides can be parsed as `float64`, a numeric comparison is performed. If not, both sides are converted to strings and compared lexicographically. This means:

* `amount > 1000` -> Numeric comparison (correct).
* `currency == "USD"` -> String comparison (correct).
* `"100" > "99"` -> String comparison (`"1" < "9"`, so this is **false**). Be careful with stringified numbers.

**Important:** For string comparisons, only `eq` and `ne` are supported. Using `>`, `<`, `>=`, or `<=` on non-numeric strings will return `false`.

**Examples:**

```shellscript theme={null}
// Numeric: Check if amount exceeds a threshold
when amount > 10000

// String: Check for a specific currency
when currency == "USD"

// String: Exclude a specific status
when metadata.status != "verified"

// Numeric: Check a range (using two conditions)
when amount >= 5000
 and amount <= 50000
```

### 2.3 Logical Operators: `and` / `or`

Logical operators combine multiple conditions into a single boolean result.

| Operator | Behavior                                                      |
| -------- | ------------------------------------------------------------- |
| `and`    | True only if **both** the left and right conditions are true. |
| `or`     | True if **either** the left or right condition is true.       |

**Syntax:**

```go theme={null}
// AND: Both conditions must be true
when amount > 10000
 and currency == "USD"

// OR: At least one condition must be true
when hour_of_day(timestamp) >= 23
  or hour_of_day(timestamp) <= 4
```

**Operator Precedence:** Currently, `and` and `or` have **equal precedence** and are evaluated **left-to-right**. There is no implicit grouping that makes `and` bind tighter than `or`.

For the rule:

```go theme={null}
when A or B and C
```

This is parsed as `(A or B) and C`, **not** `A or (B and C)`. This is a critical detail. If you need specific grouping, structure your rule conditions carefully or split into multiple rules.

**Multi-line conditions:** The parser supports conditions that span multiple lines. You can place `and`/`or` at the beginning of a new line for readability:

```go theme={null}
when metadata.destination_country in $sanctioned_countries
 and amount > 10000
 and currency == "USD"
```

**Short-circuit evaluation:** The interpreter uses short-circuit logic:

* For `and`: If the left side is `false`, the right side is **not evaluated**.
* For `or`: If the left side is `true`, the right side is **not evaluated**.

This is important for performance — expensive aggregate checks placed on the right side of an `and` will be skipped if a cheap check on the left already fails.

### 2.4 Set Operators: `in`

The `in` operator checks whether a field's value exists within a given list. This is essential for checking against blacklists, whitelists, or known-bad values.

**Syntax:**

```go theme={null}
// Check against a variable list
when metadata.destination_country in $sanctioned_countries

// Check against an inline array
when metadata.mcc in ("7995", "6012", "4829")
```

**How it works:** The interpreter converts the field value to a string and iterates through the list, comparing each element as a string. This means `in` is a **string membership check**.

**Example: Sanctioned Country Check**

```go theme={null}
rule SanctionedCountryCheck {
    description "Blocks transactions to sanctioned countries."

    when metadata.destination_country in $sanctioned_countries

    then block
         score   1.0
         reason  "Destination country is on global sanctions list"
}
```

**Example: Suspicious MCC Check**

```go theme={null}
rule SuspiciousMCCCheck {
    description "Flags transactions with suspicious merchant category codes."

    when metadata.mcc in ("7995", "6012", "4829")

    then review
         score   0.4
         reason  "Transaction uses a high-risk merchant category code"
}
```

### 2.5 Pattern Operators: `regex` and `not_regex`

The `regex` operator performs regular expression matching on string fields. This is powerful for detecting suspicious patterns in free-text fields like transaction descriptions.

**Syntax:**

```go theme={null}
when <field> regex "<pattern>"
when <field> not_regex "<pattern>"
```

**Key Facts:**

* The pattern is a standard Go regular expression (RE2 syntax).
* `regex` returns `true` if the pattern matches anywhere in the field value.
* `not_regex` returns `true` if the pattern does **not** match.
* The pattern must be a double-quoted string.
* Use `(?i)` at the start for case-insensitive matching.

**Example: Detecting Suspicious Descriptions**

```go theme={null}
rule SuspiciousDescriptionCheck {
    description "Detects suspicious keywords or patterns in transaction descriptions."

    when description regex "(?i)(btc|bitcoin|crypto|wallet|transfer|gift.?card|western.?union)"
     and amount > 1000

    then review
         score   0.2
         reason  "Suspicious description pattern."
}
```

**Pitfall:** Complex regex patterns can be expensive. Avoid catastrophic backtracking patterns like `(.+)+` on large strings. Keep patterns as simple and specific as possible.
