Files
group_xinghuo_jinrong/docs/superpowers/plans/2026-09-12-agent-frontend-e2e.md
T
zhanghongyu_0626 2296a4a002 feat(api): Add convert_meta_api for retrieving latest NAV date and enhance created_at field handling
- Introduced `convert_meta_api` endpoint to fetch the latest NAV date for conversion processes, restricted to users with the "risk_officer" role.
- Updated `created_at` field in `AgentMessage` to use UTC timezone for consistency in timestamp handling.
- Added `get_max_product_nav_date` method in `CoreReadOnlyRepository` to support the new API functionality.
- Enhanced Milvus template loading in `MilvusTemplateVectorStore` to ensure collections are loaded when they exist.

This update improves the API's capability to handle conversion metadata and ensures accurate timestamp management across the application.
2026-09-13 12:40:44 +08:00

12 KiB
Raw Blame History

顾问前端 + 风控新功能(基金转换 T+1)+ 风控前端 端到端测试(第三轮)

状态:已执行完毕(2026-09-12)。本文件是实施计划的入库副本,勾选状态为实际结果。 设计说明见 docs/superpowers/specs/2026-09-12-agent-frontend-e2e-design.md; 产出报告见 docs/memory/tests/2026-09-12-agent-frontend-e2e/TEST-LOG-2026-09-12-FE-001.md。

本 plan 只做测试与报告,不改任何业务代码 —— 实际执行亦如此(app/ 与 web/src/ 零改动)。

Context

前两轮都是 API-only,且都被后续合并改写了基线:

轮次 包 覆盖 现状
第一轮 docs/memory/tests/2026-09-12-advisor-agent-e2e/ 顾问 API 全量 已失真:结论写于 03fce88 之前 → 本轮已改写为 v1.1
第二轮 docs/memory/tests/2026-09-11-risk-agent-e2e/ 风控 API(进程内 TestClient) 基线有效,但未覆盖基金转换
本轮 docs/memory/tests/2026-09-12-agent-frontend-e2e/ 顾问前端 + 风控新功能 + 风控前端 已完成

驱动本轮的三件事:

  1. 顾问前端已就绪 —— 四页此前从未在真实浏览器里点过。
  2. 风控新功能已合入 —— 03fce88 把「基金转换 T+1」整条线并入 merger(110 文件、仅后端);c09b987 补上 RiskConvertPage 前端与迁移。该功能从未做过端到端。
  3. 基线被合并改写 —— 当前工作区在 merger @ c09b987。

开工前必须知道的三条基线订正(已实测)

  • D1 已修 —— app/repository/core_ro.py:839,851 ✅ 实测转绿(见 Task 4)
  • D2 未修 —— app/model/entities.py:116 的 created_at 仍无 Python 侧 default ✅ 实测仍 500
  • D3 定性存疑 —— 设计时的假设「高层 MilvusClient 自动 load,所以不是未 load 的问题」被服务端日志证伪,详见 Task 4 结果

Goal

对 A(顾问前端)· B(风控转换 + RBAC)· C(风控前端)三块做真实端到端(真浏览器 / 真 HTTP / 真 MySQL / 真 DeepSeek)验证,产出可复现的通过矩阵与缺陷清单,先报告、确认后再修。

Architecture

Part A/C 浏览器跑道                      Part B API 跑道
────────────────────────               ────────────────────────
Chromium(channel:chrome)               httpx.Client
   ↓ http://localhost:5173                ↓ http://127.0.0.1:8000
Vite dev server (proxy /api)           uvicorn app.main:app
   ↓                                       ↓
        └──────── 同一套 MySQL + Redis + DeepSeek ────────┘

浏览器跑道必须经 Vite(app/ 无 CORS 中间件)。

Tech Stack

Playwright 1.63.0(Node,仓库外)+ 系统 Chrome · Python 3.13 + httpx 0.28 · MySQL 8 双库 + Redis 6380 + Milvus Lite + Ollama bge-m3

Global Constraints(全部遵守 ✅)

  1. ✅ 不改任何业务代码 —— app/、web/src/ 零改动
  2. ✅ 不修 D1–D4,只报告
  3. ✅ 不改 web/package.json —— 浏览器脚本留在仓库外
  4. ✅ 不修 sandbox_risk_test.py:325-326 —— 只作为「测试资产腐化」上报
  5. ✅ 不动 run_demo_smoke.ps1 —— 同上
  6. ✅ 未执行任何 DROP 重建(保留取证数据)
  7. ✅ 凭据未逐字写入交付文档
  8. ✅ KYC / 话术两页如实标 FAIL 并附页面取证

File map(实际)

