Files
ccdi/docs/plans/backend/2026-03-25-lsfx-mock-all-hit-sql-alignment-backend-implementation.md

372 lines
12 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.
# lsfx-mock All 模式 SQL 对齐强命中 Backend Implementation Plan
> **For agentic workers:** REQUIRED: Use superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 仅调整 `lsfx-mock-server``--rule-hit-mode all` 生成策略,让 5 条已落地真实 SQL 的规则在真实链路下稳定命中,并尽量抑制噪声命中。
**Architecture:** 保留 `FileService -> StatementService -> phase2_baseline_service` 现有分层,不改主工程。`all` 模式改为“规则专属样本 + 最小关联表基线 + 受控噪声”组合方案;`subset` 模式保持现状。所有实现以 [`2026-03-25-lsfx-mock-all-hit-sql-alignment-design.md`](/Users/wkc/Desktop/ccdi/ccdi/docs/design/2026-03-25-lsfx-mock-all-hit-sql-alignment-design.md) 为准。
**Tech Stack:** Python, FastAPI, pytest, 项目内 Mock 服务、MySQL 关联表基线
---
### Task 1: 锁定规则范围与 all 模式计划
**Files:**
- Modify: `lsfx-mock-server/services/file_service.py`
- Test: `lsfx-mock-server/tests/test_file_service.py`
- Reference: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagAnalysisMapper.xml`
- [ ] **Step 1: 为 all 模式规则清单补充失败测试**
在 [test_file_service.py](/Users/wkc/Desktop/ccdi/ccdi/lsfx-mock-server/tests/test_file_service.py) 新增断言:
- `SPECIAL_AMOUNT_TRANSACTION` 存在于 `phase1_hit_rules`
- `SUSPICIOUS_INCOME_KEYWORD` 存在于 `phase1_hit_rules`
- `MONTHLY_FIXED_INCOME``FIXED_COUNTERPARTY_TRANSFER``LOW_INCOME_RELATIVE_LARGE_TRANSACTION` 存在于 `phase2_statement_hit_rules`
- `all` 模式不把占位 SQL 规则误加入强命中计划
示例断言:
```python
assert "SPECIAL_AMOUNT_TRANSACTION" in plan["phase1_hit_rules"]
assert "MONTHLY_FIXED_INCOME" in plan["phase2_statement_hit_rules"]
assert "INTEREST_PAYMENT_BY_OTHERS" not in plan["phase2_statement_hit_rules"]
```
- [ ] **Step 2: 运行测试确认当前实现不能完整表达新口径**
Run: `cd lsfx-mock-server && pytest tests/test_file_service.py -k "all_mode or phase2_rule_hit_plan" -v`
Expected:
- 新增断言失败,暴露 all 模式规则计划仍是旧口径
- [ ] **Step 3: 修改 `file_service.py` 的 all 模式计划生成逻辑**
在 [file_service.py](/Users/wkc/Desktop/ccdi/ccdi/lsfx-mock-server/services/file_service.py)
- 保持 `subset` 模式逻辑不变
- 明确 all 模式只包含真实 SQL 已落地且本次需强命中的规则
- 保持现有计划字段结构,避免调用方联动修改
实现要求:
- 不重命名已有字段
- 不引入新的计划 DSL
- 仅调整 all 模式规则集合和注释说明
- [ ] **Step 4: 运行测试确认计划生成通过**
Run: `cd lsfx-mock-server && pytest tests/test_file_service.py -k "all_mode or phase2_rule_hit_plan" -v`
Expected:
- PASS
- [ ] **Step 5: 提交本任务**
```bash
git add lsfx-mock-server/services/file_service.py lsfx-mock-server/tests/test_file_service.py
git commit -m "调整all模式规则命中计划"
```
### Task 2: 为 5 条规则补充样本函数测试
**Files:**
- Modify: `lsfx-mock-server/tests/test_statement_service.py`
- Reference: `lsfx-mock-server/services/statement_rule_samples.py`
- Reference: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagAnalysisMapper.xml`
- [ ] **Step 1: 为 `SPECIAL_AMOUNT_TRANSACTION` 增加失败测试**
新增测试断言:
- 样本金额仅为 `520``1314`
- 样本主体使用员工本人证件号
Run: `cd lsfx-mock-server && pytest tests/test_statement_service.py -k "special_amount" -v`
Expected:
- FAIL当前样本金额仍为 `88888.88`
- [ ] **Step 2: 为 `MONTHLY_FIXED_INCOME` 增加失败测试**
新增测试断言:
- 命中月份数不少于 `6`
- 对手方固定
- 摘要不带工资关键词
Run: `cd lsfx-mock-server && pytest tests/test_statement_service.py -k "monthly_fixed_income" -v`
Expected:
- FAIL当前仅有 4 个月
- [ ] **Step 3: 为 `SUSPICIOUS_INCOME_KEYWORD` 增加失败测试**
新增测试断言:
- `userMemo``cashType` 命中 SQL 关键词集合中的明确词
Run: `cd lsfx-mock-server && pytest tests/test_statement_service.py -k "suspicious_income_keyword" -v`
Expected:
- FAIL当前“咨询返现收入”不在 SQL 关键词集内
- [ ] **Step 4: 为 `FIXED_COUNTERPARTY_TRANSFER` 增加失败测试**
新增测试断言:
- 样本 `cretNo` 为员工本人
- 至少跨 2 个季度
- 同一对手方季度金额落在 `[3000,15000]`
Run: `cd lsfx-mock-server && pytest tests/test_statement_service.py -k "fixed_counterparty_transfer" -v`
Expected:
- FAIL当前主体落在家属号
- [ ] **Step 5: 为 `LOW_INCOME_RELATIVE_LARGE_TRANSACTION` 增加失败测试**
新增测试断言:
- 使用家属证件号
- 累计金额大于 `100000`
- 依赖的低收入基线需要单独由 baseline 服务补齐
Run: `cd lsfx-mock-server && pytest tests/test_statement_service.py -k "low_income_relative_large_transaction" -v`
Expected:
- 可先只验证流水样本金额与主体范围,若测试已通过则继续后续 baseline 测试
- [ ] **Step 6: 提交本任务**
```bash
git add lsfx-mock-server/tests/test_statement_service.py
git commit -m "补充SQL对齐样本测试"
```
### Task 3: 按真实 SQL 改写 5 条样本生成函数
**Files:**
- Modify: `lsfx-mock-server/services/statement_rule_samples.py`
- Test: `lsfx-mock-server/tests/test_statement_service.py`
- [ ] **Step 1: 改写 `build_special_amount_transaction_samples`**
要求:
- 使用员工本人证件号
- 生成 `520``1314`
- 不复用配偶/子女姓名
- [ ] **Step 2: 改写 `build_monthly_fixed_income_samples`**
要求:
- 连续至少 6 个月
- 每月固定收入
- 对手方固定
- 不命中工资排除条件
- [ ] **Step 3: 改写 `build_suspicious_income_keyword_samples`**
要求:
- 直接命中 SQL 关键词
- 保持收入流水
- 优先用摘要关键词,不依赖偶然命中对手方名称
- [ ] **Step 4: 改写 `build_fixed_counterparty_transfer_samples`**
要求:
- 主体切换为员工本人
- 固定对手方
- 至少 2 个季度
- 每季度累计金额位于 `[3000,15000]`
- [ ] **Step 5: 改写 `build_low_income_relative_large_transaction_samples`**
要求:
- 主体为家属证件号
- 累计金额大于 `100000`
- 与 baseline 服务使用同一目标家属域
- [ ] **Step 6: 运行规则样本测试**
Run: `cd lsfx-mock-server && pytest tests/test_statement_service.py -k "special_amount or monthly_fixed_income or suspicious_income_keyword or fixed_counterparty_transfer or low_income_relative_large_transaction" -v`
Expected:
- PASS
- [ ] **Step 7: 提交本任务**
```bash
git add lsfx-mock-server/services/statement_rule_samples.py lsfx-mock-server/tests/test_statement_service.py
git commit -m "按真实SQL改写命中样本"
```
### Task 4: 扩展 baseline 服务,补齐低收入家属基线
**Files:**
- Modify: `lsfx-mock-server/services/phase2_baseline_service.py`
- Modify: `lsfx-mock-server/services/file_service.py`
- Modify: `lsfx-mock-server/tests/test_phase2_baseline_service.py`
- Modify: `lsfx-mock-server/tests/test_file_service.py`
- [ ] **Step 1: 为 baseline 服务补充失败测试**
新增测试断言:
- 当命中 `LOW_INCOME_RELATIVE_LARGE_TRANSACTION` 时,目标家属 `annual_income` 被写成 `0``NULL` 或小于 `36000`
- 重复执行时保持幂等
Run: `cd lsfx-mock-server && pytest tests/test_phase2_baseline_service.py -k "low_income" -v`
Expected:
- FAIL当前 baseline 服务未覆盖该规则的低收入写入
- [ ] **Step 2: 扩展 `phase2_baseline_service.py`**
实现要求:
- 只补当前目标员工域相关关系数据
- 不污染其他员工或历史关系记录
-`FileService` 当前身份绑定保持一致
- [ ] **Step 3: 确认 `FileService` 在 all 模式下会触发对应 baseline**
若已有计划写入链路不够明确,则在 [test_file_service.py](/Users/wkc/Desktop/ccdi/ccdi/lsfx-mock-server/tests/test_file_service.py) 补充断言:
- 包含该规则时baseline 服务收到对应规则编码与家属上下文
- [ ] **Step 4: 运行 baseline 相关测试**
Run: `cd lsfx-mock-server && pytest tests/test_phase2_baseline_service.py tests/test_file_service.py -k "low_income or baseline" -v`
Expected:
- PASS
- [ ] **Step 5: 提交本任务**
```bash
git add lsfx-mock-server/services/phase2_baseline_service.py lsfx-mock-server/services/file_service.py lsfx-mock-server/tests/test_phase2_baseline_service.py lsfx-mock-server/tests/test_file_service.py
git commit -m "补充低收入家属基线写入"
```
### Task 5: 收紧 all 模式噪声,避免聚合规则被干扰
**Files:**
- Modify: `lsfx-mock-server/services/statement_service.py`
- Modify: `lsfx-mock-server/tests/test_statement_service.py`
- [ ] **Step 1: 为 all 模式噪声约束补充失败测试**
新增测试断言:
- 员工本人不会被随机生成多个稳定季度重复对手
- 员工本人不会被随机叠加过多大额同月收入,破坏 `MONTHLY_FIXED_INCOME`
Run: `cd lsfx-mock-server && pytest tests/test_statement_service.py -k "noise and (monthly or fixed_counterparty)" -v`
Expected:
- FAIL当前噪声仍可能污染聚合规则
- [ ] **Step 2: 修改 `statement_service.py` 的噪声生成约束**
实现要求:
- 仅在 `all` 模式生效
- 不取消背景噪声,只收紧对目标员工域的对手方与收入分布
- 不影响 `subset` 模式
- [ ] **Step 3: 运行噪声相关测试**
Run: `cd lsfx-mock-server && pytest tests/test_statement_service.py -k "noise and (monthly or fixed_counterparty)" -v`
Expected:
- PASS
- [ ] **Step 4: 提交本任务**
```bash
git add lsfx-mock-server/services/statement_service.py lsfx-mock-server/tests/test_statement_service.py
git commit -m "收紧all模式噪声生成"
```
### Task 6: 补充集成测试,验证 all 模式真实链路
**Files:**
- Modify: `lsfx-mock-server/tests/integration/test_full_workflow.py`
- Reference: `lsfx-mock-server/routers/api.py`
- [ ] **Step 1: 为 all 模式新增集成测试场景**
测试目标:
- 固定 `all` 模式计划包含这 5 条规则
- 调用 Mock 取数链路后,返回流水中可见对应关键样本
- baseline 服务在链路中被调用
建议断言示例:
```python
assert any(item["userMemo"] == "劳务费发放" for item in statements)
assert any(item["transAmount"] in (520.0, 1314.0) for item in statements)
```
- [ ] **Step 2: 运行集成测试**
Run: `cd lsfx-mock-server && pytest tests/integration/test_full_workflow.py -k "all_hit or baseline or workflow" -v`
Expected:
- PASS
- [ ] **Step 3: 提交本任务**
```bash
git add lsfx-mock-server/tests/integration/test_full_workflow.py
git commit -m "补充all模式强命中集成测试"
```
### Task 7: 完整回归与人工联调核验
**Files:**
- Modify: `docs/reports/implementation/2026-03-25-lsfx-mock-all-hit-sql-alignment-record.md`
- [ ] **Step 1: 运行 Mock 服务回归**
Run: `cd lsfx-mock-server && pytest tests/test_file_service.py tests/test_statement_service.py tests/test_phase2_baseline_service.py tests/integration/test_full_workflow.py -v`
Expected:
- 全部 PASS
- [ ] **Step 2: 启动 Mock 服务进行手工联调**
Run:
```bash
cd lsfx-mock-server
python main.py --rule-hit-mode all
```
Expected:
- 服务正常启动
- [ ] **Step 3: 按真实链路执行联调**
使用现有后端联调路径:
- 拉取流水
- 触发重打标
- 查询 `ccdi_bank_statement_tag_result`
人工核验结果:
- `SPECIAL_AMOUNT_TRANSACTION`
- `MONTHLY_FIXED_INCOME`
- `SUSPICIOUS_INCOME_KEYWORD`
- `FIXED_COUNTERPARTY_TRANSFER`
- `LOW_INCOME_RELATIVE_LARGE_TRANSACTION`
都至少命中 1 条,并且无明显失控噪声命中。
- [ ] **Step 4: 记录实施与验证结果**
在 [2026-03-25-lsfx-mock-all-hit-sql-alignment-record.md](/Users/wkc/Desktop/ccdi/ccdi/docs/reports/implementation/2026-03-25-lsfx-mock-all-hit-sql-alignment-record.md) 记录:
- 修改文件
- 测试命令
- 联调项目与命中结果
- 是否需要后续补充规则
- [ ] **Step 5: 停止测试进程**
若本轮启动了 Mock 或后端进程,结束后立即停止,避免残留端口占用。
- [ ] **Step 6: 提交本任务**
```bash
git add docs/reports/implementation/2026-03-25-lsfx-mock-all-hit-sql-alignment-record.md
git commit -m "记录lsfx-mock全命中改造结果"
```