Files
zclaw_openfang/docs/superpowers/specs/2026-04-21-core-chain-hardening-design.md
iven 751ec000d5
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(specs): 核心链路硬化设计文档 — 缝测试+胶水层瘦身方案
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 21:04:22 +08:00

6.3 KiB
Raw Blame History

核心链路硬化设计文档

2026-04-21 | 状态: 实施中 | 计划文件: plans/skill-mellow-valiant.md

1. 问题定义

ZCLAW 经过 20+ 轮审计修复,仍频繁发现功能链路断链。根因不是"Bug 修不完",而是 系统复杂度超出了可验证范围

  • 190 个 Tauri 命令 × 137 个 API 端点 × 15 层中间件 = 数千个集成点
  • 手动审计永远无法覆盖全部集成点

1.1 胶水层诊断

架构骨架健康crate 分层无环、中间件设计优雅),但 3 个"胶水点"是断链重灾区:

胶水点 文件 行数 问题
Tauri 命令层 desktop/src-tauri/src/kernel_commands/chat.rs 548 业务逻辑未下沉,agent_chat_stream ~390行
流式状态管理 desktop/src/store/chat/streamStore.ts 886 sendMessage ~397行嵌套回调依赖 5 个 Store
连接管理 desktop/src/store/connectionStore.ts 891 连接 + 模型配置 + 网关生命周期混杂

1.2 影响范围

断链集中在 3 条核心链路:

  1. 对话链路 — 用户消息 → 流式响应 → 消息持久化
  2. Hands 链路 — LLM tool_call → Hand 注册分发 → 执行回调 → 结果回传
  3. 记忆链路 — 对话 → 经验提取 → FTS5 存储 → 检索 → system prompt 注入

2. 方案设计

2.1 策略:先建安全网再瘦身

混合路径,避免"边修边破"

Phase 1 (Week 1): 缝测试安全网 — 自动检测断链
Phase 2 (Week 2): 瘦身 chat.rs — 消除 Rust 侧 Bug 温床
Phase 3 (Week 3): 瘦身 Store 层 — 消除前端侧 Bug 温床
Phase 4 (Week 4): 全量冒烟验证 — 建立发布前信心基线

2.2 缝测试策略

"缝测试"(seam test) 验证的是集成点之间的契约,不是单元行为:

[Store] --缝1--> [Tauri invoke] --缝2--> [Kernel] --缝3--> [LLM Driver] --缝4--> [UI Event]

每个缝测试只验证一个集成点的输入/输出格式是否正确。

MockLlmDriver已有

crates/zclaw-runtime/src/test_util.rs 已包含完整的 MockLlmDriver

  • Builder 风格响应队列:with_text_response(), with_tool_call(), with_error()
  • 调用检查:call_count(), last_request()
  • 流式模拟:默认发射 TextDelta("mock stream") + Complete
  • 线程安全:Arc<Mutex<>> + AtomicUsize

无需新建,只需在集成测试中引用。

2.3 缝测试清单

对话链路4 缝)

位置 验证内容
Store→Tauri Vitest (mock invoke) sendMessage() 调用参数格式正确
Tauri→Kernel Rust 集成测试 chat_command 正确转发给 kernel
Kernel→LLM Rust 集成测试 中间件处理后 prompt 正确传递给 MockLlmDriver
LLM→UI Rust + Vitest 事件顺序: delta → delta → complete

Hands 链路3 缝)

位置 验证内容
工具路由 Rust 集成测试 LLM tool_call → HandRegistry 正确分发
执行回调 Rust + Vitest Hand 完成 → Tauri event → Store 收到结果
Approval Rust 集成测试 needs_approval=true → 确认后继续

记忆链路3 缝)

位置 验证内容
提取存储 Rust 集成测试 对话 → 经验提取 → FTS5 写入
检索注入 Rust 集成测试 新对话 → FTS5 检索 → system prompt 包含记忆
去重 Rust 集成测试 同一经验不重复存储

2.4 chat.rs 瘦身方案

agent_chat_stream~390行从 Tauri 命令层下沉到 kernel/runtime

下沉项 当前位置 目标位置
调度拦截 chat_command 内联 kernel chat_stream()
会话守卫 chat_command 内联 kernel SessionGuard
事件翻译 LoopEvent→StreamChatEvent 内联 runtime StreamEventTranslator
Intelligence Hooks chat_command 内联 kernel chat_stream()

预期效果:chat.rs 548→~200行Tauri 命令层只做参数验证和调用转发。

2.5 Store 层瘦身方案

streamStore.sendMessage 拆分(~397行 → 5 个函数)

sendMessage() → startStream() + bufferDeltas() + handleToolCalls() + handleHandEvents() + completeStream()

connectionStore 拆分891行 → 3 个 Store

新 Store 职责 预计行数
connectionStore 只管连接状态 ~300
modelConfigStore 模型列表 + 当前模型 + API Key ~300
gatewayStore 外部网关 start/stop/restart ~300

3. 执行时间线

Phase 交付物 验证标准
W1 缝测试 13 缝测试 + 3 冒烟测试 能自动检测 3 条核心链路断链
W2 chat.rs 瘦身 chat.rs 548→~200行 所有缝测试 + 987 Rust 测试通过
W3 Store 瘦身 streamStore 886→~300行, connectionStore 拆分 3×~300行 所有缝测试 + 前端测试通过
W4 全量验证 发布前信心基线 全量测试 + 生产构建 + 手动验证

4. 约束

  • 不新增功能 — 只做内部重组和测试覆盖
  • 不新增 API 端点 — 稳定化约束
  • 不新增 Tauri 命令 — 只瘦身已有命令
  • 每步验证 — 重构前先有缝测试,重构后验证通过
  • 立即提交 — 每完成一个独立工作单元立即 commit + push

5. 验证命令

# Rust 全量
cargo test --workspace --exclude zclaw-saas

# 缝测试(新增)
cargo test -p zclaw-kernel --test chat_chain --test smoke_chat --test smoke_hands
cargo test -p zclaw-growth --test memory_chain --test smoke_memory
cargo test -p zclaw-runtime --test hand_chain

# 前端全量
cd desktop && pnpm vitest run

# 前端缝测试(新增)
cd desktop && pnpm vitest run chat-seam hand-seam

# 类型检查
pnpm tsc --noEmit
cargo check --workspace --exclude zclaw-saas

# 生产构建
pnpm build

6. 风险与缓解

风险 概率 缓解
缝测试发现新断链 Phase 1 的目的就是发现断链,发现后立即修复
chat.rs 下沉破坏现有功能 缝测试作为安全网,每步验证
Store 拆分导致 import 风暴 逐步迁移,保留旧 Store re-export
测试环境搭建复杂 MockLlmDriver 已就绪FTS5 用临时文件