refactor(middleware): 移除数据脱敏中间件及相关代码
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

移除不再使用的数据脱敏功能,包括:
1. 删除data_masking模块
2. 清理loop_runner中的unmask逻辑
3. 移除前端saas-relay-client.ts中的mask/unmask实现
4. 更新中间件层数从15层降为14层
5. 同步更新相关文档(CLAUDE.md、TRUTH.md、wiki等)

此次变更简化了系统架构,移除了不再需要的敏感数据处理逻辑。所有相关测试证据和截图已归档。
This commit is contained in:
iven
2026-04-22 19:19:07 +08:00
parent 14f2f497b6
commit fa5ab4e161
68 changed files with 8049 additions and 3684 deletions

View File

@@ -0,0 +1,432 @@
# ZCLAW 全系统功能测试设计规格书
> **日期**: 2026-04-17
> **类型**: 全系统功能测试 (Full System Functional Test)
> **执行方式**: AI Agent 自动执行 (Chrome DevTools MCP + Tauri MCP + HTTP)
> **验证深度**: 深度验证 (结构完整性 + 数据合理性 + 状态一致性 + 错误合理性 + 跨系统流通)
---
## 1. 背景与目标
### 1.1 为什么需要这次测试
ZCLAW 已完成发布前稳定化阶段的核心功能开发,系统包含:
- 10 个 Rust Crates (~77K 行)
- 190 个 Tauri 命令 (104 个有前端 invoke 调用)
- 137 个 SaaS HTTP 端点 (.route())
- 14 层 Runtime 中间件 + 10 层 SaaS HTTP 中间件
- 9 个 Hands + 75 个 Skills + 17 个 Pipeline 模板
之前的 E2E 测试 (04-16, 22 条, 77% 通过率) 覆盖有限,且主要是冒烟级别验证。本测试方案旨在:
1. **全面覆盖** — 10 个子系统逐一验证,不留盲区
2. **深度断言** — 不仅验证"能运行",还验证"数据真实、逻辑正确、状态一致"
3. **跨系统流通** — 验证数据在系统间的端到端流转,而非孤立功能点
### 1.2 先决条件
| 条件 | 状态 |
|------|------|
| PostgreSQL 运行 + SaaS 后端 (8080 端口) | 已就绪 |
| Tauri 桌面端 (1420 端口) | 已就绪 |
| Admin V2 开发服务器 (5173 端口) | 已就绪 |
| 至少一个 LLM Provider + 有余额的 API Key | 已就绪 |
### 1.3 不覆盖范围
| 排除项 | 原因 |
|--------|------|
| Model Groups 7 个端点 | 前端无调用方 |
| Account API Keys (/keys) | 与 /tokens 重叠,疑似孤儿 |
| A2A Multi-Agent 5 个命令 | feature-gated 禁用 |
| Webhook 系统 | 已 deprecated |
| 负载/压力测试 | 非功能测试范畴 |
---
## 2. 测试架构
### 2.1 三层结构
```
Layer 0: 基础设施健康 (5 条)
└─ DB 连接、SaaS 健康、Admin 加载、Tauri 窗口、LLM 可达性
Layer 1: 子系统垂直测试 (10 组 × 7-15 条 = 100 条)
├─ V1: 认证与安全 (12 条)
├─ V2: 聊天流与流式响应 (10 条)
├─ V3: 管家模式与行业路由 (10 条)
├─ V4: 记忆管道 (8 条)
├─ V5: Hands 自主能力 (10 条)
├─ V6: SaaS Relay 与 Token 池 (10 条)
├─ V7: Admin 后台全页面 (15 条)
├─ V8: 模型配置与计费 (10 条)
├─ V9: Pipeline 与工作流 (8 条)
└─ V10: 技能系统 (7 条)
Layer 2: 跨系统横向验证 (4 角色 × 6 条 = 24 条)
├─ R1: 医院行政 — 日常使用全链路
├─ R2: IT 管理员 — 后台配置全链路
├─ R3: 开发者 — API + 工作流全链路
└─ R4: 普通用户 — 注册→首次体验→持续使用
```
### 2.2 断言标准(深度验证)
每条链路的断言覆盖以下维度:
| 维度 | 验证内容 |
|------|----------|
| **结构完整性** | 响应包含所有必填字段、字段类型正确 |
| **数据合理性** | token 用量 > 0、时间戳在合理范围、ID 格式正确 |
| **状态一致性** | 创建后能查询到、删除后不存在、更新后值已变更 |
| **错误合理性** | 错误响应包含明确 message、HTTP 状态码正确、不泄露内部信息 |
| **跨系统流通** | 聊天后记忆被提取、计费记录增加、审计日志有记录 |
---
## 3. Layer 0: 基础设施健康检查 (5 条)
| # | 链路 | 验证方式 | 预期 |
|---|------|----------|------|
| L0-01 | PostgreSQL 连接 | `SELECT 1` via SaaS health | 200 + `{"status": "ok"}` |
| L0-02 | SaaS 后端健康 | `GET /api/health` | 200 + 服务信息 |
| L0-03 | Admin V2 加载 | 浏览器导航到 `localhost:5173` | 页面标题含 "ZCLAW" + 无 JS 错误 |
| L0-04 | Tauri 桌面端运行 | Chrome DevTools 连接 `localhost:1420` | 页面可见 + 无白屏 |
| L0-05 | LLM Provider 可达 | `GET /api/v1/relay/models` | 返回至少 1 个可用模型 |
---
## 4. Layer 1: 子系统垂直测试
### V1: 认证与安全 (12 条)
| # | 链路 | 深度验证点 |
|---|------|-----------|
| V1-01 | 注册新用户 | 用户名/邮箱/密码校验规则生效;响应含 account_id(非空) + JWT(可解码) + refresh_tokenGET /auth/me 返回 status=active + role=user + totp_enabled=false |
| V1-02 | 重复注册拒绝 | 相同用户名→409 + 明确 message相同邮箱→409用户名<3字符400密码<8字符400 |
| V1-03 | 登录获取 Token | 响应含 access_token + refresh_tokenJWT 解码后 sub=account_id, role 正确, pwv=1HttpOnly cookie 设置正确 |
| V1-04 | 错误密码锁定 | 连续 5 次错误密码账户锁定 15 分钟 6 次尝试423 + "账户已锁定"正确密码在锁定期内也不可登录 |
| V1-05 | Token 刷新轮换 | refresh_token 换新 token refresh_token 立即失效(二次使用401) token jti 不同 |
| V1-06 | 密码修改使旧 Token 失效 | 修改密码后 pwv 递增 JWT 访问受保护端点401重新登录后正常 |
| V1-07 | 登出撤销 | 登出后 refresh_token 失效access_token 仍在有效期但 refresh 不可用 |
| V1-08 | TOTP 设置与验证 | setup 返回 secret+QRverify 成功后 totp_enabled=truelogin 需额外 totp_code |
| V1-09 | API Token CRUD | 创建返回明文 token(仅一次)列表hash 不含明文 token API成功撤销不可用 |
| V1-10 | 权限中间件 | user 角色访问 admin 端点403admin 角色成功 token401 |
| V1-11 | 限流验证 | 登录接口 >5次/分钟→429注册 >3次/小时→429公共接口 >20次/分钟→429 |
| V1-12 | 并发会话 | 同一账户多设备同时登录;各设备 token 独立有效;一处修改密码全部失效 |
### V2: 聊天流与流式响应 (10 条)
| # | 链路 | 深度验证点 |
|---|------|-----------|
| V2-01 | KernelClient 流式聊天 | 发消息→收到 text_delta 事件流;最终消息完整(非截断)token 统计 input>0, output>0消息持久化到 IndexedDB |
| V2-02 | SaaS Relay SSE 流式 | 走 Relay 路径→SSE 格式正确(data: [DONE])Admin Usage 页可见新增 token 记录GET /relay/tasks 返回对应任务记录 |
| V2-03 | 模型切换后聊天 | 切换到不同模型→发送消息→验证响应确实来自新模型;模型字段正确 |
| V2-04 | 流式取消 | 发消息→中途 cancelStream→收到已生成部分+取消标记;不产生完整 token 计费session 状态恢复为 idle |
| V2-05 | 多轮对话上下文 | 连续 3 轮对话;第 3 轮能引用第 1 轮内容;上下文窗口不溢出 |
| V2-06 | 错误恢复 | 模拟 401→自动 token 刷新→重试成功;模拟网络断开→优雅降级+重连 |
| V2-07 | thinking_delta 处理 | 模型返回 thinking 内容→前端正确展示折叠/展开thinking 不计入 output token 统计 |
| V2-08 | tool_call 事件流 | LLM 调用工具→收到 tool_call 事件→工具执行→tool_result 事件→最终回复包含工具结果 |
| V2-09 | Hand 触发事件流 | 触发 Hand→handStart 事件→handEnd 事件+结果;消息列表含 role=hand 消息 |
| V2-10 | 消息持久化验证 | 发送 5 条消息→刷新页面→消息恢复完整(含时间戳、角色、内容)IDB 中数据结构正确 |
### V3: 管家模式与行业路由 (10 条)
| # | 链路 | 深度验证点 |
|---|------|-----------|
| V3-01 | 关键词分类命中 | 发送医疗相关查询→ButlerRouter 分类为 healthcare响应 system prompt 包含 `<butler-context>` XML 块 |
| V3-02 | 行业关键词动态加载 | Admin 创建自定义行业+关键词→Tauri 加载→查询命中该行业关键词→分类正确 |
| V3-03 | 未命中默认行为 | 发送无关查询→无 `<butler-context>` 注入→正常对话流程不受影响 |
| V3-04 | 多关键词饱和度 | 连续命中 3+关键词→饱和度达到 1.0→分类置信度最高 |
| V3-05 | 痛点记录 | 用户表达痛点→butler_record_pain_point→痛点存入 SQLite→list 可查询 |
| V3-06 | 方案生成 | 累积足够痛点→butler_generate_solution→返回结构化方案(标题+描述+步骤) |
| V3-07 | 简洁/专业模式切换 | 切换到简洁模式→UI 隐藏高级选项→对话风格变化(管家更主动) |
| V3-08 | 跨会话连续性 | 新会话→管家引用上次痛点→通过 Tauri 命令 `butler_list_pain_points` 查询痛点数据并验证正确 |
| V3-09 | 冷启动体验 | 新用户首次聊天→管家自我介绍+引导→不出现空白或错误 |
| V3-10 | 4 内置行业覆盖 | 分别用医疗/数据报告/政策合规/会议协调关键词查询→4 个行业各至少命中一次 |
### V4: 记忆管道 (8 条)
| # | 链路 | 深度验证点 |
|---|------|-----------|
| V4-01 | 对话后记忆提取 | 3 轮对话含明确偏好→对话结束后触发 extraction→SQLite 中有新记忆记录 |
| V4-02 | FTS5 全文检索 | 存入 3 条记忆(A="我喜欢 Python 编程", B="我偏好 Rust 开发", C="今天天气很好")→搜索"编程语言"→viking_find 返回 [A, B]A/B 排在 C 之前 |
| V4-03 | TF-IDF 语义评分 | 存入多条不同主题记忆→查询特定主题→viking_find 返回按 TF-IDF 相似度排序;语义最相关的排在首位 |
| V4-04 | 记忆注入系统提示 | 用户有偏好记忆→新对话→system prompt 中包含 `## 用户偏好` 段+记忆内容 |
| V4-05 | Token 预算约束 | 大量记忆→注入后不超过 500 token 预算;低分记忆被截断 |
| V4-06 | 记忆去重 | 重复表达相同偏好→不产生重复记录;或旧记录更新而非新增 |
| V4-07 | Agent 级记忆隔离 | Agent A 的记忆不出现在 Agent B 的上下文中;切换 Agent 后记忆正确加载 |
| V4-08 | 记忆统计 | memory_stats 返回正确的记忆总数/各类型计数/存储大小 |
### V5: Hands 自主能力 (10 条)
| # | 链路 | 深度验证点 |
|---|------|-----------|
| V5-01 | Browser Hand 执行 | 触发 browser_hand→创建浏览器实例→导航到 URL→返回页面内容hand_run_status 正确流转 |
| V5-02 | Researcher Hand | 触发 researcher→返回研究报告结构(摘要+来源+建议);执行时间合理 |
| V5-03 | Speech Hand + TTS | 触发 speech→文本生成→浏览器 TTS 播放(检查 speechSynthesis.speak 调用) |
| V5-04 | Quiz Hand | 触发 quiz→返回题目结构(题干+选项+答案);格式可解析 |
| V5-05 | Slideshow Hand | 触发 slideshow→返回幻灯片数据(标题+内容+布局) |
| V5-06 | Hand 审批流程 | needs_approval 的 Hand→审批前状态=pending→approve 后执行→状态=completed |
| V5-07 | Hand 并发限制 | 同一 Hand 并发触发超过 semaphore 限制→排队等待;不崩溃 |
| V5-08 | Hand 依赖检查 | Clip Hand 无 FFmpeg→check_dependencies 返回缺失依赖→graceful 错误消息 |
| V5-09 | Hand 列表与注册 | hand_list 返回 9 个启用的 Hand每个含 name+description+tool_count |
| V5-10 | Hand 审计日志 | Hand 执行后→Admin 日志审计页可见对应记录(action=hand_execute, target=hand_name) |
### V6: SaaS Relay 与 Token 池 (10 条)
| # | 链路 | 深度验证点 |
|---|------|-----------|
| V6-01 | Relay 聊天完成 | POST /relay/chat/completions→SSE 流返回GET /relay/tasks 返回该任务且状态为 completed |
| V6-02 | Token 池轮换 | provider_keys 有多个 key→连续请求→RPM/TPM 跟踪正确→key 自动轮换 |
| V6-03 | Key 限流生效 | 单个 key 达到 RPM 限制→自动切换到下一个 key所有 key 耗尽→返回 429 |
| V6-04 | Relay 任务列表 | 完成多次 relay→list_tasks 返回历史;分页正确;状态字段准确 |
| V6-05 | Relay 失败重试 | 使用 intentionally invalid API key 创建 provider→通过 relay 发送聊天→期望失败→使用有效 key 调用 retry 端点→验证成功 |
| V6-06 | 可用模型列表 | list_available_models 返回当前 key 池支持的模型;不含已禁用模型 |
| V6-07 | 配额检查 | 用户配额已满→relay 请求→被 quota middleware 拦截→返回 429 + quota exceeded |
| V6-08 | Key 创建/切换/删除 | Admin CRUD provider_key→创建后可见→toggle 禁用→删除后不可用 |
| V6-09 | Usage 记录完整性 | relay 请求→GET /usage 返回新增记录→account_id, model, input_tokens, output_tokens 全部正确 |
| V6-10 | Relay 超时处理 | 长时间请求→15s 超时→返回 timeout 错误(非 hang) |
### V7: Admin 后台全页面 (15 条)
| # | 链路 | 深度验证点 |
|---|------|-----------|
| V7-01 | Dashboard 统计数据 | 加载 Dashboard→stats 数值与 DB 一致(用户数/请求数/收入);图表渲染完整 |
| V7-02 | 账户管理 CRUD | 列表→分页+搜索→创建账户→编辑角色/状态→状态切换(冻结/解冻)→DB 同步 |
| V7-03 | 模型服务配置 | 列表 providers→添加 provider→配置 key→关联模型→切换回桌面端→模型可选 |
| V7-04 | 计费套餐管理 | 查看 plans→切换用户订阅→GET /billing/subscriptions/:userId 返回更新后的订阅→用户下次登录新配额生效 |
| V7-05 | 知识库管理 | 创建分类→添加知识条目→编辑→版本历史→搜索功能→返回匹配结果 |
| V7-06 | 知识库分析 | knowledge/analytics 返回 overview+trends+top_items+quality+gaps 各端点数据合理 |
| V7-07 | 结构化数据源 | 上传 Excel→解析为 structured_rows→SQL 查询返回结果→删除后不可查 |
| V7-08 | Prompt 模板管理 | 创建 prompt→编辑→查看版本→回滚到旧版本→版本号正确 |
| V7-09 | 角色权限矩阵 | 创建角色→配置权限→分配给用户→用户权限生效(可访问/不可访问的端点) |
| V7-10 | 行业配置管理 | 创建行业+关键词→配置 pain_seeds→关联到用户→用户查询命中该行业 |
| V7-11 | Agent 模板管理 | 创建模板→配置 soul/scenarios→分配给用户→用户端创建 Agent 基于→Agent 配置正确 |
| V7-12 | 定时任务管理 | 创建 cron 任务→列表显示→下次执行时间计算正确→手动触发→结果记录 |
| V7-13 | Relay 监控 | 查看任务列表→按状态筛选→查看任务详情→包含完整的 input/output/error |
| V7-14 | 日志审计 | 操作日志列表→按时间/用户/操作类型筛选→日志详情含 IP+UA+变更详情 |
| V7-15 | Config 同步 | 修改配置→同步到桌面端→桌面端 configStore 更新→sync_logs 有记录 |
### V8: 模型配置与计费 (10 条)
| # | 链路 | 深度验证点 |
|---|------|-----------|
| V8-01 | Provider CRUD | 创建 provider→设置 base_url + api_key + rate_limits→列表可见→更新→删除 |
| V8-02 | 模型 CRUD | 创建模型→关联 provider→设置 max_tokens/temperature→列表可见→参数正确 |
| V8-03 | Key 池管理 | Provider 下添加多个 key→各 key 独立 RPM/TPM 跟踪→禁用某 key→请求不再使用 |
| V8-04 | 计费套餐定义 | plans 列表含 Free/Pro/Team每个 plan 含 features+limits JSON 结构完整 |
| V8-05 | 订阅切换 | 用户从 Free→Pro→配额限制更新Pro→Free→超出 Free 配额的请求被拒绝 |
| V8-06 | 用量实时递增 | 每次聊天→GET /billing/usage 返回递增后的 used_tokens数值与 GET /usage 统计一致 |
| V8-07 | 支付流程 | 创建支付→返回支付链接→mock-pay 确认→支付状态变为 paid→订阅生效 |
| V8-08 | 发票生成 | 支付完成后→GET /billing/invoices/:id/pdf 返回有效 PDF (Content-Type: application/pdf) |
| V8-09 | 模型白名单 | Free plan 只能用指定模型→请求不在白名单的模型→被拒绝 |
| V8-10 | Token 配额耗尽 | 配额用完→后续请求→429 + 明确的 quota exceeded 信息→不扣除额外费用 |
### V9: Pipeline 与工作流 (8 条)
| # | 链路 | 深度验证点 |
|---|------|-----------|
| V9-01 | Pipeline 模板列表 | pipeline_templates 返回 17 个模板;每个含 name+description+stepsYAML 格式有效 |
| V9-02 | Pipeline 创建与执行 | 从模板创建 pipeline→执行→progress 事件流→result 包含各步骤输出 |
| V9-03 | Pipeline DAG 验证 | 创建含依赖的 pipeline→验证 DAG 无环→执行顺序正确(依赖先完成) |
| V9-04 | Pipeline 取消 | 执行中 pipeline→cancel→已完成的步骤保留结果+未开始的不执行 |
| V9-05 | Pipeline 错误处理 | 某步骤失败→pipeline 状态=failed→错误信息含失败步骤名+原因 |
| V9-06 | 工作流 CRUD | 创建 workflow→编辑步骤→保存→列表可见→删除后不可见 |
| V9-07 | 工作流执行 | 执行 workflow→各节点按序执行→最终输出正确→运行历史可查 |
| V9-08 | 意图路由 | 发送自然语言描述→route_intent→匹配到正确的 pipeline 模板 |
### V10: 技能系统 (7 条)
| # | 链路 | 深度验证点 |
|---|------|-----------|
| V10-01 | 技能列表 | skill_list 返回已加载技能;每个含 name+description+triggers非空 |
| V10-02 | 语义路由 | 发送匹配某技能 trigger 的查询→SkillIndex 中间件匹配→执行对应技能 |
| V10-03 | 技能执行 | skill_execute→返回结构化结果执行时间合理无 panic |
| V10-04 | 技能 CRUD | skill_create→列表可见→skill_update→字段更新→skill_delete→不可见 |
| V10-05 | 技能刷新 | 添加新 SKILL.md→skill_refresh→列表增加移除 SKILL.md→刷新后减少 |
| V10-06 | 技能与聊天集成 | 聊天中触发技能→tool_call 事件→技能执行→结果注入对话 |
| V10-07 | 技能按需加载 | 无技能配置时→SkillIndex 中间件不注册;有技能时→正常注册 |
---
## 5. Layer 2: 跨系统横向验证 (24 条)
设计原则:每个角色走完一条完整的端到端旅程,每一步的输出是下一步的输入。
### R1: 医院行政 (日常使用全链路)
| # | 链路 | 跨系统验证点 |
|---|------|-------------|
| R1-01 | 新用户注册→管家冷启动 | 注册→登录→首次打开桌面端→管家自我介绍+引导→无报错saasStore 写入账户信息→connectionStore 选择连接模式→KernelClient 初始化 |
| R1-02 | 医疗排班对话→管家路由→记忆 | 发"这周排班太乱了"→ButlerRouter 分类 healthcare→`<butler-context>` 注入→管家主动追问→痛点记录到 VikingStorage→SQLite 可查 |
| R1-03 | 第二次对话→记忆注入+痛点回访 | 新会话→系统提示含 `## 用户偏好` 段(上次偏好)→管家主动问"排班问题解决了吗"→记忆提取闭环完成 |
| R1-04 | 请求研究报告→Hand 触发→计费 | 发"帮我调研一下智能排班系统"→触发 Researcher Hand→Hand 执行返回结果→GET /usage 返回新增 token 记录→GET /billing/usage 返回递增配额 |
| R1-05 | 管家生成方案→痛点闭环 | 累积痛点足够→butler_generate_solution→返回结构化方案→用户查看→butler_update_proposal_status(accepted)→痛点状态变为 addressed |
| R1-06 | 审计验证全旅程 | Admin 审计日志页可见全旅程日志→上述所有操作均有记录(注册/登录/聊天/Hand 触发/方案生成);日志含正确的时间戳+操作类型+目标 |
### R2: IT 管理员 (后台配置全链路)
| # | 链路 | 跨系统验证点 |
|---|------|-------------|
| R2-01 | Admin 登录→Provider+Key 配置 | Admin 登录→添加 Provider(DeepSeek)+API Key→GET /providers/:id/keys 返回新 key→key 的 RPM/TPM 初始值为 0 |
| R2-02 | 配置模型→桌面端同步 | 创建模型(deepseek-v3)→关联 Provider→Admin 可见→切换到桌面端→模型列表含新模型→发起聊天→模型字段正确 |
| R2-03 | 配额+计费联动 | 创建计费套餐→给用户分配→desktop 端 saasStore 更新订阅信息→用户发消息→quota 检查通过→聊天后 usage 递增→Admin 端 Usage 页数据同步 |
| R2-04 | 知识库→行业→管家路由 | Admin 创建行业"教育"+关键词+pain_seeds→关联到用户→触发 Tauri 命令 `viking_load_industry_keywords` 加载→用户发教育相关查询→ButlerRouter 命中自定义行业 |
| R2-05 | Agent 模板→用户端创建 | Admin 创建 Agent 模板(含 soul+scenarios)→分配给用户→用户端 AgentTemplates 可见→创建 Agent→配置从模板加载→聊天使用新 Agent 人格 |
| R2-06 | 定时任务→执行→审计 | 创建 cron 定时任务→等待触发(或手动触发)→GET /scheduler/tasks/:id 返回结果记录→操作日志有执行记录→状态流转 pending→running→completed |
### R3: 开发者 (API + 工作流全链路)
| # | 链路 | 跨系统验证点 |
|---|------|-------------|
| R3-01 | API Token 认证→Relay 调用 | 创建 API Token→用 token 调 POST /relay/chat/completions→SSE 响应正确→GET /relay/tasks 有记录→GET /usage 有 token 统计 |
| R3-02 | 多模型切换→Token 池→用量 | 连续用 3 个不同模型调 Relay→key 池自动选择对应 Provider→usage 按模型分别记录→Admin Usage 页可按 model 分组查看 |
| R3-03 | Pipeline 创建→执行→结果 | 从模板创建 pipeline→执行→progress 实时推送→result 包含完整输出→pipeline_runs 历史可查 |
| R3-04 | 技能触发→工具调用→结果 | 通过 API 触发技能→tool_call 执行→tool_result 返回→对话中包含工具输出 |
| R3-05 | 浏览器 Hand→自动化流程 | 通过 API 触发 Browser Hand→执行导航+点击+提取→结果返回→审计日志记录 |
| R3-06 | API 限流+权限→错误处理 | 超出 RPM→429 + Retry-After header用 user 角色 token 调 admin 端点→403过期 token→401 + 明确 message |
### R4: 普通用户 (注册→首次体验→持续使用)
| # | 链路 | 跨系统验证点 |
|---|------|-------------|
| R4-01 | 注册→邮箱验证→首次登录 | 注册→邮箱格式被验证→密码强度校验→注册成功→自动登录→JWT + refresh_token 存储→saasStore 初始化 |
| R4-02 | 首次聊天→模型选择→流式体验 | 无历史对话→选择模型→发消息→流式响应→消息持久化到 IDB→关闭重开→消息恢复 |
| R4-03 | 多轮对话→记忆积累→个性化 | 在 3 个独立对话会话中分别表达偏好(不模拟时间流逝)→每轮对话后记忆提取→第 4 个会话聊天→记忆检索返回至少 1 个先前偏好→系统提示含偏好段 |
| R4-04 | 触发 Hand→审批→结果查看 | 需要审批的操作→Hand 状态 pending→用户审批→执行→结果展示→操作日志记录 |
| R4-05 | 配额用尽→升级提示 | Free 配额耗尽→聊天返回 429→UI 显示升级提示→引导到计费页→支付后继续使用 |
| R4-06 | 安全设置→密码修改→TOTP | 修改密码→旧 session 失效→重新登录→设置 TOTP→下次登录需要验证码→设备信任管理 |
---
## 6. 执行策略
### 6.1 执行顺序与依赖
```
Phase 0: 基础设施健康检查 (5 条)
↓ 全部 PASS 才继续
Phase 1: 垂直测试 — 无依赖组 (并行)
├─ V1 认证与安全
├─ V2 聊天流 (依赖 V1-03 登录)
└─ V8 模型配置与计费 (依赖 V1-03 登录)
↓ 认证+聊天+模型 PASS 后
Phase 2: 垂直测试 — 依赖组 (并行)
├─ V3 管家模式 (依赖 V2 聊天)
├─ V4 记忆管道 (依赖 V2 聊天)
├─ V5 Hands (依赖 V2 聊天)
├─ V6 Relay+Token 池 (依赖 V2 + V8)
├─ V9 Pipeline (依赖 V2 聊天)
└─ V10 技能系统 (依赖 V2 聊天)
↓ 所有垂直组完成 (允许 PARTIAL)
Phase 3: 横向验证 (顺序执行)
├─ R1 医院行政旅程
├─ R2 IT 管理员旅程
├─ R3 开发者旅程
└─ R4 普通用户旅程
```
### 6.2 测试数据策略
| 策略 | 说明 |
|------|------|
| **隔离前缀** | 所有测试创建的数据加前缀 `e2e_test_` |
| **测试账户** | V1 阶段创建:`e2e_admin`, `e2e_user`, `e2e_dev` |
| **幂等性** | 每条链路可独立重跑;检查"已存在则跳过" |
| **清理策略** | 不自动删除数据(保留用于分析),标注为测试数据 |
| **时间锚点** | 记录测试开始时间戳,断言基于 `> 开始时间` 过滤 |
### 6.3 断言失败分级
| 级别 | 含义 | 处理 |
|------|------|------|
| **CRITICAL** | 系统核心功能不可用 | 立即停止当前 Phase报告根因 |
| **HIGH** | 功能可用但数据不正确 | 标记失败,继续执行,汇总报告 |
| **MEDIUM** | 非关键字段缺失或格式不完美 | 记录警告,不阻断 |
| **LOW** | UI 细节问题、性能轻微波动 | 记录观察,不影响判定 |
### 6.4 链路超时与重试
| 参数 | 值 |
|------|-----|
| 单条链路超时 | 120 秒 |
| LLM 响应等待超时 | 60 秒 |
| 页面加载超时 | 15 秒 |
| 截图等待 | 2 秒 |
| 失败重试 | 不重试(记录原始失败,保留现场) |
---
## 7. 结果报告
### 7.1 单条链路结果格式
```json
{
"id": "V2-01",
"name": "KernelClient 流式聊天",
"phase": 1,
"group": "V2",
"status": "PASS | FAIL | SKIP | PARTIAL",
"severity": "CRITICAL | HIGH | MEDIUM | LOW",
"assertions": [
{
"point": "收到 text_delta 事件",
"expected": ">0 events",
"actual": "47 events",
"result": "PASS"
}
],
"duration_ms": 4230,
"evidence": {
"screenshot": "path/to/screenshot.png",
"api_response": "response snippet"
},
"error": null
}
```
### 7.2 汇总报告结构
| 指标 | 说明 |
|------|------|
| 总链路数 | 129 (5 + 100 + 24) |
| 通过率 | PASS / 总数 × 100% |
| 各 Phase 通过率 | Phase 0/1/2/3 分别统计 |
| CRITICAL 失败数 | 需立即修复 |
| Bug 清单 | 按 CRITICAL/HIGH/MEDIUM/LOW 分级 |
| 覆盖热力图 | 10 子系统 × 4 角色 矩阵 |
| SaaS API 覆盖率 | 已测试端点 / 总端点 |
| Admin 页面覆盖率 | 已测试页面 / 总页面 |
| Tauri 命令覆盖率 | 已测试命令 / 有前端调用的命令 |
---
## 8. 规模汇总
| 维度 | 数量 |
|------|------|
| Layer 0 基础设施 | 5 条 |
| Layer 1 垂直测试 | 100 条 |
| Layer 2 横向验证 | 24 条 |
| **总计** | **129 条** |
| 子系统覆盖 | 10/10 |
| 跨系统角色覆盖 | 4/4 |
| SaaS API 端点覆盖 | ~90/137 |
| Admin 页面覆盖 | 14/17 (Login 由 V1 隐式覆盖, ApiKeys/Usage 待后续补充) |
| Tauri 命令覆盖 | ~60/104 (有前端调用的) |
| 预估执行时间 | ~60 分钟 |
---
## 9. 前次 Bug 回归验证
以下为 04-16 E2E 报告中发现的 Bug在本测试方案中的对应覆盖
| Bug ID | 描述 | 对应测试链路 | 回归验证点 |
|--------|------|-------------|-----------|
| BUG-01 | Agent 创建返回 HTTP 502 | V7-11 (Agent 模板管理) + R2-05 (Agent 模板→用户端创建) | 验证 Agent 创建返回 201 (非 502)Agent 配置从模板正确加载 |
| BUG-02 | 8 条历史消息显示"重试"按钮 | V2-10 (消息持久化验证) | 验证历史消息不包含"重试"伪影;刷新后消息状态正确恢复 |
| BUG-03 | Key Pool exhaustion — "所有 Key 均在冷却中" | V6-03 (Key 限流生效) + V6-02 (Token 池轮换) | 验证所有 key 耗尽场景返回 429 + 明确 messagekey 冷却后自动恢复 |