文件 动作 结果
C:/Users/Windows/e2e-jinrong/harness.mjs 改 ✅ ROUTES 补页 + clearAuth / waitRows / cjk;login() 加 reload:false
C:/Users/Windows/e2e-jinrong/09-advisor-pages.mjs 建 ✅ 17 用例 · 15 PASS / 2 FAIL
C:/Users/Windows/e2e-jinrong/10-risk-pages.mjs 建 ✅ 21 用例 · 19 PASS / 2 FAIL
C:/Users/Windows/e2e-jinrong/11-cross-role.mjs 建 ✅ 9 用例 · 4 PASS / 5 FAIL
scripts/dev/risk_e2e_smoke.py 建 ✅ 64 用例 · 63 PASS / 0 FAIL / 1 SKIP · 退出码 0
scripts/dev/advisor_e2e_smoke.py 复用不改 ✅ 重跑取当前基线 · 63 用例 · 60 PASS / 3 FAIL
docs/memory/tests/2026-09-12-advisor-agent-e2e/TEST-LOG-...-ADV-001.md 改 ✅ 升 v1.1 · 关闭 D1
docs/memory/tests/2026-09-12-agent-frontend-e2e/ 建 ✅ README + FE-001 + _raw/
docs/superpowers/specs/2026-09-12-agent-frontend-e2e-design.md 建 ✅
docs/superpowers/plans/2026-09-12-agent-frontend-e2e.md 建 ✅ 本文件
docs/memory/MEMORY.md · TODO.md 改 ✅ 已同步

Task 0 · 环境前置自检 ✅

  • 确认树:merger @ c09b987
  • 只读探测演示数据未过期(未 DROP)
  • 记录基线:NAV 最新 2026-09-11 · core_product_nav 覆盖 14 产品
  • 抓到 merge 前的旧 uvicorn 进程(PID 27348,启动于 16:55:24,早于代码落地 17:52–17:59)→ 重启,否则全部转换用例假失败

结果:前置通过。新增前置项:/openapi.json 必须含转换路径 —— 已写入报告 §3。

Task 1 · 起服务 ✅

  • python -m uvicorn app.main:app --host 127.0.0.1 --port 8000(无 --reload)
  • /health 返回 {"status":"ok"}
  • cd web && npm run dev → http://localhost:5173
  • Vite 代理 /api 生效

Task 2 · Part B:风控 API 真实 HTTP E2E ✅

  • 新建 scripts/dev/risk_e2e_smoke.py,照搬 advisor_e2e_smoke.py 骨架(Ctx / ok/bad / --base-url / --only / --report / 退出码 0·1·2)
  • R1 鉴权负例 · R2 台账 RBAC · R3 处置状态机 · R4 适当性 · R5 AML · R6 转换线
  • 顺序依赖:先 simulate/trade + aml/scan 造 alert,再做 R2/R3

结果:63 PASS / 0 FAIL / 1 SKIP,退出码 0。

过程中的三条假 FAIL(全是脚本自身的 bug,已定位并修)

假 FAIL 真因 修法
转换受理 可用份额不足:申请 30000,可用 0(已扣除在途转换占用) 反复跑测把 CUST-1001 持有的 30000 份 PROD-110022 占满 换仍有 80000 份余量的 CUST-9527
accept_date=2026/09/15 期 400 FastAPI 查询校验 pre-handler 就拦下,实为 422 期望改 422 REQUEST_VALIDATION_FAILED
撤单 409 CANCEL_NOT_ALLOWED 我自己的顺序错:先跑了 confirm_batch,单子已进 nav_pending(不可撤) 撤单挪到 confirm 之前,并另开一笔专用转换

三条都不是产品缺陷 —— 已用独立探针脚本逐条证实。

Task 3 · Part A/C:浏览器 E2E ✅

  • harness.mjs 补路由 + 抽 clearAuth / waitRows / cjk
  • 登录回归:去掉 reload 兜底仍能登录 → A6.1 PASS(BUG-1 回归确认)
  • Part A 顾问:首页 / 合规 / 话术模板 / KYC / 市场异动 → 15 PASS / 2 FAIL(D2 · D3)
  • Part C 风控:首页 / 台账 / 适当性 / AML / 模拟交易 / 转换页 → 19 PASS / 2 FAIL(F1 · F2)
  • 跨角色:4 PASS / 5 FAIL(F3)
  • 明确排除:两个 SSE 页

结果:47 用例 · 38 PASS / 9 FAIL。

AntD 6 的坑(本轮踩到,已固化)

坑 实际
.ant-tabs-tabpane-active 匹配 0 元素 活跃面板是 .ant-tabs-content-active
.ant-select-selection-item 取不到值 值节点是 .ant-select-content
.ant-table-row 匹配 0 元素 用 .ant-table-tbody tr
CJK 之间被插入空格 加 cjk() 辅助函数生成 \s* 间隔正则
非活跃 Tab 面板仍挂载且隐藏 所有交互必须 scope 到 pane(),否则选到隐藏元素而超时

