Files
qihuaiflow/tests/evolution-v2-test-case-report.md
T
qyyfw 78ff261b5a 初始提交: Qihu-AIFlow v2.0.1 完整项目
- 前端 React+TypeScript (源码+构建产物)
- 后端 Python FastAPI
- 数据库迁移 001-015
- Docker部署配置
- 微信ClawBot API频道绑定
- 项目文档 README.md
2026-07-02 14:40:46 +08:00

450 lines
35 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.
# AI自进化第二版 (v2) - 测试用例报告
## 文档信息
| 项目 | 详情 |
|------|------|
| **测试对象** | AIFlow AI自进化模块 v2 迭代 |
| **测试阶段** | 第一阶段 - 测试用例生成 |
| **测试工程师** | QA Engineer |
| **文档日期** | 2026-05-30 |
| **基于文档** | PRD-self-evolution-v2.md |
| **基于代码** | evolution.py (348行), evolution_service.py (1220行), models.py (739-889行), EvolutionDashboard.tsx (1015行), EvolutionDashboard.css, ChatPage.tsx, api/index.ts |
---
## 1. 版本变更概览
### 1.1 PRD vs 实际代码实现对照
PRD v2 规划了 10 大功能、9 个新增 API端点、4 张新增表、5 个现有表新增字段。代码实现了其中大部分功能,但存在具体差异如下:
| PRD规划 | 代码实现状态 |
|----------|-------------|
| xSkill流水线自动调度 (P0) | ✅ 已实现 PipelineScheduler (service层, 54-232行) |
| Watcher线程管理 (P0) | ✅ 已实现 EvolutionWatcherManager 单例 (235-374行) |
| 技能回滚 (P0) | ✅ 已实现 rollback API + 前端UI (evolution.py:229, EvolutionDashboard.tsx:101-114) |
| 萌芽动画 (P1) | ✅ 已实现 baby-sprout/staging-breathe CSS动画 (EvolutionDashboard.css:1020-1580) |
| 时间线导出 (P1) | ✅ 已实现导出菜单+模拟导出 (EvolutionDashboard.tsx:370-383) |
| 画像分享卡片 (P1) | ✅ 已实现3主题卡片+分享动作 (EvolutionDashboard.tsx:572-691) |
| Skill加载提示标签 (P1) | ✅ 已实现 (ChatPage.tsx:710-740, chat.py:238-250) |
| 技能市场联动 (P2) | ✅ 已实现 publish_to_market + 前端发布UI |
| 团队共享进化 (P2) | ✅ 已实现 share_to_team + 前端共享API |
| 进化报告推送 (P2) | ✅ 已实现 EvolutionReport 模型 + generate_report + ReportsPanel 前端 |
### 1.2 API端点对比
PRD v2 规划新增9个端点:
| PRD规划端点 | 方法 | 实际代码路径 | 状态 |
|------------|------|-------------|------|
| `/skills/{name}/rollback/{version}` | POST | `/evolution/skills/{skill_name}/rollback/{version}` (evolution.py:229) | ✅ 已实现 |
| `/skills/{name}/versions` | GET | **不存在**: 仅有 `/skills/{skill_name}/history` (返回事件列表) | ❌ **缺失, GAP** |
| `/skills/{name}/publish` | POST | `/evolution/skills/{skill_name}/publish` (evolution.py:244) | ✅ 已实现 |
| `/reports/generate` | POST | **不存在**: generate_report() 仅在service层定义, 无API暴露 | ❌ **缺失, GAP** |
| `/reports` | GET | `/evolution/reports` (evolution.py:307) | ✅ 已实现 |
| `/reports/{id}` | GET | `/evolution/reports/{report_id}` (evolution.py:318) | ✅ 已实现 |
| `/watcher/status` | GET | `/evolution/watcher/status` (evolution.py:296) | ✅ 已实现 |
| `/watcher/restart` | POST | **不存在**: restart逻辑仅在 `/pipeline/trigger` 中内联调用 (evolution.py:291) | ❌ **缺失, GAP** |
| `/team/sync` | POST | **不存在**: 仅有 `/skills/{name}/share-to-team` (单个技能共享) | ❌ **缺失, GAP** |
**代码额外实现但PRD未要求**:
| 端点 | 方法 | 说明 |
|------|------|------|
| `/evolution/pipeline/status` | GET | 流水线状态查询 - PRD v2 5.2 中规划, 但用户测试范围未列 |
| `/evolution/pipeline/trigger` | POST | 手动触发流水线 - PRD v2 5.2 中规划, 但用户测试范围未列 |
| `/evolution/skills/{name}/share-to-team` | POST | 团队共享 - PRD 5.4 中规划, 替代 team/sync |
| `/evolution/admin/watchers` | GET | 管理员全平台watcher汇总 |
### 1.3 数据库变更对比
| PRD 规划表 | 表名 | 状态 |
|-----------|------|------|
| 现有表新增字段 | `evolution_trajectories.error_msg` | ✅ 模型已定义 (models.py:795) |
| 现有表新增字段 | `evolution_trajectories.retry_count` | ✅ 模型已定义 (models.py:796) |
| 现有表新增字段 | `evolution_trajectories.tasks_extracted` | ✅ 模型已定义 (models.py:797) |
| 现有表新增字段 | `messages.used_skills` | ✅ 模型已定义 (models.py:100) |
| 现有表新增字段 | `user_evolution_config.watcher_error` | ✅ 模型已定义 (models.py:749) |
| 新增表 | `skill_versions` | ✅ 模型已定义 (models.py:818-833), ❌ **数据库中不存在** |
| 新增表 | `evolution_reports` | ✅ 模型已定义 (models.py:836-850), ❌ **数据库中不存在** |
| 新增表 | `skill_publish_records` | ✅ 模型已定义 (models.py:853-871), ❌ **数据库中不存在** |
| 新增表 | `team_shared_skills` | ✅ 模型已定义 (models.py:874-888), ❌ **数据库中不存在** |
**严重问题**: 4张v2新增表在SQLAlchemy models中已定义,但实际MySQL数据库中未创建。这意味着:技能回滚需要 `skill_versions` 表、进化报告需要 `evolution_reports` 表、市场发布需要 `skill_publish_records` 表、团队共享需要 `team_shared_skills` 表。这些功能在表未创建的情况下将无法正常运行。
同样,现有表的5个新字段在模型层面已定义,但数据库层面未通过 `DESC` 验证确认存在(`DESC messages` 未显示 `used_skills`、`DESC evolution_trajectories` 未显示 `error_msg/retry_count/tasks_extracted`、`DESC user_evolution_config` 未显示 `watcher_error`)。
---
## 2. 测试范围与分类
### 2.1 测试分类维度
| 维度 | 说明 |
|------|------|
| **P0 核心引擎** | xSkill流水线调度、Watcher管理、技能回滚 |
| **P1 体验增强** | 萌芽动画、时间线导出、画像分享、Skill标签 |
| **P2 业务联动** | 技能市场联动、进化报告推送 |
| **API端点** | 9个新增API + 流水线/团队共享API |
| **数据库** | 4张新表 + 5个新字段 |
| **前端交互** | 6大前端功能模块 |
### 2.2 统计摘要
| 类别 | 数量 |
|------|------|
| 功能模块 | 10 |
| API端点 | 15(含PRD规划的9个 + 代码额外实现的6个) |
| P0测试用例 | 26 |
| P1测试用例 | 28 |
| P2测试用例 | 21 |
| 数据库测试用例 | 7 |
| 数据隔离测试用例 | 6 |
| **测试用例总计** | **88** |
| PRD未覆盖代码功能 (GAP) | 9 |
| 代码未实现PRD需求 (缺失) | 4 |
---
## 3. P0 核心引擎类 - 测试用例
### 3.1 xSkill流水线自动调度 (PipelineScheduler)
#### API: GET /evolution/pipeline/status
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-001 | P0 | 获取流水线状态 - 正常运行 | 用户已登录, watcher已启动 | GET /app/api/evolution/pipeline/status | 返回200, code=0, data包含scheduler_running/watcher_status/pipeline_status/discovered_count/done_count/total_skills/total_trajectories |
| TC-EVO-V2-P0-002 | P0 | 获取流水线状态 - 未启动 | 用户已登录, watcher未启动 | GET /app/api/evolution/pipeline/status | 返回200, code=0, scheduler_running=false, watcher_status=unknown/stopped |
| TC-EVO-V2-P0-003 | P1 | 未登录访问流水线状态 | 无认证token | GET /app/api/evolution/pipeline/status | 返回401 |
| TC-EVO-V2-P0-004 | P1 | 流水线状态数据隔离 | user_a登录查看 | GET /app/api/evolution/pipeline/status | 返回仅user_a的数据,不包含其他用户的数据 |
#### API: POST /evolution/pipeline/trigger
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-005 | P0 | 手动触发流水线 | 用户已登录 | POST /app/api/evolution/pipeline/trigger | 返回200, code=0, message="流水线已触发", watcher重新启动 |
| TC-EVO-V2-P0-006 | P1 | 未登录触发流水线 | 无认证token | POST /app/api/evolution/pipeline/trigger | 返回401 |
#### PipelineScheduler 功能逻辑
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-007 | P0 | 轨迹自动状态流转 discovered->splitting->split_done->indexed->clustering->done | 创建一条status=discovered的轨迹, watcher运行中 | 等待PipelineScheduler扫描处理 | 轨迹依次经历6个状态, 最终status=done, processed_at非空 |
| TC-EVO-V2-P0-008 | P0 | AtomTask拆分模拟 - tasks_extracted更新 | 轨迹处理中 | 查看轨迹tasks_extracted字段 | tasks_extracted值为2-5(模拟生成的atom数量) |
| TC-EVO-V2-P0-009 | P0 | 轨迹处理创建SkillTrajectoryLink | 轨迹处理完成 | 查询skill_trajectory_links表 | 为每个atom创建了关联记录, skill_name为__pending__或真实技能名 |
| TC-EVO-V2-P0-010 | P0 | 新轨迹归类到已有技能 | 用户已有至少1个技能 | 提交新轨迹并等待处理 | 轨迹的SkillTrajectoryLink指向已有技能, 技能use_count+1 |
| TC-EVO-V2-P0-011 | P0 | 新轨迹创建新baby技能 | 用户无任何技能 | 提交新轨迹并等待处理 | 创建新baby技能new_skill_XXXXXXX, state=baby, version=1 |
| TC-EVO-V2-P0-012 | P0 | 候选轨迹>=3自动baby->staging晋升 | 某baby技能关联轨迹>=3 | PipelineScheduler处理更多轨迹 | 技能state自动从baby变为staging, 记录promoted事件 |
| TC-EVO-V2-P0-013 | P0 | 轨迹处理失败 - error状态 | 模拟处理异常 (数据库连接中断等) | 轨迹处理失败 | 轨迹status=error, error_msg记录失败原因, retry_count递增 |
| TC-EVO-V2-P0-014 | P1 | 轨迹处理重试机制 | 轨迹之前失败过(retry_count<3) | PipelineScheduler再次扫描 | 尝试重新处理该轨迹 |
| TC-EVO-V2-P0-015 | P1 | PipelineScheduler停止信号 | scheduler正在运行 | 调用scheduler.stop() | _stop被设置, _run_loop退出, 线程终止 |
| TC-EVO-V2-P0-016 | P1 | PipelineScheduler扫描间隔 | scheduler运行 | 观察扫描日志间隔 | 扫描间隔为poll_interval(默认30s) |
### 3.2 Watcher线程管理 (EvolutionWatcherManager)
#### API: GET /evolution/watcher/status
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-017 | P0 | 获取Watcher状态 | 用户已登录, watcher已启动 | GET /app/api/evolution/watcher/status | 返回200, data包含watcher_status/pipeline_status/pipeline_processed/scheduler_running/skill_count/trajectory_count |
| TC-EVO-V2-P0-018 | P1 | Watcher状态数据隔离 | user_a和user_b分别查询 | 分别GET /app/api/evolution/watcher/status | 返回各自的数据, 互不包含 |
| TC-EVO-V2-P0-019 | P2 | 管理员查看全平台watcher | 管理员登录 | GET /app/api/evolution/admin/watchers | 返回200, data包含所有在运行scheduler的用户ID和运行状态 |
#### WatcherManager 功能逻辑
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-020 | P0 | 启动用户进化引擎 (start_user_evolution) | 新用户无scheduler | 调用WatcherManager.start_user_evolution() | scheduler被创建并启动, user_evolution_config表watcher_status=running, pipeline_status=running |
| TC-EVO-V2-P0-021 | P0 | 重复启动已运行的进化引擎 | 用户engin已运行 | 再次调用start | 返回False, 提示已在运行 |
| TC-EVO-V2-P0-022 | P0 | 停止用户进化引擎 (stop_user_evolution) | 用户engin运行中 | 调用WatcherManager.stop_user_evolution() | scheduler线程停止, 从_schedulers移除, config表更新为stopped/idle |
| TC-EVO-V2-P0-023 | P0 | 重启用户进化引擎 (restart_user_evolution) | 用户已运行 | 调用restart → 通过POST /evolution/pipeline/trigger触发 | scheduler先停止再启动, pipeline_status重新变为running |
| TC-EVO-V2-P0-024 | P1 | 达到最大scheduler限制 | 已有100个scheduler运行 | 新用户尝试启动 | 返回False, 提示达到数量限制 |
| TC-EVO-V2-P0-025 | P1 | 优雅关闭所有scheduler | 多个scheduler运行中 | 调用shutdown_all() | 所有scheduler依次停止, 日志记录关闭过程 |
| TC-EVO-V2-P0-026 | P1 | watcher_error 字段写入 | 更新用户进化配置失败场景 | 触发配置更新失败 | user_evolution_config.watcher_error 记录异常信息 |
### 3.3 技能回滚 (Skill Rollback)
#### API: POST /evolution/skills/{skill_name}/rollback/{version}
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-027 | P0 | 回滚技能到指定版本 | skill已存在, skill_versions表有目标版本记录, version=3 | POST /app/api/evolution/skills/{name}/rollback/1 | 返回200, code=0, data包含回滚后的技能信息, version变为4 (3+1) |
| TC-EVO-V2-P0-028 | P0 | 回滚后SKILL.md内容恢复 | 同上, skill_md_path存在 | POST rollback | SKILL.md文件被目标版本内容覆盖, 回滚前内容作为快照存入skill_versions |
| TC-EVO-V2-P0-029 | P0 | 回滚后事件记录 | 回滚操作完成 | 查询evolution_events表 | 记录event_type="rolled_back", version_before=回滚前, version_after=回滚后, description含回滚版本信息 |
| TC-EVO-V2-P0-030 | P0 | 技能不存在 | skill不存在 | POST /app/api/evolution/skills/nonexistent_skill/rollback/1 | 返回404, "技能或版本不存在" |
| TC-EVO-V2-P0-031 | P0 | 目标版本不存在 | skill存在但目标版本无记录 | POST rollback to non-existing version | 返回404, "技能或版本不存在" |
| TC-EVO-V2-P0-032 | P1 | 未登录回滚 | 无认证 | POST rollback | 返回401 |
#### 前端: VersionHistoryModal + 回滚确认
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-033 | P0 | 版本历史弹窗打开 | 技能详情弹窗中 | 点击「版本历史」按钮 | 弹出版本历史弹窗, 显示事件列表(时间线格式), 每条含版本号/事件类型/时间/描述 |
| TC-EVO-V2-P0-034 | P0 | 版本历史加载中状态 | 点击版本历史 | API请求中 | 显示"加载中..."文字 |
| TC-EVO-V2-P0-035 | P0 | 版本历史空状态 | skill无历史事件 | 打开版本历史 | 显示"暂无版本历史" |
| TC-EVO-V2-P0-036 | P0 | 当前版本标识 | 多个版本存在 | 查看版本历史 | 当前版本行显示"当前"标签, 非当前版本行才显示"回滚到此版本"按钮 |
| TC-EVO-V2-P0-037 | P0 | 回滚确认弹窗 | 点击非当前版本的「回滚到此版本」按钮 | 弹出确认弹窗 | 弹窗标题「确认回滚?」, 显示目标版本和当前版本号对比 |
| TC-EVO-V2-P0-038 | P0 | 确认回滚操作 | 回滚确认弹窗打开 | 点击「确认回滚」按钮 | 调用API, 成功后显示toast提示, 关闭弹窗 |
| TC-EVO-V2-P0-039 | P0 | 取消回滚 | 回滚确认弹窗打开 | 点击「取消」按钮 | 关闭确认弹窗, 不调用API |
| TC-EVO-V2-P0-040 | P1 | 回滚失败toast | API返回错误 | 确认回滚 | 显示红色toast "回滚失败: {错误原因}" |
---
## 4. P1 体验增强类 - 测试用例
### 4.1 萌芽动画 (Baby/Staging Animations)
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P1-001 | P1 | baby技能萌芽脉冲动画 | 存在state=baby的技能, 动画开关=ON | 查看技能图谱面板 | baby技能节点周期性缩放脉冲 scale(1.0→1.15→1.0) 周期2s, 粉色光晕淡入淡出 |
| TC-EVO-V2-P1-002 | P1 | staging技能呼吸动画 | 存在state=staging的技能, 动画开关=ON | 查看技能图谱面板 | staging技能节点呼吸动画 scale(1.0→1.08→1.0) 周期3s, 橙色脉冲 |
| TC-EVO-V2-P1-003 | P1 | 动画被关闭 | 动画开关=OFF | 查看技能图谱面板 | baby/staging技能节点静态显示, 无CSS动画效果 |
| TC-EVO-V2-P1-004 | P1 | 动画开关开关切换 | 默认动画开启 | 点击「动画效果」开关 | 动画立即开/关, CSS class变化 |
| TC-EVO-V2-P1-005 | P1 | 动画偏好持久化 | 关闭动画 | 刷新页面重新加载驾驶舱 | 动画仍保持关闭状态 (localStorage evo_anim_enabled=false) |
| TC-EVO-V2-P1-006 | P2 | 无baby/staging技能时 | 所有技能均为main/frozen | 查看技能图谱面板 | 所有节点静态显示, 无动画播放 |
| TC-EVO-V2-P1-007 | P2 | main/frozen技能无动画 | 各种状态的技能混合 | 检查main/frozen节点 | main和frozen技能节点无CSS animation |
### 4.2 时间线导出 (Timeline Export)
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P1-008 | P1 | 导出按钮显示 | 进化时间线面板激活 | 查看面板右上角 | 显示「导出」按钮 |
| TC-EVO-V2-P1-009 | P1 | 导出下拉菜单 | 点击「导出」按钮 | 展开下拉菜单 | 显示两项: 「导出为 PNG」和「导出为 PDF」 |
| TC-EVO-V2-P1-010 | P1 | PNG导出触发 | 点击「导出为 PNG」 | 触发导出 | 显示"导出中..."按钮状态, 完成后显示toast: "时间线已导出为 PNG 格式: AI进化时间线_{用户名}_{日期}.png" |
| TC-EVO-V2-P1-011 | P1 | PDF导出触发 | 点击「导出为 PDF」 | 触发导出 | 同上, 格式为PDF |
| TC-EVO-V2-P1-012 | P1 | 时间范围选择器 | 时间线面板 | 使用下拉菜单选择 | 有3个选项: 全部时间 / 最近30天 / 最近7天, 选择后时间线自动筛选 |
| TC-EVO-V2-P1-013 | P1 | 导出遵循当前筛选 | 设置时间范围「最近7天」+ 事件类型「promoted」 | 点击导出 | 导出内容仅包含最近7天的promoted事件 (所见即所得) |
| TC-EVO-V2-P1-014 | P2 | 导出时空时间线 | 筛选后无事件 | 点击导出 | toast仍显示成功 (导出空白时间线) |
| TC-EVO-V2-P1-015 | P2 | 导出按钮disabled状态 | 正在导出中 | 查看导出按钮 | 按钮显示"导出中..."且disabled |
### 4.3 画像分享卡片 (Profile Share Card)
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P1-016 | P1 | 分享按钮存在 | AI能力画像面板激活 | 查看面板右上角 | 显示「分享画像」按钮 (share图标) |
| TC-EVO-V2-P1-017 | P1 | 分享弹窗打开 | 点击「分享画像」 | 弹出分享弹窗 | 弹窗标题「AI能力画像分享」, 显示卡片预览+主题切换+操作按钮 |
| TC-EVO-V2-P1-018 | P1 | 3种主题切换 | 分享弹窗内 | 依次点击「深空蓝」「极光绿」「暖阳橙」主题 | 卡片背景色和各元素配色切换为对应主题 |
| TC-EVO-V2-P1-019 | P1 | 卡片内容完整性 | 分享卡片预览 | 查看卡片 | 包含: 平台Logo + 标题「我的AI进化画像」 + 等级环 + 维度条 + 标签云(最多6个) + 日期水印「Qihu-AIFlow」 |
| TC-EVO-V2-P1-020 | P1 | 保存到相册 | 分享弹窗 | 点击「保存到相册」按钮 | 关闭弹窗, toast显示"画像卡片已保存到相册(模拟)" |
| TC-EVO-V2-P1-021 | P1 | 复制图片 | 分享弹窗 | 点击「复制图片」按钮 | 关闭弹窗, toast显示"画像卡片已复制图片(模拟)" |
| TC-EVO-V2-P1-022 | P2 | 关闭分享弹窗 | 分享弹窗打开 | 点击背景或关闭按钮 | 弹窗关闭 |
| TC-EVO-V2-P1-023 | P2 | 隐私保护验证 | 分享卡片预览 | 检查卡片内容 | 卡片仅包含聚合数据(等级/维度/标签), 不包含具体技能名称或对话内容 |
### 4.4 Skill加载提示标签 (Used Skills Tags)
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P1-024 | P1 | 标签显示 | 用户有main状态技能, AI对话回复 | 发送消息等待AI回复 | AI回复气泡下方显示标签, 格式: 图标 + "使用了专属技能:{技能名}" |
| TC-EVO-V2-P1-025 | P1 | 多技能标签展示(<=3个) | AI使用了2-3个技能 | 查看回复下方 | 2-3个标签横向排列 |
| TC-EVO-V2-P1-026 | P1 | 多技能标签展示(>3个) | AI使用了4+个技能 | 查看回复下方 | 显示3个技能标签 + "+N" 折叠标签 |
| TC-EVO-V2-P1-027 | P1 | 标签点击跳转 | 消息下方有技能标签 | 点击技能标签 | 跳转到 #/evolution?skill={技能名} |
| TC-EVO-V2-P1-028 | P1 | 无技能时不显示标签 | 用户无main状态技能, 发送消息 | 查看AI回复 | AI回复下方无标签区域 |
| TC-EVO-V2-P1-029 | P1 | 聊天API返回used_skills字段 | 发送消息 | 检查API响应 | assistant_message.used_skills 存在, 为字符串数组 |
| TC-EVO-V2-P1-030 | P1 | 技能使用后use_count更新 | 某技能被used_skills触发 | 查询该技能详情 | use_count+1, last_used_at更新为当前时间 |
| TC-EVO-V2-P1-031 | P2 | 标签样式 | 有技能标签的消息 | 查看UI | 标签为圆角样式, 左侧图标, 底色半透明 |
---
## 5. P2 业务联动类 - 测试用例
### 5.1 技能市场联动 (Publish to Market)
#### API: POST /evolution/skills/{skill_name}/publish
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-001 | P2 | 发布main技能到市场 | skill state=main, 未发布过 | POST /app/api/evolution/skills/{name}/publish, body: {price: 0, market_description: "测试发布"} | 返回200, code=0, data含market_app_id, price, status="published" |
| TC-EVO-V2-P2-002 | P2 | 非main状态发布失败 | skill state=baby/staging | POST publish | 返回404/error, 提示只有main状态技能可发布 |
| TC-EVO-V2-P2-003 | P2 | 重复发布检测 | skill已发布过 | POST publish | 返回error, "该技能已发布到市场,不能重复发布" |
| TC-EVO-V2-P2-004 | P2 | 发布后在market_apps表创建记录 | 发布成功 | 查询market_apps表 | 创建一条type=skill, source=user的记录, name="{技能名}(进化)" |
| TC-EVO-V2-P2-005 | P2 | 发布后在skill_publish_records表创建记录 | 发布成功 | 查询skill_publish_records表 | 创建一条status=published的记录 |
| TC-EVO-V2-P2-006 | P2 | 发布后事件记录 | 发布成功 | 查询evolution_events | 记录event_type="published" |
| TC-EVO-V2-P2-007 | P2 | 技能不存在 | skill不存在 | POST publish | 返回404 |
| TC-EVO-V2-P2-008 | P2 | 未登录发布 | 无认证 | POST publish | 返回401 |
#### 前端: 发布按钮+发布表单
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-009 | P2 | main技能显示发布按钮 | 技能详情弹窗, skill.state=main | 查看操作按钮区域 | 显示「发布到市场」按钮(金色边框) |
| TC-EVO-V2-P2-010 | P2 | 非main技能不显示发布按钮 | 技能详情弹窗, skill.state=baby/staging/frozen | 查看操作按钮区域 | 不显示「发布到市场」按钮 |
| TC-EVO-V2-P2-011 | P2 | 发布表单弹窗 | 点击「发布到市场」 | 弹窗显示 | 标题「发布到应用市场」, 显示技能名, 包含价格输入框(默认为0)和市场描述文本框 |
| TC-EVO-V2-P2-012 | P2 | 发布表单提交 | 设置价格和市场描述 | 点击「确认发布」 | 调用API, 成功后显示toast "技能已发布到应用市场" |
| TC-EVO-V2-P2-013 | P2 | 发布失败toast | API返回错误 | 提交发布 | 显示toast "发布失败: {错误原因}" |
| TC-EVO-V2-P2-014 | P2 | 取消发布 | 发布弹窗 | 点击「取消」 | 关闭弹窗 |
### 5.2 团队共享进化 (Share to Team)
#### API: POST /evolution/skills/{skill_name}/share-to-team
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-015 | P2 | 分享技能到团队 | 技能存在, 用户是team owner | POST /app/api/evolution/skills/{name}/share-to-team, body: {team_id: "valid_team_id"} | 返回200, code=0, data包含shared_id, skill_name, team_name |
| TC-EVO-V2-P2-016 | P2 | 团队不存在 | team_id无效 | POST share-to-team | 返回error "团队不存在" |
| TC-EVO-V2-P2-017 | P2 | 用户不属于该团队 | 用户不是team owner | POST share-to-team | 返回error "用户不属于该团队" |
| TC-EVO-V2-P2-018 | P2 | 重复分享 | 技能已分享至该团队 | POST share-to-team | 返回error "该技能已分享至此团队" |
| TC-EVO-V2-P2-019 | P2 | 技能不存在 | 技能不存在 | POST share-to-team | 返回error "技能不存在或不属于当前用户" |
| TC-EVO-V2-P2-020 | P2 | 分享后创建team_shared_skills记录 | 分享成功 | 查询team_shared_skills表 | 创建一条记录, 含team_id, skill_id, shared_by, is_public=true |
### 5.3 进化报告 (Evolution Reports)
#### API: GET /evolution/reports
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-021 | P2 | 获取报告列表 | 用户有至少1条报告 | GET /app/api/evolution/reports | 返回200, code=0, data为报告列表(按时间倒序), 每项含id, report_type, period_start, period_end, created_at |
| TC-EVO-V2-P2-022 | P2 | 按类型过滤报告 | 用户有weekly和monthly报告 | GET /app/api/evolution/reports?report_type=weekly | 仅返回weekly类型报告 |
| TC-EVO-V2-P2-023 | P2 | 空报告列表 | 用户无报告 | GET /app/api/evolution/reports | 返回空数组 [] |
#### API: GET /evolution/reports/{report_id}
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-024 | P2 | 获取报告详情 | 报告存在 | GET /app/api/evolution/reports/{id} | 返回200, data含report_data(JSON)包含summary/new_skills/upgrades/top_skills/dimensions |
| TC-EVO-V2-P2-025 | P2 | 报告不存在 | report_id无效 | GET /app/api/evolution/reports/nonexistent_id | 返回404, "报告不存在" |
| TC-EVO-V2-P2-026 | P2 | 数据隔离 | user_a查询user_b的报告 | GET /app/api/evolution/reports/{user_b_report_id} | 返回404或空 (不能看到其他用户报告) |
#### Service: generate_report
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-027 | P2 | 生成周报 (weekly) | 用户有技能/轨迹/事件 | 调用EvolutionService.generate_report("weekly") | 创建evolution_reports记录, 含period_start=7天前, 统计新增技能/升级/调用次数/等级变化 |
| TC-EVO-V2-P2-028 | P2 | 生成月报 (monthly) | 同上 | 调用generate_report("monthly") | 同上但period_start=30天前 |
| TC-EVO-V2-P2-029 | P2 | 报告生成后发送通知 | 生成报告成功 | 查询notifications表 | 创建一条type="evolution_report"的通知 |
| TC-EVO-V2-P2-030 | P2 | 不支持的报告类型 | - | 调用generate_report("daily") | 返回error "不支持的报告类型: daily" |
#### 前端: ReportsPanel
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-031 | P2 | 报告列表展示 | 驾驶舱切换到「进化报告」面板 | 进入面板 | 显示报告卡片列表, 每张卡片含报告类型图标+标题+时间段 |
| TC-EVO-V2-P2-032 | P2 | 报告空列表状态 | 无报告 | 进入「进化报告」面板 | 显示"暂无进化报告。系统将在每周一自动生成周报。" |
| TC-EVO-V2-P2-033 | P2 | 点击查看报告详情 | 报告列表有数据 | 点击某条报告 | 弹出报告详情弹窗, 显示概览(新增技能数/技能升级数/总调用次数) + TOP5最活跃技能 |
| TC-EVO-V2-P2-034 | P2 | 关闭报告详情 | 报告详情弹窗 | 点击背景或关闭按钮 | 返回报告列表 |
| TC-EVO-V2-P2-035 | P2 | 报告详情加载中 | 点击报告卡片 | API请求中 | 报告列表页正常显示, 切换到详情时的loading由弹窗内处理 |
---
## 6. 数据库变更 - 测试用例
### 6.1 新增表验证
| TC-ID | 优先级 | 测试场景 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|
| TC-EVO-V2-DB-001 | P0 | skill_versions表结构 | DESC aiflow.skill_versions | 表存在, 字段含: id, user_id, skill_name, version, skill_md_content(LONGTEXT), git_commit_sha, description, created_at |
| TC-EVO-V2-DB-002 | P0 | evolution_reports表结构 | DESC aiflow.evolution_reports | 表存在, 字段含: id, user_id, report_type, period_start, period_end, report_data(JSON), created_at |
| TC-EVO-V2-DB-003 | P0 | skill_publish_records表结构 | DESC aiflow.skill_publish_records | 表存在, 字段含: id, skill_id, skill_name, user_id, market_app_id, price, market_description, status, published_at, created_at |
| TC-EVO-V2-DB-004 | P0 | team_shared_skills表结构 | DESC aiflow.team_shared_skills | 表存在, 字段含: id, team_id, skill_id, skill_name, shared_by, shared_by_name, is_public, created_at + uk_tss_team_skill唯一约束 |
### 6.2 现有表新增字段验证
| TC-ID | 优先级 | 测试场景 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|
| TC-EVO-V2-DB-005 | P0 | evolution_trajectories新字段 | DESC aiflow.evolution_trajectories | error_msg VARCHAR(500), retry_count INT DEFAULT 0, tasks_extracted INT DEFAULT 0 |
| TC-EVO-V2-DB-006 | P0 | messages.used_skills字段 | DESC aiflow.messages | used_skills JSON 字段存在 |
| TC-EVO-V2-DB-007 | P0 | user_evolution_config.watcher_error | DESC aiflow.user_evolution_config | watcher_error VARCHAR(500) 字段存在 |
---
## 7. 数据隔离 - 测试用例
| TC-ID | 优先级 | 测试场景 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|
| TC-EVO-V2-ISO-001 | P0 | 回滚操作数据隔离 | user_a对user_b的技能发起rollback | 返回404 (用户只能操作自己的技能) |
| TC-EVO-V2-ISO-002 | P0 | 流水线状态数据隔离 | user_a查询流水线状态 | 仅返回user_a的discovered/done/total数据 |
| TC-EVO-V2-ISO-003 | P0 | 发布操作数据隔离 | user_a对user_b的技能发起publish | 返回404 |
| TC-EVO-V2-ISO-004 | P0 | 报告数据隔离 | user_a查询报告 | 仅返回user_a的报告, 不含其他用户 |
| TC-EVO-V2-ISO-005 | P0 | 团队共享数据隔离 | user_a查询user_b团队的共享技能 | 非团队成员不可见 (由team_shared_skills关联team表约束) |
| TC-EVO-V2-ISO-006 | P1 | Watcher状态数据隔离 | user_a查询watcher状态 | 仅返回user_a的watcher/scheduler/skill_count |
---
## 8. PRD未覆盖的代码功能 (GAP清单)
以下功能在代码中已实现,但PRD v2文档中未覆盖或差异较大:
| GAP编号 | 类型 | 描述 | 严重程度 | 代码位置 |
|---------|------|------|----------|----------|
| GAP-V2-01 | API差异 | PRD规划 `POST /reports/generate` 但未实现API暴露, generate_report()仅在service层定义无路由 | 高 | evolution_service.py:963-1063 |
| GAP-V2-02 | API差异 | PRD规划 `GET /skills/{name}/versions` (版本列表) 未实现, 仅有 `/skills/{name}/history` (事件列表) 复用 | 中 | evolution.py:124-133 |
| GAP-V2-03 | API差异 | PRD规划 `POST /watcher/restart` 独立端点未实现, restart逻辑内联在pipeline/trigger中 | 中 | evolution.py:284-293 |
| GAP-V2-04 | API差异 | PRD规划 `POST /team/sync` (批量团队同步)未实现, 仅有单个技能share-to-team | 中 | evolution.py:259-271 |
| GAP-V2-05 | 前端差异 | 时间线导出为模拟实现 (setTimeout模拟), 未集成html2canvas/jsPDF库实现真实导出 | 高 | EvolutionDashboard.tsx:370-383 |
| GAP-V2-06 | 前端差异 | 画像分享卡片为模拟实现 (toast显示"模拟"), 未集成html2canvas实现真实截图 | 高 | EvolutionDashboard.tsx:582-587 |
| GAP-V2-07 | 数据库差异 | 4张v2新表在models中定义但数据库未创建 | 致命 | models.py:818-888; MySQL confirmed missing |
| GAP-V2-08 | 数据库差异 | 5个现有表新字段在models中定义但数据库未确认存在 | 致命 | models.py:795-797,100,749 |
| GAP-V2-09 | API差异 | PRD未规划但代码实现 `GET /pipeline/status` 和 `POST /pipeline/trigger` 两个流水线端点 - extra code | 信息 | evolution.py:274-293 |
---
## 9. 代码中实现但PRD未覆盖的功能模块
| 编号 | 功能 | 代码位置 | 说明 |
|------|------|----------|------|
| EXTRA-V2-01 | PipelineScheduler 零技能冷启动处理 | evolution_service.py:168-190 | 当用户无任何技能时, 自动创建new_skill_XXXXXXX baby技能 |
| EXTRA-V2-02 | PipelineScheduler promoter 候选>=3自晋升 | evolution_service.py:194-218 | 关联轨迹>=3自动 baby→staging, 记录promoted事件 |
| EXTRA-V2-03 | PipelineScheduler pipeline_processed计数 | evolution_service.py:224-230 | 轨迹处理完成后更新user_evolution_config.pipeline_processed |
---
## 10. 功能优先级分布
| 优先级 | 测试用例数 | 占比 |
|--------|----------|------|
| P0 | 26 | 29.5% |
| P1 | 28 | 31.8% |
| P2 | 21 | 23.9% |
| DB | 7 | 8.0% |
| ISO | 6 | 6.8% |
| **总计** | **88** | **100%** |
---
## 11. 风险与建议
### 11.1 致命问题(阻塞测试)
**1. 数据库表未创建**(GAP-V2-07、GAP-V2-08)
4张v2新增表 (`skill_versions`, `evolution_reports`, `skill_publish_records`, `team_shared_skills`) 在SQLAlchemy models中已定义但在MySQL数据库中不存在。此外 `evolution_trajectories` 的 `error_msg`/`retry_count`/`tasks_extracted`、`messages` 的 `used_skills`、`user_evolution_config` 的 `watcher_error` 字段在数据库中也可能不存在。
**影响范围**: 技能回滚、进化报告、市场发布、团队共享功能将全部失败。PipelineScheduler的error_msg/retry_count写入也会失败。
**建议**: 需开发工程师执行数据库迁移(创建新表和新字段),然后再进入API测试阶段。
### 11.2 高风险问题
**2. 前端导出/分享为模拟实现**(GAP-V2-05、GAP-V2-06)
时间线PNG/PDF导出和画像分享卡片生成均使用`setTimeout`模拟,未集成`html2canvas`/`jsPDF`库。这意味着这两个功能目前只是UI展示,用户无法真正获得导出文件。
**3. 报告生成API缺失**(GAP-V2-01)
`generate_report()` 在service层实现了完整逻辑,但没有对应的API路由端点,前端无法主动触发报告生成。目前只能依赖外部定时任务触发。
### 11.3 中风险问题
**4. 几个PRD规划的端点缺失**(GAP-V2-02, GAP-V2-03, GAP-V2-04)
- `GET /skills/{name}/versions` - 版本列表独立端点
- `POST /watcher/restart` - 独立restart端点
- `POST /team/sync` - 批量团队同步
其中技能版本列表功能有近似的history端点替代但语义不完全一致(history返回事件列表而非版本列表);watcher重启功能有pipeline/trigger替代;团队同步仅有单个技能共享。
---
## 12. 结论
AI自进化 v2 代码实现基本覆盖了PRD v2 规划的10大功能中的核心逻辑,23个API端点中有19个已实现(含PRD未明确规划的pipeline和团队共享端点)。前端6大交互体验功能全部有实现。**当前阻塞测试的关键问题是数据库表未创建**,建议优先修复此项后进入下一测试阶段。
---
> **文档状态**: 已定稿
> **创建日期**: 2026-05-30
> **测试用例总计**: 88 条 (P0: 26, P1: 28, P2: 21, DB: 7, ISO: 6)
> **发现GAP**: 9 项
> **发现PRD未覆盖代码功能**: 3 项