## 行指纹生成算法

- **DDS-Section**: 7.2 严格去重 — 行指纹算法
- **DDS-Lines**: L709-L726

### Extract

#### 指纹生成函数

```go
func GenerateRowFingerprint(t *Transaction) string {
    raw := fmt.Sprintf("%s|%s|%s|%s|%s|%s",
        t.TradeTime.Format("2006-01-02 15:04"),  // 分钟粒度（非秒级）
        t.Amount.String(),
        t.Direction,
        normalizeString(t.Counterparty),
        normalizeString(t.MerchantName),
        t.OrderID,
    )
    hash := sha256.Sum256([]byte(raw))
    return hex.EncodeToString(hash[:])
}
```

#### 关键设计决策

- **分钟粒度**：使用 `2006-01-02 15:04` 格式（精确到分钟），不是 `15:04:05`（秒级）
- **原因**：不同平台对同一交易的记录时间可能有秒级差异（如支付宝记录 10:30:15，微信记录 10:30:22），分钟粒度可以容忍这种差异
- **normalizeString** 处理：去除前后空格、全角转半角、统一大小写
- **SHA256 输出**：64 字符的十六进制字符串

#### 参与指纹的字段

| 字段 | 处理方式 |
|------|----------|
| `TradeTime` | `Format("2006-01-02 15:04")` — 分钟粒度 |
| `Amount` | `Decimal.String()` — 标准化数字字符串 |
| `Direction` | 原值：income/expense/... |
| `Counterparty` | `normalizeString()` — 去空格、标准化 |
| `MerchantName` | `normalizeString()` — 去空格、标准化 |
| `OrderID` | 原值（已在 Parser 中去除空格） |