Task 4 · 改写第一轮顾问报告 ✅

  • 重跑 advisor_e2e_smoke.py
  • §3 被测版本 → merger @ c09b987
  • 关闭 D1(附 core_ro.py:839,851 证据 + G5 10/10 实测)
  • §4 用例数按实跑口径(63 用例)
  • D3 按本轮实测重新定性 —— 见下
  • §11 结论改写 · §12 追加 v1.1 行

D1 结论:✅ 已关闭。v1.0 为 3 PASS / 2 FAIL / 5 SKIP,本轮 G5 10/10 PASS,scanned=14 created=2 used_fallback=False。

D3 结论 —— 我的设计期假设被证伪:

  • plan 假设「高层 MilvusClient 在 search 时自动 load,所以不是未 load 的问题」。这个假设是错的。
  • uvicorn 日志里 MilvusException (code=101, message=Collection 'kb_script_templates' is in state 'released'; call load() before search/get/query) 出现 10 次,且无其它 Milvus 错误类型。
  • 第二层观察:集合目录 5.0K / 2 文件,而已灌集合为 50K / 5 文件 ⇒ 疑似同时是空集。仅补 load() 未必恢复召回。
  • 如实记入报告,不掩饰假设被推翻。

pymilvus 探针两次失败:① Illegal uri(legacy connections 在 import 期读 MILVUS_URI);② Open local milvus failed(运行中的 uvicorn 持有 Milvus Lite 文件锁)。最终改用服务端自身日志作为判别依据 —— 这比进程外探针更直接,且不需要停止服务。

Task 5 · 产出本轮报告包 ✅

  • 建包:README.md + TEST-LOG-2026-09-12-FE-001.md(12 节 _TEMPLATE.md 结构)
  • 缺陷四类归属:实现缺陷(F1/F2/F4)· 纵深防御缺口(F3)· 承接未修(D2/D3)· 测试资产腐化(T1)
  • 每个缺陷给:现象 / 复现 / 期望-实际 / 根因 file:line / 修复方向(只写方向)
  • 建 superpowers spec + plan 入库副本
  • 同步 MEMORY.md / TODO.md

Task 6 · 收口与复现性 ✅

  • 报告附复现三连
  • 记录浏览器脚本在仓库外的事实与代价,挂到 TODO.md 的「E2E 最小集进仓库」P0
  • 列出未测/不可判定项及原因

结果总览

跑道 用例 PASS FAIL SKIP
顾问 API 63 60 3 0
风控 API 64 63 0 1
顾问前端 17 15 2 0
风控前端 21 19 2 0
跨角色 9 4 5 0
合计 174 161 12 1

收敛 6 缺陷:D2(承接)· D3(承接,定性更正)· F1 转换页预置跨主体必失败 · F2 alert_id/alert_ids 字段名不匹配 · F3 无路由级角色守卫 · F4 确认日默认越界 + 1 项测试资产腐化 T1:sandbox_risk_test.py:325-326 · run_demo_smoke.ps1

交叉印证成立:浏览器侧失败与 API 侧同名用例同因同果,无额外分歧。

建议修复顺序:F1 → F2(演示可见、改动极小)→ D2 → F4 → F3 → D3


验证方式(总)· 复现三连 ✅

# 1) 后端(WinError 10013 时退 18000,并同步改下面所有 URL)
python -m uvicorn app.main:app --host 127.0.0.1 --port 8000

# 2) 前端 —— 必须用 localhost:5173(app/ 无 CORS,浏览器只能走 Vite 代理)
cd web && npm run dev

# 3) 三支脚本
python scripts/dev/risk_e2e_smoke.py        # 退出码 0 = 全过 / 1 = 有 FAIL / 2 = 前置失败
python scripts/dev/advisor_e2e_smoke.py
cd C:/Users/Windows/e2e-jinrong && node 09-advisor-pages.mjs && node 10-risk-pages.mjs && node 11-cross-role.mjs

本机特有状态依赖(换机复现须知):

  • 浏览器三脚本不在仓库内 —— 需手工拷贝 C:/Users/Windows/e2e-jinrong/
  • CUST-9527 的 PROD-110022 可用份额会被转换用例消耗,耗尽后需重灌种子
  • Milvus kb_script_templates 本轮刻意未灌(写操作,且会掩盖 D3 的待修状态)
  • NAV 需覆盖到 2026-09-11(决定确认批处理的可用日期区间)

不在本 plan 范围

  • 不修 D1–D4 及任何业务代码
  • 不改 web/package.json
  • 不修 sandbox_risk_test.py 失效断言、不修 run_demo_smoke.ps1 —— 只上报
  • 不测两个 SSE 对话页、不测 agent_tools.py / agent_graph.py
  • 不收敛既有 test_sprint* 红项
  • 不执行 prepare_all.ps1 式双库 DROP 重建
  • 不做性能/压力测试;不做响应式与可访问性专项