View File

@@ -0,0 +1,492 @@
# Evolution Engine 设计文档
> **日期**: 2026-04-18
> **状态**: Draft
> **目标**: 让 ZCLAW 管家从"记住用户信息"进化到"从交互中自主生成新能力"
## 1. 问题陈述
### 1.1 现状
ZCLAW 在"信息层进化"方面已有基础:
| 能力 | 状态 | 说明 |
|------|------|------|
| 记忆闭环 | ✅ 可用 | 对话→LLM 提取→FTS5+TF-IDF 存储→检索注入 system prompt |
| 经验存储结构 | ✅ 定义完整 | `Experience { pain_pattern, solution_steps, outcome }` |
| 语义路由 | ✅ 三层架构 | TF-IDF + Embedding + LLM fallback |
| 技能 CRUD API | ✅ 就绪 | `create_skill` / `update_skill` / `delete_skill` |
| Pipeline DAG | ✅ 可执行 | 并行/串行/条件分支16 个 YAML 模板 |
| 轨迹记录 | ✅ 可用 | TrajectoryRecorder 记录 UserRequest/ToolExecution/LlmGeneration |
### 1.2 核心缺口
系统在"能力层进化"方面完全空白:
| 缺口 | 影响 |
|------|------|
| 没有从对话自动生成技能 | 用户解决了问题,系统不会记住"怎么解决的"并固化成可复用技能 |
| Experience 是空壳 | 结构定义完美,但 GrowthIntegration 只提取文本记忆,不填充结构化 solution_steps |
| 用户画像不自动更新 | UserProfileStore 有字段但没有从对话自动填充的管道 |
| 轨迹数据只存不用 | TrajectoryRecorder 记录了行为但没有代码消费它来改善路由 |
| 没有 plan→execute→verify 循环 | 只能执行预定义 Pipeline不能动态分解新任务 |
### 1.3 目标
实现 Hermes Agent 级别的自我进化能力:
1. **对话→自动生成 SKILL.md** — 用户解决了复杂问题后,系统自动将解决步骤固化为可复用技能
2. **对话→动态 Pipeline** — 从用户交互中学习工作流模式,自动组装 Pipeline
3. **用户反馈→迭代优化** — 根据反馈调整 skill 的 prompt/参数,逐步提升质量
一句话:**让管家"越用越懂你",从被动问答变成主动能力积累。**
## 2. 设计决策
| 决策 | 选择 | 理由 |
|------|------|------|
| 方案 | 独立 EvolutionEngine 层 | 复用现有积木Experience/Skill/Pipeline/Memory/Trajectory只做中枢调度 |
| 目标场景 | 混合(自动执行 + 对话辅助) | 用户群混合,管家模式会根据场景自动判断 |
| 进化时机 | 分层:低风险静默,高风险确认 | 记忆层自动、技能层征得同意、工作流层明确确认 |
| 进化粒度 | 混合:记忆细粒度,技能粗粒度 | 信息积累快,能力固化有质量门控 |
| LLM 成本 | 最小化,用 Haiku 级别 | 进化分析不需要深度推理Haiku 足够 |
## 3. 架构总览
### 3.1 三层进化模型
```
┌─────────────────────────────────────────────────┐
│ EvolutionEngine (zclaw-growth) │
│ │
│ L1 记忆进化 (已有,增强) │
│ ├── 每次: 对话→提取偏好/知识/经验→FTS5存储 │
│ ├── 每次: 结构化 Experience 提取 │
│ ├── 每次: 用户画像增量更新 │
│ └── 每次: 轨迹事件记录 │
│ │
│ L2 技能进化 (新建) │
│ ├── 触发: Experience 复用次数 >= 3 或 用户主动要求 │
│ ├── 流程: 模式分析 → SKILL.md 生成/优化 → 确认 │
│ └── 产物: 新建/更新的 SKILL.md 文件 │
│ │
│ L3 工作流进化 (新建) │
│ ├── 触发: 轨迹中检测到重复的工具调用链模式 │
│ ├── 流程: 模式提取 → Pipeline YAML 组装 → 确认 │
│ └── 产物: 新建/更新的 Pipeline YAML 文件 │
│ │
│ 反馈闭环 (新建) │
│ ├── 用户对技能/工作流结果的反馈 → 质量评分 │
│ ├── 低评分 → 触发 L2/L3 重新优化 │
│ └── 高评分 + 高频使用 → 提升信任度 │
└─────────────────────────────────────────────────┘
```
### 3.2 与现有系统集成点
| 现有组件 | crate | 集成方式 |
|---------|-------|---------|
| `MemoryExtractor` | zclaw-growth | L1 增强:合并 Experience 结构化提取到同一 prompt |
| `ExperienceStore` | zclaw-growth | L2 输入:复用 `reuse_count` 作为模式检测信号 |
| `TrajectoryRecorder` | zclaw-runtime | L3 输入:分析 `compressed_trajectories` 的工具调用链 |
| `UserProfileStore` | zclaw-memory | L1 增强:自动从对话更新画像字段 |
| `SkillRegistry.create_skill()` | zclaw-skills | L2 输出:调用现有 API 生成 SKILL.md |
| `Pipeline executor` | zclaw-pipeline | L3 输出:生成 YAML 配置文件 |
| `ButlerRouter` | zclaw-runtime | 消费:新技能自动加入语义路由索引 |
| `GrowthIntegration` | zclaw-runtime | 管线增强:在 process_conversation() 中串入新提取器 |
### 3.3 关键设计约束
1. **LLM 调用最小化** — 进化分析只在触发条件满足时才调用,不是每次对话都调
2. **人确认不可绕过** — L2/L3 的产物必须经过用户确认才生效
3. **可回滚** — 每次进化产物附带版本号,用户可以回退到之前版本
4. **成本感知** — 进化分析使用较便宜的模型Haiku不用 Opus
5. **内置/用户隔离** — 用户生成的技能存放在独立目录,项目更新不覆盖定制
## 4. L1 记忆进化增强
### 4.1 现状问题
| 问题 | 根因 |
|------|------|
| Experience 结构是空壳 | GrowthIntegration 只提取文本记忆,不填充结构化 Experience |
| 用户画像不自动更新 | UserProfileStore 有 update_field() 但无调用方 |
| 轨迹数据只存不用 | CompressedTrajectory 的 satisfaction_signal 无消费代码 |
### 4.2 新增 ExperienceExtractor
与现有 MemoryExtractor 并行运行,合并到单次 LLM 调用:
```rust
// zclaw-growth/src/experience_extractor.rs
pub struct ExperienceExtractor {
llm: Arc<dyn LlmDriver>,
}
pub struct ExperienceCandidate {
pub pain_pattern: String, // 用户需求的自然语言描述
pub context: String, // 上下文信息
pub solution_steps: Vec<String>, // 解决步骤(有序)
pub outcome: Outcome, // Success | Partial | Failed
pub confidence: f32, // 提取置信度
pub tools_used: Vec<String>, // 使用了哪些 tools/hands
pub industry_context: Option<String>,
}
impl ExperienceExtractor {
/// 从完整对话中提取结构化经验
/// 与 MemoryExtractor 合并在同一次 LLM 调用中执行
pub async fn extract(
&self,
conversation: &[Message],
) -> Result<Vec<ExperienceCandidate>> { ... }
}
```
### 4.3 增强对话后处理管线
修改 `GrowthIntegration.process_conversation()`
```
对话结束
├── 现有: MemoryExtractor.extract() → 文本记忆存储
├── 新增: ExperienceExtractor.extract() → 结构化经验存储到 ExperienceStore
├── 新增: UserProfileUpdater.update() → 画像增量更新
└── 现有: TrajectoryRecorder 压缩轨迹 → 轨迹存储
```
### 4.4 画像增量更新
```rust
// zclaw-growth/src/profile_updater.rs
pub struct UserProfileUpdater;
impl UserProfileUpdater {
/// 从单次 LLM 提取结果中更新画像
/// 不额外调用 LLM复用 ExperienceExtractor 的输出
pub async fn update(
profile_store: &UserProfileStore,
extraction: &CombinedExtraction, // 包含记忆+经验+画像信号
) -> Result<()> {
// 更新字段:
// - industry: 从 Experience 中的 industry_context 推断
// - recent_topics: 追加本次对话主题
// - pain_points: 追加 Experience 的 pain_pattern
// - preferred_tools: 统计 tools_used 更新频率
// - communication_style: 分析用户消息长度/格式
}
}
```
| 画像维度 | 提取逻辑 | 更新频率 |
|---------|---------|---------|
| `industry` | 对话中提到的行业关键词 | 检测到变化时 |
| `recent_topics` | 对话主题分类 | 每次对话追加 |
| `pain_points` | Experience 中的 pain_pattern | 每次新经验 |
| `preferred_tools` | 轨迹中高频使用的 tools | 每次对话更新 |
| `communication_style` | 用户消息的长度/格式偏好 | 每次对话微调 |
### 4.5 成本控制
- ExperienceExtractor 和 MemoryExtractor **合并为单次 LLM 调用**
- 画像更新从同一个 LLM 响应中提取,不额外调用
- 总新增成本:**0 次额外 LLM 调用**prompt 更长token 开销增加约 20%
## 5. L2 技能进化
### 5.1 触发机制
| 触发条件 | 说明 | 进化级别 |
|---------|------|---------|
| `Experience.reuse_count >= 3` | 同一 pain_pattern 被检索复用了 3 次+ | 自动触发 |
| 用户明确要求 | "帮我保存成一个技能" / "下次直接这样做" | 立即触发 |
| 管家主动提议 | 检测到用户第 N 次问同类问题N=2 | 管家触发 |
| `CompressedTrajectory.outcome = Success` + 高频 | 轨迹分析发现成功模式 | 批量触发 |
### 5.2 技能生成流程
```
触发信号
Phase 1: 模式聚合 (PatternAggregator)
收集同一 pain_pattern 下的所有 Experience
对比 solution_steps找出共同步骤
Phase 2: 技能生成 (SkillGenerator) — LLM 调用Haiku
输入:聚合的模式 + 原始对话样本
输出SKILL.md 文件内容
包含name, description, triggers, tools, steps
Phase 3: 质量门控 (QualityGate)
- triggers 不与现有 75 个内置技能冲突
- tools 依赖是否已在 HandRegistry 注册
- SKILL.md 格式校验loader.rs 可解析)
- 置信度 >= 0.7
Phase 4: 用户确认 (ConfirmationGate)
管家对话中呈现:
"我注意到你经常做 [X]
我帮你整理成了一个技能 [技能名]
以后直接说 [触发词] 就能用了。确认?"
用户可以:确认 / 修改 / 拒绝
▼ (确认)
Phase 5: 注册生效 (SkillRegistrar)
调用 SkillRegistry.create_skill()
自动重建语义路由索引
通知 ButlerRouter 新技能可用
```
### 5.3 核心数据结构
```rust
// zclaw-growth/src/skill_generator.rs
pub struct SkillCandidate {
pub name: String,
pub description: String,
pub triggers: Vec<String>,
pub tools: Vec<String>,
pub steps: Vec<SkillStep>,
pub category: String,
pub source_experiences: Vec<Uuid>, // 来源 Experience ID
pub confidence: f32,
pub version: u32, // 迭代版本
}
pub struct SkillStep {
pub instruction: String, // 步骤说明
pub tool: Option<String>, // 使用的工具(如果有)
pub expected_output: String, // 预期输出
}
pub struct EvolutionEvent {
pub id: Uuid,
pub event_type: EvolutionEventType,
pub candidate: SkillCandidate,
pub status: EvolutionStatus, // Pending | Confirmed | Rejected | Optimized
pub user_feedback: Option<String>,
pub created_at: DateTime<Utc>,
}
```
### 5.4 技能迭代优化
```
用户使用自动生成的技能
├── 满意 → reuse_count++ → 强化(不改动)
└── 不满意 → 收集反馈信号
反馈分析 (LLM 调用)
├── 修改 triggers → 重新路由
├── 修改 steps → 优化流程
├── 修改 tools → 换工具
└── 降级为记忆 → 不够通用,回退为 Experience
```
### 5.5 技能存储隔离
| 类型 | 存储路径 | 来源 | 可修改 |
|------|---------|------|--------|
| 内置技能 | `skills/` | 随项目发布 | 否 |
| 用户技能 | `~/.zclaw/skills/` 或 SaaS 存储 | L2 进化生成 | 是 |
| 临时技能 | 仅内存 | 对话中临时 | 自动销毁 |
`SkillRegistry` 已支持 `add_skill_dir()`,只需增加用户技能目录扫描。
## 6. L3 工作流进化
### 6.1 触发机制
```
TrajectoryAnalyzer后台周期任务每小时执行一次
├── 扫描最近 7 天的 CompressedTrajectory
├── 按相似度聚类(工具链序列相似度)
├── 发现重复模式(出现 2 次以上的相同工具链)
└── 触发信号:发现可固化的工作流模式
```
### 6.2 Pipeline 自动组装
```rust
// zclaw-growth/src/workflow_composer.rs
pub struct WorkflowComposer {
llm: Arc<dyn LlmDriver>,
}
pub struct PipelineCandidate {
pub name: String,
pub description: String,
pub triggers: Vec<String>,
pub yaml_content: String, // 生成的 Pipeline YAML
pub source_trajectories: Vec<Uuid>, // 来源轨迹
pub confidence: f32,
}
impl WorkflowComposer {
/// 从相似轨迹中组装 Pipeline
/// 输入:聚类后的轨迹组(相同工具链模式)
/// 输出PipelineCandidateYAML + 元数据)
pub async fn compose(
&self,
trajectories: &[CompressedTrajectory],
hand_registry: &HandRegistry,
) -> Result<Option<PipelineCandidate>> { ... }
}
```
### 6.3 生成示例
用户经常做:搜索→抓取→总结→格式化
```yaml
# 自动生成的 Pipeline
name: "每日资讯简报"
description: "搜索指定主题,抓取内容,生成结构化简报"
triggers:
- "每日简报"
- "资讯汇总"
- "新闻总结"
steps:
- id: search
action: hand
hand: researcher
params:
action: search
query: "${inputs.topic}"
- id: fetch
action: hand
hand: collector
params:
urls: "${steps.search.output.urls}"
- id: summarize
action: llm_generate
params:
prompt: "将以下内容整理为结构化简报:${steps.fetch.output}"
```
## 7. 反馈闭环
### 7.1 反馈信号收集
| 信号类型 | 收集方式 | 权重 |
|---------|---------|------|
| 显式反馈 | 用户说"不好"/"换一个"/"就这样" | 高 |
| 隐式反馈 | 用户是否继续追问同类问题 | 中 |
| 使用频率 | 技能/Pipeline 被调用的次数 | 中 |
| 完成率 | 技能执行后用户是否继续操作 | 低 |
| 对比评分 | 同一任务使用技能 vs 不使用的满意度差异 | 高 |
### 7.2 闭环路径
```
用户使用进化产物(技能/Pipeline
├── 正面反馈 → 信任度++ → 推荐优先级提升
│ → 如果足够成熟 → 提升为"推荐技能"
├── 负面反馈 → 信任度-- → 触发优化循环
│ → LLM 分析失败原因
│ → 修改技能 steps/triggers/tools
│ → 重新请用户确认
└── 长期不用 → 自然衰减 → 降级为记忆 → 最终清理
```
### 7.3 反馈数据结构
```rust
// zclaw-growth/src/feedback_collector.rs
pub struct EvolutionFeedback {
pub evolution_id: Uuid, // 关联的 EvolutionEvent
pub artifact_type: ArtifactType, // Skill | Pipeline
pub signal: FeedbackSignal, // Explicit | Implicit | Usage | Completion
pub sentiment: Sentiment, // Positive | Negative | Neutral
pub details: Option<String>, // 用户原始反馈文本
pub timestamp: DateTime<Utc>,
}
```
## 8. 数据流全景
```
用户对话
├──[L1] 每次对话后 ──→ 合并 LLM 提取
│ ├── 文本记忆 (偏好/知识/经验)
│ ├── 结构化 Experience (pain→solution→outcome)
│ ├── 画像增量更新
│ └── 轨迹事件记录
│ │
│ ▼
│ 经验库 (FTS5)
│ 轨迹库 (SQLite)
│ 用户画像 (SQLite)
│ │
├──[L2] 模式触发时 ──→ 模式聚合 → 技能生成 → 质量门控 → 用户确认 → 注册
├──[L3] 周期分析时 ──→ 轨迹聚类 → 工作流组装 → 质量门控 → 用户确认 → 注册
└──[反馈] 使用后 ──→ 质量评分 → 优化/衰减/提升
```
## 9. 新增模块清单
所有模块在 `zclaw-growth` crate 中,不新增 crate
| 模块 | 文件 | 职责 |
|------|------|------|
| ExperienceExtractor | `experience_extractor.rs` | 结构化经验提取 |
| ProfileUpdater | `profile_updater.rs` | 画像增量更新 |
| PatternAggregator | `pattern_aggregator.rs` | 经验模式聚合 |
| SkillGenerator | `skill_generator.rs` | SKILL.md 生成 |
| WorkflowComposer | `workflow_composer.rs` | Pipeline YAML 组装 |
| QualityGate | `quality_gate.rs` | 质量门控验证 |
| EvolutionEngine | `evolution_engine.rs` | 中枢调度(触发+协调) |
| FeedbackCollector | `feedback_collector.rs` | 反馈信号收集与分析 |
需修改的现有文件:
| 文件 | 修改内容 |
|------|---------|
| `zclaw-runtime/src/growth.rs` | GrowthIntegration 增加新提取器和触发检查 |
| `zclaw-runtime/src/middleware/butler_router.rs` | 消费进化事件,呈现确认对话 |
| `zclaw-skills/src/registry.rs` | 增加用户技能目录扫描 |
| `zclaw-kernel/src/kernel/skills.rs` | 暴露进化相关 Tauri 命令 |
| `zclaw-kernel/src/kernel/mod.rs` | 注册 EvolutionEngine 到 Kernel |
## 10. 实施建议
### 10.1 分阶段实施
| 阶段 | 内容 | 依赖 |
|------|------|------|
| Phase 1: L1 增强 | ExperienceExtractor + ProfileUpdater + 合并提取 | 无外部依赖 |
| Phase 2: L2 核心 | PatternAggregator + SkillGenerator + QualityGate | Phase 1 |
| Phase 3: L2 集成 | 确认对话 UI + SkillRegistrar + ButlerRouter 集成 | Phase 2 |
| Phase 4: L3 核心 | TrajectoryAnalyzer + WorkflowComposer | Phase 1 |
| Phase 5: 反馈闭环 | FeedbackCollector + 优化循环 | Phase 2 + 3 |
### 10.2 风险和缓解
| 风险 | 缓解措施 |
|------|---------|
| LLM 提取质量不稳定 | 置信度阈值过滤 + 质量门控 + 用户确认 |
| 进化产物与内置技能冲突 | QualityGate 检查 triggers 冲突 |
| 用户技能目录膨胀 | 信任度衰减 + 长期不用自动归档 |
| 增加系统复杂度 | 所有进化逻辑集中在 zclaw-growth不侵入运行时主流程 |
| 隐私问题 | 经验/技能数据本地存储,用户可查看/删除 |

