Files
group_xinghuo_jinrong/docs/memory/tests/2026-09-13-risk-e2e/TEST-LOG-2026-09-13-RK-001.md
T
zhanghongyu_0626 188bf6a438 feat(analyst_agent): Add support for recent days queries and enhance SQL hint generation
- Introduced `_recent_days_series_hint` to handle queries related to "最近N天" for time series data aggregation.
- Added `_cn_num_to_int` function to convert Chinese numerals to integers for better query parsing.
- Updated `_nl_sql_hints` to incorporate the new hint generation logic, ensuring accurate SQL output for recent days queries.
- Enhanced documentation to reflect these changes and improve clarity on the new functionalities.
2026-09-13 22:36:19 +08:00

9.4 KiB
Raw Blame History

测试日志:风控线(风控 Agent)端到端边界补测与恒真断言修复对照

1. 文档元数据

项 值
测试记录编号 TEST-LOG-2026-09-13-RK-001
缺陷/变更标题 风控线端到端补测(RK7 后端边界与语义 · RK8 恒真断言修复后对照)+ Part B/C
文档版本 v1.0
创建日期 2026-09-13
关联分支 merger
关联拍板/TODO 本轮七项口径;另有 RK 发现-1「未知资源语义分裂」待拍板
风险等级 LOW(无 P0/P1;两条发现均为 P3 契约/口径类)
缺陷类型 契约不一致("找不到"语义分裂)· 时区口径 · 测试资产腐化(F-01,已修)
发现阶段 端到端覆盖缺口补测轮 · Part A/B/C

2. 组织与责任

项 值
所属模块 风控线(风控 Agent):app/api/risk.py · app/service/risk_* · app/tool/core_ro_tool.py
模块负责人 —
发现人 本轮补测
修改人 无(本轮只报告不修业务代码);测试资产 F-01 已修(单独记账)
测试执行人 本轮补测
评审人 —

3. 缺陷描述

RK 发现-1 —— suitability/check 的「找不到」语义在同一路由内按角色分裂

项 值
缺陷编号 RK-1
严重等级 P3(契约不一致;fail-closed,无安全后果)
复现步骤 python scripts/dev/risk_gap_e2e_smoke.py --only RK7(用例 7-07 / 7-07c / 7-07d / 7-07e / 7-08b)
期望 未知客户的响应形态在角色间一致
实际 risk_officer → 200(blocked=true mismatch_type='not_found' SUIT_NOT_FOUND)· advisor → 403 AUTH_403_NOT_ASSIGNED · customer → 403 AUTH_403_NOT_OWNER;未知产品则 200+blocked。404 从未出现
根因 归属/数据域校验先于资源存在性校验 ⇒ "不存在"被"无权"遮蔽;app/api/risk.py:134 的 LookupError → 404 分支因此不可达(本轮未能构造)
修复方案 本轮不修。待拍板:统一为 404(信息更准)还是维持现状(不泄漏客户存在性,安全上更优)。当前实现 fail-closed,不静默放行,三个角色均被拒

RK 发现-2 —— risk_alert.created_at 的时区口径未统一

项 值
缺陷编号 RK-2
严重等级 P3(口径/系统性坑)
复现步骤 python scripts/dev/risk_gap_e2e_smoke.py --only RK7(用例 7-10)
期望 时间字段带明确时区语义
实际 '2026-09-13T21:05:39.109000' —— 本地时区、无偏移后缀的 ISO 串
根因 落库写入未带时区,读出不标注
修复方案 本轮不修。影响面:audit_log.created_at >= DATE_SUB(NOW(), INTERVAL 15 MINUTE) 这类「近 N 分钟」查询,距上轮 <15 分钟复跑会假 FAIL(本项目 R4 已多次踩到)。处置:同类窗口查询一律距上轮 ≥15 分钟,或改按本轮 runstamp 过滤(更优)

测试资产腐化 F-01 —— 03-risk.mjs:23 恒真断言(本轮已修,单独记账)

项 值
缺陷编号 F-01
严重等级 P2(测试基建:该断言永远 PASS,不构成任何证据)
复现步骤 修复前:任意运行 03-risk.mjs,第 23 行恒 PASS
期望 对实测值做真实断言
实际 原写法 ok(..., true, ...) —— 期望值写死为 true
根因 资产腐化:脚本从未被校准(本轮首跑才暴露同类问题)
修复方案 已修:改为对实测值的真实断言(风控首页 KPI 为真实正整数(非 0/非占位),实测 heroTotal:37)。不写死为某个具体数字 —— 因为预警数随演示动作变化,写死会在下次跑批时假 FAIL

4. 变更清单

