完成异常账户Mock服务后端实施记录

This commit is contained in:
wkc
2026-03-31 20:49:27 +08:00
parent 2877e26fa5
commit d4dc66a514
4 changed files with 125 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
# LSFX Mock Server 异常账户后端实施记录
## 1. 实施范围
本次改动仅覆盖 `lsfx-mock-server` 后端 Mock 造数主链路,目标是在不新增接口的前提下,为异常账户规则补齐稳定命中能力。
涉及规则:
- `SUDDEN_ACCOUNT_CLOSURE`
- `DORMANT_ACCOUNT_LARGE_ACTIVATION`
## 2. 主要改动
### 2.1 FileRecord 新增异常账户计划与事实
`lsfx-mock-server/services/file_service.py` 中扩展了 `FileRecord`
- 新增 `abnormal_account_hit_rules`
- 新增 `abnormal_accounts`
同时把异常账户规则池并入现有规则命中计划生成逻辑:
- `subset` 模式下按 `logId` 稳定随机命中异常账户规则
- `all` 模式下自动纳入全部异常账户规则
- 在上传链路与 `fetch_inner_flow(...)` 中同步生成最小异常账户事实
最小账户事实字段包括:
- `account_no`
- `owner_id_card`
- `account_name`
- `status`
- `effective_date`
- `invalid_date`
### 2.2 新增两类异常账户样本生成器
`lsfx-mock-server/services/statement_rule_samples.py` 中新增:
- `build_sudden_account_closure_samples(...)`
- `build_dormant_account_large_activation_samples(...)`
口径落实如下:
- `SUDDEN_ACCOUNT_CLOSURE` 的样本流水全部落在销户日前 30 天窗口内
- `DORMANT_ACCOUNT_LARGE_ACTIVATION` 的首笔流水晚于开户满 6 个月
- 休眠激活样本同时满足累计金额阈值与单笔最大金额阈值
### 2.3 接入现有种子流水主链路
未新增平行入口,直接复用现有:
- `FileService -> FileRecord`
- `StatementService._generate_statements(...)`
- `build_seed_statements_for_rule_plan(...)`
接入方式:
- 在统一种子流水构造入口增加 `abnormal_account_hit_rules` 分支
- 根据 `abnormal_accounts` 为每条异常账户规则选择匹配账户事实
- 生成的异常账户样本继续与既有规则样本一起补噪声、编号、打乱和分页
## 3. 测试补充
新增并通过的关键测试包括:
- `test_fetch_inner_flow_should_attach_abnormal_account_rule_plan`
- `test_sudden_account_closure_samples_should_stay_within_30_days_before_invalid_date`
- `test_dormant_account_large_activation_samples_should_exceed_threshold_after_6_months`
- `test_generate_statements_should_follow_abnormal_account_rule_plan_from_file_record`
## 4. 联动修正
`all` 模式安全噪声测试中,原有用例只清空了旧规则维度,未同步清空新增的 `abnormal_account_hit_rules`。本次已将该测试夹具补齐,保证它继续只验证“月固定收入 + 安全噪声”的原始语义。
## 5. 结果
异常账户命中计划、最小账户事实、样本生成器和服务层主链路均已落地,现有 Mock 服务可以为同一个 `logId` 稳定提供异常账户命中流水样本。

View File

@@ -0,0 +1,39 @@
# LSFX Mock Server 异常账户后端验证记录
## 1. 验证命令
按实施过程实际执行了以下命令:
```bash
cd lsfx-mock-server
python3 -m pytest tests/test_file_service.py::test_fetch_inner_flow_should_attach_abnormal_account_rule_plan -v
python3 -m pytest tests/test_statement_service.py -k "sudden_account_closure or dormant_account_large_activation" -v
python3 -m pytest tests/test_statement_service.py::test_generate_statements_should_follow_abnormal_account_rule_plan_from_file_record -v
python3 -m pytest tests/test_file_service.py tests/test_statement_service.py -v
python3 -m pytest tests/ -v
```
README 补充后按计划追加执行:
```bash
cd lsfx-mock-server
python3 -m pytest tests/test_statement_service.py -v
```
## 2. 验证结果摘要
- `tests/test_file_service.py::test_fetch_inner_flow_should_attach_abnormal_account_rule_plan`:通过
- `tests/test_statement_service.py -k "sudden_account_closure or dormant_account_large_activation"`:通过
- `tests/test_statement_service.py::test_generate_statements_should_follow_abnormal_account_rule_plan_from_file_record`:通过
- `python3 -m pytest tests/test_file_service.py tests/test_statement_service.py -v``43 passed`
- `python3 -m pytest tests/ -v``84 passed`
- `python3 -m pytest tests/test_statement_service.py -v``26 passed`
## 3. 过程说明
- 回归期间发现 `all` 模式安全噪声测试未同步清空新增的异常账户规则维度,导致异常账户样本被计入噪声断言
- 已通过补齐测试夹具方式修正,随后重新执行聚焦回归和全量回归,结果均通过
## 4. 进程清理
本轮只执行了 `pytest` 命令,未启动额外前端、后端或 Mock 服务进程,因此无需清理残留进程。

View File

@@ -37,6 +37,12 @@ python dev.py --reload --rule-hit-mode all
- `subset`:默认模式,按 `logId` 稳定随机命中部分规则
- `all`:全部兼容规则命中模式,会命中当前可共存的全部规则
补充说明:
- `fetch_inner_flow` 与上传链路会在内部生成 `abnormal_account_hit_rules`
- 当前异常账户规则样本包含 `SUDDEN_ACCOUNT_CLOSURE``DORMANT_ACCOUNT_LARGE_ACTIVATION`
- `/watson/api/project/getBSByLogId` 会沿用现有种子流水主链路,自动混入与异常账户事实匹配的命中流水样本
### 3. 访问 API 文档
- **Swagger UI**: http://localhost:8000/docs

View File

@@ -649,6 +649,8 @@ def test_generate_statements_should_keep_all_mode_noise_as_safe_debits(monkeypat
"MONTHLY_FIXED_INCOME",
"FIXED_COUNTERPARTY_TRANSFER",
]
record.abnormal_account_hit_rules = []
record.abnormal_accounts = []
statements = statement_service._generate_statements(group_id=1001, log_id=log_id, count=30)
noise_statements = [