## 规则执行顺序与可解释性

- **DDS-Section**: 8.3 规则执行顺序 + 8.4 规则引擎核心实现 + 8.5 可解释性设计
- **DDS-Lines**: L969-L1045

### Extract

#### 固定执行顺序（不可变）

```
1. 对手方归一化 (COUNTERPARTY_NORMALIZE)
    ↓
2. 商户归一化 (MERCHANT_NORMALIZE)
    ↓
3. 分类映射 (CATEGORY_MAPPING)
    ↓
4. 账户映射 (ACCOUNT_MAPPING)
    ↓
5. 标签映射 (TAG_MAPPING)
    ↓
6. Firefly 字段映射 (FIREFLY_FIELD_MAPPING)
```

**设计原因**：先做归一再做分类，可提升规则命中率与稳定性。例如先将"美团外卖-北京"归一为"美团外卖"，再匹配分类规则"美团 → 餐饮美食"。

#### 执行原则

- 同一类型内按 `priority` 升序执行（数字越小优先级越高）
- **首条命中即停止**（同类型中第一个匹配的规则生效，后续不再匹配）
- 每条交易记录所有命中的规则 ID 和前后字段对比

#### 规则引擎核心实现

```go
type Engine struct {
    ruleRepo repository.RuleRepo
    hitRepo  repository.RuleHitRepo
}

func (e *Engine) Apply(ctx context.Context, txns []*Transaction) error {
    ruleGroups := e.loadRulesGroupByType(ctx)

    executionOrder := []string{
        "COUNTERPARTY_NORMALIZE",
        "MERCHANT_NORMALIZE",
        "CATEGORY_MAPPING",
        "ACCOUNT_MAPPING",
        "TAG_MAPPING",
        "FIREFLY_FIELD_MAPPING",
    }

    for _, txn := range txns {
        for _, ruleType := range executionOrder {
            rules := ruleGroups[ruleType]
            for _, rule := range rules {
                if !rule.MatchPlatform(txn.SourcePlatform) { continue }
                if rule.MatchConditions(txn) {
                    before := txn.Snapshot()
                    rule.ApplyActions(txn)
                    after := txn.Snapshot()
                    e.hitRepo.Save(ctx, &RuleHit{
                        TransactionID:    txn.ID,
                        RuleID:           rule.ID,
                        MatchedCondition: rule.ConditionsJSON,
                        BeforeValue:      before,
                        AfterValue:       after,
                    })
                    break // 同类型首条命中即停止
                }
            }
        }
    }
    return nil
}
```

#### 可解释性设计 — RuleHit 审计

每条交易保留完整的规则命中记录：

| 信息项 | 说明 |
|--------|------|
| 命中规则 ID | 关联 rules 表 |
| 命中条件摘要 | 匹配的具体关键词/正则 |
| 变更前值 | 规则执行前的字段值 |
| 变更后值 | 规则执行后的字段值 |
| 命中时间 | 规则执行时间戳 |

用于前端"为何被分到餐饮/交通"的解释展示。
