Files
group_fqcd_jr/docs/07-测试问题修复记录.md
T
qyqy 7677aeaee1 merge: 并入同事的场外申购/推广/行情/NL2SQL 线(11 提交、334 文件)
冲突仅 3 个文件,全部取并集(双方都没有需要丢弃的改动):
- app/main.py:import 双方路由(我方 knowledge_management + 同事的 offsite_fund/
  promotion_material);include_router 段本已自动合并
- app/service/agent/bootstrap.py:import 与工具注册均取并集
  (query_customer_profile + query_financial_data 都注册)
- tests/integration/test_config_release_mysql.py:outbox 清理同时保留
  架构师的 event_type 限定(防误删其它域 outbox 行)与同事新增的 peer_release_id

同事这轮带入:11 个 alembic 迁移(建 offsite_* / promotion_* 等表)、
场外申购与推广素材 Agent、financial NL2SQL 工具。
注意:本库尚无 offsite_*/promotion_* 表,跑相关测试前需要执行 alembic upgrade。

边界核对:同事的场外代码未写入场内交易表(fin_sim_order/fin_capital_flow/fin_cash_ledger),
符合 AGENTS.md 规则 8。
2026-09-11 18:56:26 +08:00

132 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 测试问题修复记录
> ⚠️ **两处已过期**:① 启动命令用 `conda activate jr_py313`,本机实际解释器是 `.\\.venv\\Scripts\\python.exe`;② 文中称「当前没有组员业务 Agent」,实际已在 `app\\service\\agent\\bootstrap.py` 注册 `FundQueryDemoAgent` 与 `CustomerServiceAgent`。
>
> (此批注由 2026-09-11 只读审计加入;原文未改动。详见 `docs/superpowers/ARCHIVE-2026-09-11-文档清理归档.md` §3)
P1-1:JWT sub 在认证阶段验证为 ASCII 正整数且不超过 BIGINT UNSIGNED 范围。
`test_security.py` 11 项通过,非法 sub 的真实 ASGI HTTP 请求在查询身份前返回 401。
> ⚠️ **一处已过期**:下文 P0-3 的启动命令用 `conda activate jr_py313`,本机实际解释器是
> `.\.venv\Scripts\python.exe`。(原文未改动,仅加此批注。)
>
> **背景变更(2026-09-11)**:本文原先的「问题来源」`docs\06-底座代码测试报告.md`
> 已随文档清理删除 —— 但**本文已完整承载该报告的全部 P0/P1 结论**(P0-1/2/3、P1-1/2/3/4/5 逐条在册),
> 因此本文现在是这些修复结论的**唯一权威来源**,不依赖已删文件。
问题来源(已删除,见上):06-底座代码测试报告.md(当时保留原报告、不覆盖原始证据)。
当前完成状态以 `docs/superpowers/sdd/2026-09-10-客服Agent与RAG-qyqy版/phase1-acceptance-report.md` 为准。
## P1-3 / P1-4:SSE 与分层
SSE 首次等待完成后输出 delta,终态重连用 replace;6 项测试覆盖 Unicode 分块和恢复。
Controller 数据查询移至 Repository,权限/事务/状态判断移至 Service;SSE 轮询由
RunQueryService 读取数据库快照,连接期间不持有数据库 Session。12 项相关回归通过。
AST 架构测试禁止 Controller 依赖 Model/Repository 和直接操作 Session。
接口目录实为 50 项(4 运行 + 7 会话 + 2 记忆 + 1 知识 + 33 管理 + 3 运维)。
这些是底座范围;不能把未实现的管理接口当作组员业务范围排除。报告的 46 项计数修正。
## P1-2:治理钩子接线及当前支持范围
工厂向每个新 Agent 注入 AgentGovernance;BaseAgent 调用 resolve/recall/review。
默认实现直读生效 ConfigRelease、按意图收窄工具集合、读取已审核禁止表达规则,
并通过 MemoryService 读取当前客户有效记忆。handle 可读取 config/memories。
输出校验使用进入 handle 之前捕获的快照;业务代码改写实例属性不改变审查输入。
没有工厂注入的 Agent 不可执行;禁止覆盖全部治理钩子。
合规覆盖:固定禁止表达、已审核 contains/exact 规则、号码脱敏、已授权记忆引用校验。
敏感记录、工具调用和其他类型引用在公共执行器尚未接入时拒绝,不允许 Agent 自报成功。
正则规则因 Python re 无执行超时暂时失败关闭。适当性产品比较、真实模型意图分类和
公共工具执行器尚未完成;本项只证明报告所列三个空钩子已接线,不宣称完整合规体系。
配置工具上限按意图保存,不使用 Agent 级并集。没有 active 发布使用 code:version,
默认不给工具权限。已补 conversation_message 原有 intent/confidence/source_references
ORM 映射和结果持久化;没有数据库结构改动。
验证:9 项治理单测及 1 项真实 MySQL 配置读取、客户记忆和已审核禁止表达替换测试。
## P0-1 / P0-2:统一授权与注册校验
JWT 验签后每次读取 MySQL 的 sys_user、有效 sys_user_role/sys_role、权限及客户归属。
账号状态只接受基线的“正常”,角色状态采用 active;不从 user_type/employee_role
或客户端 roles/portal 推导权限。权限数据暂不缓存,撤权在下次请求立即生效。
REST 服务端入口为 api,工厂要求 definition.allowed_roles/allowed_portals 及 agent:run。
受理在写入消息/幂等/run/Outbox 前校验;拒绝写独立审计。
未知 Agent 按 05 权威规范返回 404 AGENT_TYPE_NOT_FOUND,而非报告建议的 400。
验证:41 项单元测试;真实 MySQL 身份权限测试;4 项注册拒绝及受理回归。
## P0-3:独立 Worker 与持久化闭环
启动(两个终端,均先激活 conda 环境 jr_py313):
```powershell
python -m uvicorn app.main:app --host 127.0.0.1 --port 8099
python -m app.worker
```
Worker 的轮询周期、租约和重试次数配置在 .env 的 WORKER_POLL_SECONDS、
WORKER_LEASE_SECONDS、WORKER_RETRY_LIMIT。`python -m app.worker --once` 只处理一轮。
启动命令会消费本库待处理任务;测试使用唯一 run_id 隔离,不消费开发者其他历史运行。
## 2026-09-11:自审口径、测试基座与错误码对齐
配置发布允许创建人自审(用户确认口径):撤销 `config_release` 的
`chk_config_release_separation` 约束(迁移 `20260911_drop_review_separation`),
`ConfigReleaseService.approve` 与 `AdminService` 驳回分支均如实写入 `reviewer_id`。
升级/降级往返验证通过,68 张表字段、索引、外键指纹不变。
测试基座:`tests/conftest.py` 在导入 app 前把测试期引擎换成 `NullPool`,消除多事件循环
下的连接复用(集成失败 30 → 2);单元测试显式给定外部识别开关,不再读取本机 `.env`
(注意 `app/core/config.py` 的 `load_dotenv` 会让 `_env_file=None` 失效,必须用构造参数)。
错误码以 `docs/05-接口文档.md` §3.5/§3.6 为唯一权威:删除第二套配置发布入口
(`app/api/controllers/config_releases.py` 及其专属 `ConfigApplicationService`);
`app/main.py` 新增 `RequestValidationError` 统一信封;`docs/09` 错误码表同步对齐。
跑集成测试前必须停掉 `python -m app.worker`:worker 会认领任意
`queued/running/cancel_requested` 运行并消费 Outbox 事件,与测试共用同一数据库时会造成
偶发失败(实测:测试造的 queued 运行 1 秒内被外部 worker 领走;取消用例两次响应仅
`status` 从 `cancel_requested` 变为 `cancelled`)。长期方案是让集成测试指向独立测试库。
记忆抽取事件按策略门控(`MemoryService.should_extract_memory`):只有显式持久事实
(用户偏好/约束/身份/目标信号、成功工具结果、业务事件)才写 `memory.extraction_requested`。
断言该事件的用例必须使用带信号的消息。
集成测试统一走独立测试库,避免与开发用的 worker 争抢同一份数据:
```powershell
python -m tools.run_tests_on_test_db # 默认 tests/integration
python -m tools.run_tests_on_test_db tests/unit tests/contract tests/integration
```
该工具只在本进程内把 `MYSQL_DSN` 换成 `jr_agent_test`(`.env` 不改),空库时先导入
`alembic/baseline_generated.sql`(33 张历史基线表不在迁移链里),再 `alembic upgrade head`
并灌入 9001/9002/9003 测试账号。首次使用需由有权限的账号建库并授权:
```sql
CREATE DATABASE IF NOT EXISTS jr_agent_test CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
GRANT ALL PRIVILEGES ON jr_agent_test.* TO 'jr_app'@'localhost';
```
HTTP 与 Worker 共用 app/service/agent/bootstrap.py 注册入口。当前没有组员业务 Agent;
未注册业务类型明确拒绝。集成测试显式注入 TestAgent,不在生产注册假业务实现。
Outbox 消费确认的是 MySQL 中已存在的持久运行;进程在确认后退出,下一进程仍可扫描
queued 或过期 running。模型执行期间不持有数据库长事务;续租使用独立短事务。
每次领取生成新的 worker_id;complete_run 行锁、终态幂等和所有权校验阻止迟到提交。
执行前重新加载用户权限。恢复性错误有上限重试;终止错误同步幂等状态及审计。
验证:`test_worker_runtime_mysql.py` 三项真实 MySQL 测试,覆盖 HTTP 受理、Outbox
消费、并发执行、结果查询、记忆事件提交、重复执行、执行前撤权和迟到 Worker 提交。
这是底座执行闭环验收,不代表真实模型供应商或业务 Agent 流程已通过验收。
## P1-5:底座接口和事务幂等
补充统一动态资源管理路由,覆盖配置发布、平台配置、模型端点、路由、Prompt、意图、回复模板、
禁止表达和审计;公共会话/取消/记忆/知识/健康/指标入口已注册。写操作通过新增
`api_request_receipt` 保存用户、作用域、幂等键、请求摘要和结果,结果与业务写入及审计同一事务。
配置只能编辑草稿,审核需要双人,激活/停用/回滚校验状态;模型路由禁止重复备用端点,
端点必须 active;HTTP 不暴露密钥或旧 `fallback_endpoint_ids`。OpenAPI 以 FastAPI 运行时生成,
具体路径使用资源注册表,避免 Controller 复制业务字段。