Files
ccdi/docs/design/2026-03-20-lsfx-mock-phase2-random-hit-design.md

254 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 兰溪流水 Mock 第二期稳定随机命中设计
## 1. 背景
当前仓库已经具备两条基础能力:
- `lsfx-mock-server` 已支持按 `logId` 稳定随机命中第一期规则子集,并通过 Mock 流水为主工程提供可重复联调输入。
- 主工程第二期真实规则已在 [`docs/plans/backend/2026-03-20-bank-tag-real-rule-phase2-backend-implementation.md`](/Users/wkc/Desktop/ccdi/ccdi/docs/plans/backend/2026-03-20-bank-tag-real-rule-phase2-backend-implementation.md) 中明确范围,但 `lsfx-mock-server` 尚未补齐第二期命中输入与配套基线。
本次目标不是重写主工程打标逻辑,而是在保留第一期稳定随机命中方案的前提下,为第二期补齐可联调、可重复、可命中真实 SQL 的输入数据。
## 2. 目标
- 保留现有第一期 `logId -> 稳定随机规则子集` 行为不变。
- 为第二期规则新增稳定随机命中计划。
- 让“拉取本行信息 / 获取流水列表 -> 入库到本地 -> 执行重打标”后,最终标签结果中可以查到抽中的第二期规则命中。
- 对依赖采购、资产等外部事实表的规则,补最小且幂等的本地数据库基线。
## 3. 非目标
- 不新增主工程打标补丁逻辑。
- 不把采购类、资产类规则伪造成纯银行流水规则。
- 不引入“指定特殊 `logId` 固定命中全部第二期规则”的双轨模式。
- 不扩展第二期范围外的新规则。
## 4. 方案对比
### 4.1 方案 A稳定随机命中 + 第二期基线编排
保留现有 `FileService -> StatementService -> 缓存分页` 主链路;对可由银行流水驱动的第二期规则继续通过 Mock 流水样本触发;对依赖采购、资产等外部事实表的规则,通过本地数据库最小基线补齐真实 SQL 输入。
优点:
- 与主工程真实 SQL 数据来源一致。
- 能同时覆盖“Mock 取数正确”和“真实规则可命中”。
- 保持现有第一期链路结构不变,扩展成本最低。
缺点:
- 需要同时维护流水样本和数据库基线两类输入。
### 4.2 方案 B只改 Mock 流水
只扩充 `lsfx-mock-server` 返回的流水数据,不补采购、资产等业务表。
缺点:
- 第二期中存在真实依赖 `ccdi_purchase_transaction``ccdi_asset_info` 的规则,最终会出现 Mock 看似有数据、真实 SQL 仍然无法命中的偏差。
### 4.3 方案 C只补数据库基线
Mock 仅返回普通流水,把第二期命中主要交给数据库灌数。
缺点:
- 无法证明“兰溪本地接口获取流水列表并入库”的链路本身正确。
- 偏离本次验收口径。
## 5. 推荐方案
采用方案 A。
原因:
- 第二期联调必须同时证明两件事Mock 取数入库链路没问题,真实 SQL 也确实能命中。
- 采购类和资产类规则本来就不是纯流水规则,直接补最小事实基线才符合真实业务口径。
- 继续使用“同一 `logId` 稳定随机命中一部分规则”可以复用现有测试与排障习惯。
## 6. 模块边界与数据流
### 6.1 `FileService`
继续负责生成并持久化规则命中计划。
在现有字段基础上新增两组规则计划:
- `phase2_statement_hit_rules`
- `phase2_baseline_hit_rules`
职责边界:
- 只负责决定“这个 `logId` 抽中了哪些第二期规则”。
- 不直接构造流水明细,也不直接写数据库业务基线。
### 6.2 `StatementService` 与 `statement_rule_samples.py`
继续负责把命中计划转成最小流水样本,并与噪声流水合并后返回。
职责边界:
- 只生成能通过 `ccdi_bank_statement` 真实入库后触发的第二期样本。
- 不为采购、资产等外部事实规则伪造流水替代。
### 6.3 第二期基线服务
`lsfx-mock-server/services/` 下新增一个轻量服务,负责根据 `phase2_baseline_hit_rules` 幂等写入本地 MySQL 最小事实数据。
职责边界:
- 只补真实 SQL 所需输入。
- 不直接写标签结果表,不参与打标逻辑计算。
### 6.4 主工程
主工程 `CcdiFileUploadServiceImpl -> CcdiBankStatement -> CcdiBankTagServiceImpl` 链路保持不变。
验收以真实链路为准:
1. 拉取本行信息或通过兰溪接口获取流水。
2. 流水成功入库到 `ccdi_bank_statement`
3. 执行项目重打标。
4.`ccdi_bank_statement_tag_result` 或结果接口中看到抽中的第二期规则命中。
## 7. 第二期规则分层
### 7.1 流水样本直接驱动
以下规则以 `ccdi_bank_statement` 为核心输入,使用 Mock 流水样本驱动:
- `LOW_INCOME_RELATIVE_LARGE_TRANSACTION`
- `MULTI_PARTY_GAMBLING_TRANSFER`
- `MONTHLY_FIXED_INCOME`
- `FIXED_COUNTERPARTY_TRANSFER`
- `SALARY_QUICK_TRANSFER`
- `SALARY_UNUSED`
要求:
- 样本必须落在同一个真实员工域或其亲属域上。
- 时间窗口、金额区间、对手方稳定性等聚合条件必须在同一对象范围内闭环。
- 互斥规则不得使用同一员工样本组。
### 7.2 数据库基线驱动
以下规则需要外部事实表配合:
- `HOUSE_REGISTRATION_MISMATCH`
- `PROPERTY_FEE_REGISTRATION_MISMATCH`
- `TAX_ASSET_REGISTRATION_MISMATCH`
- `SUPPLIER_CONCENTRATION`
处理方式:
- 三条资产不匹配规则:
- Mock 生成对应交易流水。
- 基线服务在 `ccdi_asset_info` 中补“故意缺失或不匹配”的最小资产事实。
- `SUPPLIER_CONCENTRATION`
- 直接补 `ccdi_purchase_transaction` 聚合命中基线。
- 不伪造银行流水替代。
## 8. 第二期样本设计
### 8.1 `LOW_INCOME_RELATIVE_LARGE_TRANSACTION`
- 选择一个真实员工及其亲属身份证范围。
- 亲属收入基线维持低收入事实。
- 生成大额累计转入或转出流水,确保超过低收入亲属的大额交易阈值。
### 8.2 `MULTI_PARTY_GAMBLING_TRANSFER`
- 同一员工对象、同一天、多名不同对手方。
- 每笔金额落在 `MULTI_PARTY_AMT_MIN ~ MULTI_PARTY_AMT_MAX` 区间。
- 命中依赖“多人 + 多次 + 同日 + 区间金额”,不依赖敏感词。
### 8.3 `MONTHLY_FIXED_INCOME`
- 为同一员工构造连续 3 至 4 个月的固定收入转入。
- 排除工资代发主体和工资关键词。
- 每月金额稳定高于 `MONTHLY_FIXED_INCOME`
### 8.4 `FIXED_COUNTERPARTY_TRANSFER`
- 为同一员工与固定对手方构造季度稳定转入。
- 每季累计金额落在 `FIXED_COUNTERPARTY_TRANSFER_MIN ~ FIXED_COUNTERPARTY_TRANSFER_MAX` 区间。
### 8.5 `SALARY_QUICK_TRANSFER`
- 先生成可识别工资入账。
- 再在 24 小时内生成大额转出,满足比例条件。
### 8.6 `SALARY_UNUSED`
- 先生成工资入账。
- 后续 30 天不生成可计入“工资使用”的消费或转账支出。
-`SALARY_QUICK_TRANSFER` 不共用同一员工对象。
### 8.7 资产不匹配三条规则
- `HOUSE_REGISTRATION_MISMATCH`:生成购房交易流水,但不提供可匹配房产登记。
- `PROPERTY_FEE_REGISTRATION_MISMATCH`:生成物业缴费流水,但不提供对应房产登记。
- `TAX_ASSET_REGISTRATION_MISMATCH`:生成大额纳税流水,但不提供与税费相符的资产登记。
### 8.8 `SUPPLIER_CONCENTRATION`
- 为同一申请人写入多笔采购记录。
- 使单一供应商采购额占比显著超过 70%。
- 使用固定业务主键和稳定供应商集合,确保可重复验证。
## 9. 实现落点
- Modify: `lsfx-mock-server/services/file_service.py`
- Modify: `lsfx-mock-server/services/statement_service.py`
- Modify: `lsfx-mock-server/services/statement_rule_samples.py`
- Add: `lsfx-mock-server/services/phase2_baseline_service.py`
- Add/Modify: `lsfx-mock-server/tests/test_file_service.py`
- Add/Modify: `lsfx-mock-server/tests/test_statement_service.py`
- Add/Modify: `lsfx-mock-server/tests/integration/test_full_workflow.py`
- Add: `sql/migration/2026-03-20-lsfx-mock-phase2-hit-baseline.sql`
## 10. 幂等策略
- 规则命中计划继续由 `logId` 决定,不新增第二随机源。
- 流水样本继续由 `StatementService` 缓存,同一 `logId` 重复分页读取结果一致。
- 采购基线使用固定业务主键,按固定主键删后重建。
- 资产基线使用固定特征组合,确保可精确清理与重建。
- 所有基线写入都必须只作用于本次选中的员工域,避免污染无关人员。
## 11. 验证设计
### 11.1 Mock 单元测试
- 第二期规则池抽样稳定性。
- 第二期流水样本只装配被抽中的规则。
- 第二期数据库基线写入的幂等性。
### 11.2 Mock 集成测试
- `getJZFileOrZjrcuFile -> getBSByLogId` 同一 `logId` 下结果稳定。
- 抽中第二期规则时,流水样本与基线写入同步成立。
### 11.3 主工程端到端验证
- 拉取本行信息后流水成功入库。
- 执行项目重打标后,第二期目标规则出现在结果中。
- 明细型规则可通过流水详情接口回查。
- 对象型规则可在标签结果表中看到正确 `objectType/objectKey/reasonDetail`
## 12. 风险与边界
- 不为了联调成功去修改主工程真实 SQL。
- 不把 `SUPPLIER_CONCENTRATION` 伪造成纯流水命中。
- 不引入兜底、补丁或兼容性双轨逻辑。
- 若第二期真实 SQL 与现有基线字段口径不一致,按验证失败暴露,不在 Mock 侧偷偷修正业务规则。
## 13. 结论
本方案采用“保留第一期稳定随机命中方案 + 为第二期补齐稳定随机命中计划、最小流水样本和幂等数据库基线”的最短路径实现。
这样可以同时保证:
- 兰溪本地接口能够正确返回并入库存量流水;
- 第二期新增模型所需输入事实完整;
- 主工程重打标后能够命中新增模型的真实规则结果。