From 7cdf9212b60fc0fb9b48f1f58a5254bbd9443308 Mon Sep 17 00:00:00 2001 From: wkc <978997012@qq.com> Date: Fri, 20 Mar 2026 15:13:19 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=96=B0=E5=A2=9E=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E6=89=93=E6=A0=87=E9=AA=8C=E8=AF=81=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E8=AE=A1=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...nk-tag-new-model-validation-plan-record.md | 38 ++ ...tag-new-model-validation-execution-plan.md | 521 ++++++++++++++++++ 2 files changed, 559 insertions(+) create mode 100644 docs/reports/implementation/2026-03-20-bank-tag-new-model-validation-plan-record.md create mode 100644 docs/tests/plans/2026-03-20-bank-tag-new-model-validation-execution-plan.md diff --git a/docs/reports/implementation/2026-03-20-bank-tag-new-model-validation-plan-record.md b/docs/reports/implementation/2026-03-20-bank-tag-new-model-validation-plan-record.md new file mode 100644 index 00000000..7a36e4f3 --- /dev/null +++ b/docs/reports/implementation/2026-03-20-bank-tag-new-model-validation-plan-record.md @@ -0,0 +1,38 @@ +# 新增模型打标验证计划实施记录 + +## 修改目标 + +- 将已确认的“新增模型打标完整验证”文档归档到项目现有测试计划目录 +- 基于确认后的验证计划补充一份可直接执行的实施计划 +- 保持本次工作只覆盖验证方案与执行步骤,不混入修复内容 + +## 修改范围 + +- `docs/tests/plans/2026-03-20-bank-tag-new-model-validation-test-plan.md` +- `docs/tests/plans/2026-03-20-bank-tag-new-model-validation-execution-plan.md` + +## 修改内容 + +### 1. 调整验证计划归档路径 + +- 将原先放在 `docs/superpowers/specs/` 下的验证设计文档迁移到 `docs/tests/plans/` +- 文件名调整为 `2026-03-20-bank-tag-new-model-validation-test-plan.md` +- 标题与正文表述从“设计”收敛为“验证计划”语境,和目录职责保持一致 + +### 2. 新增执行计划 + +- 新增 `docs/tests/plans/2026-03-20-bank-tag-new-model-validation-execution-plan.md` +- 按“环境与基线 -> Mock 自动化 -> 主工程自动化 -> 数据库核验 -> 接口端到端 -> 进程清理”的顺序拆解任务 +- 为每个阶段补充了明确的执行命令、预期结果、停点条件和文档沉淀要求 + +## 目录选择理由 + +- `docs/tests/plans/` 当前已用于承载测试计划类文档 +- 本次文档内容核心是验证目标、执行步骤、通过标准和失败停点 +- 相比 `docs/plans/misc/`,该目录与本次任务的语义更一致 + +## 结果 + +- 验证计划路径已修正为项目目录下的测试计划位置 +- 执行计划已补齐,后续可直接进入验证执行阶段 +- 本次改动未触碰业务代码,也未启动前后端或 Mock 服务进程 diff --git a/docs/tests/plans/2026-03-20-bank-tag-new-model-validation-execution-plan.md b/docs/tests/plans/2026-03-20-bank-tag-new-model-validation-execution-plan.md new file mode 100644 index 00000000..a1c1b37c --- /dev/null +++ b/docs/tests/plans/2026-03-20-bank-tag-new-model-validation-execution-plan.md @@ -0,0 +1,521 @@ +# 新增模型打标完整验证 Implementation Plan + +> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 对 2026-03-20 新加入的模型打标改动执行一轮完整验证,覆盖 Mock 随机命中、第一期真实规则、数据库事实和接口端到端结果。 + +**Architecture:** 这次工作不是改代码,而是按“环境与基线 -> 自动化回归 -> 数据库核验 -> 接口链路 -> 文档沉淀”五层顺序执行。只要某一层失败,就停在该层记录证据,不继续给出“验证通过”的结论,也不进入修复。 + +**Tech Stack:** Bash, Python 3, FastAPI, Java 21, Spring Boot 3, Maven, pytest, MySQL, curl, jq + +--- + +## File Structure + +- `docs/tests/plans/2026-03-20-bank-tag-new-model-validation-test-plan.md`: 已确认的验证计划,执行时必须严格对齐范围与停点。 +- `docs/tests/plans/2026-03-20-bank-tag-new-model-validation-execution-plan.md`: 本执行计划,负责把验证计划拆成可执行步骤。 +- `docs/reports/implementation/2026-03-20-bank-tag-new-model-validation-record.md`: 本次实施记录,记录执行内容与范围。 +- `docs/tests/records/2026-03-20-bank-tag-new-model-validation-verification.md`: 本次验证记录,记录命令、SQL、接口结果和结论。 +- `docs/reports/implementation/2026-03-20-lsfx-mock-random-hit-rule-backend-record.md`: Mock 随机命中改动的既有实施记录。 +- `docs/tests/records/2026-03-20-lsfx-mock-random-hit-rule-backend-verification.md`: Mock 随机命中改动的既有验证记录。 +- `docs/reports/implementation/2026-03-20-bank-tag-real-rule-phase1-backend-record.md`: 第一期真实规则改动的既有实施记录。 +- `docs/tests/records/2026-03-20-bank-tag-real-rule-phase1-backend-verification.md`: 第一期真实规则改动的既有验证记录。 +- `ruoyi-admin/src/main/resources/application-dev.yml`: 读取数据库连接与后端本地配置。 +- `sql/migration/2026-03-20-lsfx-mock-random-hit-rule-purchase-baseline.sql`: `LARGE_PURCHASE_TRANSACTION` 采购基线脚本。 +- `lsfx-mock-server/tests/test_file_service.py`: Mock 规则命中计划测试。 +- `lsfx-mock-server/tests/test_statement_service.py`: Mock 样本装配与缓存稳定性测试。 +- `lsfx-mock-server/tests/integration/test_full_workflow.py`: Mock 端到端链路测试。 +- `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/BankTagRuleConfigResolverTest.java`: 规则参数映射测试。 +- `ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapperXmlTest.java`: 真实 SQL 结构测试。 +- `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImplTest.java`: 规则分发测试。 +- `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceRiskCountRefreshTest.java`: 风险人数刷新回归测试。 +- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiFileUploadController.java`: 拉取本行信息接口。 +- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiBankTagController.java`: 手动重算接口。 +- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiBankStatementController.java`: 流水详情接口。 +- `bin/restart_java_backend.sh`: 后端 Jar 启停脚本。 + +### Task 1: 锁定执行环境、目标项目和记录文档 + +**Files:** +- Create: `docs/reports/implementation/2026-03-20-bank-tag-new-model-validation-record.md` +- Create: `docs/tests/records/2026-03-20-bank-tag-new-model-validation-verification.md` +- Reference: `docs/tests/plans/2026-03-20-bank-tag-new-model-validation-test-plan.md` +- Reference: `ruoyi-admin/src/main/resources/application-dev.yml` +- Reference: `docs/reports/implementation/2026-03-20-lsfx-mock-random-hit-rule-backend-record.md` +- Reference: `docs/reports/implementation/2026-03-20-bank-tag-real-rule-phase1-backend-record.md` + +- [ ] **Step 1: 阅读既有计划与两份来源实施记录** + +Run: + +```bash +sed -n '1,220p' docs/tests/plans/2026-03-20-bank-tag-new-model-validation-test-plan.md +sed -n '1,220p' docs/reports/implementation/2026-03-20-lsfx-mock-random-hit-rule-backend-record.md +sed -n '1,220p' docs/reports/implementation/2026-03-20-bank-tag-real-rule-phase1-backend-record.md +``` + +Expected: + +- 明确本次只验证双线已落地内容 +- 不把第二期规则和修复方案带进执行范围 + +- [ ] **Step 2: 从数据库中选出本次端到端验证使用的项目** + +Run: + +```bash +python3 - <<'PY' +from pathlib import Path +import pymysql, re + +text = Path('ruoyi-admin/src/main/resources/application-dev.yml').read_text(encoding='utf-8') +match = re.search(r"url:\s*jdbc:mysql://(?P[^:/?#]+):(?P\d+)/(?P[^?\n]+).*?\n\s*username:\s*(?P[^\n]+)\n\s*password:\s*(?P[^\n]+)", text, re.S) +conn = pymysql.connect( + host=match.group('host'), + port=int(match.group('port')), + user=match.group('user').strip(), + password=match.group('pwd').strip(), + database=match.group('db').strip(), + charset='utf8mb4', + cursorclass=pymysql.cursors.DictCursor, +) +with conn, conn.cursor() as cursor: + cursor.execute(""" + SELECT project_id, project_name, lsfx_project_id, config_type + FROM ccdi_project + WHERE del_flag = '0' + AND lsfx_project_id IS NOT NULL + ORDER BY update_time DESC, project_id DESC + LIMIT 10 + """) + for row in cursor.fetchall(): + print(row) +PY +``` + +Expected: + +- 至少找到 1 个可用于 LSFX 联调的项目 +- 在实施记录和验证记录中记下最终采用的 `project_id` + +- [ ] **Step 3: 创建本次实施记录与验证记录骨架** + +在两个文档中先写入以下固定章节: + +- 实施记录:验证目标、范围、执行阶段、产物路径 +- 验证记录:执行命令、数据库核验、接口验证、结论、环境清理 + +- [ ] **Step 4: Commit** + +```bash +git add docs/reports/implementation/2026-03-20-bank-tag-new-model-validation-record.md docs/tests/records/2026-03-20-bank-tag-new-model-validation-verification.md docs/tests/plans/2026-03-20-bank-tag-new-model-validation-execution-plan.md +git commit -m "补充新增模型打标验证执行计划" +``` + +### Task 2: 先完成 Mock 随机命中自动化回归 + +**Files:** +- Reference: `lsfx-mock-server/tests/test_file_service.py` +- Reference: `lsfx-mock-server/tests/test_statement_service.py` +- Reference: `lsfx-mock-server/tests/integration/test_full_workflow.py` +- Modify: `docs/tests/records/2026-03-20-bank-tag-new-model-validation-verification.md` +- Modify: `docs/reports/implementation/2026-03-20-bank-tag-new-model-validation-record.md` + +- [ ] **Step 1: 跑 Mock 聚焦回归** + +Run: + +```bash +cd lsfx-mock-server +python3 -m pytest tests/test_file_service.py -k "rule_hit_plan or persist_rule_hit_plan" -v +python3 -m pytest tests/test_statement_service.py -k "rule_plan_should_only_include or withdraw_cnt_samples" -v +python3 -m pytest tests/test_statement_service.py -k "follow_rule_hit_plan or fixed_total_count_200 or cached_result" -v +python3 -m pytest tests/integration/test_full_workflow.py -k "same_rule_subset or share_same_primary_binding" -v +``` + +Expected: + +- 全部 `PASS` +- 能证明规则命中计划、样本装配和缓存稳定性未回退 + +- [ ] **Step 2: 跑 Mock 全量回归** + +Run: + +```bash +cd lsfx-mock-server +python3 -m pytest tests/test_file_service.py tests/test_statement_service.py tests/test_api.py tests/integration/test_full_workflow.py -v +``` + +Expected: + +- `PASS` +- 若失败,停止后续阶段并把失败用例和首个错误栈写入验证记录 + +- [ ] **Step 3: 将结果写入验证记录** + +记录: + +- 实际执行时间 +- `passed / failed / warnings` 摘要 +- 若存在 warning,只说明是否为既有 warning,不做修复 + +### Task 3: 完成主工程第一期真实规则自动化回归 + +**Files:** +- Reference: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/BankTagRuleConfigResolverTest.java` +- Reference: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapperXmlTest.java` +- Reference: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImplTest.java` +- Reference: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceRiskCountRefreshTest.java` +- Modify: `docs/tests/records/2026-03-20-bank-tag-new-model-validation-verification.md` + +- [ ] **Step 1: 逐步跑第一期目标测试** + +Run: + +```bash +mvn test -pl ccdi-project -Dtest=BankTagRuleConfigResolverTest +mvn test -pl ccdi-project -Dtest=CcdiBankTagAnalysisMapperXmlTest +mvn test -pl ccdi-project -Dtest=CcdiBankTagAnalysisMapperXmlTest,CcdiBankTagServiceImplTest +mvn test -pl ccdi-project -Dtest=CcdiBankTagAnalysisMapperXmlTest,BankTagRuleConfigResolverTest,CcdiBankTagServiceImplTest,CcdiBankTagServiceRiskCountRefreshTest +``` + +Expected: + +- 全部 `BUILD SUCCESS` +- 若任一命令失败,停止后续阶段并把失败命令、失败类名和错误摘要写入验证记录 + +- [ ] **Step 2: 在验证记录中沉淀主工程自动化结果** + +记录: + +- 每条命令的执行结果 +- 规则映射、真实 SQL、对象分发、风险人数刷新是否都保持通过 + +### Task 4: 做数据库基线和规则元数据核验 + +**Files:** +- Reference: `sql/migration/2026-03-20-lsfx-mock-random-hit-rule-purchase-baseline.sql` +- Reference: `sql/2026-03-16-bank-tagging.sql` +- Modify: `docs/tests/records/2026-03-20-bank-tag-new-model-validation-verification.md` +- Modify: `docs/reports/implementation/2026-03-20-bank-tag-new-model-validation-record.md` + +- [ ] **Step 1: 幂等执行采购基线脚本** + +Run: + +```bash +bin/mysql_utf8_exec.sh sql/migration/2026-03-20-lsfx-mock-random-hit-rule-purchase-baseline.sql +``` + +Expected: + +- 脚本执行成功 +- 无中文乱码、无 SQL 报错 + +- [ ] **Step 2: 校验采购基线记录存在** + +Run: + +```bash +python3 - <<'PY' +from pathlib import Path +import pymysql, re + +text = Path('ruoyi-admin/src/main/resources/application-dev.yml').read_text(encoding='utf-8') +match = re.search(r"url:\s*jdbc:mysql://(?P[^:/?#]+):(?P\d+)/(?P[^?\n]+).*?\n\s*username:\s*(?P[^\n]+)\n\s*password:\s*(?P[^\n]+)", text, re.S) +conn = pymysql.connect( + host=match.group('host'), + port=int(match.group('port')), + user=match.group('user').strip(), + password=match.group('pwd').strip(), + database=match.group('db').strip(), + charset='utf8mb4', + cursorclass=pymysql.cursors.DictCursor, +) +with conn, conn.cursor() as cursor: + cursor.execute(""" + SELECT purchase_id, actual_amount, supplier_name + FROM ccdi_purchase_transaction + WHERE purchase_id = 'LSFXMOCKPUR001' + AND actual_amount > 100000 + """) + print(cursor.fetchone()) +PY +``` + +Expected: + +- 返回 `LSFXMOCKPUR001` +- `actual_amount` 大于 `100000` + +- [ ] **Step 3: 校验第一期规则元数据保持大写且可识别** + +Run: + +```bash +python3 - <<'PY' +from pathlib import Path +import pymysql, re + +TARGET_RULES = ( + 'GAMBLING_SENSITIVE_KEYWORD','SPECIAL_AMOUNT_TRANSACTION','SUSPICIOUS_INCOME_KEYWORD', + 'FOREX_BUY_AMT','FOREX_SELL_AMT','LARGE_PURCHASE_TRANSACTION', + 'STOCK_TFR_LARGE','WITHDRAW_CNT','LARGE_STOCK_TRADING' +) + +text = Path('ruoyi-admin/src/main/resources/application-dev.yml').read_text(encoding='utf-8') +match = re.search(r"url:\s*jdbc:mysql://(?P[^:/?#]+):(?P\d+)/(?P[^?\n]+).*?\n\s*username:\s*(?P[^\n]+)\n\s*password:\s*(?P[^\n]+)", text, re.S) +conn = pymysql.connect( + host=match.group('host'), + port=int(match.group('port')), + user=match.group('user').strip(), + password=match.group('pwd').strip(), + database=match.group('db').strip(), + charset='utf8mb4', + cursorclass=pymysql.cursors.DictCursor, +) +sql = f""" +SELECT model_code, rule_code, indicator_code +FROM ccdi_bank_tag_rule +WHERE rule_code IN ({','.join(['%s'] * len(TARGET_RULES))}) +ORDER BY model_code, sort_order, rule_code +""" +with conn, conn.cursor() as cursor: + cursor.execute(sql, TARGET_RULES) + for row in cursor.fetchall(): + print(row) +PY +``` + +Expected: + +- 所有目标规则均能查到 +- `rule_code`、`indicator_code` 继续保持全大写风格 + +- [ ] **Step 4: 将 SQL 与结果摘要写入验证记录** + +记录: + +- 执行的 SQL 或脚本命令 +- 返回结果摘要 +- 若数据缺失,明确归类为“数据基线异常” + +### Task 5: 执行接口端到端验证并清理进程 + +**Files:** +- Reference: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiFileUploadController.java` +- Reference: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiBankTagController.java` +- Reference: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiBankStatementController.java` +- Modify: `docs/tests/records/2026-03-20-bank-tag-new-model-validation-verification.md` +- Modify: `docs/reports/implementation/2026-03-20-bank-tag-new-model-validation-record.md` + +- [ ] **Step 1: 启动 Mock 服务** + +Run: + +```bash +mkdir -p logs +cd lsfx-mock-server +nohup python3 main.py > ../logs/lsfx-mock-validation.log 2>&1 & +echo $! > ../logs/lsfx-mock-validation.pid +cd .. +``` + +Expected: + +- `logs/lsfx-mock-validation.pid` 已生成 +- `http://localhost:8000/docs` 可访问 + +- [ ] **Step 2: 启动后端 Jar 服务** + +Run: + +```bash +./bin/restart_java_backend.sh stop +nohup ./bin/restart_java_backend.sh start > logs/backend-validation.log 2>&1 & +echo $! > logs/backend-validation.pid +``` + +Expected: + +- 后端监听在 `http://localhost:62318` +- 若启动失败,先看 `logs/backend-console.log`,记录失败后停止执行 + +- [ ] **Step 3: 登录并取 token** + +Run: + +```bash +curl -s http://localhost:62318/login/test \ + -H 'Content-Type: application/json' \ + -d '{"username":"admin","password":"admin123"}' | tee /tmp/bank-tag-login.json +jq -r '.token' /tmp/bank-tag-login.json +``` + +Expected: + +- 返回非空 token + +- [ ] **Step 4: 触发拉取本行信息链路生成新的 Mock 流水** + +先从数据库挑 1-3 个真实身份证号,再调用接口: + +```bash +python3 - <<'PY' >/tmp/bank-tag-id-cards.json +from pathlib import Path +import json, pymysql, re + +text = Path('ruoyi-admin/src/main/resources/application-dev.yml').read_text(encoding='utf-8') +match = re.search(r"url:\s*jdbc:mysql://(?P[^:/?#]+):(?P\d+)/(?P[^?\n]+).*?\n\s*username:\s*(?P[^\n]+)\n\s*password:\s*(?P[^\n]+)", text, re.S) +conn = pymysql.connect( + host=match.group('host'), + port=int(match.group('port')), + user=match.group('user').strip(), + password=match.group('pwd').strip(), + database=match.group('db').strip(), + charset='utf8mb4', + cursorclass=pymysql.cursors.DictCursor, +) +with conn, conn.cursor() as cursor: + cursor.execute(""" + SELECT DISTINCT id_card + FROM ccdi_base_staff + WHERE del_flag = '0' + AND id_card IS NOT NULL + AND id_card <> '' + ORDER BY id ASC + LIMIT 3 + """) + print(json.dumps([row['id_card'] for row in cursor.fetchall()], ensure_ascii=False)) +PY + +TOKEN=$(jq -r '.token' /tmp/bank-tag-login.json) +PROJECT_ID=<把 Task 1 选定的 project_id 填到这里> +curl -s http://localhost:62318/ccdi/file-upload/pull-bank-info \ + -H "Authorization: Bearer $TOKEN" \ + -H 'Content-Type: application/json' \ + -d "{\"projectId\":${PROJECT_ID},\"idCards\":$(cat /tmp/bank-tag-id-cards.json),\"startDate\":\"2026-03-01\",\"endDate\":\"2026-03-20\"}" +``` + +Expected: + +- 返回 `拉取任务已提交` +- 说明 Mock 随机命中链路已被主工程实际调用 + +- [ ] **Step 5: 触发整项目手动重算** + +Run: + +```bash +TOKEN=$(jq -r '.token' /tmp/bank-tag-login.json) +curl -s http://localhost:62318/ccdi/project/tags/rebuild \ + -H "Authorization: Bearer $TOKEN" \ + -H 'Content-Type: application/json' \ + -d "{\"projectId\":${PROJECT_ID},\"modelCode\":null}" +``` + +Expected: + +- 返回 `{"code":200,...}` +- 手动重算任务成功提交 + +- [ ] **Step 6: 轮询数据库确认重算任务成功,并查出一条新增模型命中记录** + +Run: + +```bash +python3 - <<'PY' +from pathlib import Path +import pymysql, re, time + +PROJECT_ID = int("<把 Task 1 选定的 project_id 填到这里>") +TARGET_RULES = ( + 'GAMBLING_SENSITIVE_KEYWORD','SPECIAL_AMOUNT_TRANSACTION','SUSPICIOUS_INCOME_KEYWORD', + 'FOREX_BUY_AMT','FOREX_SELL_AMT','LARGE_PURCHASE_TRANSACTION', + 'STOCK_TFR_LARGE','WITHDRAW_CNT','LARGE_STOCK_TRADING' +) + +text = Path('ruoyi-admin/src/main/resources/application-dev.yml').read_text(encoding='utf-8') +match = re.search(r"url:\s*jdbc:mysql://(?P[^:/?#]+):(?P\d+)/(?P[^?\n]+).*?\n\s*username:\s*(?P[^\n]+)\n\s*password:\s*(?P[^\n]+)", text, re.S) +conn = pymysql.connect( + host=match.group('host'), + port=int(match.group('port')), + user=match.group('user').strip(), + password=match.group('pwd').strip(), + database=match.group('db').strip(), + charset='utf8mb4', + cursorclass=pymysql.cursors.DictCursor, +) +with conn, conn.cursor() as cursor: + task = None + for _ in range(30): + cursor.execute(""" + SELECT id, status, model_code, hit_count, success_rule_count, failed_rule_count + FROM ccdi_bank_tag_task + WHERE project_id = %s + ORDER BY id DESC + LIMIT 1 + """, (PROJECT_ID,)) + task = cursor.fetchone() + print(task) + if task and task['status'] == 'SUCCESS': + break + time.sleep(2) + + cursor.execute(f""" + SELECT id, rule_code, bank_statement_id, object_key, reason_detail + FROM ccdi_bank_statement_tag_result + WHERE project_id = %s + AND rule_code IN ({','.join(['%s'] * len(TARGET_RULES))}) + ORDER BY id DESC + LIMIT 10 + """, (PROJECT_ID, *TARGET_RULES)) + for row in cursor.fetchall(): + print(row) +PY +``` + +Expected: + +- 最新任务状态为 `SUCCESS` +- 至少查到 1 条目标规则命中结果 + +- [ ] **Step 7: 用命中的 `bank_statement_id` 回查接口详情** + +Run: + +```bash +TOKEN=$(jq -r '.token' /tmp/bank-tag-login.json) +BANK_STATEMENT_ID=<把 Step 6 查到的 bank_statement_id 填到这里> +curl -s "http://localhost:62318/ccdi/project/bank-statement/detail/${BANK_STATEMENT_ID}" \ + -H "Authorization: Bearer $TOKEN" +``` + +Expected: + +- 返回 `code = 200` +- `data.hitTags` 中能看到至少 1 个目标规则对应的命中标签 + +- [ ] **Step 8: 写结论并关闭本次启动的进程** + +Run: + +```bash +if [ -f logs/lsfx-mock-validation.pid ]; then kill "$(cat logs/lsfx-mock-validation.pid)" || true; rm -f logs/lsfx-mock-validation.pid; fi +./bin/restart_java_backend.sh stop || true +rm -f logs/backend-validation.pid +``` + +Expected: + +- Mock 进程已关闭 +- 后端 Jar 进程已关闭 +- 验证记录中明确写出“已完成进程清理” + +- [ ] **Step 9: Commit** + +```bash +git add docs/reports/implementation/2026-03-20-bank-tag-new-model-validation-record.md docs/tests/records/2026-03-20-bank-tag-new-model-validation-verification.md docs/tests/plans/2026-03-20-bank-tag-new-model-validation-execution-plan.md +git commit -m "补充新增模型打标完整验证记录" +```