Files
zclaw_openfang/docs/superpowers/plans/2026-04-05-pre-launch-functional-audit.md
iven 0a3ba2fad4
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
docs: add pre-launch functional audit test execution plan (T1-T12, 5 chunks, 112 TCs)
2026-04-05 17:53:39 +08:00

68 KiB
Raw Blame History

ZCLAW 上线前功能审计 — 测试执行计划

For agentic workers: REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 系统性验证 ZCLAW 全部 12 个功能模块T1-T12发现并修复所有 P0/P1 缺陷,达到上线标准。

Architecture: 基于 V12 模块化审计框架12 模块按风险排序HIGH→MEDIUM→LOW分 4 阶段执行。测试工具Tauri 端用 tauri-mcpRust 用 cargo testAdmin 用 Playwright + vitestSaaS API 用 HTTP + cargo test。

Tech Stack: Tauri 2.x + React 19 + Zustand + Rust Workspace (10 crates) + Axum + PostgreSQL + tauri-mcp

Spec: docs/superpowers/specs/2026-04-05-pre-launch-functional-audit-design.md

⚠️ 执行注意: 计划中的 execute_js 代码块使用 window.__TAURI_INTERNALS__.invoke() 调用 Tauri 命令。V12 审计后代码已发生变更,部分命令名称/参数可能已更新。执行前必须

  1. 验证每个 Tauri 命令名是否存在于 desktop/src-tauri/src/lib.rsinvoke_handler 注册列表中
  2. 验证参数签名是否匹配 Rust 函数定义
  3. V12 审计发现的部分问题(如 M4-01 双数据库、M4-02 反思 LLM可能已在后续提交中修复测试时应以实际代码为准

文件结构

测试结果输出

docs/test-results/
├── TEST_PLAN.md                    # 本文件
├── DEFECT_LIST.md                  # 缺陷汇总清单
├── RELEASE_READINESS.md            # 上线评估
├── baseline/                       # 基线测试结果
│   ├── cargo-test.txt
│   ├── desktop-vitest.txt
│   └── admin-vitest.txt
├── T1-hands/                       # 每个 T 模块一个目录
│   ├── REPORT.md
│   └── screenshots/
├── T2-intelligence/
├── T3-agent/
├── ... (T3-T12 同理)
└── T12-e2e/

V12 审计报告(测试基线)

docs/features/audit-v12/
├── M1-intelligent-chat.md          # T8 (91/100)
├── M2-agent-clones.md              # T3 (67/100)
├── M3-hands-system.md              # T1 (58/100) ⚠️ 最高风险
├── M4-intelligence-layer.md        # T2 (61/100) ⚠️ 含 P0
├── M5-skill-ecosystem.md           # T7 (85/100)
├── M6-pipeline-workflow.md         # T5 (72/100)
├── M7-saas-desktop.md              # T6 (85/100)
├── M8-admin-v2.md                  # T9 (82/100)
├── M9-communication-security.md    # T10 (86/100)
└── M11-classroom.md                # T4 (70/100)

关键源码文件

# Hands (T1)
desktop/src/store/handStore.ts
desktop/src/store/browserHandStore.ts
desktop/src/lib/kernel-hands.ts
desktop/src/lib/browser-client.ts
desktop/src/lib/autonomy-manager.ts
desktop/src/components/Automation/
desktop/src-tauri/src/kernel_commands/hand.rs
desktop/src-tauri/src/kernel_commands/approval.rs
crates/zclaw-hands/src/hands/ (9 .rs)
crates/zclaw-kernel/src/kernel/hands.rs
crates/zclaw-kernel/src/kernel/approvals.rs
hands/*.HAND.toml (9 配置)

# Intelligence (T2)
desktop/src/store/memoryGraphStore.ts
desktop/src/lib/intelligence-client/ (memory/identity/reflection/heartbeat)
desktop/src-tauri/src/intelligence/ (memory/identity/reflection/heartbeat/compactor.rs)
crates/zclaw-growth/src/
crates/zclaw-runtime/src/middleware/memory.rs
crates/zclaw-runtime/src/middleware/compaction.rs

# Agent (T3)
desktop/src/store/agentStore.ts
desktop/src/lib/kernel-agent.ts
desktop/src/components/AgentSelector.tsx
desktop/src-tauri/src/kernel_commands/agent.rs
crates/zclaw-kernel/src/kernel/agents.rs

# Classroom (T4)
desktop/src/store/classroomStore.ts
desktop/src/components/Classroom/
desktop/src-tauri/src/kernel_commands/classroom.rs
desktop/src-tauri/src/intelligence/classroom/

# Pipeline (T5)
desktop/src/store/workflowStore.ts
desktop/src/components/WorkflowBuilder/
crates/zclaw-pipeline/src/

# SaaS Desktop (T6)
desktop/src/lib/saas-client.ts
desktop/src/store/saasStore.ts
desktop/src/components/SaaS/

# Skills (T7)
desktop/src/lib/skill-discovery.ts
crates/zclaw-skills/src/
skills/ (75 SKILL.md)

# Chat (T8)
desktop/src/store/chat/ (streamStore, conversationStore, messageStore, artifactStore)
desktop/src/lib/kernel-chat.ts
desktop/src/components/ChatArea.tsx

# Admin V2 (T9)
admin-v2/src/pages/ (15 页面)
admin-v2/tests/ (~71 测试)

# Security (T10)
desktop/src/lib/secure-storage.ts
desktop/src/store/connectionStore.ts
crates/zclaw-saas/src/auth/

# SaaS API (T11)
crates/zclaw-saas/src/ (12 modules + workers)
crates/zclaw-saas/tests/

Chunk 1: Phase 1 环境准备 + T1 Hands 自主能力


Task 0: 环境准备 — 基线验证

Files:

  • Verify: Cargo.toml, desktop/package.json, admin-v2/package.json

  • Output: docs/test-results/baseline/

  • Step 1: 创建测试结果目录

mkdir -p docs/test-results/baseline
mkdir -p docs/test-results/T1-hands/screenshots
mkdir -p docs/test-results/T2-intelligence/screenshots
mkdir -p docs/test-results/T3-agent/screenshots
mkdir -p docs/test-results/T4-classroom/screenshots
mkdir -p docs/test-results/T5-pipeline/screenshots
mkdir -p docs/test-results/T6-saas-desktop/screenshots
mkdir -p docs/test-results/T7-skills/screenshots
mkdir -p docs/test-results/T8-chat/screenshots
mkdir -p docs/test-results/T9-admin/screenshots
mkdir -p docs/test-results/T10-security/screenshots
mkdir -p docs/test-results/T11-saas-api
mkdir -p docs/test-results/T12-e2e/screenshots
  • Step 2: 启动 PostgreSQL
docker compose up -d postgres

Expected: docker compose ps 显示 postgres healthy

  • Step 3: 启动 SaaS 后端
cd crates/zclaw-saas && ZCLAW_SAAS_DEV=true cargo run

Expected: 服务监听 0.0.0.0:8080,日志无 ERROR

  • Step 4: 启动 Tauri 桌面端
cd desktop && pnpm tauri dev

Expected: 窗口打开,无 panic

  • Step 5: 验证 tauri-mcp 连接
manage_window(action='list')

Expected: 返回至少 1 个窗口,标题含 "ZCLAW"

  • Step 6: 运行 Rust 基线测试
cargo test --workspace 2>&1 | tee docs/test-results/baseline/cargo-test.txt

Expected: 全部 pass记录总测试数和通过数

  • Step 7: 运行 Desktop 前端基线测试
cd desktop && pnpm vitest run 2>&1 | tee ../docs/test-results/baseline/desktop-vitest.txt

Expected: 全部 pass记录总测试数

  • Step 8: 运行 Admin 前端基线测试
cd admin-v2 && pnpm vitest run 2>&1 | tee ../docs/test-results/baseline/admin-vitest.txt

Expected: 全部 pass记录总测试数

  • Step 9: 确认 LLM Provider 可用

通过 tauri-mcp 在桌面端:

query_page(mode='map', interactive_only=True)

找到模型选择器,确认至少有 1 个模型可选。

或> 注: tauri-mcp 命令使用伪代码表示Python kwarg 风格),实际执行时需转换为对应工具的 JSON 参数格式。execute_js 中 window.__TAURI_INTERNALS__.invoke(cmd, args) 为 Tauri WebView 内部调用约定,需在执行时验证确切签名。

Expected: 至少 1 个 LLM Provider 的 API Key 已配置

  • Step 10: 记录基线结果

docs/test-results/baseline/README.md 记录:

  • cargo test: X/Y passed

  • desktop vitest: X/Y passed

  • admin vitest: X/Y passed

  • SaaS 后端: running/not running

  • LLM Provider: available/unavailable

  • Step 11: Commit 基线

git add docs/test-results/baseline/
git commit -m "test: add pre-launch audit baseline results"
git push

Task 1: T1 Hands 自主能力 — V12 已知问题验证

V12 健康度: 58/100 | 风险: HIGH | V12 问题: M3-01~M3-13

Files:

  • Audit: docs/features/audit-v12/M3-hands-system.md
  • Source: desktop/src/store/handStore.ts, desktop/src/lib/kernel-hands.ts, desktop/src-tauri/src/kernel_commands/hand.rs
  • Config: hands/*.HAND.toml
  • Rust impl: crates/zclaw-hands/src/hands/

TC-1-01 | Hand 列举(正常)

  • Step 1: 导航到自动化面板
query_page(mode='map', interactive_only=True)

找到 Automation/Hands 相关导航元素。

click(selector_type='ref', selector_value='{nav_ref}')

Expected: 自动化面板显示 9 个已启用的 Hand

  • Step 2: 截图记录 Hand 列表
take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-01-hand-list.png')

Expected: 截图显示 9 个 Hand 卡片Browser/Researcher/Collector/Clip/Twitter/Whiteboard/Slideshow/Speech/Quiz状态为 available

TC-1-02 | Hand 直接触发 — Researcher正常

  • Step 3: 触发 Researcher Hand

在自动化面板点击 Researcher Hand

click(selector_type='ref', selector_value='{researcher_ref}')

如有参数输入框,输入测试参数:

type_text(text='测试研究主题AI Agent 框架对比')

点击执行:

click(selector_type='ref', selector_value='{execute_ref}')

Expected: Hand 进入 running 状态

  • Step 4: 验证执行状态
wait_for(text=['completed', 'failed', 'Running', 'running'], timeout_ms=30000)
take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-02-researcher-result.png')

Expected: Researcher Hand 完成执行,显示研究结果

TC-1-03 | M3-01 验证: run_id 丢失问题

V12 问题: hand.rs:184 丢弃 _run_id,前端无法跟踪执行状态 注意: 当前 Rust 代码 HandResult 已有 run_id 字段,但前端类型定义 kernel-hands.ts:94 仍使用 { instance_id, status } 与实际返回不匹配

  • Step 5: 通过 tauri-mcp 检查 triggerHand 返回值

触发任意 Hand如 Researcher通过 execute_js 检查返回值结构:

async () => {
  try {
    const result = await window.__TAURI_INTERNALS__.invoke('hand_execute', {
      id: 'quiz', input: { topic: 'run_id test' }, autonomyLevel: 'autonomous'
    });
    return JSON.stringify({ keys: Object.keys(result), hasRunId: 'run_id' in result || 'runId' in result, runIdValue: result.run_id || result.runId });
  } catch (e) { return 'Error: ' + e; }
}

Expected: 返回值含 run_id 字段Rust 端已修复),但前端 kernel-hands.ts 的类型定义可能仍不匹配

  • Step 6: 截图记录
take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-03-run-id-check.png')

记录结果到报告run_id 是否存在、前端类型是否与 Rust 端对齐。

TC-1-04 | M3-07 验证: hand-execution-complete 事件监听

V12 问题: onHandExecutionComplete 未被调用,前端不更新执行结果

  • Step 7: 触发 Hand 并观察 UI 是否自动更新
  1. 触发一个 Hand如 Quiz
  2. 不手动刷新页面
  3. 等待 30 秒
# 触发 Quiz Hand
click(selector_type='ref', selector_value='{quiz_ref}')
type_text(text='测试 Quiz 主题')
click(selector_type='ref', selector_value='{execute_ref}')

# 等待完成
wait_for(text=['completed', 'Complete', 'finished'], timeout_ms=60000)

Expected (如未修复): UI 不自动更新执行状态,需手动刷新 Expected (如已修复): UI 自动显示执行完成状态

  • Step 8: 截图
take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-04-event-listener.png')

TC-1-05 | M3-02 验证: Browser Hand 双路径断裂

V12 问题: Rust execute() 只返回结构化指令不执行实际操作

  • Step 9: 通过 handStore 触发 Browser Hand

在自动化面板找到 Browser Hand 并触发:

click(selector_type='ref', selector_value='{browser_ref}')

配置参数(如打开网页):

type_text(text='https://example.com')
click(selector_type='ref', selector_value='{execute_ref}')

Expected (如未修复): 返回结构化指令 JSON 但不执行浏览器操作 Expected (如已修复): 实际打开/访问网页

  • Step 10: 对比 browserHandStore 路径

通过 tauri-mcp 检查是否有独立的浏览器面板/功能:

query_page(mode='map', interactive_only=True)

Expected: browserHandStore 有独立的浏览器操作 UI绕过 handStore 审批流程

  • Step 11: 截图
take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-05-browser-hand.png')

TC-1-06 | M3-03 验证: browserHandStore 绕过审批

V12 问题: 无视 TOML requires_approval = true

  • Step 12: 设置自主级别为非自动

在自动化设置中,将自主级别设为"需审批"(非 autonomous

通过 tauri-mcp:

navigate(action='goto', url='tauri://localhost/settings/automation')
# 或点击设置页
click(selector_type='ref', selector_value='{settings_ref}')

找到自主级别滑块/下拉框,设置为"需审批"。

  • Step 13: 通过 browserHandStore 执行操作

在浏览器面板执行一个操作(如导航到 URL

Expected (如未修复): 操作直接执行,不弹出审批确认 Expected (如已修复): 弹出审批确认对话框

  • Step 14: 截图
take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-06-bypass-approval.png')

TC-1-07 | 审批流程 — 完整闭环(正常)

  • Step 15: 触发需审批的 Hand

确认有一个 Hand 配置了 requires_approval = true(检查 hands/*.HAND.toml)。

在自主级别为"需审批"模式下触发该 Hand。

Expected: 弹出审批队列/确认对话框

  • Step 16: 审批通过
click(selector_type='ref', selector_value='{approve_ref}')

Expected: Hand 开始执行,完成后结果出现在 UI

  • Step 17: 审批拒绝(重新触发)

再次触发需审批的 Hand这次拒绝

click(selector_type='ref', selector_value='{reject_ref}')

Expected: Hand 不执行,状态显示"已拒绝"

  • Step 18: 截图记录审批流程
take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-07-approval-flow.png')

TC-1-08 | M3-04 验证: max_concurrent 未实现(边界)

V12 问题: TOML 定义但运行时无检查

  • Step 19: 并发触发同一 Hand

同时触发同一 Hand 3-5 次:

方式 A如 UI 允许):快速多次点击执行按钮。 方式 B通过 execute_js

async () => {
  // 连续触发同一 Hand 多次
  for (let i = 0; i < 5; i++) {
    await window.__TAURI_INTERNALS__.invoke('hand_execute', {
      id: 'researcher',
      input: { query: `test ${i}` },
      autonomyLevel: 'autonomous'
    });
  }
  return 'triggered 5 times';
}

Expected (如未修复): 5 个全部开始执行,无并发限制 Expected (如已修复): 达到 max_concurrent 后拒绝或排队

  • Step 20: 截图
take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-08-concurrent.png')

TC-1-09 | M3-05 验证: timeout_secs 未实现(边界)

V12 问题: Hand 可无限挂起

  • Step 21: 触发可能长时间运行的 Hand

触发一个 Hand如 Researcher 配合复杂查询),观察是否在 timeout_secs 内终止。

如果无法构造超时场景,检查 TOML 配置:

grep -r "timeout_secs" hands/*.HAND.toml

Expected (如未修复): Hand 无超时保护,可能无限运行 Expected (如已修复): 超过 timeout_secs 后 Hand 自动终止

  • Step 22: 截图
take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-09-timeout.png')

TC-1-10 | Hand 取消(正常)

  • Step 23: 触发长时间 Hand 并中途取消

触发一个 Hand在其 running 状态时点击取消:

click(selector_type='ref', selector_value='{cancel_ref}')

Expected: Hand 停止执行,状态变为 cancelled

  • Step 24: 截图
take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-10-cancel.png')

TC-1-11 | M3-09 验证: 重复审批路径(正常)

V12 问题: hand_approve vs approval_respond 两条重复路径

  • Step 25: 验证两条审批路径

通过 Rust 日志或前端行为检查:

路径 A: hand_approve — 通过 handStore 直接审批 路径 B: approval_respond — 通过审批队列审批

检查两条路径是否行为一致(都触发执行,都 emit 事件)。

take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-11-dual-approval.png')

Expected: 两条路径均能完成审批并触发执行

TC-1-12 | 不存在的 Hand 触发(异常)

  • Step 26: 触发不存在的 Hand

通过 execute_js:

async () => {
  try {
    const result = await window.__TAURI_INTERNALS__.invoke('hand_execute', {
      id: 'nonexistent-hand',
      input: {},
      autonomyLevel: 'autonomous'
    });
    return JSON.stringify(result);
  } catch (e) {
    return `Error: ${e}`;
  }
}

Expected: 返回错误 "not found" 或类似

TC-1-13 | M3-08 验证: 审批条目永不过期(异常)

V12 问题: pending_approvals Vec 无限增长

  • Step 27: 累积审批条目

触发多个需审批的 Hand不审批它们。观察内存中 pending_approvals 是否持续增长。

通过 execute_js 检查:

async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('approval_list', {});
  return JSON.stringify(result);
}

Expected (如未修复): 列表持续增长,无过期清理 Expected (如已修复): 有过期机制自动清理 量化标准: 触发 5 次审批,等待 60 秒,检查是否执行了过期清理(列表长度应 <= 5

TC-1-14 | 各 Hand 基础触发验证(正常)

  • Step 28: 逐一触发 9 个已启用 Hand

对每个 Hand 执行基本触发测试:

Hand 测试输入 预期
Researcher 主题:"AI 测试" 返回研究结果
Collector URL"https://example.com" 收集内容
Quiz 主题:"Rust 基础" 生成测验
Slideshow 主题:"ZCLAW 介绍" 生成幻灯片
Speech 文本:"你好世界" TTS 朗读
Whiteboard 主题:"架构图" 显示白板
Twitter (需 OAuth 配置) 检查是否正确报告配置缺失
Clip (需 FFmpeg 检查是否正确报告依赖缺失
Browser URL"https://example.com" 返回操作结果

每个 Hand 截图一张:

take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-14-{hand_name}.png')

Expected: 每个 Hand 至少能触发(成功或返回明确的配置缺失提示)

TC-1-15 | Hand 执行状态查询(正常)

  • Step 29: 查询正在运行的 Hand 状态

触发一个 Hand在其 running 时查询状态:

async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('hand_run_status', {
    handName: 'researcher',
    runId: '{run_id_if_available}'
  });
  return JSON.stringify(result);
}

Expected: 返回 running/pending/completed 状态

  • Step 30: 查询已完成 Hand 的状态

Expected: 返回 completed + 结果

TC-1-16 | M3-06 验证: hand_execute 返回值类型不匹配(正常)

V12 问题: 前端期望 { instance_id, status },实际返回 { success, output, error, durationMs }

  • Step 31: 检查 triggerHand 完整返回值
async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('hand_execute', {
    id: 'quiz',
    input: { topic: 'test' },
    autonomyLevel: 'autonomous'
  });
  return JSON.stringify(Object.keys(result));
}

Expected (如未修复): 返回 ["success","output","error","durationMs"] Expected (如已修复): 返回包含 runId 字段

  • Step 32: 截图
take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-16-return-type.png')

TC-1-17 | M3-10 验证: tool_count/metric_count 硬编码为 0正常

  • Step 33: 检查 hand_list 返回值
async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('hand_list', {});
  const counts = result.map(h => ({ name: h.name, toolCount: h.tool_count, metricCount: h.metric_count }));
  return JSON.stringify(counts);
}

Expected (如未修复): 所有 Hand 的 tool_count 和 metric_count 均为 0 Expected (如已修复): 返回实际工具和指标数量

TC-1-18 | TOML 配置加载验证(正常)

  • Step 34: 验证 TOML 配置被正确读取
async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('hand_list', {});
  // 检查每个 hand 的 enabled、requires_approval 等字段
  return JSON.stringify(result.map(h => ({
    name: h.name,
    enabled: h.enabled,
    requiresApproval: h.requires_approval,
    timeoutSecs: h.timeout_secs,
    maxConcurrent: h.max_concurrent
  })));
}

对照 hands/*.HAND.toml 中的配置值验证一致性。

Expected: enabled/requires_approval 正确timeout_secs/max_concurrent 定义但可能未生效

TC-1-19 | Hand 错误处理(异常)

  • Step 35: 触发 Hand 传入无效参数
async () => {
  try {
    const result = await window.__TAURI_INTERNALS__.invoke('hand_execute', {
      id: 'researcher',
      input: null,
      autonomyLevel: 'autonomous'
    });
    return JSON.stringify(result);
  } catch (e) {
    return `Error: ${e}`;
  }
}

Expected: 返回明确错误信息(非 panic

TC-1-20 | M3-12 验证: hand_trigger 永远不自动允许(边界)

V12 问题: autonomy-manager.ts:268 映射错误hand_trigger 在 autonomous 模式下也不返回 allow

  • Step 35b: 验证三个自主级别下 hand_trigger 的 canAutoExecute 结果
async () => {
  // 检查 autonomy-manager 中 hand_trigger 映射
  const levels = ['supervised', 'assisted', 'autonomous'];
  const results = {};
  for (const level of levels) {
    // 模拟不同级别的 canAutoExecute 逻辑
    results[level] = '需手动在 UI 中切换级别后验证';
  }
  return JSON.stringify(results);
}

实际操作:在 UI 中依次切换自主级别为 supervised → assisted → autonomous每次触发一个 Hand如 Quiz

Expected (如未修复): autonomous 模式下 Hand 仍需审批canAutoExecute 不返回 allow Expected (如已修复): autonomous 模式下 Hand 自动执行canAutoExecute 返回 allow

  • 截图
take_screenshot(filePath='docs/test-results/T1-hands/screenshots/TC-1-20-autonomy-mapping.png')

TC-1-21 | M3-13 验证: Clip Hand 路径含单引号(边界)

V12 问题: clip.rs:448 FFmpeg concat 文件路径单引号未转义

  • Step 35c: 触发 Clip Hand 使用含单引号的路径
async () => {
  try {
    const result = await window.__TAURI_INTERNALS__.invoke('hand_execute', {
      id: 'clip',
      input: { files: ["C:\\User's Files\\video.mp4"], action: 'concat' },
      autonomyLevel: 'autonomous'
    });
    return JSON.stringify(result);
  } catch (e) { return 'Error: ' + e; }
}

Expected (如未修复): FFmpeg 解析失败或命令注入风险 Expected (如已修复): 正确转义单引号,返回正常结果或明确的路径错误

TC-1-22 | 无 LLM Provider 时触发 Hand边界

  • Step 35d: 临时移除 LLM API Key 后触发 Researcher
  1. 进入设置,移除当前 Agent 的 API Key
  2. 触发 Researcher Hand
  3. 恢复 API Key

Expected: 返回明确错误提示("未配置 API Key" 等),非 panic/空结果

TC-1-23 | 超长输入触发 Hand边界

  • Step 35e: 触发 Hand 传入超长字符串
async () => {
  const longInput = 'A'.repeat(100000);
  try {
    const result = await window.__TAURI_INTERNALS__.invoke('hand_execute', {
      id: 'quiz',
      input: { topic: longInput },
      autonomyLevel: 'autonomous'
    });
    return JSON.stringify({ status: 'returned', outputLen: JSON.stringify(result).length });
  } catch (e) { return 'Error: ' + e; }
}

Expected: 拒绝超长输入或截断处理,非崩溃

  • Step 36: Commit T1 测试结果
git add docs/test-results/T1-hands/
git commit -m "test(T1): hands system functional audit results"
git push
  • Step 37: 生成 T1 测试报告

docs/test-results/T1-hands/REPORT.md 中记录:

  • 执行用例数: 19/19
  • 通过/失败数
  • V12 已知问题验证结果M3-01~M3-13
  • 新发现问题清单
  • 健康度重新评估(基线 58/100
git add docs/test-results/T1-hands/REPORT.md
git commit -m "test(T1): add hands system audit report"
git push

Chunk 2: T2 智能层 + T3 Agent 分身


Task 2: T2 智能层(记忆/反思/心跳/自主)— V12 已知问题验证

V12 健康度: 61/100 | 风险: HIGH | V12 问题: M4-01~M4-15 (含 2 个 P0)

Files:

  • Audit: docs/features/audit-v12/M4-intelligence-layer.md
  • Source:
    • 记忆: desktop/src/store/memoryGraphStore.ts, desktop/src/lib/intelligence-client/memory.ts, desktop/src-tauri/src/intelligence/memory.rs
    • 身份: desktop/src/lib/intelligence-client/identity.ts, desktop/src-tauri/src/intelligence/identity.rs
    • 反思: desktop/src/lib/intelligence-client/reflection.ts, desktop/src-tauri/src/intelligence/reflection.rs
    • 心跳: desktop/src/lib/intelligence-client/heartbeat.ts, desktop/src-tauri/src/intelligence/heartbeat.rs
    • 自主: desktop/src/lib/autonomy-manager.ts, desktop/src/components/AutonomyConfig.tsx
    • 压缩: desktop/src/lib/intelligence-client/fallback-compactor.ts, desktop/src-tauri/src/intelligence/compactor.rs
    • Runtime 中间件: crates/zclaw-runtime/src/middleware/memory.rs, crates/zclaw-runtime/src/middleware/compaction.rs
    • 存储: crates/zclaw-growth/src/storage/sqlite.rs

TC-2-01 | M4-01 验证: 双数据库问题P0

V12 问题: PersistentMemoryStore(LIKE) vs SqliteStorage(FTS5),数据不互通

  • Step 1: 通过前端保存一条记忆

导航到记忆面板:

navigate(action='goto', url='tauri://localhost/memories')
# 或通过导航点击

手动保存一条记忆:"测试记忆条目 - 上线前审计"。

take_screenshot(filePath='docs/test-results/T2-intelligence/screenshots/TC-2-01a-save-memory.png')
  • Step 2: 验证该记忆出现在对话注入中

进入对话界面,发送消息触发记忆搜索(发送与记忆相关的问题)。

type_text(text='你记得什么关于上线前审计的信息?')
click(selector_type='ref', selector_value='{send_ref}')
wait_for(text=['测试记忆', '审计'], timeout_ms=15000)

Expected (如未修复): 手动保存的记忆不出现在对话回复中(因为 Runtime 用 SqliteStorage前端用 PersistentMemoryStore Expected (如已修复): 对话回复引用了手动保存的记忆内容

  • Step 3: 反向验证 — Agent 自动提取的记忆是否出现在前端面板

进行多轮对话,触发自动记忆提取。然后检查记忆面板是否显示新提取的记忆。

take_screenshot(filePath='docs/test-results/T2-intelligence/screenshots/TC-2-01b-memory-panel.png')

Expected (如未修复): Agent 提取的记忆不出现在前端记忆面板 Expected (如已修复): Agent 提取的记忆出现在前端面板

TC-2-02 | M4-02 验证: 反思 LLM 未接入P0

V12 问题: reflection_reflect 传入 driver=NoneLLM 分析从未生效

  • Step 4: 触发反思并检查是否使用 LLM

通过 execute_js 直接调用反思:

async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('reflection_reflect', {
    agentId: '{current_agent_id}',
    force: true
  });
  return JSON.stringify({ keys: Object.keys(result), analysis: result.analysis?.substring(0, 200) });
}

Expected (如未修复): 返回规则分析结果(基于启发式规则),无 LLM 深度分析 Expected (如已修复): 返回包含 LLM 分析内容(更丰富的洞察)

  • Step 5: 检查 Rust 端日志

查看日志中是否有 LLM 调用记录:

# 如果日志输出到文件
grep -i "reflection.*driver\|reflection.*llm\|reflect.*None" /tmp/zclaw-*.log 2>/dev/null || echo "No log file found"

Expected (如未修复): 日志显示 driver=None Expected (如已修复): 日志显示 driver=Some(...),有 LLM API 调用

  • Step 6: 截图
take_screenshot(filePath='docs/test-results/T2-intelligence/screenshots/TC-2-02-reflection.png')

TC-2-03 | 记忆 CRUD正常

  • Step 7: 创建记忆
navigate(action='goto', url='tauri://localhost/memories')

创建一条新记忆:

  • 类型: fact
  • 内容: "ZCLAW 上线前审计测试记忆"
  • 重要性: 7
take_screenshot(filePath='docs/test-results/T2-intelligence/screenshots/TC-2-03a-create-memory.png')
  • Step 8: 搜索记忆

搜索关键词 "上线前审计"。

type_text(text='上线前审计')
click(selector_type='ref', selector_value='{search_ref}')
wait_for(text=['ZCLAW 上线前审计'], timeout_ms=5000)

Expected: 搜索结果显示刚创建的记忆

  • Step 9: 更新记忆

修改记忆内容为 "ZCLAW 上线前审计测试记忆 - 已更新"。

Expected: 记忆内容成功更新

  • Step 10: 删除记忆

删除刚创建的记忆。

Expected: 记忆从列表中消失

take_screenshot(filePath='docs/test-results/T2-intelligence/screenshots/TC-2-03b-memory-crud.png')

TC-2-04 | M4-05 验证: 前端记忆搜索用 LIKE 非 FTS5正常

V12 问题: PersistentMemoryStore 用 LIKE 模糊匹配,非 FTS5

  • Step 11: 测试搜索精度
  1. 创建多条记忆,内容包含 "机器学习"
  2. 搜索 "机器"
  3. 搜索 "学习"

Expected (LIKE): 两个搜索都返回结果(模糊匹配) Expected (FTS5): "机器" 返回结果,"学习" 可能不返回(分词差异)

take_screenshot(filePath='docs/test-results/T2-intelligence/screenshots/TC-2-04-search-like.png')

TC-2-05 | 身份演化(正常)

  • Step 12: 查看当前 Agent 身份
async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('identity_get', {
    agentId: '{current_agent_id}'
  });
  return JSON.stringify({ hasSoul: !!result.soul, hasInstructions: !!result.instructions });
}

Expected: 返回当前 Agent 的 Soul 和 Instructions

  • Step 13: 提出身份变更提案
async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('identity_propose_change', {
    agentId: '{current_agent_id}',
    dimension: 'communication_style',
    proposedValue: '更加技术性',
    reason: '测试身份演化'
  });
  return JSON.stringify(result);
}

Expected: 创建变更提案

  • Step 14: 审批/拒绝身份变更
take_screenshot(filePath='docs/test-results/T2-intelligence/screenshots/TC-2-05-identity.png')

TC-2-06 | M4-03 验证: 心跳不自动启动(正常)

V12 问题: 需前端手动初始化 heartbeat_init + heartbeat_start

  • Step 15: 检查心跳是否自动运行

应用启动后,检查心跳状态:

async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('heartbeat_status', {});
  return JSON.stringify(result);
}

Expected (如未修复): 心跳未运行(需手动启动) Expected (如已修复): 心跳自动启动并运行

  • Step 16: 手动启动心跳(如未自动启动)
async () => {
  await window.__TAURI_INTERNALS__.invoke('heartbeat_init', { intervalMinutes: 5 });
  await window.__TAURI_INTERNALS__.invoke('heartbeat_start', {});
  const status = await window.__TAURI_INTERNALS__.invoke('heartbeat_status', {});
  return JSON.stringify(status);
}

Expected: 心跳开始运行,显示下次巡检时间

  • Step 17: 截图
take_screenshot(filePath='docs/test-results/T2-intelligence/screenshots/TC-2-06-heartbeat.png')

TC-2-07 | M4-04 验证: 自主授权后端无强制(正常)

V12 问题: 仅前端咨询层,后端不检查自主授权级别

  • Step 18: 验证后端不检查自主级别

设置自主级别为 supervised然后通过 execute_js 直接调用 Rust 命令绕过前端:

async () => {
  // 前端 autonomy-manager 设为 supervised
  // 但直接调用 Tauri 命令绕过前端检查
  const result = await window.__TAURI_INTERNALS__.invoke('hand_execute', {
    id: 'quiz',
    input: { topic: 'autonomy test' },
    autonomyLevel: 'supervised'  // 后端是否检查?
  });
  return JSON.stringify({ executed: result.success });
}

Expected (如未修复): 后端直接执行,不检查自主级别 Expected (如已修复): 后端根据自主级别决定是否需要审批

TC-2-08 | 上下文压缩(正常)

  • Step 19: 触发上下文压缩

进行多轮对话使上下文变长,然后触发压缩:

async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('compaction_compact', {
    agentId: '{current_agent_id}',
    sessionId: '{current_session_id}'
  });
  return JSON.stringify({ success: result.success, originalTokens: result.original_tokens, compressedTokens: result.compressed_tokens });
}

Expected: 返回压缩结果compressedTokens < originalTokens

take_screenshot(filePath='docs/test-results/T2-intelligence/screenshots/TC-2-08-compaction.png')

TC-2-09 | M4-06 验证: types 参数数组 vs 单值(边界)

V12 问题: 前端 types?: MemoryType[] vs 后端 memory_type?: string

  • Step 20: 测试传入多种类型搜索
async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('memory_search', {
    query: 'test',
    types: ['fact', 'procedure']  // 前端传数组
  });
  return JSON.stringify({ count: result?.length || 0 });
}

Expected (如未修复): 后端只接收第一个类型或报错 Expected (如已修复): 后端正确处理多类型搜索

TC-2-10 | 记忆内容无长度限制(异常)

V12 问题: M4-07 content 无长度限制

  • Step 21: 保存超长记忆
async () => {
  const longContent = 'A'.repeat(1000000);  // 1MB
  try {
    const result = await window.__TAURI_INTERNALS__.invoke('memory_save', {
      agentId: '{current_agent_id}',
      memory: { content: longContent, memoryType: 'fact', importance: 5 }
    });
    return JSON.stringify({ saved: true, id: result.id });
  } catch (e) { return 'Error: ' + e; }
}

Expected: 拒绝或截断(非无限制保存导致内存问题)

TC-2-11 | 心跳 interval 下限验证(边界)

V12 问题: M4-09 interval_minutes 无下限验证

  • Step 22: 设置极短心跳间隔
async () => {
  try {
    await window.__TAURI_INTERNALS__.invoke('heartbeat_init', { intervalMinutes: 0.001 });
    return 'No validation - accepted 0.001 minutes';
  } catch (e) { return 'Blocked: ' + e; }
}

Expected (如未修复): 接受极短间隔,可能导致频繁心跳 Expected (如已修复): 拒绝低于最小值(如 1 分钟)

TC-2-12 | 反思引擎边界测试(边界)

  • Step 23: 在无记忆的情况下触发反思
async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('reflection_reflect', {
    agentId: 'nonexistent-agent',
    force: true
  });
  return JSON.stringify(result);
}

Expected: 返回空分析或明确的"无数据"提示,非 panic

TC-2-13 | 两套压缩实现验证(正常)

V12 问题: M4-13 Tauri 层和 Runtime 层各有独立压缩实现

  • Step 24: 对比两套压缩配置

检查 Tauri 层 compactor.rs 和 Runtime 层 compaction.rs 的默认配置是否一致。

take_screenshot(filePath='docs/test-results/T2-intelligence/screenshots/TC-2-13-compaction-dual.png')
  • Step 25: Commit T2 测试结果
git add docs/test-results/T2-intelligence/
git commit -m "test(T2): intelligence layer functional audit results"
git push
  • Step 26: 生成 T2 测试报告

docs/test-results/T2-intelligence/REPORT.md 中记录:

  • 执行用例数: 13/13
  • 通过/失败数
  • V12 已知问题验证结果M4-01~M4-15
  • 新发现问题清单
  • 健康度重新评估(基线 61/100
git add docs/test-results/T2-intelligence/REPORT.md
git commit -m "test(T2): add intelligence layer audit report"
git push

Task 3: T3 Agent 分身 — V12 已知问题验证

V12 健康度: 67/100 | 风险: HIGH | V12 问题: M2-01~M2-14 (含 2 个 P1)

Files:

  • Audit: docs/features/audit-v12/M2-agent-clones.md
  • Source: desktop/src/store/agentStore.ts, desktop/src/lib/kernel-agent.ts, desktop/src/components/AgentSelector.tsx
  • Rust: desktop/src-tauri/src/kernel_commands/agent.rs, crates/zclaw-kernel/src/kernel/agents.rs

TC-3-01 | Agent 列举(正常)

  • Step 27: 查看 Agent 列表
query_page(mode='map', interactive_only=True)

找到 Agent 选择器/管理入口并点击。

Expected: 显示至少 1 个默认 Agent

take_screenshot(filePath='docs/test-results/T3-agent/screenshots/TC-3-01-agent-list.png')

TC-3-02 | M2-01 验证: KernelClient createClone 字段丢失P1

V12 问题: kernel-agent.ts 只传 name/description/model 3 字段,丢 7+ 人格字段

  • Step 28: 通过 Kernel 模式创建 Agent含完整人格字段

在 Agent 管理界面创建新 Agent填写所有字段

  • 名称: "审计测试 Agent"
  • 描述: "用于测试字段传递"
  • 表情: "🤖"
  • 性格: "严谨、精确"
  • 沟通风格: "技术导向"
  • 备注: "测试备注"
type_text(text='审计测试 Agent')
# 依次填写其他字段
click(selector_type='ref', selector_value='{create_ref}')
  • Step 29: 检查 SQLite 中 Agent 配置
async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('agent_list', {});
  const testAgent = result.find(a => a.name === '审计测试 Agent');
  if (!testAgent) return 'Agent not found';
  return JSON.stringify({
    name: testAgent.name,
    hasEmoji: !!testAgent.config?.emoji,
    hasPersonality: !!testAgent.config?.personality,
    configKeys: Object.keys(testAgent.config || {})
  });
}

Expected (如未修复): config 中缺少 emoji/personality/communicationStyle 等字段 Expected (如已修复): config 包含所有传入的人格字段

take_screenshot(filePath='docs/test-results/T3-agent/screenshots/TC-3-02-field-loss.png')

TC-3-03 | M2-02 验证: 双通路创建不对等P1

V12 问题: Gateway 构建完整 TOML manifestKernel 仅 3 字段

  • Step 30: 对比 Kernel 和 Gateway 两条通路的创建结果

创建两个 Agent

  1. Agent A: 通过 Kernel 模式创建
  2. Agent B: 通过 Gateway 模式创建(如 Gateway 可用)

对比两个 Agent 的配置完整度。

Expected (如未修复): Kernel 创建的 Agent 缺少人格字段Gateway 创建的完整 Expected (如已修复): 两条通路创建结果一致

take_screenshot(filePath='docs/test-results/T3-agent/screenshots/TC-3-03-dual-path.png')

TC-3-04 | Agent 更新(正常)

  • Step 31: 更新 Agent 属性

修改刚创建的 Agent

  • 更新名称
  • 更新描述
  • 更新 system prompt
  • 更新模型
click(selector_type='ref', selector_value='{edit_ref}')
type_text(text='审计测试 Agent - 已更新')
click(selector_type='ref', selector_value='{save_ref}')

Expected: 所有更新生效

take_screenshot(filePath='docs/test-results/T3-agent/screenshots/TC-3-04-update.png')

TC-3-05 | Agent 切换(正常)

  • Step 32: 切换到新创建的 Agent
click(selector_type='ref', selector_value='{agent_selector_ref}')
click(selector_type='ref', selector_value='{test_agent_ref}')

Expected: Agent 切换成功UI 显示新 Agent 名称

  • Step 33: 发送消息验证 Agent 身份
type_text(text='你好,你是谁?')
click(selector_type='ref', selector_value='{send_ref}')
wait_for(text=['审计测试', 'Agent'], timeout_ms=15000)

Expected: AI 回复体现新 Agent 的身份/个性

TC-3-06 | M2-06 验证: Agent 切换不通知 Kernel正常

V12 问题: 切换 Agent 不更新 defaultAgentId

  • Step 34: 切换 Agent 后检查 Kernel 状态
async () => {
  // 切换到新 Agent 后检查
  const agentId = await window.__TAURI_INTERNALS__.invoke('get_default_agent', {});
  return JSON.stringify({ defaultAgentId: agentId });
}

Expected (如未修复): defaultAgentId 未更新为刚切换的 Agent Expected (如已修复): defaultAgentId 正确更新

TC-3-07 | M2-07 验证: 切换不取消流(正常)

V12 问题: 流式中切换 Agent消息可能追到错误对话

  • Step 35: 流式中切换 Agent
  1. 发送一条长消息(触发长时间流式响应)
  2. 在流式响应进行中,切换到另一个 Agent
type_text(text='请详细解释 Rust 的生命周期系统')
click(selector_type='ref', selector_value='{send_ref}')
# 立即切换 Agent
click(selector_type='ref', selector_value='{agent_selector_ref}')
click(selector_type='ref', selector_value='{another_agent_ref}')

Expected (如未修复): 原有流继续在后台运行,响应可能出现在错误的对话 Expected (如已修复): 切换前自动取消进行中的流

take_screenshot(filePath='docs/test-results/T3-agent/screenshots/TC-3-07-switch-during-stream.png')

TC-3-08 | Agent 删除(正常)

  • Step 36: 删除测试 Agent
click(selector_type='ref', selector_value='{delete_ref}')

Expected: 删除成功Agent 从列表消失

TC-3-09 | M2-05 验证: 删除不检查活跃状态(异常)

V12 问题: 删除正在使用的 Agent 无警告

  • Step 37: 删除当前活跃的 Agent

切换到一个 Agent然后直接删除它。

Expected (如未修复): 直接删除,无警告 Expected (如已修复): 弹出警告"该 Agent 正在使用中"

take_screenshot(filePath='docs/test-results/T3-agent/screenshots/TC-3-09-delete-active.png')

TC-3-10 | M2-08 验证: 无参数验证(异常)

V12 问题: 空 name、温度越界无验证

  • Step 38: 创建空名 Agent
async () => {
  try {
    const result = await window.__TAURI_INTERNALS__.invoke('agent_create', {
      name: '',
      description: 'test',
      model: 'gpt-4'
    });
    return JSON.stringify({ created: true, id: result.id });
  } catch (e) { return 'Error: ' + e; }
}

Expected (如未修复): 成功创建空名 Agent Expected (如已修复): 拒绝空名称

  • Step 39: 设置越界 temperature
async () => {
  try {
    const result = await window.__TAURI_INTERNALS__.invoke('agent_update', {
      agentId: '{test_agent_id}',
      updates: { temperature: 5.0 }
    });
    return JSON.stringify({ updated: true });
  } catch (e) { return 'Error: ' + e; }
}

Expected (如未修复): 接受 temperature=5.0 Expected (如已修复): 拒绝越界值

TC-3-11 | M2-09 验证: 删除后 selectedAgent 引用(异常)

V12 问题: 删除当前选中 Agent 后引用可能悬挂

  • Step 40: 删除当前选中 Agent 后检查状态
  1. 选中 Agent A
  2. 删除 Agent A
  3. 检查 conversationStore.currentAgent 是否有效
async () => {
  // 删除后检查
  const state = document.querySelector('[data-agent-name]')?.textContent;
  return state || 'No agent selected';
}

Expected (如未修复): currentAgent 指向已删除 Agent Expected (如已修复): 自动切换到第一个可用 Agent

TC-3-12 | Agent 从模板创建(正常)

  • Step 41: 从模板创建 Agent

检查是否有模板创建功能,如有则测试。

take_screenshot(filePath='docs/test-results/T3-agent/screenshots/TC-3-12-template-create.png')
  • Step 42: Commit T3 测试结果
git add docs/test-results/T3-agent/
git commit -m "test(T3): agent clones functional audit results"
git push
  • Step 43: 生成 T3 测试报告

docs/test-results/T3-agent/REPORT.md 中记录:

  • 执行用例数: 12/12
  • 通过/失败数
  • V12 已知问题验证结果M2-01~M2-14
  • 新发现问题清单
  • 健康度重新评估(基线 67/100
git add docs/test-results/T3-agent/REPORT.md
git commit -m "test(T3): add agent clones audit report"
git push

Chunk 2 执行前必读: 所有 execute_js 中的 Tauri 命令名需在执行时与 desktop/src-tauri/src/lib.rsinvoke_handler 注册列表核对。V12 审计后部分问题M4-01/M4-02可能已修复以实际代码为准。


Chunk 3: T4 课堂系统 + T5 Pipeline 工作流


Task 4: T4 课堂系统 — V12 已知问题验证

V12 健康度: 70/100 | 风险: HIGH | V12 问题: M11-01~M11-08 (含 3 个 P1)

Files:

  • Audit: docs/features/audit-v12/M11-classroom.md
  • Source: desktop/src/store/classroomStore.ts, desktop/src/components/Classroom/
  • Rust: desktop/src-tauri/src/kernel_commands/classroom.rs, desktop/src-tauri/src/intelligence/classroom/

TC-4-01 | 课堂生成(正常)

  • Step 44: 触发课堂生成

导航到课堂功能,输入主题生成课堂:

type_text(text='Rust 所有权系统')
click(selector_type='ref', selector_value='{generate_ref}')

Expected: 显示生成进度4 阶段 pipeline 逐步完成

  • Step 45: 等待生成完成
wait_for(text=['completed', '生成完成', 'Complete'], timeout_ms=120000)
take_screenshot(filePath='docs/test-results/T4-classroom/screenshots/TC-4-01-generation.png')

Expected: 课堂生成成功,显示场景列表

TC-4-02 | M11-01 验证: is_cancelled() blocking_lock 死锁P1

V12 问题: generate.rs:141-144 async 函数中使用 blocking_locktokio 可能死锁

  • Step 46: 生成过程中取消课堂
  1. 开始生成一个课堂
  2. 在生成过程中点击取消
click(selector_type='ref', selector_value='{cancel_generation_ref}')

Expected (如未修复): 取消请求可能触发 tokio 死锁,应用卡住 Expected (如已修复): 取消成功,生成停止,无死锁

take_screenshot(filePath='docs/test-results/T4-classroom/screenshots/TC-4-02-cancel-deadlock.png')

TC-4-03 | M11-02 验证: LLM 调用无 map_errP1

V12 问题: Stage 0/1 LLM 调用无 map_errdriver 未配置时可能 panic

  • Step 47: 在无 LLM 配置时生成课堂

临时移除 LLM API Key然后尝试生成课堂。

Expected (如未修复): 可能 panic 或返回空结果无错误提示 Expected (如已修复): 返回明确的错误信息

TC-4-04 | 场景播放(正常)

  • Step 48: 播放已生成的课堂场景
click(selector_type='ref', selector_value='{scene_1_ref}')

Expected: 场景自动播放,显示 speech/whiteboard/quiz actions

take_screenshot(filePath='docs/test-results/T4-classroom/screenshots/TC-4-04-scene-play.png')

TC-4-05 | TTS 朗读(正常)

  • Step 49: 触发 TTS 朗读

在场景播放中点击朗读按钮。

Expected: 浏览器 TTS 以 zh-CN 语言朗读场景内容

take_screenshot(filePath='docs/test-results/T4-classroom/screenshots/TC-4-05-tts.png')

TC-4-06 | 白板渲染(正常)

  • Step 50: 查看白板场景

导航到含白板 action 的场景。

Expected: 白板内容正确渲染SVG 或 Canvas

take_screenshot(filePath='docs/test-results/T4-classroom/screenshots/TC-4-06-whiteboard.png')

TC-4-07 | M11-03 验证: 课堂数据仅存内存P1

V12 问题: HashMap 存储,重启丢失

  • Step 51: 重启应用后检查课堂数据
  1. 确认有已生成的课堂
  2. 重启 Tauri 应用
  3. 检查课堂是否还在

Expected (如未修复): 重启后所有课堂消失 Expected (如已修复): 课堂数据持久化,重启后仍存在

TC-4-08 | 课堂聊天(正常)

  • Step 52: 在课堂中进行聊天
type_text(text='请解释一下这个概念')
click(selector_type='ref', selector_value='{chat_send_ref}')
wait_for(text=['解释'], timeout_ms=15000)

Expected: LLM 多 agent 响应课堂聊天

TC-4-09 | 课堂导出(正常)

  • Step 53: 导出课堂为 JSON/Markdown
click(selector_type='ref', selector_value='{export_ref}')

Expected: 文件下载成功

take_screenshot(filePath='docs/test-results/T4-classroom/screenshots/TC-4-09-export.png')

TC-4-10 | M11-04 验证: LLM 失败静默 fallback异常

V12 问题: LLM 失败静默 fallback 到 placeholder

  • Step 54: 制造 LLM 失败场景

在课堂聊天中,临时使 LLM 不可用。

Expected (如未修复): 回复是 placeholder 但用户无法区分 Expected (如已修复): 标记为 placeholder 或显示错误提示

TC-4-11 | M11-05 验证: 生成完成强制打开(正常)

V12 问题: 生成完成后强制打开 player

  • Step 55: 生成期间关闭 player观察完成后行为

Expected (如未修复): player 被强制重新打开 Expected (如已修复): 尊重手动关闭状态

TC-4-12 | 课堂历史列表(正常)

  • Step 56: 检查课堂历史列表功能

Expected: 确认 classroom_list 前端集成状态

  • Step 57: Commit T4 测试结果
git add docs/test-results/T4-classroom/
git commit -m "test(T4): classroom system functional audit results"
git push

Task 5: T5 Pipeline 工作流 — V12 已知问题验证

V12 健康度: 72/100 | 风险: MEDIUM | V12 问题: M6-01~M6-08 (含 2 个 P1)

Files:

  • Audit: docs/features/audit-v12/M6-pipeline-workflow.md
  • Source: desktop/src/store/workflowStore.ts, desktop/src/components/WorkflowBuilder/
  • Rust: crates/zclaw-pipeline/src/

TC-5-01 | Pipeline 列举发现(正常)

  • Step 58: 查看 Pipeline 列表
navigate(action='goto', url='tauri://localhost/pipelines')

Expected: 显示已有 Pipeline含 10 行业模板)

take_screenshot(filePath='docs/test-results/T5-pipeline/screenshots/TC-5-01-pipeline-list.png')

TC-5-02 | M6-02 验证: v1/v2 解析器分裂P1

V12 问题: pipeline_list 只用 v1 解析器v2 格式被静默丢弃

  • Step 59: 检查 v2 格式 Pipeline 是否显示
async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('pipeline_list', {});
  return JSON.stringify({ count: result?.length, names: result?.map(p => p.name) });
}

Expected (如未修复): 仅显示 v1 格式 Pipeline Expected (如已修复): v1 和 v2 格式都正确列举

TC-5-03 | Pipeline 执行(正常)

  • Step 60: 执行一个 Pipeline
click(selector_type='ref', selector_value='{pipeline_ref}')
click(selector_type='ref', selector_value='{execute_ref}')
wait_for(text=['completed', 'Running'], timeout_ms=60000)
take_screenshot(filePath='docs/test-results/T5-pipeline/screenshots/TC-5-03-execution.png')

TC-5-04 | Pipeline 监控(正常)

  • Step 61: 查看执行进度

Expected: 返回进度信息(百分比、当前步骤)

TC-5-05 | M6-01 验证: route_intent 未注册P1

V12 问题: route_intent Tauri 命令未注册

  • Step 62: 验证 IntentInput 组件

Expected (如未修复): IntentInput 报错或无响应 Expected (如已修复): IntentInput 返回推荐 Pipeline

TC-5-06 | Pipeline 取消(正常)

  • Step 63: 执行中取消 Pipeline

Expected: Pipeline 停止执行

TC-5-07 | M6-03 验证: pipeline_create Action 类型丢失(正常)

V12 问题: 只映射 Hand 类型,丢失 LLM/Parallel/Condition

  • Step 64: 创建包含多种 Action 类型的 Pipeline

Expected (如未修复): 非 Hand 类型步骤被映射为 Hand Expected (如已修复): 正确保留所有 Action 类型

TC-5-08 | Pipeline 导出(正常)

  • Step 65: 导出 Pipeline 配置

Expected: 导出为 YAML/JSON 格式

  • Step 66: Commit T5 测试结果
git add docs/test-results/T5-pipeline/
git commit -m "test(T5): pipeline workflow functional audit results"
git push

Chunk 4: T6 SaaS 集成 + T7 技能生态 + T8 智能对话

所有 execute_js 命令名需在执行时验证。


Task 6: T6 SaaS 桌面集成

V12 健康度: 85/100 | 风险: MEDIUM | V12 问题: M7-01~M7-06 (含 2 个 P1)

Files:

  • Audit: docs/features/audit-v12/M7-saas-desktop.md
  • Source: desktop/src/lib/saas-client.ts, desktop/src/store/saasStore.ts, desktop/src/components/SaaS/

TC-6-01 | SaaS 登录(正常)

  • Step 67: SaaS 登录流程

导航到 SaaS 登录页面,输入凭据登录。

Expected: 登录成功JWT Cookie 设置session 恢复

take_screenshot(filePath='docs/test-results/T6-saas-desktop/screenshots/TC-6-01-login.png')

TC-6-02 | M7-04 验证: refreshToken 未传 refresh_token bodyP1

V12 问题: Tauri 非浏览器可能无 cookie 自动附加

  • Step 68: 验证 token 刷新

等待 JWT 过期(或手动触发刷新),检查是否成功获取新 token。

Expected (如未修复): 刷新失败cookie 未附加) Expected (如已修复): 刷新成功

TC-6-03 | M7-02 验证: ConfigMigrationWizard PUT 路径参数错误P1

V12 问题: PUT 使用布尔值 exists 作为路径参数

  • Step 69: 触发配置迁移向导

Expected (如未修复): PUT 请求发送错误参数 Expected (如已修复): PUT 请求发送正确的 config item ID

TC-6-04 | 模型列表 + 聊天中继(正常)

  • Step 70: 通过 SaaS Relay 获取模型列表

Expected: 返回可用模型列表

  • Step 71: 通过 SaaS Relay 发送聊天消息

Expected: SSE 流式响应正确

TC-6-05 | 配置同步(正常)

  • Step 72: 配置 pull + diff + sync

Expected: 配置正确同步

TC-6-06 | M7-01 验证: 密码长度不一致(边界)

  • Step 73: 验证前端密码最少 6 字符 vs 后端 8 字符

Expected (如未修复): 前端允许 6 字符密码但后端拒绝 Expected (如已修复): 前后端统一为 8 字符

  • Step 74: Commit T6 测试结果
git add docs/test-results/T6-saas-desktop/
git commit -m "test(T6): SaaS desktop integration audit results"
git push

Task 7: T7 技能生态

V12 健康度: 85/100 | 风险: LOW | V12 问题: M5-01~M5-06 (含 1 个 P1)

Files:

  • Audit: docs/features/audit-v12/M5-skill-ecosystem.md
  • Source: desktop/src/lib/skill-discovery.ts, crates/zclaw-skills/src/, skills/ (75 SKILL.md)

TC-7-01 | M5-01 验证: tags 误映射为 triggersP1

V12 问题: convertFromBackend() 将 tags 映射为 triggers

  • Step 75: 检查技能列表中 tags 和 triggers 字段
async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('skill_list', {});
  const sample = result.slice(0, 5).map(s => ({
    name: s.name,
    tags: s.tags,
    triggers: s.triggers,
    category: s.category
  }));
  return JSON.stringify(sample);
}

对照 skills/*.SKILL.md 中的 frontmatter 验证 tags 和 triggers 是否正确映射。

Expected (如未修复): tags 值出现在 triggers 字段,真实 triggers 丢失 Expected (如已修复): tags 和 triggers 各自正确

TC-7-02 | 技能加载 + 解析(正常)

  • Step 76: 验证 75 个 SKILL.md 全部加载
async () => {
  const result = await window.__TAURI_INTERNALS__.invoke('skill_list', {});
  return JSON.stringify({ total: result.length });
}

Expected: 返回 75 个技能

TC-7-03 | 技能语义路由(正常)

  • Step 77: 测试语义路由匹配

发送一条消息触发技能路由,验证是否正确匹配到相关技能。

TC-7-04 | M5-02 验证: SKILL.md tools 字段未解析P2

  • Step 78: 检查 skill_list 返回值中是否有 tools 字段

Expected (如未修复): 技能对象中无 tools 字段 Expected (如已修复): 技能对象包含 tools 定义

TC-7-05 | M5-03 验证: Python 硬编码 python3边界

  • Step 79: 在 Windows 上执行 Python 模式技能

Expected (如未修复): Windows 上 python3 不存在,执行失败 Expected (如已修复): 自动检测 pythonpython3

TC-7-06 | 技能采样执行(正常)

  • Step 80: 采样执行 5 个不同执行模式的技能
执行模式 测试技能 预期
PromptOnly 任选 1 个 LLM 处理
Python 任选 1 个 Python 脚本执行
Shell 任选 1 个 Shell 命令执行

每个技能截图一张

  • Step 81: Commit T7 测试结果
git add docs/test-results/T7-skills/
git commit -m "test(T7): skill ecosystem audit results"
git push

Task 8: T8 智能对话

V12 健康度: 91/100 | 风险: LOW | V12 问题: M1-01~M1-11 (全部 P2/P3)

Files:

  • Audit: docs/features/audit-v12/M1-intelligent-chat.md

由于健康度最高91/100仅执行核心流程验证和已知 P2 问题抽样。

TC-8-01 | 流式聊天核心流程(正常)

  • Step 82: 发送消息验证流式响应
type_text(text='你好,请介绍一下你自己')
click(selector_type='ref', selector_value='{send_ref}')
wait_for(text=['AI', '助手', '你好'], timeout_ms=15000)

Expected: 流式响应正常显示

take_screenshot(filePath='docs/test-results/T8-chat/screenshots/TC-8-01-streaming.png')

TC-8-02 | 模型切换(正常)

  • Step 83: 切换模型并验证

在模型选择器中切换到不同的 Provider/模型,发送新消息。

Expected: 切换后使用新模型响应

TC-8-03 | 推理模式(正常)

  • Step 84: 启用推理模式发送消息

Expected: 显示推理过程ReasoningBlock

TC-8-04 | 工具调用链(正常)

  • Step 85: 触发工具调用的消息

Expected: 显示工具调用链ToolCallChain

TC-8-05 | 取消流(正常)

  • Step 86: 流式中取消

Expected: 取消成功,部分结果显示

TC-8-06 | 多 Provider 连通(正常)

  • Step 87: 逐一验证可用 Provider

对每个已配置的 Provider 发送一条测试消息。

Expected: 每个返回有效响应或明确的配置错误

TC-8-07 | Markdown 渲染(正常)

  • Step 88: 请求 Markdown 格式回复
type_text(text='请用 Markdown 格式列出 5 个编程语言的特点')

Expected: 代码块、列表、表格等正确渲染

  • Step 89: Commit T8 测试结果
git add docs/test-results/T8-chat/
git commit -m "test(T8): intelligent chat audit results"
git push

Chunk 5: T9 Admin V2 + T10 安全 + T11 SaaS API + T12 端到端


Task 9: T9 Admin V2 管理后台

V12 健康度: 82/100 | 风险: MEDIUM | V12 问题: M8-01~M8-08 (P2/P3)

Files:

  • Audit: docs/features/audit-v12/M8-admin-v2.md
  • Source: admin-v2/src/pages/ (15 页面), admin-v2/tests/ (~71 测试)
  • Config: admin-v2/vitest.config.ts

TC-9-01 | Admin 登录(正常)

  • Step 90: 登录 Admin V2

在浏览器中打开 Admin V2默认 http://localhost:5174使用管理员凭据登录

Expected: 登录成功Cookie 设置正确

TC-9-02 | 15 页面 CRUD正常

  • Step 91: 逐一验证 15 个页面加载
页面 测试操作 预期
Dashboard 查看概览 数据正常显示
Accounts 查看/编辑账户 CRUD 正常
ModelServices CRUD 操作 模型配置正确保存
Relay 查看中继任务 列表显示
Billing 查看计费 信息显示
Logs 查看日志 分页正常
Prompts CRUD + 版本 版本历史正确
Roles CRUD 角色权限正确
Knowledge CRUD + 搜索 FTS5 搜索工作
ScheduledTasks CRUD 调度配置正确
AgentTemplates CRUD 模板保存正确
Usage 查看 统计图表显示
Config 查看/编辑 配置同步
Login 登录/登出 认证流程完整

每个页面截图一张。

TC-9-03 | M8-02 验证: Relay 缺 retry正常

  • Step 92: 检查 Relay 页面是否有重试按钮

Expected (如未修复): Relay 任务只有查看,无重试操作 Expected (如已修复): 有重试按钮

TC-9-04 | 5 页缺失测试验证(正常)

  • Step 93: 确认 5 个缺测试页面的状态
缺测试页面 验证方式
Billing 手动 CRUD 测试
ConfigSync 手动同步测试
Knowledge FTS5 搜索测试
Roles CRUD + 权限测试
ScheduledTasks CRUD 测试

TC-9-05 | TOTP 验证(正常)

  • Step 94: Admin 账户设置 TOTP

Expected: QR 码显示TOTP 验证通过

TC-9-06 | M8-03 验证: ROLE_PERMISSIONS 硬编码(边界)

  • Step 95: 验证前端权限是否与后端同步

Expected (如未修复): 前端硬编码权限与后端可能不一致 Expected (如已修复): 权限从 API 动态获取

  • Step 96: Commit T9 测试结果
git add docs/test-results/T9-admin/
git commit -m "test(T9): admin V2 audit results"
git push

Task 10: T10 通信与安全

V12 健康度: 86/100 | 风险: LOW | V12 问题: M9-01~M9-09 (P2/P3)

Files:

  • Audit: docs/features/audit-v12/M9-communication-security.md

TC-10-01 | 三模式连接验证(正常)

  • Step 97: 验证 Kernel 模式连接

Expected: Tauri invoke 正常工作

  • Step 98: 验证 SaaS Relay 模式连接

Expected: HTTP Cookie + SSE 正常

TC-10-02 | M9-01/M9-02 验证: require() 混用P2

  • Step 99: 检查 SaaS Relay 分支是否使用 require()

在浏览器控制台观察是否有 CommonJS 错误。

Expected (如未修复): ESM+Vite 环境下 require() 报错 Expected (如已修复): 使用 await import() 替代

TC-10-03 | 安全基线验证(正常)

  • Step 100: 运行安全相关 cargo test
cargo test --workspace -- security 2>&1 | tee docs/test-results/T10-security/cargo-security.txt

Expected: 安全测试全部通过

TC-10-04 | JWT/TOTP/限流验证(正常)

  • Step 101: 验证 JWT password_version 机制

修改密码后,旧 JWT 应失效。

  • Step 102: 验证登录限流5次/分钟)

快速尝试 6 次登录。

Expected: 第 6 次被限流拒绝

  • Step 103: Commit T10 测试结果
git add docs/test-results/T10-security/
git commit -m "test(T10): communication and security audit results"
git push

Task 11: T11 SaaS 后端 API

V12 健康度: N/A | 风险: MEDIUM | 无 V12 审计报告

Files:

  • Source: crates/zclaw-saas/src/ (12 modules + workers), crates/zclaw-saas/tests/

TC-11-01 | SaaS 集成测试基线(正常)

  • Step 104: 运行 SaaS 集成测试
cd crates/zclaw-saas && cargo test 2>&1 | tee ../../../docs/test-results/T11-saas-api/cargo-test.txt

Expected: 全部 pass

TC-11-02 | 核心 API 端点抽样验证(正常)

  • Step 105: 验证关键端点
端点 方法 预期
/api/v1/auth/login POST 返回 JWT
/api/v1/auth/me GET 返回用户信息
/api/v1/relay/models GET 返回模型列表
/api/v1/relay/chat/completions POST SSE 流
/api/v1/admin/accounts GET 返回账户列表
/api/v1/admin/dashboard/stats GET 返回统计数据

每个端点用 curl 验证:

# 示例
curl -s -X POST http://localhost:8080/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"test"}' | jq .

TC-11-03 | 权限检查验证(正常)

  • Step 106: 验证非管理员无法访问 admin 端点

Expected: 返回 403 Forbidden

TC-11-04 | 数据库迁移验证(正常)

  • Step 107: 验证数据库 schema 版本
PGPASSWORD=zclaw psql -h localhost -U zclaw -d zclaw -c "SELECT * FROM _schema_version;" 2>&1

Expected: schema_version = 14当前版本

  • Step 108: Commit T11 测试结果
git add docs/test-results/T11-saas-api/
git commit -m "test(T11): SaaS backend API audit results"
git push

Task 12: T12 端到端用户场景

V12 健康度: N/A | 风险: HIGH | 跨模块集成

TC-12-01 | E2E-01: 新用户首次对话

  • Step 109: 完整新用户对话流程
  1. 打开应用 → 首次引导
  2. 选择模型 → 发送消息
  3. 验证流式响应

涉及模块: T8, T3, T7

take_screenshot(filePath='docs/test-results/T12-e2e/screenshots/TC-12-01-first-chat.png')

TC-12-02 | E2E-02: Agent 创建与使用

  • Step 110: 创建 Agent → 配置 → 切换 → 验证身份

涉及模块: T3, T8, T2

TC-12-03 | E2E-03: Hand 触发与审批

  • Step 111: 对话中触发 Hand → 审批 → 查看结果

涉及模块: T1, T2, T8

TC-12-04 | E2E-04: SaaS 登录与订阅

  • Step 112: SaaS 登录 → 订阅状态 → 配置同步

涉及模块: T6, T10

TC-12-05 | E2E-05: Pipeline 创建与执行

  • Step 113: 创建 Pipeline → 配置 → 执行 → 导出

涉及模块: T5, T1

TC-12-06 | E2E-06: 记忆与反思闭环

  • Step 114: 多轮对话 → 记忆提取 → 验证存储 → 反思触发

涉及模块: T2, T3, T8

TC-12-07 | E2E-07: Admin 管理全流程

  • Step 115: Admin 登录 → 管理 → 配置 → 日志

涉及模块: T9, T11

TC-12-08 | E2E-08: 离线与重连

  • Step 116: 断开 SaaS 后端 → 离线模式 → 恢复 → 重连
  1. 关闭 SaaS 后端进程
  2. 验证应用降级到 Kernel 模式
  3. 恢复 SaaS 后端
  4. 验证自动重连

涉及模块: T1, T2, T6, T8

TC-12-09 | E2E-09: 课堂场景播放

  • Step 117: 进入课堂 → 播放 → TTS → 白板 → 笔记

涉及模块: T4, T1

TC-12-10 | E2E-10: 技能发现与执行

  • Step 118: 浏览技能 → 安装 → 触发 → 验证结果

涉及模块: T7, T8

TC-12-11 | 回归验证

  • Step 119: 重新运行基线测试
cargo test --workspace 2>&1 | tee docs/test-results/T12-e2e/regression-cargo.txt
cd desktop && pnpm vitest run 2>&1 | tee ../docs/test-results/T12-e2e/regression-vitest.txt
cd admin-v2 && pnpm vitest run 2>&1 | tee ../docs/test-results/T12-e2e/regression-admin.txt

Expected: 通过率不低于基线

  • Step 120: 生成最终缺陷清单

docs/test-results/DEFECT_LIST.md 中汇总所有 T1-T12 发现的缺陷:

  • P0 缺陷数(目标: 0

  • P1 缺陷数(目标: <= 2

  • P2/P3/P4 缺陷列表

  • Step 121: 生成上线评估报告

docs/test-results/RELEASE_READINESS.md 中对照达标标准:

强制达标项 标准 结果
P0 缺陷 0 ?
P1 缺陷 <= 2 ?
核心流程通过 100% ?
自动化测试 全部通过 ?
安全 无 HIGH 缺陷 ?
  • Step 122: Commit 最终结果
git add docs/test-results/
git commit -m "test: complete pre-launch functional audit T1-T12"
git push

执行总结

测试用例统计

模块 风险 测试用例数 预计时间
T0 环境准备 - 11 步 0.5 天
T1 Hands HIGH 23 用例 1 天
T2 智能层 HIGH 13 用例 1 天
T3 Agent HIGH 12 用例 0.5 天
T4 课堂 HIGH 12 用例 0.5 天
T5 Pipeline MEDIUM 8 用例 0.5 天
T6 SaaS 集成 MEDIUM 6 用例 0.5 天
T7 技能 LOW 6 用例 0.5 天
T8 对话 LOW 7 用例 0.5 天
T9 Admin MEDIUM 6 用例 0.5 天
T10 安全 LOW 4 用例 0.5 天
T11 SaaS API MEDIUM 4 用例 0.5 天
T12 E2E HIGH 11 用例 1.5 天
总计 ~123 用例 8-10 天

注: 实际用例数 ~123 低于 spec 估计的 170-230因为本计划聚焦于 V12 已知问题验证和核心流程测试,而非穷举测试。每个模块的边界和异常用例可在执行中根据发现的问题补充。

执行顺序

Phase 1: Task 0 (环境准备) → 阻塞门控
Phase 2: T1 → T2 → T3 → T4 (高风险模块)
Phase 3: T5 → T6 → T7 → T8 → T9 → T10 → T11 (中低风险)
Phase 4: T12 (E2E 集成)
最终: DEFECT_LIST.md + RELEASE_READINESS.md

上线达标门控

在 Phase 2 完成后T1-T4检查

  • P0 缺陷 = 0
  • P1 缺陷 <= 2
  • 聊天/Agent CRUD/Hand 触发/SaaS 登录 4 条主路径通过

如果未达标,暂停 Phase 3优先修复 P0/P1。