# 后端全量打标规则验证记录

## 验证时间

- 2026-03-22

## 验证对象

- 项目：`project_id=49`
- 后端：`http://localhost:62318`
- Mock：`http://localhost:8000`
- Mock 启动参数：`main.py --rule-hit-mode all`

## 执行命令

```bash
mvn -pl ccdi-project \
  -Dtest=CcdiBankTagServiceImplTest,CcdiBankTagServiceRiskCountRefreshTest,CcdiBankTagAnalysisMapperXmlTest,CcdiBankTagRuleSqlMetadataTest,CcdiModelParamSqlDefaultsTest \
  test

curl -s http://localhost:62318/login/test \
  -H 'Content-Type: application/json' \
  -d '{"username":"admin","password":"admin123"}'

curl -s http://localhost:62318/ccdi/file-upload/pull-bank-info \
  -H "Authorization: Bearer <TOKEN>" \
  -H 'Content-Type: application/json' \
  -d '{"projectId":49,"idCards":["558455197203132040","523342199111246421","38056420050404632X"],"startDate":"2026-03-01","endDate":"2026-03-22"}'

curl -s http://localhost:62318/ccdi/project/tags/rebuild \
  -H "Authorization: Bearer <TOKEN>" \
  -H 'Content-Type: application/json' \
  -d '{"projectId":49,"modelCode":null}'
```

## 自动化结果

- Maven 回归结果：`BUILD SUCCESS`
- 用例统计：`Tests run: 29, Failures: 0, Errors: 0, Skipped: 0`
- 说明：
  - 当前规则元数据、服务分发、XML 结构与风险人数刷新回归未发现失败
  - 测试日志中的异常路径日志属于断言场景，不代表回归失败

## 数据库核验

### 最新任务

- 查询表：`ccdi_bank_tag_task`
- 结果：
  - `id=47`
  - `project_id=49`
  - `trigger_type=MANUAL`
  - `status=SUCCESS`
  - `hit_count=2340`
  - `success_rule_count=33`
  - `failed_rule_count=0`

### 实际命中规则

- 查询表：`ccdi_bank_statement_tag_result`
- 项目 `49` 实际命中规则数：`19`
- 实际命中规则：
  - `HOUSE_OR_CAR_EXPENSE`
  - `TAX_EXPENSE`
  - `SINGLE_LARGE_INCOME`
  - `CUMULATIVE_INCOME`
  - `ANNUAL_TURNOVER`
  - `LARGE_CASH_DEPOSIT`
  - `LARGE_TRANSFER`
  - `MULTI_PARTY_GAMBLING_TRANSFER`
  - `GAMBLING_SENSITIVE_KEYWORD`
  - `HOUSE_REGISTRATION_MISMATCH`
  - `PROPERTY_FEE_REGISTRATION_MISMATCH`
  - `TAX_ASSET_REGISTRATION_MISMATCH`
  - `FOREX_BUY_AMT`
  - `FOREX_SELL_AMT`
  - `LARGE_PURCHASE_TRANSACTION`
  - `SUPPLIER_CONCENTRATION`
  - `STOCK_TFR_LARGE`
  - `SALARY_QUICK_TRANSFER`
  - `LARGE_STOCK_TRADING`

### 未命中规则分类

- 未命中总数：`14`

#### A. 当前仍是占位 SQL 的规则

- `ABNORMAL_CUSTOMER_TRANSACTION`
- `INCOME_ASSET_MISMATCH`
- `CROSS_BORDER_AMT`
- `INTEREST_PAYMENT_BY_OTHERS`
- `WITHDRAW_AMT`
- `PROXY_ACCOUNT_OPERATION`

结论：

- 这 6 条当前不能判定为“可正确打标”，因为实现仍停留在占位层。

#### B. 已有真实 SQL，但本次 all 模式项目数据未打中

- `FREQUENT_CASH_DEPOSIT`
- `LOW_INCOME_RELATIVE_LARGE_TRANSACTION`
- `SPECIAL_AMOUNT_TRANSACTION`
- `MONTHLY_FIXED_INCOME`
- `FIXED_COUNTERPARTY_TRANSFER`
- `SUSPICIOUS_INCOME_KEYWORD`
- `WITHDRAW_CNT`
- `SALARY_UNUSED`

逐条追因：

- `FREQUENT_CASH_DEPOSIT`
  - 项目 `49` 的 `batch_id=45565/69755/70053` 中，分别存在 `2026-03-10` 同日 `6` 笔存现样本，金额均为 `3000000~3500000` 元，证件号为员工本人。
  - `taskId=47` 日志显示运行时阈值为 `{LARGE_CASH_DEPOSIT=5000, FREQUENT_CASH_DEPOSIT=2}`，但仍记录为“规则无命中”。
  - 当前按源码 SQL 直接复核，这批数据已经足以查出 `3` 个对象，因此这条不是“项目数据不满足”，而是 `2026-03-22 09:11` 验证时复用的旧后端进程与当前 Mapper XML 不一致，属于验证环境版本不一致造成的假阴性。
- `LOW_INCOME_RELATIVE_LARGE_TRANSACTION`
  - Mock 样本确实写入了两笔亲属转入，单个关系人累计交易额为 `120000` 元。
  - 但对应关系人的 `annual_income` 实际为 `64000~128000` 元，折算月收入均高于 `3000` 元。
  - 该规则卡在“低收入关系人”前置条件，不是金额不足，而是家庭关系表里的收入数据不满足 SQL 口径。
