# LSFX Mock 随机命中规则后端实施记录

## 修改范围
- `lsfx-mock-server/services/file_service.py`
- `lsfx-mock-server/services/statement_rule_samples.py`
- `lsfx-mock-server/services/statement_service.py`
- `lsfx-mock-server/tests/test_file_service.py`
- `lsfx-mock-server/tests/test_statement_service.py`
- `lsfx-mock-server/tests/integration/test_full_workflow.py`
- `sql/migration/2026-03-20-lsfx-mock-random-hit-rule-purchase-baseline.sql`

## 规则命中计划生成方式
- 在 `FileService` 中新增 `LARGE_TRANSACTION_RULE_CODES` 与 `PHASE1_RULE_CODES` 两组规则池。
- 新增 `_build_rule_hit_plan(log_id)`，使用 `random.Random(f"rule-plan:{log_id}")` 生成稳定随机源。
- 通过 `_pick_rule_subset()` 从两组规则池内分别稳定选出 `2-4` 条规则，并保留规则池原始顺序。
- 在 `upload_file()` 与 `fetch_inner_flow()` 创建 `FileRecord` 时同步写入：
  - `large_transaction_hit_rules`
  - `phase1_hit_rules`

## 样本模块按规则子集装配
- 将原有“大额交易全量样本”拆成按规则代码独立调用的 builder。
- 新增 `LARGE_TRANSACTION_BUILDERS` 与 `PHASE1_RULE_BUILDERS` 两组映射，覆盖：
  - 大额交易 8 条规则
  - 第一期可由银行流水构造的 8 条规则
- 提供统一入口 `build_seed_statements_for_rule_plan(...)`，仅按 `rule_plan` 中被选中的规则拼装最小命中样本，不再默认返回全量命中样本。
- `build_large_transaction_seed_statements(...)` 保留为兼容测试入口，但内部已改为走新的规则映射。

## StatementService 接通方式
- `StatementService._generate_statements()` 改为优先读取 `FileRecord` 中保存的命中计划。
- 若存在真实 `FileRecord`，则复用其主体、账号、员工及亲属身份证范围，并把命中计划传给 `build_seed_statements_for_rule_plan(...)`。
- 命中样本与随机噪声流水继续统一走 `_assign_statement_ids()` 分配稳定 ID。
- 首次生成后仍缓存固定 `200` 条流水；同一 `logId` 重复分页读取保持结果稳定。

## LARGE_PURCHASE_TRANSACTION 单独补数据库基线原因
- `LARGE_PURCHASE_TRANSACTION` 的真实命中来源是 `ccdi_purchase_transaction`，不依赖 `ccdi_bank_statement`。
- 为避免伪造银行流水造成业务链路偏移，本次不把该规则塞进 Mock 流水样本。
- 通过新增 `sql/migration/2026-03-20-lsfx-mock-random-hit-rule-purchase-baseline.sql`，只补一条最小采购记录 `LSFXMOCKPUR001`。
- 脚本通过 `ccdi_base_staff` 选取一条真实员工主数据作为 `applicant_id/applicant_name` 来源，`actual_amount=186000.00`，满足真实 SQL 的 `>100000` 命中门槛。

## 实施结果
- `FileService -> StatementService -> 缓存分页` 主链路保持不变。
- 大额交易规则与第一期新增规则均已支持“按 `logId` 稳定随机命中一部分”。
- `LARGE_PURCHASE_TRANSACTION` 已通过独立数据库基线补齐联调数据来源。