View File

@@ -0,0 +1,246 @@
# ZCLAW 发布前审计设计文档
> 日期: 2026-04-18
> 目标: 全维度审计系统问题,为首次用户发布做准备
> 方法: 4 专家组并行分析 + 交叉评审
## 背景
ZCLAW 已完成稳定化基线,进入发布准备阶段。在发布前组织了一次多维度深度审计,通过 4 个专家代理(后端稳定性、前端质量、安全与数据、工程卫生)并行分析,发现并验证了 24 个问题点。经交叉评审后纠正了 4 项原始审计误判。
## 审计纠正(原始误判)
| 原始声称 | 实际情况 |
|----------|----------|
| Cargo.lock 缺失 | 已提交并跟踪,`git ls-files Cargo.lock` 确认 |
| 无 CI/CD | `.github/workflows/ci.yml` + `release.yml` 完整存在 |
| src-tauri LOC 偏差 3x | 实际 61,257 行,与 TRUTH.md ~61,400 基本一致 |
| Token INTEGER 溢出 | 每行存单次请求 token 不溢出SUM() 已返回 BIGINT |
---
## 第一层:发布阻塞项(必须修复)
### 1. Director 死锁风险 — P0 CRITICAL
**文件**: `crates/zclaw-kernel/src/director.rs:506-536`
**问题**: `send_to_agent()` 顺序获取 `pending_requests.lock()`L506`inbox.lock()`L519后者在 `tokio::time::timeout` 内跨 `rx.recv().await` 持有L521-536。两个并发调用可互相阻塞。另有一条死信通道 `_response_tx/_response_rx`L490从未连接——sender 存入 pending_requests 但 receiver 无人读取。
**验证**: 修复后需添加并发 `send_to_agent()` 测试验证死锁消除。
**修复方案**: 用 `oneshot` channel 重构响应接收模式:
- 每次 `send_to_agent()` 创建 `oneshot::channel`
- sender 存入 `pending_requests`receiver 配合 `tokio::time::timeout` 等待
- 新增独立的 inbox 消费任务分发响应到对应 oneshot sender
- 变更 `pending_requests` 类型为 `HashMap<String, oneshot::Sender<A2aEnvelope>>`
**工时**: 2-4h重构 + 测试更新)
### 2. Pipeline Executor 内存泄漏 — P0 HIGH
**文件**: `crates/zclaw-pipeline/src/executor.rs`
**问题**: `runs: RwLock<HashMap<String, PipelineRun>>``cancellations: RwLock<HashMap<String, bool>>` 无限增长,无清理路径。
**修复方案**:
- 添加 `cleanup(max_age: Duration)` 方法,清除已完成/失败/取消的旧记录
-`execute_with_id()` 完成后自动调用清理
- 设置 `max_completed_runs` 上限(如 100超限淘汰最旧记录
**工时**: <1h
### 3. Pipeline 步骤超时缺失 + Delay 无上限 — P0 HIGH
**文件**: `crates/zclaw-pipeline/src/executor.rs`
**问题**: `ExecuteError::Timeout` 已定义但从未触发每步执行无超时包装`Action::Delay { ms }` 接受原始 u64恶意 YAML 可设 `ms: u64::MAX`
**修复方案**:
- `tokio::time::timeout` 包装每步 `execute_action` 调用
- 使用 `PipelineSpec.timeout_secs`已存在但未使用cap 5 分钟
- Delay ms 上限 60000超出时 warn 并截断
- `parser.rs`/`parser_v2.rs` 添加 YAML 解析时验证
**工时**: 1-2h
### 4. TRUTH.md Hands 数量偏差 — P0 (文档完整性)
**文件**: `docs/TRUTH.md`, `CLAUDE.md`
**问题**: 声称 9 Hand 启用实际 kernel 注册 7
- 6 个通过 `hands/*.HAND.toml` 扫描注册Browser/Clip/Collector/Quiz/Researcher/Twitter
- 1 个通过 `kernel/mod.rs:96` 编程注册ReminderHand`_` 前缀豁免 HAND.toml 扫描 `trigger_manager.rs:139`
- Whiteboard/Slideshow/Speech HAND.toml 仅存在于 `.claude/worktrees/` 开发分支 `impl Hand for`未合并到主分支
**修复方案**:
- TRUTH.md: 更新为 "6 HAND.toml + Reminder 系统内部 = 7 注册"
- CLAUDE.md §6: 明确标注 Whiteboard/Slideshow/Speech "开发中未合并"
- 确认桌面 UI 是否展示 9 Hand如有则同步更新
**工时**: <1h
### 5. rate_limit_events 清理 Worker 是空壳 — P0 (数据膨胀)
**文件**: `crates/zclaw-saas/src/workers/cleanup_rate_limit.rs`
**问题**: Worker body no-op注释说"rate limit entries are in-memory" main.rs batch flush 确实将限流条目写入数据库注意内存中的 DashMap 清理每 300 秒运行一次`state.rs:118`**数据库持久化条目**无限增长无任何删除机制
**修复方案**: 实现 Worker body执行 `DELETE FROM rate_limit_events WHERE created_at < NOW() - INTERVAL '1 hour'`确认调度器已注册此 Workermain.rs:47 已注册)。
**工时**: <1h
---
## 第二层:强烈建议修复
### 6. TypeScript 编译排除安全关键文件
**文件**: `desktop/tsconfig.json`
**问题**: 排除了 `ErrorAlert.tsx`文件已不存在残留排除项 `ErrorBoundary.tsx`527 行安全关键组件)。
**修复**: 删除排除项运行 `tsc --noEmit` 验证 ErrorBoundary 无类型错误
**工时**: <1h
### 7. LlmConfig api_key Debug 泄露
**文件**: `crates/zclaw-kernel/src/config.rs`
**问题**: `#[derive(Debug)]` 会在 `format!("{:?}", config)` 中打印 api_key 明文虽然当前无代码 Debug-print 此结构但日志调试时容易触发
**修复**: 移除 `Debug` derive实现自定义 `Debug` impl `"***REDACTED***"` 遮蔽 api_key
**工时**: <30min
### 8. 关键 .unwrap() 调用
**文件**:
- `crates/zclaw-saas/src/billing/handlers.rs:598` Response builder unwrap
- `desktop/src-tauri/src/classroom_commands/mod.rs:58` db_path.parent().unwrap()
**修复**: 替换为 `map_err` + `?` 传播
**工时**: <1h
### 9. 静默吞错关键集群
**文件与修复**:
- `crates/zclaw-kernel/src/kernel/approvals.rs:88,93,124` 已有 `tracing::warn!` 日志但级别应为 `error`审批状态丢失是严重事件
- `crates/zclaw-protocols/src/mcp_transport.rs:429` 记录僵尸进程风险
- `crates/zclaw-kernel/src/events.rs:21` `tracing::debug!("Event dropped: {:?}", e)`
- `crates/zclaw-runtime/src/tool/builtin/task.rs` 日志记录 subtask 事件丢失
- `crates/zclaw-growth/src/storage/sqlite.rs` 迁移 匹配 `sqlx::Error::Database` 检查 SQLite 错误码 1 子错误 "duplicate column name"区分幂等迁移与真实错误
**工时**: 2-4h
### 10. 缺失数据库索引
**新文件**: `crates/zclaw-saas/migrations/20260418000001_add_missing_indexes.sql`
```sql
CREATE INDEX IF NOT EXISTS idx_rle_created_at ON rate_limit_events(created_at);
CREATE INDEX IF NOT EXISTS idx_billing_sub_plan ON billing_subscriptions(plan_id);
CREATE INDEX IF NOT EXISTS idx_ki_created_by ON knowledge_items(created_by);
```
**工时**: <1h
### 11. 配置验证缺失
**文件**: `crates/zclaw-saas/src/config.rs`
**修复**: `SaaSConfig::load()` 添加
- `jwt_expiration_hours >= 1`
- `max_connections > 0`
- 改善默认 DB URL 连接失败的错误信息
**工时**: <1h
### 12. MCP Transport 响应错配
**文件**: `crates/zclaw-protocols/src/mcp_transport.rs`
**问题**: stdin/stdout 分离的 Mutex 可导致并发请求收到错误响应
**修复**: 合并 stdin + stdout 为单一 Mutex write-then-read 周期内持有锁
**工时**: 3-4h
---
## 第三层:可延后至首个补丁
| # | 问题 | 工时 |
|---|------|------|
| 13 | console.log 清理105处createLogger | 2-3h |
| 14 | ChatStore 双源真相重构 | 2-4h |
| 15 | 33处内联样式Tailwind | <1h |
| 16 | SaaS mixin `prototype: any` 类型约束 | <1h |
| 17 | serde_yaml 统一到 serde_yaml_bw | 1-2h |
| 18 | 32处 dead_code 审查清理 | 2-4h |
| 19 | webhook 废弃表删除迁移 | <30min |
| 20 | A2A feature gate 或移除 feature 定义 | <30min |
| 21 | dependency 内联声明workspace 引用 | 1-2h |
| 22 | KernelGrowth 隐式依赖显式化 | <30min |
| 23 | noUncheckedIndexedAccess 添加 | 2-4h |
| 24 | handStore/configStore duck-typingdiscriminator | <1h |
---
## TRUTH.md 数值校准清单
| 指标 | 当前值 | 应更正为 | 验证命令 |
|------|--------|----------|----------|
| #[test] (crates) | 433 | 425 | `grep -rn '^\s*#\[test\]\s*$' crates/ --include="*.rs" \| wc -l` |
| #[tokio::test] (crates) | 368 | 309 | `grep -rn '^\s*#\[tokio::test\]' crates/ --include="*.rs" \| wc -l` |
| Zustand Store | 21 | 26 (含子目录) | `find desktop/src/store/ -name "*.ts" \| wc -l` |
| Admin V2 页面 | 15 | 17 | `ls admin-v2/src/pages/*.tsx \| wc -l` |
| Pipeline YAML | 17 | 18 | `find pipelines/ -name "*.yaml" \| wc -l` |
| Hands 启用 | 9 | 7 (6 HAND.toml + Reminder) | `ls hands/*.HAND.toml \| wc -l` + kernel registry |
---
## 实施计划
### Batch 1: 发布阻塞修复 (Day 1, 上午 + 下午)
按依赖顺序执行总工时 ~6-9h建议分上下午
1. Pipeline 超时 + 内存泄漏 + Delay 上限#2, #3)— 上午
2. Director 死锁修复#1)— 上午可并行
3. rate_limit_events Worker 实现#5)— 下午
4. TRUTH.md + CLAUDE.md 数值校准#4)— 下午
**验证**: `cargo test --workspace --exclude zclaw-saas` + `tsc --noEmit`
### Batch 2: 强烈建议修复 (Day 2)
5. tsconfig 修复#6
6. LlmConfig Debug 遮蔽#7
7. 关键 unwrap 修复#8
8. 静默吞错修复 关键集群#9
9. 缺失索引迁移#10
10. Config 验证#11
11. MCP Transport 锁合并#12
**验证**: `cargo test --workspace --exclude zclaw-saas` + `pnpm tsc --noEmit` + `pnpm vitest run`
### Batch 3: 补丁迭代 (Day 3+)
按优先级从高到低处理第三层 12
---
## 关键文件列表
- `crates/zclaw-kernel/src/director.rs` P0 Director 死锁
- `crates/zclaw-pipeline/src/executor.rs` P0 Pipeline 内存泄漏 + 超时
- `crates/zclaw-saas/src/workers/cleanup_rate_limit.rs` P0 Worker 空壳
- `docs/TRUTH.md` P0 文档校准
- `desktop/tsconfig.json` P1 类型排除
- `crates/zclaw-kernel/src/config.rs` P1 Debug 泄露
- `crates/zclaw-saas/src/billing/handlers.rs` P1 unwrap
- `desktop/src-tauri/src/classroom_commands/mod.rs` P1 unwrap
- `crates/zclaw-protocols/src/mcp_transport.rs` P1 响应错配
- `crates/zclaw-saas/src/config.rs` P1 配置验证