- `SPECIAL_AMOUNT_TRANSACTION`
  - Mock 样本金额固定为 `88888.88` 元，对手方为“兰溪特别金额结算中心”。
  - SQL 只识别 `520`、`1314` 两类特殊金额。
  - 这条未命中的直接原因是样本金额语义与真实 SQL 的金额枚举不一致。
- `MONTHLY_FIXED_INCOME`
  - Mock 只为每个对象生成了 `2025-12`、`2026-01`、`2026-02`、`2026-03` 共 `4` 个月、每月 `7200` 元的稳定转入。
  - SQL 要求近 `12` 个月内至少 `6` 个月月收入超过阈值，且波动系数不高于 `0.3`。
  - 本次样本满足金额稳定，但月数只有 `4`，被 `COUNT(DISTINCT incomeMonth) >= 6` 这一层拦截。
- `FIXED_COUNTERPARTY_TRANSFER`
  - “季度稳定兼职收入”样本都落在 `secondary` 身份，也就是家属证件号；项目 `49` 复核可见这些证件号均为 `NON_STAFF`。
  - SQL 从 `ccdi_base_staff` 开始内连接，只统计员工本人近 `12` 个月的固定对手方转入。
  - 这条未命中的直接原因是样本主体落在家属号，进入 SQL 第一层 `inner join ccdi_base_staff` 时就被过滤掉了。
- `SUSPICIOUS_INCOME_KEYWORD`
  - Mock 样本摘要为“咨询返现收入”，对手方为“灰度信息咨询有限公司”。
  - SQL 关键词仅覆盖“工资、分红、红利、奖金、劳务费、批量代付”等收入表达，不包含“返现”“咨询”。
  - 这条未命中的直接原因是摘要关键词与真实 SQL 的关键词集合不一致。
- `WITHDRAW_CNT`
  - 当前按源码 SQL 直接复核，项目 `49` 已能查出 `3` 个对象在 `2026-03-12` 单日提现次数超过阈值 `3` 次，其中计数分别为 `4`、`4`、`5`。
  - 但 `taskId=47` 日志在同一阈值 `{WITHDRAW_CNT=3}` 下仍记录为“规则无命中”。
  - 结合 `taskId=47` 发生在 `2026-03-22 09:11:57`、当前后端进程启动于 `2026-03-22 12:11:28` 这一事实，可以判定这条与 `FREQUENT_CASH_DEPOSIT` 一样，属于验证时后端运行版本未刷新导致的假阴性，而不是数据本身不满足。
- `SALARY_UNUSED`
  - `2026-02-10` 那组“工资入账 + 代扣公积金”样本全部落在家属证件号，SQL 的 `inner join ccdi_base_staff` 会直接排除。
  - 员工本人侧仅保留了 `2026-03-14` 的工资入账样本，但这些样本正是 `SALARY_QUICK_TRANSFER` 的基础数据，工资到账后 `30` 天内均已有 `2~5` 笔非代扣支出。
  - 因此这条是“双重不满足”：专用样本被员工主表连接挡掉，员工本人样本又被 `not exists` 的“30 天内无支出”条件挡掉。

结论：

- 这 8 条里，`LOW_INCOME_RELATIVE_LARGE_TRANSACTION`、`SPECIAL_AMOUNT_TRANSACTION`、`MONTHLY_FIXED_INCOME`、`FIXED_COUNTERPARTY_TRANSFER`、`SUSPICIOUS_INCOME_KEYWORD`、`SALARY_UNUSED` 属于“样本/主数据口径与 SQL 条件不一致”。
- `FREQUENT_CASH_DEPOSIT`、`WITHDRAW_CNT` 不属于数据不满足，而是 `2026-03-22` 那次验证复用了旧后端进程，导致运行时 SQL 与当前源码不一致。

### Mock all 模式边界

- Mock all 模式当前直接覆盖 26 条规则，不包含：
  - `ABNORMAL_CUSTOMER_TRANSACTION`
  - `INCOME_ASSET_MISMATCH`
  - `CROSS_BORDER_AMT`
  - `INTEREST_PAYMENT_BY_OTHERS`
  - `LARGE_PURCHASE_TRANSACTION`
  - `WITHDRAW_AMT`
  - `PROXY_ACCOUNT_OPERATION`
- 其中 `LARGE_PURCHASE_TRANSACTION` 通过采购基线事实命中，已在本次结果中验证到

## 接口回查

- 回查接口：`GET /ccdi/project/bank-statement/detail/70334`
- 返回：
  - `code=200`
  - `data.hitTags` 非空
  - 命中标签包含 `LARGE_TRANSFER`

样例摘要：

- `bank_statement_id=70334`
- `rule_code=LARGE_TRANSFER`
- `reason_detail=大额转账支出 12000000.00 元，超过阈值 5000 元`

## 最终结论

- 本次验证证明：
  - 后端当前 33 条规则都已经进入执行链路，最新任务 `success_rule_count=33`
  - 在项目 `49` 的真实联调链路下，只有 19 条规则产生了实际标签结果
- 因此截至 2026-03-22，结论应为：
  - 后端打标方法“不是全部规则都已验证可正确打标”
  - 当前状态更准确地说是“部分规则已验证通过，部分规则未命中，另有 6 条规则仍为占位实现”

## 环境说明

- 本次验证复用了已经运行中的本地后端与 Mock 服务
- 未额外启动新的前后端进程，因此本次无新增进程需要清理
