- 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.
TEST-AD-001 · 理财师线(顾问 Agent)端到端包
当前结论(2026-09-13):
- Part A 缺口补测(真实 HTTP):31 PASS / 4 FAIL / 0 SKIP / 10 INFO,退出码 1。 4 条 FAIL 全部来自 AD8 接缝取证组,是预期内的取证结果,不计入通过率分母(见下「AD8 单列」)。
- Part B 浏览器(
09-advisor-pages.mjs收复后复跑):17 PASS / 0 FAIL / 0 SKIP,退出码 0。 - Part C 回归基线(
advisor_e2e_smoke.py原样未改):63 PASS / 0 FAIL / 0 SKIP,退出码 0。
读数纪律(沿用
TEST-CT-001/TEST-AN-003): ① INFO 不是 PASS,不得计入通过率分母;② AD8 的 4 条 FAIL 是「取证」不是「退化」,单列不入分母;③ 本线既有基线脚本一个字都没改 —— 回归对照的前提就是它不变。
⚠️ 与既有覆盖的关系(如实声明,勿夸大本包的新增性): 本线此前并非零覆盖。
advisor_e2e_smoke.py已覆盖/api/advisor-agent/*的写操作主链路(63 条),docs/memory/tests/2026-09-12-advisor-agent-e2e已覆盖 KYC 与会话。 本包新增的是三块此前无脚本级覆盖的面:① 接缝取证(build_advisor_tools的 5 个工具调真实 service,AD8);② 无前端调用方的端点(AD9 四条,实测接口可用但全仓无引用);③ 代客下单链路(AD10,对应前端浅覆盖点AdvisorCustomersPage的代客入口从未被点)。
产物
| 产物 | 路径 | 位置 |
|---|---|---|
| 企业级测试日志 | TEST-LOG-2026-09-13-AD-001.md |
本包 |
| 缺口补测脚本(AD7–AD10) | scripts/dev/advisor_gap_e2e_smoke.py |
仓库内(本轮新建) |
| 回归基线脚本(原样未改) | scripts/dev/advisor_e2e_smoke.py |
仓库内(既有) |
| 浏览器脚本(本轮收复进仓库) | scripts/e2e/09-advisor-pages.mjs |
仓库内(原在仓库外 C:/Users/Windows/e2e-jinrong/) |
结果明细 _raw/(逐用例原始记录,未加工)
| 文件 | 内容 | 结果 |
|---|---|---|
ad-gap.md |
AD7–AD10 逐条矩阵(期望 / 实测 / 证据) | 31 PASS / 4 FAIL / 10 INFO |
results-09-advisor.json |
09-advisor-pages.mjs 的原生 JSON 结果(Part B) |
17 PASS / 0 FAIL |
09-advisor-pages.stdout.txt |
同轮终端原始输出 | 退出码 0 |
_partc-advisor.md |
Part C 回归基线报告(advisor_e2e_smoke.py) |
63 PASS / 0 FAIL |
_partc-advisor.stdout.txt |
同轮终端原始输出 | 退出码 0 |
shots/ |
Part B 四张页面截图(09-advisor-*.png) |
— |
复跑一致性: AD8 的 4 条 FAIL 在本轮多次复跑中稳定复现,且对照组 8-01/8-02 稳定 PASS —— 这两点共同排除了"探针本身写错"这一解释(见下)。
AD8 —— 接缝取证组(4 FAIL 是预期结果,不计入分母)
这是一组「把读代码的推断变成运行取证」的用例,不是回归。 判据是能否稳定复现,不是 PASS。
build_advisor_graph 构造的 5 个工具里,有 3 个(占 4 条用例)接到了不存在的 service 方法:
| 用例 | 工具 | 工具内写的是 | 真实 API | 实测异常 |
|---|---|---|---|---|
| 8-03 | manage_kyc_session(action="chat") |
kyc_service.chat(...) |
kyc_session_service.py:140 chat_session |
AttributeError: 'KycSessionService' object has no attribute 'chat' |
| 8-04 | manage_kyc_session(action="get") |
kyc_service.get_session(session_id=) |
kyc_session_service.py:133 get_session(session_id, *, auth) —— 缺 keyword-only auth |
TypeError: missing 1 required keyword-only argument: 'auth' |
| 8-05 | search_templates |
template_service.search(...) |
TemplateService 只有 reload/try_render/list_published_prompts,无 search |
AttributeError: no attribute 'search' |
| 8-06 | compliance_check |
compliance_service.check(text=, scene=) |
compliance_check_service.py:38 check_text(payload, *, trace_id, advisor_id)(连调用形态都不同) |
AttributeError: no attribute 'check' |
两个对照组(8-01 持仓 / 8-02 净值)稳定 PASS —— 同一条探针路径、同一个 invoke 方法、同样的真实 service 注入,只有接错的那三个失败。这正是排除"探针写错"的关键证据。
为什么一直没被发现(8-07,本组最值得记的一条)
build_advisor_graph 在本仓是孤儿代码:全仓唯一调用方是 tests/test_step11_agent_graph.py:113,而它在 :114-117 给四个 service 全注入 Mock()。
Mock() 对任意属性访问都返回可调用对象,于是 kyc_service.chat(...)、template_service.search(...)、compliance_service.check(...) 在测试里全部"成功"。实测 8-07:同一调用在 Mock 下返回 ok → <Mock name='mock.chat()' id=...>。
这正是盘点里「19 个
test_sprint*.py伪造全部 Core 数据源 → 结构上不可能发现接缝不匹配」的具体实例:不是测试没覆盖,而是测试用的替身把错误吃掉了。
严重度定位(不高报)
整支 agent_graph.py 是孤儿代码(无生产调用方)⇒ 定为潜在缺陷,不列 P0/P1。但它同时也是"测试给出假绿"的实证,故必须记账。
缺陷与发现(报告侧;本轮不修)
ADV 缺陷-3 —— 三处工具绑定错误(P3,孤儿代码)
见上表。根因已逐条定位到真实 service 的方法名与签名(含行号)。修复方向(供修复轮参考,本轮不动):把工具内调用改为 chat_session / get_session(session_id, auth=...) / script_template_service 的真搜索 / check_text(payload, trace_id=..., advisor_id=...),并让 test_step11_agent_graph.py 改用真实 service 或严格的 spec= Mock,否则改完仍会被遮蔽。
ADV 缺陷-4 —— 四条端点可用但无消费方(P3,观察)
| 端点 | 前端调用方(实测) |
|---|---|
GET /api/advisor-agent/dashboard/ping |
无 |
GET /api/advisor-agent/allocation/ping |
无 |
POST /api/advisor-agent/guard/check |
有 |
POST /api/advisor-agent/copy/track |
有 |
两个 ping 端点实测 module/status 回显正确({'module': 'dashboard', 'status': 'ready'}),属可用但无消费方。不构成故障,记录以备清理或接入。
已验证转绿的正面证据(本包价值最高的部分)
| 项 | 取证方式 | 结果 |
|---|---|---|
| KYC 会话链路端到端可用 | AD7:建会话 → 读视图 → chat → complete,全链 HTTP 200 | ✅ |
| v1.0 的 500 已修复且可复现验证 | 7-02(GET /sessions/{id},v1.0 时 500)→ HTTP 200;7-04(POST /sessions/{id}/chat,v1.0 时 500)→ HTTP 200 |
✅ 双点回归 |
agent_message.created_at 无 NULL(v1.0 500 的根因面) |
7-05 直连库:实际 2 行,NULL 的 seq_no=[] |
✅ |
| 状态机严格 | 7-09 completed 后再 chat → 409/40901;7-10 completed 后再 complete → 409/40901 |
✅ 非法迁移被拒 |
| 越权与不存在的会话都不静默放行 | 7-06 非归属顾问读同一会话 → 403/40302;7-07 不存在 session → 404/40401 |
✅ |
| 代客下单的归属校验 | 10-03 非名下客户 CUST-1004 → 403 AUTH_403_NOT_ASSIGNED;10-05 不存在的 CUST-000000 → 403(非静默放行);10-02a 名下客户回显 customer_id='CUST-1001' 一致 |
✅ |
| 通道冒用被矩阵层拦下 | 10-06 用 customer 型 token 冒用 advisor 通道 → 403 AUTH_403_AGENT_MISMATCH |
✅ |
| 缺头即拒 | 10-04 缺 X-Agent-Type → 401 AUTH_401_MISSING_AGENT_TYPE |
✅ |
| 提示词注入被拦 | 9-04 → HTTP 400 / 40002 |
✅ |
| 安全文本放行的枚举契约 | 9-03a action='passed'(拦截值为 'blocked');9-03b 放行时 guard_type=None |
✅ |
一处期望订正(我方,非产品):
9-03a首跑我把期望写成action='pass'而 FAIL。查源码后确认真实枚举是'passed'(input_guard_service.py:22),拦截是'blocked'(input_guard.py:111)。是我的期望错,不是产品错 —— 已订正并补9-03b区分"放行"与"未命中规则"两件事。
复现三连
# 0) 前置:uvicorn 8000 + MySQL 在跑
curl -s http://127.0.0.1:8000/api/ready # 期望 ok=true
# 1) AD7–AD10 缺口补测(退出码 0 无 FAIL / 1 有 FAIL / 2 前置失败)
# 注意:AD8 是取证组,预期 4 条 FAIL ⇒ 退出码 1 属预期
python scripts/dev/advisor_gap_e2e_smoke.py --report D:/tmp/e2e-gap/ad-gap.md
# 2) 只跑 AD8 接缝取证(最快复现那 4 条)
python scripts/dev/advisor_gap_e2e_smoke.py --only AD8
# 3) 回归基线(必须保持退出码 0)
python scripts/dev/advisor_e2e_smoke.py --report D:/tmp/e2e-gap/_partc-advisor.md
# 4) 浏览器(须 Vite 5173;串行执行,勿与其他包并发)
cd scripts/e2e && node 09-advisor-pages.mjs
数据副作用: 本线 Part A 建了 KYC 会话、发了 copy/track 留痕,均落在 jinrong_agent 的追加型表(按语义不回滚)。Part C 回归基线 advisor_e2e_smoke.py 会写 Core 交易表 —— 该表已在 Phase 6 按 snapshot.sql 还原并逐表 CHECKSUM 校验通过(见横切包 XC-001 §6)。
剩余风险 / 未覆盖
| # | 项 | 说明 |
|---|---|---|
| 1 | AD8 修法未经实施验证 | 本轮只取证。修复后需同时改测试替身(改真实 service 或 spec= Mock),否则仍被遮蔽 |
| 2 | 7-03 用例号缺位 |
AD7 现有 7-01→7-02→7-04,无 7-03(历史编号沿革,非丢失用例) |
| 3 | 7-05 的判定面偏窄 |
只验 created_at 非 NULL(2 行),未覆盖 agent_message 的其它列约束 |
| 4 | 代客下单未走写入侧 | AD10 只验到"受理与归属",未实际提交一笔代客交易(那属客户线写表,与 CT-001 的还原口径耦合) |
| 5 | 无前端调用方的两条 ping 端点 | 记录在案,未判定该删该接 |