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

# Best Practices & Style Guide

### 6.1 Naming Conventions

**Rules:**

* Use `PascalCase` or `PascalCase_With_Underscores`.
* Name should describe the **fraud pattern**, not the implementation detail.
* Good: `HighFrequencyDestination`, `DormantAccountActivity`
* Bad: `CheckAmount`, `Rule_v2_final`

**Variables:**

* Use `$snake_case`.
* Good: `$sanctioned_countries`, `$high_risk_bins`
* Bad: `$myList`, `$SC`

### 6.2 One Rule, One Purpose

Each `.ws` file should contain a single rule that detects a single, specific fraud pattern. This provides:

* **Clear audit trails:** When a transaction is blocked, you know exactly which pattern triggered it.
* **Independent tuning:** You can adjust the score of one rule without affecting others.
* **Clean version history:** Git diffs show exactly what changed and why.

**Don't do this:**

```ws theme={null}
// BAD: Trying to detect multiple unrelated patterns in one rule
rule EverythingCheck {
    when amount > 10000
      or metadata.country in $sanctioned_countries
      or hour_of_day(timestamp) > 23
    then block score 0.9 reason "Something is wrong"
}
```

**Do this instead:** Write three separate rules, each with its own score, reason, and description.

### 6.3 Writing Clear Descriptions

Your description should answer three questions:

1. **What** does this rule detect?
2. **Why** is this pattern suspicious?
3. **What** is the expected action?

```ws theme={null}
// Excellent: Answers all three questions.
description "Detects more than 10 payments to the same destination within 24 hours, which may indicate account compromise or automated fraud."
```

### 6.4 Performance Considerations

**Order your `and` conditions wisely.** Place **cheap** checks before **expensive** checks. The interpreter uses short-circuit evaluation, so if the first condition fails, the expensive ones are never executed.

```ws theme={null}
// GOOD: Cheap 'amount' check first, expensive 'count()' second.
when amount > 100
 and count(when destination == $current.destination, "PT24H") > 10

// BAD: Expensive 'count()' runs even for $1 transactions.
when count(when destination == $current.destination, "PT24H") > 10
 and amount > 100
```

**Keep time windows as small as possible.** `"PT1H"` is much faster to query than `"P30D"`. Use the smallest window that effectively catches the pattern.

**Avoid overly complex regex.** Catastrophic backtracking in regex can cause severe performance degradation. Keep patterns simple and specific. Avoid nested quantifiers like `(.+)+`.

### 6.5 Scoring Strategy

Adopt a consistent scoring philosophy across your entire rule set:

| Category          | Score Range | Example Rules                          |
| ----------------- | ----------- | -------------------------------------- |
| **Informational** | `0.1 - 0.3` | Unusual time, minor pattern            |
| **Suspicious**    | `0.4 - 0.6` | High velocity, dormant account         |
| **High Risk**     | `0.7 - 0.8` | Failed previous tx + high amount       |
| **Critical**      | `0.9 - 1.0` | Sanctioned country, known fraud entity |

The risk consolidator aggregates scores. If multiple rules fire with `0.3` scores, the combined risk may still escalate the transaction to a `block`. Design your scores with this aggregation in mind.

### 6.6 Common Pitfalls

| Pitfall                                     | Consequence                                             | Fix                                                      |
| ------------------------------------------- | ------------------------------------------------------- | -------------------------------------------------------- |
| Typo in field name (`ammount` vs `amount`)  | Rule **never** triggers, no error                       | Double-check field names against your transaction schema |
| Missing `description`                       | Analysts can't understand why a transaction was flagged | Always write a description                               |
| Using `or` without understanding precedence | Unexpected rule behavior                                | Keep `or` usage simple, or split into multiple rules     |
| Very large time windows (`P365D`)           | Slow query performance                                  | Use the smallest effective window                        |
| Score of `0.0`                              | Rule fires but has no impact on risk consolidation      | Always assign a meaningful score                         |
| Regex without `(?i)`                        | Misses case variations                                  | Use `(?i)` for case-insensitive matching                 |
| Missing `reason`                            | Analysts see "No reason provided"                       | Always write a specific reason                           |