类型 路径 说明
新建 scripts/dev/risk_gap_e2e_smoke.py RK7–RK8 缺口补测脚本(真实 HTTP)
修复(测试资产) scripts/e2e/03-risk.mjs:23 F-01 恒真断言 → 真实断言
收复 scripts/e2e/10-risk-pages.mjs · scripts/e2e/03-risk.mjs 自仓库外收回,改指向仓库内 scripts/e2e/harness.mjs(F-05)
未改 scripts/dev/risk_e2e_smoke.py 回归基线,一个字未动
未改 app/** · web/src/** 本轮边界:不改业务代码

5. 测试执行记录

序号 类型 用例/命令 执行人 结果 证据
1 Part A python scripts/dev/risk_gap_e2e_smoke.py --report …/rk-gap.md 本轮 23 PASS / 0 FAIL / 0 SKIP / 8 INFO(退出码 0) _raw/rk-gap.md · _raw/rk-gap.stdout.txt
2 Part B node 10-risk-pages.mjs 本轮 21 PASS / 0 FAIL _raw/results-10-risk.json
3 Part B node 03-risk.mjs(F-01 修复后) 本轮 14 PASS / 0 FAIL / 2 INFO _raw/…(见横切包 03-risk.stdout.txt)
4 Part C python scripts/dev/risk_e2e_smoke.py --report …/_partc-risk.md 本轮 63 PASS / 0 FAIL / 1 SKIP(退出码 0,基线未退步) _raw/_partc-risk.md · _raw/_partc-risk.stdout.txt

分组明细(Part A):

组 覆盖对象 PASS FAIL SKIP INFO
RK7 后端补漏(分页边界 · 接口↔库对账 · 处置前后差值 · 语义分裂 · G-08 三要素 · 时区口径) 22 0 0 4
RK8 浏览器复跑对照(恒真断言修复后逐条比对基线) 1 0 0 4
合计 23 0 0 8

RK7 逐条关键实测:

用例 断言 实测
7-01 / 7-01b page=0 / page=-3 → 422 HTTP 422 REQUEST_VALIDATION_FAILED ×2
7-02 / 7-02a / 7-02b / 7-02c 超末页 page=999999 → 200、items=[]、total 与首页一致、回显 page 一致 total=53(两页一致)
7-03 / 7-03a 分页不重复,且两页各自非空 重复 [] · page1=5 page2=5
7-04 / 7-04a / 7-04b status=pending_review 过滤生效 + stats 自洽 n=36 states=['pending_review'] · stats=36 total=36
7-05 接口 total ↔ 库计数 API 36 / DB 36 ✅
7-06 / 7-06a 处置 → 计数恰好 −1(前后差值) 36 → 35
7-07 / 7-07a 未知客户(officer)→ 200 且 fail-closed blocked=True mismatch_type='not_found' code='SUIT_NOT_FOUND'
7-07c 通道值与账号类型不符 → 矩阵层先拦 HTTP 403 AUTH_403_AGENT_MISMATCH
7-07d 未知客户(advisor 归属分支)→ 403 非 404 HTTP 403 AUTH_403_NOT_ASSIGNED
7-07e 未知客户(customer self 域)→ 403 非 404 HTTP 403 AUTH_403_NOT_OWNER
7-08 / 7-08a 已知客户 + 未知产品 → 200 + blocked blocked=True mismatch_type='not_found'
7-09 阻断响应补齐 G-08 三要素 advice='请联系持证投资顾问' · notice='本次请求已记录'

RK8 对照结果(F-01 修复后):

用例 断言 实测
8-00 对照规模 基线 21 条 / 本轮 21 条 · 交集 21 条
8-01 无 PASS→FAIL 退化 ✅ 比较 21 条交集,退化集 ∅
8-02 / 8-03 / 8-04 修复的旧 FAIL / 本轮新增 / 基线独有 均无

这条对照是本包的核心价值: 恒真断言被替换为真实断言后,原 21 条 PASS 全部仍然 PASS ⇒ 反证原基线不是被恒真断言撑起来的。缺少这一步,"修好了"就无法与"改断言把 FAIL 藏起来"区分。

本轮我方订正(1 处,非产品缺陷): 7-07 首跑我按 risk.py:134 的代码读法期望未知客户 → 404,实测 200。三角色逐一探测后确认是三分的 fail-closed 语义而非 404,遂改写为实测真值并把 404 分支登记为未覆盖路径。是我的期望错,不是产品错。

6. 数据准备

数据集 是否重灌 操作
jinrong_agent.risk_alert 否(且按纪律不还原) RK7-06 每跑一次推进 1 条 pending_review → confirmed_normal;本轮共 4 次含处置跑批,pending_review 41 → 35。追加型审计表,还原反而破坏审计链
jinrong_core 5 写表 — Part C 的 risk_e2e_smoke.py 会写入;已在 Phase 6 依 snapshot.sql 还原并逐表 CHECKSUM 校验通过(见横切包 XC-001 §6)
演示态恢复 如需 scripts/demo/seed_risk_agent.ps1

7. 结论

项 结论
需求覆盖 风控线后端 4 条路由此前已全覆盖;本包补齐分页边界 · 对账一致性 · 语义分裂取证 · 恒真断言修复对照四块
回归 ✅ 未退步:Part C 基线 risk_e2e_smoke.py 63 PASS / 0 FAIL(退出码 0);Part B 10-risk-pages.mjs 21/21 PASS 且 无 PASS→FAIL 退化
剩余风险 ① risk.py:134 的 404 分支仍不可达(未覆盖路径);② pending_review 计数不可还原(41→35,已登记);③ created_at 时区口径未统一
建议人工再验 ① 打开 /app/risk/home 目视确认 KPI 与台账在 pending_review=35 下自洽;② 若决定统一"找不到"语义,须先拍板(404 信息更准 vs 现状不泄漏客户存在性)

8. 签核 / 修订历史

版本 日期 修订人 说明
v1.0 2026-09-13 本轮补测 首次建立:RK7–RK8 + Part B/C 证据归档;F-01 修复对照