View File

@@ -0,0 +1,650 @@
# ZCLAW 功能链路穷尽测试方案
> **方案**: B+C 混合 — 状态机转换测试(主体)+ 3 角色冒烟测试(补充)
> **范围**: 33 条功能链路345 个测试场景,分 5 批执行
> **执行方式**: 通过 Tauri MCP 模拟真实用户操作(找碴模式)
## Context
基于 wiki/feature-map.md 的 33 条功能链路,设计穷尽测试。目标不是"页面能打开就算通过",而是验证完整数据流、边界条件、错误恢复、降级机制、跨链路交互。通过 Tauri MCP 工具query_page/click/type_text/execute_js/take_screenshot/wait_for执行。
## 状态模型12 核心状态)
```
FRESH → CONFIGURED → CONNECTED_LOCAL
↓ ↓
LOGGED_OUT → LOGGED_IN → CONNECTED_SAAS
↓ ↓
TOKEN_EXPIRED DEGRADED
↓ ↓
LOGGED_IN ←───────┘
CHATTING → STREAM_COMPLETE
附加: ADMIN_MODE / BUTLER_SIMPLE / BUTLER_PRO / PIPELINE_RUN
```
| 状态 | 验证方式 |
|------|----------|
| FRESH | `!connectionStore.connectionState` |
| CONNECTED_LOCAL | `connectionState === 'connected' && mode === 'tauri'` |
| LOGGED_IN | `saasStore.token && !saasDegraded` |
| CONNECTED_SAAS | `connectionState === 'connected' && mode === 'saas'` |
| DEGRADED | `saasStore.saasReachable === false` |
| CHATTING | `streamStore.isStreaming === true` |
| STREAM_COMPLETE | `streamStore.isStreaming === false && lastMessage.role === 'assistant'` |
---
## Batch 1核心聊天F-01~F-0552 场景)
### F-01 发送消息11 场景)
| ID | 类别 | 场景 | From → To | 验证点 |
|----|------|------|-----------|--------|
| F01-01 | normal | 发送简单中文"你好" | CONNECTED → CHATTING → COMPLETE | 用户气泡出现、AI 流式响应、streaming 动画、完成状态 |
| F01-02 | normal | 发送英文长消息500字 | CONNECTED → COMPLETE | 完整接收不截断、token 计数更新 |
| F01-03 | normal | 发送含代码请求 | CONNECTED → COMPLETE | AI 返回代码块、语法高亮正确 |
| F01-04 | boundary | 空消息 | CONNECTED → CONNECTED | 发送按钮禁用/无反应 |
| F01-05 | boundary | 连续快速发送 5 条 | CHATTING → CHATTING | 排队机制正常/提示等待/不丢消息 |
| F01-06 | boundary | 超长消息10000字 | CONNECTED → COMPLETE | 不崩溃/不截断或合理提示 |
| F01-07 | error | 网络中断后发送 | CONNECTED → ERROR → CONNECTED | 错误提示友好、不丢失用户输入、可重试 |
| F01-08 | error | 模型不可用 | CONNECTED → ERROR → CONNECTED | 400 错误提示明确、自动建议可用模型 |
| F01-09 | degradation | SaaS 不可达降级 | SAAS → DEGRADED → LOCAL | 自动降级到本地、提示降级状态 |
| F01-10 | cross | 发送中切换 Agent | CHATTING → COMPLETE → 切换 | 当前流正常完成/新 Agent 独立会话 |
| F01-11 | cross | 发送后检查记忆触发 | COMPLETE → MEMORY | Memory 中间件触发提取、记忆统计增加 |
### F-02 流式响应10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F02-01 | normal | 正常流式逐字显示 | 文字逐字出现、光标闪烁、最后停止 |
| F02-02 | normal | Thinking 模式展示 | thinking 内容折叠、思考→回答分离 |
| F02-03 | normal | 工具调用流式展示 | ToolStart/ToolEnd 事件正确渲染 |
| F02-04 | normal | Hand 触发流式展示 | HandStart/HandEnd 事件、进度指示 |
| F02-05 | boundary | 极短响应(<5字 | 短响应不吞字完整显示 |
| F02-06 | boundary | 超长响应>5000字 | 不截断、不重复、滚动正常 |
| F02-07 | boundary | 中英日韩混合内容 | Unicode 正确渲染、不乱码 |
| F02-08 | error | 流式中途 500 错误 | 错误提示友好、部分内容保留 |
| F02-09 | error | 流式中途超时 | 超时守护触发5min、提示超时、可重试 |
| F02-10 | cross | 流式中取消再重新发送 | 新流正常开始、不受旧流影响 |
### F-03 模型切换10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F03-01 | normal | 切换到另一个模型 | 模型名更新、下次消息用新模型 |
| F03-02 | normal | 切换后发送验证 | 确认使用新模型响应 |
| F03-03 | normal | 列出所有可用模型 | SaaS 白名单模型完整列表 |
| F03-04 | boundary | 快速切换 10 次 | 最后一次生效、不崩溃 |
| F03-05 | boundary | 无可用模型 | 清空 Provider Key → 模型列表为空、友好提示 |
| F03-06 | error | 切换到未启用模型 | SaaS 返回 400、提示错误 |
| F03-07 | error | 模型别名不匹配 | 用非精确 ID → 400、提示精确 ID |
| F03-08 | degradation | SaaS 不可达时切换 | 降级模式下使用本地模型列表 |
| F03-09 | cross | 切换模型+发消息+检查 token | token 计数正确归属新模型 |
| F03-10 | cross | 会话中切换模型不丢上下文 | 3轮→切换→再聊→上下文保留 |
### F-04 上下文管理11 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F04-01 | normal | 单会话上下文连续5轮 | AI 记得前文、不丢上下文 |
| F04-02 | normal | 切换回来恢复会话 | 切走→切回→消息历史完整 |
| F04-03 | normal | 跨会话持久化 | 发消息→关闭→重开→IndexedDB 保留 |
| F04-04 | boundary | 超长上下文50轮 | Compaction 触发、不崩溃 |
| F04-05 | boundary | 上下文窗口满 | 自动压缩、保留关键信息 |
| F04-06 | error | 消息存储失败 | IndexedDB 空间满→优雅降级、不丢对话 |
| F04-07 | cross | 多 Agent 会话隔离 | Agent A 聊 X → Agent B 聊 Y → 回到 A → 不混 |
| F04-08 | cross | 会话标题自动生成 | 新会话聊 2 轮→Title 中间件生成标题 |
| F04-09 | cross | 记忆注入影响上下文 | 有历史记忆→新会话→system prompt 含相关记忆 |
| F04-10 | cross | 大上下文+模型切换 | 20轮后切换模型→上下文完整 |
| F04-11 | cross | 跨会话记忆检索增强 | 昨天聊 X→今天问 X→IdentityRecall 检索到 |
### F-05 取消流式10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F05-01 | normal | 流式中点击取消 | 流立即停止、已接收内容保留 |
| F05-02 | normal | 取消后发新消息 | 新消息正常发送、不受旧流影响 |
| F05-03 | normal | 取消后消息标记 | 消息标记为"已取消"/不完整状态 |
| F05-04 | boundary | 流刚完成时取消 | 无副作用、消息完整 |
| F05-05 | boundary | 连续取消 3 次 | 每次取消立即生效、不卡死 |
| F05-06 | boundary | 取消正在 tool call 的流 | 工具执行正确中断、状态清理 |
| F05-07 | error | 取消失败(网络已断) | 不崩溃、超时后自动清理 |
| F05-08 | cross | 取消+Token 统计 | 已消耗 token 正确计入 |
| F05-09 | cross | 取消+记忆提取 | 已接收部分可能触发提取 |
| F05-10 | cross | 取消+上下文保留 | 新消息引用已接收内容→AI 知道 |
---
## Batch 2Agent + 认证F-06~F-09, F-17~F-1972 场景)
### F-06 创建 Agent10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F06-01 | normal | 正常创建 Agent | 侧边栏出现新 Agent、可选中 |
| F06-02 | normal | 自定义名称+模型+提示 | 配置正确保存、生效 |
| F06-03 | boundary | 重复名称 | 允许或提示冲突、不崩溃 |
| F06-04 | boundary | 超长名称100字 | 正确处理、截断或提示 |
| F06-05 | boundary | 特殊字符名称emoji/中文/<> | 不崩溃、显示正确 |
| F06-06 | boundary | 空系统提示 | 使用默认提示、不崩溃 |
| F06-07 | error | 创建失败 | 错误提示、不产生幽灵 Agent |
| F06-08 | cross | 创建后立即发消息 | 新 Agent 独立会话、响应正常 |
| F06-09 | cross | 创建+记忆隔离 | 新 Agent 记忆统计为 0 |
| F06-10 | cross | 创建后列表刷新 | 侧边栏排序/数量正确 |
### F-07 切换 Agent10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F07-01 | normal | 正常切换 | Agent 选中、会话切换 |
| F07-02 | normal | 切换后发消息 | 使用新 Agent 的配置 |
| F07-03 | normal | 切换后上下文独立 | 不混入其他 Agent 的对话 |
| F07-04 | boundary | 快速连续切换 10 次 | 最后一次生效、不崩溃 |
| F07-05 | boundary | 切到刚创建的 Agent | 空会话、正常使用 |
| F07-06 | boundary | 切回默认 Agent | 原有会话恢复 |
| F07-07 | boundary | 仅 1 个 Agent 时 | 无切换选项或自身 |
| F07-08 | cross | 流式中切换 | 当前流完成/新 Agent 独立 |
| F07-09 | cross | 不同模型 Agent | 各用各的模型 |
| F07-10 | cross | 记忆不混淆 | Agent A 记忆不出现在 B |
### F-08 配置 Agent10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F08-01 | normal | 改名称 | 侧边栏+详情同步更新 |
| F08-02 | normal | 改模型 | 下次消息用新模型 |
| F08-03 | normal | 改系统提示 | AI 行为改变 |
| F08-04 | boundary | 空名称 | 校验提示、不允许保存 |
| F08-05 | boundary | 超长系统提示5000字 | 正确保存或提示限制 |
| F08-06 | boundary | 特殊字符提示 | 不注入/不崩溃 |
| F08-07 | error | 保存失败 | 不丢原配置、提示重试 |
| F08-08 | cross | 配置后立即生效 | 不需重启/下条消息生效 |
| F08-09 | cross | 已有对话不受影响 | 历史消息不变 |
| F08-10 | cross | 配置+记忆联动 | 改系统提示不影响已有记忆 |
### F-09 删除 Agent10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F09-01 | normal | 正常删除 | 确认弹窗→删除→列表更新 |
| F09-02 | normal | 删除当前 Agent | 自动切换到默认 |
| F09-03 | normal | 删除有对话的 Agent | 级联删除 sessions/messages |
| F09-04 | boundary | 取消删除 | 弹窗取消→无变化 |
| F09-05 | boundary | 删除最后一个(仅默认) | 不允许删除或保护 |
| F09-06 | error | 删除失败 | 提示错误、Agent 仍存在 |
| F09-07 | cross | 删除后记忆级联 | Agent 记忆一同清除 |
| F09-08 | cross | 删除使用中的 Agent | 正确处理、不崩溃 |
| F09-09 | cross | 批量删除 3 个 | 逐个确认或批量确认 |
| F09-10 | cross | 删除后切换到默认 | 会话为空、正常可用 |
### F-17 注册10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F17-01 | normal | 正常注册 | 成功→自动登录→进入聊天 |
| F17-02 | normal | 邮箱格式校验 | 无效邮箱→提示错误 |
| F17-03 | normal | 密码强度校验 | 弱密码→提示要求 |
| F17-04 | boundary | 已存在邮箱 | 提示已注册、建议登录 |
| F17-05 | boundary | 254 字符邮箱 | RFC 5322 校验 |
| F17-06 | boundary | 特殊字符密码 | 允许/正确存储 |
| F17-07 | error | 空字段提交 | 校验提示 |
| F17-08 | cross | 注册后自动登录 | token 存储+模型列表加载 |
| F17-09 | cross | 注册限流3次/小时) | 超限提示 |
| F17-10 | cross | 注册后立即发消息 | 全链路正常 |
### F-18 登录12 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F18-01 | normal | 正常登录 | token 存储+进入聊天 |
| F18-02 | normal | 错误密码 | 提示密码错误 |
| F18-03 | normal | 不存在用户 | 提示用户不存在 |
| F18-04 | boundary | 密码错误 5 次 | 账户锁定 15 分钟 |
| F18-05 | boundary | 锁定后等待 15 分钟 | 可重新登录 |
| F18-06 | normal | 登录后 token 存储 | OS keyring 有值 |
| F18-07 | normal | 登录后模型列表加载 | SaaS 白名单模型显示 |
| F18-08 | boundary | 多设备登录 | 允许/不互踢 |
| F18-09 | cross | 登录限流5次/分钟) | 超限提示 |
| F18-10 | cross | 记住登录状态 | 重启后不需重新登录 |
| F18-11 | cross | 登录后 UI 状态 | 模式/主题/设置恢复 |
| F18-12 | cross | 登录+降级模式切换 | SaaS 模式↔本地模式 |
### F-19 Token 刷新10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F19-01 | normal | 正常刷新 | 新 token 对+旧 token 失效 |
| F19-02 | normal | access 过期自动刷新 | 无感刷新+继续对话 |
| F19-03 | boundary | 刷新时发送消息 | 不丢失+正确处理 |
| F19-04 | boundary | refresh token 单次使用 | 二次使用被拒 |
| F19-05 | error | 刷新失败 | 重新登录提示 |
| F19-06 | cross | 刷新后继续对话 | 上下文完整 |
| F19-07 | cross | 并发请求触发刷新 | 不重复刷新+不竞态 |
| F19-08 | cross | 刷新+用量统计正确 | token 不丢失 |
| F19-09 | cross | 刷新+旧 token 失效 | DB 中旧 token 已撤销 |
| F19-10 | cross | 刷新+cookie 更新 | HttpOnly cookie 更新 |
---
## Batch 3Hands + 记忆F-10~F-1674 场景)
### F-10 触发 Hand11 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F10-01 | normal | 触发 Browser Hand | HandStart→执行→HandEnd 正确 |
| F10-02 | normal | 触发 Collector Hand | 数据收集+结果返回 |
| F10-03 | normal | 触发 Researcher Hand | 深度研究+结果返回 |
| F10-04 | normal | LLM 自动触发 Hand | 对话中 LLM 决定调用 Hand |
| F10-05 | normal | 手动触发 Hand | 自动化面板→选择→执行 |
| F10-06 | boundary | 触发+流式展示 | 进度指示+结果渲染 |
| F10-07 | boundary | 触发失败 | 错误提示+可重试 |
| F10-08 | error | 无权限触发 | 提示权限不足 |
| F10-09 | error | 依赖缺失WebDriver/FFmpeg | 明确提示缺什么 |
| F10-10 | cross | 并发触发 2 个 Hand | 队列或并行+不冲突 |
| F10-11 | cross | 触发+记忆存储 | Hand 结果存入记忆 |
### F-11 Hand 审批10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F11-01 | normal | 审批通过 | 审批→执行→结果返回 |
| F11-02 | normal | 审批拒绝 | 拒绝→提示取消 |
| F11-03 | boundary | 审批超时 | 超时后自动取消或提示 |
| F11-04 | boundary | 审批弹窗展示 | 需求信息完整+操作按钮 |
| F11-05 | error | 审批后执行失败 | 错误提示+可重试 |
| F11-06 | cross | 审批+流式中 | 不影响当前流 |
| F11-07 | cross | 多 Hand 同时审批 | 各自独立 |
| F11-08 | cross | 审批日志记录 | 操作日志有记录 |
| F11-09 | cross | 审批+用量统计 | token 正确计入 |
| F11-10 | cross | 审批+记忆提取 | 结果触发记忆 |
### F-12 Hand 结果查看10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F12-01 | normal | 正常查看结果 | 聊天中结果展示 |
| F12-02 | normal | 结果详情弹窗 | 完整数据展示 |
| F12-03 | boundary | 失败结果展示 | 错误信息清晰 |
| F12-04 | boundary | 结果含附件 | 附件可查看/下载 |
| F12-05 | boundary | 结果含数据表格 | 表格正确渲染 |
| F12-06 | normal | 历史 Hand 结果 | 历史列表可查看 |
| F12-07 | error | 结果持久化失败 | 不丢结果+提示 |
| F12-08 | cross | 结果+重新执行 | 可重新运行 |
| F12-09 | cross | 结果+记忆提取 | 结果触发记忆存储 |
| F12-10 | cross | 结果+上下文引用 | 后续对话可引用 Hand 结果 |
### F-13 Browser 自动化10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F13-01 | normal | 打开网页 | URL 加载+截图返回 |
| F13-02 | normal | 截图操作 | 截图正确+展示 |
| F13-03 | normal | 点击操作 | 元素点击+页面变化 |
| F13-04 | normal | 填表操作 | 表单填写+提交 |
| F13-05 | normal | 搜索操作 | 搜索+结果返回 |
| F13-06 | boundary | 多步骤操作 | 步骤链正确执行 |
| F13-07 | error | 页面超时 | 超时提示+可重试 |
| F13-08 | error | WebDriver 未连接 | 明确提示+连接指引 |
| F13-09 | cross | 结果在聊天展示 | 格式正确+可交互 |
| F13-10 | cross | 结果+记忆存储 | 浏览器内容存入记忆 |
### F-14 记忆搜索11 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F14-01 | normal | 搜索中文关键词 | FTS5+TF-IDF 结果正确 |
| F14-02 | normal | 搜索英文关键词 | 结果正确 |
| F14-03 | normal | 搜索代码片段 | 关键词优先策略 |
| F14-04 | boundary | 模糊搜索 | 部分匹配返回 |
| F14-05 | boundary | 无结果搜索 | 提示无结果 |
| F14-06 | boundary | 精确匹配 | 高分结果排前 |
| F14-07 | boundary | 排序验证 | TF-IDF 权重排序正确 |
| F14-08 | normal | 分类过滤 | Preference/Knowledge/Experience 分开 |
| F14-09 | cross | Agent 隔离 | 只返回当前 Agent 记忆 |
| F14-10 | cross | 分页/大量结果 | 不崩溃+可翻页 |
| F14-11 | cross | 搜索性能 | <500ms 返回 |
### F-15 记忆自动注入11 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F15-01 | normal | 自动提取偏好 | "我喜欢深色主题"→偏好记忆 |
| F15-02 | normal | 自动提取知识 | "Python 3.12 新特性是..."→知识记忆 |
| F15-03 | normal | 自动提取经验 | "上次部署失败了因为..."→经验记忆 |
| F15-04 | boundary | Token 预算控制 | 不超过 system prompt 预算 |
| F15-05 | boundary | 注入格式正确 | 结构化上下文块格式 |
| F15-06 | boundary | 流式中注入 | 不影响当前流 |
| F15-07 | error | 注入溢出 | 超预算时截断+不崩溃 |
| F15-08 | cross | 去重 | 不重复注入相同记忆 |
| F15-09 | cross | Agent 隔离 | Agent 独立注入 |
| F15-10 | cross | 跨会话注入 | 新会话检索旧记忆注入 |
| F15-11 | cross | 进化引擎联动 | 积累模式检测进化建议 |
### F-16 记忆手动管理11 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F16-01 | normal | 查看统计 | 总数/分类数/容量 |
| F16-02 | normal | 导出全部 | JSON 格式+完整 |
| F16-03 | normal | 导入记忆 | 正确导入+去重 |
| F16-04 | normal | 删除单条 | 删除后列表更新 |
| F16-05 | normal | 删除全部 | 确认清空+统计归零 |
| F16-06 | boundary | 查看详情 | 完整内容+元数据 |
| F16-07 | error | 编辑记忆 | 不崩溃 |
| F16-08 | cross | 批量操作 | 多选删除 |
| F16-09 | cross | 存储路径显示 | SQLite 路径正确 |
| F16-10 | cross | 容量限制 | 大量记忆不崩溃 |
| F16-11 | cross | 数据完整性 | 导出删除导入一致 |
---
## Batch 4SaaS + 管家F-20~F-2564 场景)
### F-20 订阅管理10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F20-01 | normal | 查看计划列表 | 显示所有计费计划 |
| F20-02 | normal | 查看当前订阅 | 计划名+到期日+用量 |
| F20-03 | normal | 升级计划 | FreePro配额增加 |
| F20-04 | normal | 降级计划 | ProFree配额减少 |
| F20-05 | boundary | 免费计划限制 | 超配额提示升级 |
| F20-06 | boundary | 计划对比 | 功能差异清晰 |
| F20-07 | error | 订阅过期 | 提示续费+降级处理 |
| F20-08 | cross | 订阅+用量展示 | 用量数据一致 |
| F20-09 | cross | 订阅+模型限制 | 低级计划模型受限 |
| F20-10 | cross | Admin 管理订阅 | Admin 可修改用户订阅 |
### F-21 支付计费12 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F21-01 | normal | 正常支付流程 | 选择计划支付确认 |
| F21-02 | normal | 支付宝模拟 | mock 路由回调成功 |
| F21-03 | normal | 微信模拟 | mock 路由回调成功 |
| F21-04 | boundary | 支付失败 | 回调失败提示+可重试 |
| F21-05 | normal | 支付回调验证 | 签名/金额校验 |
| F21-06 | normal | 发票生成 | 自动生成+可查看 |
| F21-07 | normal | 发票 PDF | 下载 PDF 内容正确 |
| F21-08 | cross | 用量统计 | 请求/token 计数正确 |
| F21-09 | cross | 配额耗尽 | 超额提示升级 |
| F21-10 | cross | 配额实时递增 | 每次请求+1 |
| F21-11 | cross | 聚合器数据 | aggregate_usage Worker 数据 |
| F21-12 | cross | 支付+订阅联动 | 支付成功订阅状态更新 |
### F-22 Admin 后台10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F22-01 | normal | Dashboard 展示 | 统计数据正确+图表 |
| F22-02 | normal | 账号管理 CRUD | 列表/创建/编辑/禁用 |
| F22-03 | normal | 模型服务配置 | Provider/模型/Key CRUD |
| F22-04 | normal | API 密钥管理 | 加密存储+启停+删除 |
| F22-05 | normal | 知识库管理 | 分类/条目/搜索 |
| F22-06 | normal | 行业配置 | 4 内置行业+自定义 |
| F22-07 | normal | 计费管理 | 计划/订阅/用量 |
| F22-08 | normal | 角色权限 | RBAC+权限模板 |
| F22-09 | normal | 操作日志 | 查询+筛选+分页 |
| F22-10 | normal | Agent 模板 | 模板 CRUD+分配 |
### F-23 简洁/专业模式10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F23-01 | normal | 默认简洁模式 | 隐藏高级功能 |
| F23-02 | normal | 切换到专业模式 | 显示完整功能面板 |
| F23-03 | normal | 切回简洁模式 | 重新隐藏高级功能 |
| F23-04 | boundary | 简洁模式功能验证 | 只展示聊天+基础操作 |
| F23-05 | boundary | 专业模式功能验证 | 所有面板可用 |
| F23-06 | boundary | 聊天中切换 | 不影响当前对话 |
| F23-07 | cross | 切换+设置保留 | 模式切换后设置不变 |
| F23-08 | cross | 首次启动默认模式 | 简洁模式为默认 |
| F23-09 | cross | 模式+行业联动 | 行业配置在两种模式都生效 |
| F23-10 | cross | 模式+记忆展示 | 专业模式显示更多记忆信息 |
### F-24 行业配置10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F24-01 | normal | 选择医疗行业 | 关键词加载+管家面板更新 |
| F24-02 | normal | 选择教育行业 | 关键词加载+模板推荐 |
| F24-03 | normal | 选择电商行业 | 关键词加载 |
| F24-04 | normal | 自定义行业 | 关键词自定义+保存 |
| F24-05 | boundary | 行业关键词匹配 | ButlerRouter 检测行业关键词 |
| F24-06 | cross | 行业+管家联动 | 行业 prompt 注入 system prompt |
| F24-07 | cross | 行业+痛点联动 | 行业相关痛点分类 |
| F24-08 | cross | 行业+Pipeline 联动 | 推荐行业相关模板 |
| F24-09 | cross | 行业切换 | 切换行业关键词更新 |
| F24-10 | cross | 行业+记忆 | 行业相关记忆优先检索 |
### F-25 痛点积累12 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F25-01 | normal | 自动提取痛点 | 聊天中抱怨痛点提取 |
| F25-02 | normal | 痛点列表展示 | 管家面板显示痛点 |
| F25-03 | normal | 痛点积累到阈值 | 多次抱怨积累计数 |
| F25-04 | normal | 方案生成 | 阈值触发生成解决建议 |
| F25-05 | normal | 方案状态更新 | 接受/拒绝/搁置 |
| F25-06 | boundary | 痛点+行业联动 | 行业分类痛点 |
| F25-07 | cross | 痛点跨会话 | 昨天痛点今天可见 |
| F25-08 | cross | 痛点+记忆 | 痛点存入记忆系统 |
| F25-09 | cross | 痛点去重 | 相同痛点不重复记录 |
| F25-10 | cross | 痛点+经验 | painsolutionoutcome |
| F25-11 | cross | 痛点+冷启动 | 新用户首次痛点提取 |
| F25-12 | cross | 痛点+用户画像 | 画像反映痛点偏好 |
---
## Batch 5Pipeline + 配置 + 安全F-26~F-3383 场景)
### F-26 选择模板10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F26-01 | normal | 列出所有模板 | 18 YAML 模板 |
| F26-02 | normal | 按行业过滤 | 医疗/教育/电商等 |
| F26-03 | normal | 模板详情 | 步骤+依赖+参数 |
| F26-04 | normal | 模板参数展示 | 输入/输出定义 |
| F26-05 | boundary | 模板预览 | YAML 解析正确 |
| F26-06 | boundary | 模板搜索 | 关键词匹配 |
| F26-07 | error | YAML 解析错误 | 不崩溃+提示 |
| F26-08 | cross | Pipeline 意图匹配 | 自然语言模板推荐 |
| F26-09 | cross | 模板+行业联动 | 行业模板优先 |
| F26-10 | cross | 模板收藏 | 收藏+列表 |
### F-27 参数配置10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F27-01 | normal | 正常配置参数 | 保存成功 |
| F27-02 | normal | 必填项校验 | 空必填提示 |
| F27-03 | normal | 参数类型校验 | 数字/字符串/枚举 |
| F27-04 | boundary | 默认值填充 | 预填默认值 |
| F27-05 | boundary | 参数说明 | 每个参数有说明 |
| F27-06 | error | 配置保存失败 | 不丢原配置 |
| F27-07 | cross | 配置+预览 | 预览显示参数效果 |
| F27-08 | cross | 配置重置 | 恢复默认 |
| F27-09 | cross | 配置+验证 | 提交前验证 |
| F27-10 | cross | 配置导入导出 | JSON/YAML 导出+导入 |
### F-28 执行工作流10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F28-01 | normal | 正常执行 | DAG 排序+逐步执行+完成 |
| F28-02 | normal | DAG 排序正确 | 依赖关系满足 |
| F28-03 | normal | 并行步骤 | 无依赖步骤并行 |
| F28-04 | error | 步骤失败 | 失败步骤+后续处理 |
| F28-05 | error | 步骤超时 | 超时处理+可重试 |
| F28-06 | normal | 取消执行 | 取消+状态更新 |
| F28-07 | normal | 执行进度 | 实时进度展示 |
| F28-08 | normal | 执行结果 | 结果数据完整 |
| F28-09 | cross | 执行+Hand 触发 | 步骤触发 Hand |
| F28-10 | cross | 执行+记忆存储 | 结果存入记忆 |
### F-29 模型设置10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F29-01 | normal | 配置 API Key | 8 Provider 配置 |
| F29-02 | normal | 选择 Provider | 下拉选择 |
| F29-03 | normal | 测试连接 | 验证 Key 有效 |
| F29-04 | normal | 模型参数 | 温度/max_tokens |
| F29-05 | boundary | Provider | 同时配置多个 |
| F29-06 | normal | 配置持久化 | 重启后保留 |
| F29-07 | normal | 配置热重载 | 不需重启生效 |
| F29-08 | cross | 配置+降级 | Provider 不可用降级 |
| F29-09 | cross | 配置校验 | 无效 Key提示 |
| F29-10 | cross | 配置导入导出 | TOML 导出+导入 |
### F-30 工作区配置11 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F30-01 | normal | 基本配置 | 工作区路径等 |
| F30-02 | normal | 环境变量 | ${VAR} 插值 |
| F30-03 | normal | 数据目录 | 路径设置 |
| F30-04 | normal | 日志级别 | debug/info/warn/error |
| F30-05 | boundary | 配置文件路径 | 正确读写 |
| F30-06 | error | 配置写入失败 | 不丢原配置 |
| F30-07 | cross | TOML 格式 | 格式一致 |
| F30-08 | cross | 特殊字符 | 路径含空格/中文 |
| F30-09 | cross | 配置同步 | 多设备同步 |
| F30-10 | cross | 配置重置 | 恢复默认 |
| F30-11 | cross | 配置+环境变量插值 | ${VAR_NAME} 解析 |
### F-31 数据隐私10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F31-01 | normal | 清除对话历史 | 确认清除+统计归零 |
| F31-02 | normal | 导出数据 | JSON 格式+完整 |
| F31-03 | normal | 记忆管理 | 查看/删除/导出 |
| F31-04 | boundary | 删除确认 | 二次确认弹窗 |
| F31-05 | normal | 删除持久化验证 | SQLite/IndexedDB 数据清除 |
| F31-06 | normal | 导出格式 | 格式正确+可解析 |
| F31-07 | cross | 导出完整性 | 消息+记忆+配置完整 |
| F31-08 | cross | 清除+Agent 联动 | 清除指定 Agent 数据 |
| F31-09 | cross | 清除+记忆联动 | 清除对话+保留/清除记忆 |
| F31-10 | cross | 数据统计 | 清除后统计更新 |
### F-32 JWT 认证12 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F32-01 | normal | 获取 JWT | 登录token 存储 |
| F32-02 | normal | JWT 过期处理 | 自动刷新或提示重新登录 |
| F32-03 | normal | JWT 刷新 | token+ token 失效 |
| F32-04 | normal | pwv 失效机制 | 改密码 JWT 全部失效 |
| F32-05 | boundary | cookie 双通道 | Tauri keyring + HttpOnly cookie |
| F32-06 | normal | Keyring 存储 | Win DPAPI 存储 |
| F32-07 | normal | refresh token 单次使用 | 二次使用被拒 |
| F32-08 | normal | refresh token 撤销 | logoutDB 中标记 |
| F32-09 | boundary | 并发 JWT 验证 | 不竞态 |
| F32-10 | cross | JWT+角色权限 | Claims.role 正确 |
| F32-11 | cross | JWT+限流 | 超限返回 429 |
| F32-12 | cross | JWT+多设备 | 多设备 token 独立 |
### F-33 TOTP 2FA10 场景)
| ID | 类别 | 场景 | 验证点 |
|----|------|------|--------|
| F33-01 | normal | 设置 2FA | QR 码生成+密钥加密存储 |
| F33-02 | normal | QR 码生成 | 可扫描+格式正确 |
| F33-03 | normal | 验证码验证 | 正确 TOTP通过 |
| F33-04 | normal | 禁用 2FA | 需密码确认禁用 |
| F33-05 | boundary | 错误验证码 | 提示错误 |
| F33-06 | boundary | 过期验证码 | 提示过期 |
| F33-07 | cross | 2FA+登录流程 | 密码TOTP进入 |
| F33-08 | cross | 2FA+密码确认 | 禁用需密码 |
| F33-09 | cross | 2FA 密钥加密 | AES-256-GCM 加密 |
| F33-10 | cross | 2FA+多设备 | 各设备独立密钥 |
---
## 3 角色冒烟测试
### 角色 1新用户"小王"(首次使用)
| 步骤 | 操作 | 验证点 |
|------|------|--------|
| 1 | 打开应用看到冷启动引导 | 引导消息出现+4阶段流程 |
| 2 | 注册账号登录 | token 存储+进入简洁模式 |
| 3 | 第一次发消息"你好" | 流式响应正常 |
| 4 | 切换到专业模式 | 功能面板展示 |
| 5 | 创建新 Agent和它对话 | Agent 独立会话 |
| 6 | 设置>查看记忆 | 确认自动提取了偏好 |
| 7 | 第二天打开(模拟) | 跨会话记忆注入 |
| 8 | 触发一个 Hand | 审批流程正常 |
覆盖: F-17, F-18, F-23, F-01, F-02, F-06, F-14, F-04, F-11
### 角色 2医院行政"李主任"(管家模式)
| 步骤 | 操作 | 验证点 |
|------|------|--------|
| 1 | 登录→选择"医疗"行业 | 行业关键词加载 |
| 2 | "帮我整理本周会议纪要" | ButlerRouter 医疗匹配 |
| 3 | "最近排班总出问题" | 痛点提取触发 |
| 4 | 连续几天聊排班 | 痛点积累→方案建议 |
| 5 | "上个月讨论的排班方案" | 跨会话记忆检索 |
| 6 | 查看管家面板 | 洞察/方案/记忆展示正确 |
| 7 | 专业模式→选 Pipeline 模板 | 医疗模板推荐 |
| 8 | 执行 Pipeline | DAG 执行+结果 |
覆盖: F-01, F-02, F-23, F-24, F-25, F-14, F-15, F-26, F-28
### 角色 3Admin 运维"张工"(后台管理)
| 步骤 | 操作 | 验证点 |
|------|------|--------|
| 1 | Admin V2 登录 | Dashboard 统计正确 |
| 2 | 检查模型服务 | Provider+Key 状态 |
| 3 | 检查账号管理 | 用户列表+CRUD |
| 4 | 检查知识库 | CRUD+搜索+pgvector |
| 5 | 检查行业配置 | 4 内置行业 |
| 6 | 检查计费 | 订阅+用量+支付 |
| 7 | 检查角色权限 | RBAC 验证 |
| 8 | 切回桌面端 | Admin 操作已生效 |
覆盖: F-22, F-20, F-21, F-29, F-32, F-33
---
## 执行计划
| 阶段 | 时长 | 内容 |
|------|------|------|
| 0 | 15min | 环境检查PostgreSQL + SaaS + 桌面端 + 连通验证 |
| 1 | 2-3h | Batch 1 核心聊天52 场景) |
| 2 | 2-3h | Batch 2 Agent+认证72 场景) |
| 3 | 2-3h | Batch 3 Hands+记忆74 场景) |
| 4 | 2-3h | Batch 4 SaaS+管家64 场景) |
| 5 | 2-3h | Batch 5 Pipeline+配置+安全83 场景) |
| 6 | 2h | 复合转换测试(跨 Batch 交互) |
| 7 | 1.5h | 3 角色冒烟测试 |
| 8 | 30min | 报告整理+证据归档 |
**总计:~345 个测试场景**
每个场景执行流程:
1. 截图当前状态before
2. 执行操作click/type/wait
3. 等待响应wait_for + 超时保护)
4. 验证结果query_page + execute_js
5. 截图最终状态after
6. 记录结果PASS/FAIL/PARTIAL + 证据路径)
## 结果报告
输出:`docs/test-evidence/2026-04-XX/FEATURE_CHAIN_EXHAUSTIVE_TEST.md`
报告格式:
- 转换矩阵报告(状态 × 状态 网格)
- 每条链路 PASS/FAIL/PARTIAL 统计
- Bug 密度热力图(按状态)
- 截图证据目录(按场景 ID 命名)