- Unify ToolResultEnvelope (output vs content) for built-in tools - Fix shell.run AsyncGenerator consumption in ToolRegistry.call/streaming - Scheduler: consume WorkerResult.status instead of marking all running tasks completed - WorkerProcess/WorkerManager: surface exit events and generate failed/cancelled result - MainAgent: integrate ContextAssembler, Chinese destructive regex, ArchitectureDesigner impact gate - run.ts: pendingConfirmation flow, dispatch extracted, .air files filtered from /results - CapabilityRegistry wired into RuntimeApp and ServiceRegistry; DoctorService uses it - release.ts: findRepoRoot/findBun, run air e2e + depcruise + runtime regression - New gates: release-critical-gates, CLI run command regression - 14/14 e2e gates pass; 3/3 release dry-run pass Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9.2 KiB
Executable File
集成测试阶段 MiniMax-M3 审查结果
审计日期: 2026-06-05 项目: AirCoding V1.0.0 Alpha 审计员: MiniMax-M3 (整合阶段) 审计模式: 四视角交叉审计(系统架构师 / 开发工程师 / 真实用户 / 测试工程师)
0. 核心矛盾 (E2E Gates 失真)
13/13 E2E gates 全部通过,但用户视角测试真实任务成功率近乎为零。
| 维度 | 表现 |
|---|---|
| tsc typecheck | 0 errors |
| 单元测试 | 169/169 passed |
| E2E gates | 13/13 passed |
| 真实用户场景 | 多数失败 |
E2E gates 仅验证"测试能跑通"和"组件存在",从未验证"用户场景成功"。所有 gate 仅检查语法、类型、stub 数量、单元测试通过率;没有一项 gate 验证"LLM 调通 + 文件真的写出 + 多步骤任务真完成"。
1. 系统架构师审查
FR-005 (Main Agent 对话) — 部分实现
MainAgent.chat_with_llm() 每次调用仅构造 system+user 两条消息,无 conversation history,无 context reference,无 Anthropic canonical content blocks——严重违反 FR-014 上下文分层。
追问"现在什么情况"时,LLM 没有上下文,是 stateless 单轮调用,必然幻觉。
FR-016 (TUI) — 不支持交互输入
TuiApp.setup_input 只处理 q/1/2/3/4/h 键盘事件,无文本输入路径。run.ts 用 readline 在 TUI 之外独立处理 stdin,TUI 和 CLI 互相竞争字符。TUI 实际是只读 viewer,不能输入任务。
FR-007/008 (Scheduler/Worker) — 链路通但判定错误
Worker 真实 spawn,IPC 真实 NDJSON,tool.call / llm.request 通过 IPC 回父进程由 ProviderManager 真实调用 LLM——链路是通的。
但 Scheduler.step 的 MONITORING 状态存在严重 bug:worker 还在跑就 mark completed,任务可能"假完成"。
FR-009 (执行原语) — 不强制 read-before-edit
ExecutorRole 直接接受代码块写入,不强制 read-before-edit——违反 FR-009。run.ts 的"扫描最近 60 秒修改的文件"是 post-hoc 发现,不验证文件来源、不执行 verification-before-completion。
FR-017 (C++ 完整闭环) — 工具链与主链路不联动
toolchain-cpp 实现了 cpp.detect / cpp.build / cpp.test 工具,但无 fixture 项目、无自动 configure→build→test→fix→review e2e 集成。Executor 用 fs.write 写 C++ 源文件,不调用任何 cpp. 工具*。C++ 工具链对用户不可见地存活,但与主链路不联动。
未对齐设计的关键差异
| 设计 | 实际 |
|---|---|
| ProjectionStore 消费 DB+EventBus | run.ts 直接 receive_snapshot 构造假数据绕开 EventStore |
| 严格状态机 12 态 | 真实遍历,但 MONITORING 完成判定错误 |
| 5 角色独立 worker | Debugger/Compactor/ExperienceMiner 未被 run.ts 触发 |
| Anthropic canonical messages | MainAgent 用 string content,非 content block[] |
2. 开发工程师 Bug 报告
P0 阻塞 (2)
Bug #2 — Scheduler 早判完成 (Scheduler.ts:252-260)
当 worker_manager.has_running() === false 时,将所有 running 状态任务直接标记为 completed,不管 worker 是否实际成功。失败任务可能显示为成功。
Bug #6 — MainAgent 确认门形同虚设 (run.ts:108-112)
MainAgent.classify() 对"delete/remove"类消息返回 {action: 'delegate', response: 'Are you sure? (y/n)'},但 run.ts:115 直接 console.log classification.response 并 rl.prompt()——用户的 y/n 永远到不了 MainAgent.handle_confirmation()。破坏性操作无防护。
P1 重要 (3)
Bug #3 — ExecutorRole 转义顺序错误 (ExecutorRole.ts:222)
代码块内容转义还原顺序:\\n → \n, \\t → \t, \\" → ", \\\\ → \\。若 LLM 输出 \n(单反斜杠 n),会被错误地换成真换行,破坏 JSON/Python 字面量。
Bug #4 — MainAgent 不带上下文 (MainAgent.ts:73)
chat_with_llm(message) 只发送单轮 system + user。追问"现在什么情况"时,LLM 不知道项目里有啥。
Bug #5 — DONE 竞态 (ask.ts:182-186)
若 LLM 单次输出既有 fs.write 又有 DONE,执行完 tool_call 后立即返回 completed。剩余未完成的 acceptance_criteria 被静默忽略。
Bug #7 — 多文件任务漏写
第一次写到 src/main.cpp(正确),第二次写到根 main.cpp(简化版 stub)。两个 task 缺乏协调。
P2 nice-to-have (2)
- Bug #1 — 退出码误判 (WorkerProcess.ts:127):
code || 1误判为错误 - Bug #8 —
has_running误判 (WorkerManager.ts:303-305):ready状态也算 running
3. 真实用户测试报告 (UAT)
| 用例 | 状态 | 关键现象 |
|---|---|---|
air init |
✅ PASS | 创建 .air/ 目录和 project.json |
air ask "..." 写文件 |
✅ PASS | fs.write 工作 |
| TUI 启动 | ✅ PASS | OpenTUI 渲染正确 |
air doctor |
✅ PASS | 检测 bun/sqlite/git/shell |
| shell.run 任意命令 | ❌ FAIL | 10/10 次返回 Error: undefined |
| 追问项目内容 | ❌ FAIL | LLM 答"我没有文件系统访问" |
| 危险操作 (删除) | ❌ FAIL | 静默通过,文件仍在 |
| false-positive 成功 | ❌ FAIL | tool 报错但 CLI 仍打印 ✅ |
| 多文件 C++ 任务 | ❌ FAIL | main.cpp 内容退化为 stub |
air doctor --fix |
❌ FAIL | 标 [fixable] 不修 |
用户最痛 3 个问题
- shell 工具整体坏死,让 AI 跑任何命令都失败 10/10 次。
- 报错说"成功",实际没干——用户以为工作流跑通了,回头看磁盘空的。false-positive 比直接报错危险十倍。
- TUI 和 CLI 是两套东西,
air ask能用工具,air runTUI 输入路径不可见(实际仅 readline 跑,渲染层 OK 但端到端未跑通)。
4. QA 测试矩阵
| Test | 状态 | 关键观察 |
|---|---|---|
| 1: 简单文件创建 | PASS | hello.txt 创建成功,内容正确。Worker stderr 异常但不影响产出。 |
| 2: 多文件 (C++ + CMake) | PARTIAL | main.cpp 内容退化为 stub,CMakeLists.txt 正确。两文件被写到不同位置 |
| 3: 追问项目内容 | FAIL | agent.handle_user_message("我的项目有哪几个文件?") 走 answer 分支,LLM 幻觉 |
| 4: TUI 启动 | PASS | OpenTUI 渲染正确,状态栏正常 |
| 5: E2E gates | PASS | 13/13 (但 gates 与用户场景脱节) |
5. 用户核心痛点 (按严重度排序)
| 排名 | 问题 | 严重度 | 触发场景 |
|---|---|---|---|
| 1 | shell.run 工具完全坏死 | P0 阻塞 | 任何命令执行 (编译、运行、git) |
| 2 | 追问上下文失效 (LLM 答"我没文件系统") | P0 阻塞 | 完成任务后问"现在什么情况" |
| 3 | 危险操作无 confirmation 路由 | P0 安全 | 删除、覆盖文件 |
| 4 | Scheduler 早判完成 (假完成) | P0 阻塞 | 多步任务 |
| 5 | TUI 无文本输入路径 | P0 用户体验 | TUI 实际只读 |
| 6 | 多文件任务漏写 / 覆盖 | P1 | 复杂任务 |
| 7 | false-positive 成功 banner | P1 | 任何报错场景 |
| 8 | DONE 竞态导致提前退出 | P1 | LLM 同 turn 输出 tool+DONE |
| 9 | ExecutorRole 转义顺序错误 | P1 | LLM 输出含 \n 字符 |
| 10 | 退出码误判 (stderr 噪音) | P2 | 排查时迷惑 |
6. 根因分析
E2E gates 框架本身存在结构性缺陷:
- 仅做静态检查:tsc/depcruise/单元测试
- 不做端到端真实任务验证
- 缺"用户成功完成一个 C++ 任务"等综合场景 gate
需要新增的 gates:
- 真实 LLM 端到端任务完成
- 多文件任务产出验证
- shell.run 工具真实执行
- 上下文追问验证
- 危险操作 confirmation 验证
7. 修复建议 (按优先级)
立即修复 (P0, 阻塞发布)
- 修复
shell.runAsyncGenerator 序列化问题 - 修复 Scheduler MONITORING 早判完成 bug
- MainAgent 注入工具/项目上下文到 LLM 调用
- 修复 confirmation 路由 (run.ts → MainAgent.handle_confirmation)
- TUI 增加文本输入路径 (或移除 TUI 包装直接 CLI)
必须修复 (P1, 关键)
- ExecutorRole 转义顺序
- DONE 竞态检测
- 多文件任务协调 (检查文件已存在)
- Tool 失败时正确报失败 (false-positive 修复)
- 真实集成测试加入 E2E gates
长期改进 (P2)
- 退出码误判
- has_running 误判
- Worker stderr 去噪
- Anthropic canonical content blocks 完整支持
8. 综合判断
V1.0.0 Alpha 不应发布。
- 13/13 E2E gates passed 但用户场景真实成功率极低——这是 E2E gate 设计缺陷
- 5 个 P0 问题中,3 个是用户每次使用都会触发的(shell 坏死、追问失效、确认门失效)
- C++ 工作流工具链与主链路未联动,FR-017 名存实亡
- TUI 渲染层 OK 但无输入路径,FR-016 名存实亡
修复 P0 后必须用真实任务重新端到端测试,而不是用 E2E gates 替代。需要在 E2E gates 框架中加入"真实 LLM 任务闭环"维度,否则同样的审计盲点会再次出现。
核心教训: 代码质量指标 (tsc/stub 数/单元测试) 与用户可用性指标是正交的。质量分高 ≠ 产品可用。后续每个审计必须包含真实任务端到端测试作为硬性 gate。