Files
AirCoding/集成测试阶段Deepseek审查结果.md
AirCoding ddefcbb2b1 fix: integrate audit findings round 1 - tools, worker, scheduler, main agent
- 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>
2026-06-05 18:39:10 +08:00

277 lines
16 KiB
Markdown
Executable File
Raw Permalink 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.
# 集成测试阶段 Deepseek 审查结果
**审计日期**: 2026-06-05
**项目**: AirCoding V1.0.0 Alpha
**审计模式**: 四视角交叉审计(系统架构师 / 开发工程师 / 真实用户 / 测试工程师)
---
## 0. 前置验证
**TypeScript 类型检查**: PASS (0 errors)
**E2E Gates**: 13/13 PASS
---
## 1. 系统架构师审查报告
### 一、实际运行验证结果
三项测试全部通过:
- **Test 1 (tsc)**: 零类型错误17 个 contracts 文件完整
- **Test 2 (E2E gates)**: 13/13 通过,覆盖 P0 monorepo/depcruise/tsc + P1-P8 回归测试 + SEC 命令注入 + CAP 能力信任
- **Test 3 (集成测试)**: RuntimeApp 启动成功MainAgent regex 正确将 "Create hello.txt" 路由为 delegateScheduler 调度完成,文件真实创建(内容 "HELLO from AirCoding"39 个工具注册完毕fs.read/fs.list 正确返回
### 二、FR 实现情况
#### 真正实现的 FR完整端到端链路可通
| FR | 描述 | 实现状态 |
|----|------|----------|
| FR-001 | CLI 启动与项目初始化 | ✅ runCommand 含 auto-init、项目检测 |
| FR-002/003 | 项目本地状态与 Session 持久化 | ✅ SQLite session.db + 16 Repository |
| FR-005 | Main Agent 15 状态机 + 分类 | ✅ regex/llm 双模式 + chat_with_llm |
| FR-007 | Scheduler 13 状态机 + TaskGraph | ✅ 完整状态链 + WavePlanner/RetryPlanner |
| FR-008 | 5 种 Worker Agent + NDJSON IPC | ✅ Executor/Reviewer/Debugger/Compactor/ExperienceMiner |
| FR-009 | 执行原语 (code block + tool_call 解析) | ✅ ExecutorRole.parse_actions 三种解析模式 |
| FR-010 | ToolRegistry 39 工具 | ✅ fs/shell/git/cpp/project/artifact 全覆盖 |
| FR-013 | Provider 层 (Anthropic + OpenAI-compatible) | ✅ 适配器边界清晰 |
#### 名存实亡的 FR结构存在但深度不足
| FR | 描述 | 问题 |
|----|------|------|
| FR-004 | 事件驱动运行时 | EventBus/Store/Ingestor 类齐全,但 run.ts 同步阻塞 push Scheduler未真正依赖事件总线驱动状态流转 |
| FR-006 | Architecture Designer | 影响评估类完整,但 MainAgent.classify() 路由到 delegate 时从未调用 ArchitectureDesigner——架构审查是死代码 |
| FR-011 | Permission/Security | PermissionEngine 六层模型存在,但 ToolRegistry.call() 未显示逐调用通过 PermissionEngine 评估的证据 |
| FR-012 | Plugin/Capability Foundation | CapabilityRegistry 存在但运行时未深入集成 |
| FR-016 | TUI/HUD | TuiApp.ts 渲染 ANSI 视图,但 run.ts 手工推送构造数据而非 ProjectionStore 作为单一可信源 |
| FR-017 | C++ 工作流 | cpp.* 工具存在但 debug→fix→review 证据闭环未端到端验证 |
### 三、架构基线遵守评估
**遵守良好**:
- 依赖方向正确tui 不 import runtimedepcruise 零违规
- IPC 协议正确NDJSON over stdioworker.ready 握手heartbeat 心跳
- contracts 包独立17 个文件覆盖所有核心类型
**关键偏离**:
1. **依赖边界**: runtime/cli 直接依赖 @aircoding/llm 创建适配器——架构基线要求 runtime 通过接口间接使用 llm
2. **事件驱动承诺未兑现**: 基线 §6 声明 "AirCoding is event-driven",但主循环是同步 pull 模式
3. **TUI 消费方式偏离**: 基线 §18 要求 "HUD/TUI consumes ProjectionStore only",但 TuiApp 接收手工 snapshot 而非 ProjectionStore hydrate/apply
### 四、状态机评估
**Scheduler 状态机** (13 状态): 逻辑完整但 `MONITORING` 状态存在竞态——200ms 轮询 vs 事件驱动等待,`has_running()``graph.update_status` 之间的窗口可能导致假完成。
**MainAgent 状态机** (15 状态): `CONFIRMING` 状态仅在 regex 检测 breaking 词时触发,但确认回调在 run.ts 中断裂。`ARCHITECTURE_DESIGNING``ARCHITECTURE_REVISING` 状态无实际触发路径。
### 五、架构师结论
V1.0.0 Alpha 已实现核心能力闭环CLI→MainAgent→Scheduler→Worker→LLM→Tool→File 的完整链路可以跑通并创建真实文件。三个关键缺口:**(a)** Architecture Designer 是死代码,**(b)** PermissionEngine 未在 ToolRegistry 调用路径中逐次生效,**(c)** Scheduler 轮询等待对长任务存在竞态窗口。
---
## 2. 开发工程师审计报告
### P0 问题
**1. BuiltInToolRegistrar 中 18 个工具的结果形状不一致** (`create_real_executor.ts:175-437`)
`create_real_executor` 返回 `{ status, call_id, tool_name, type, content, metadata }`,但正确的 ToolResultEnvelope 形状使用 `output` 而非 `content`。影响fs.stat, process.kill, cpp.detect, cpp.build, cpp.test, doctor.run, project.scan, debug.run, gui.screenshot, network.capture 等。
WorkerManager 第 191 行执行 `result.output || result.error || {}`——**每个通过 worker IPC 调用这些工具的任务都会收到空内容 `{}`**。ExecutorRole 的 LLM 循环看不到任何工具输出,导致每项任务崩溃或无限循环。
### P1 问题
**2. shell.run 生成器未被解包** (`shell/index.ts`)
`createShellExecutor` 返回 `async function*`。ToolRegistry.execute_branch 直接调用执行器并返回结果——对生成器函数来说,返回的是生成器对象而非 ToolResultEnvelope。WorkerManager 会再次回退到 `{}`。**shell 命令无法通过 worker chain 工作。**
**3. MainAgent.classify_via_llm API 不匹配** (`MainAgent.ts:185`)
`classify_via_llm` 调用 `this.provider_manager.complete(...)`,但 run.ts 创建的提供者只挂接了 `complete_text`。如果 `classify_mode: 'llm'``provider_manager.complete is not a function` 会导致崩溃。
**4. Scheduler DISPATCHING 缺少 await** (`Scheduler.ts:163`)
`this.worker_manager.spawn(...)` 没有 `await`——方法返回 Promise但计划程序立即进入 MONITORING。worker 进程在调度程序检查 `has_running()` 时可能尚未准备好,任务被错误标记。
### P2 问题
**5. 资源泄漏**: run.ts progressInterval 在 run_until_idle() 拒绝时永不清理
**6. 空 catch 块**: scanDir 中的 `catch {}` 默默丢弃所有文件系统错误
**7. 延迟浪费**: Scheduler.step() 使用 setTimeout(r, 200) 轮询而非事件驱动
**8. require() 调用**: DoctorService.check_capability_deps 使用同步 require('child_process') 而非静态导入
### 用户可感知的核心影响
用户输入 "创建一个 C++ hello world 程序"MainAgent 正确分类委托Scheduler 调度到 DISPATCHINGWorker 启动并调用 LLM。LLM 响应代码块ExecutorRole 调用 fs.write成功然后 LLM 调用 cpp.detect通过 IPC。WorkerManager 收到成功结果但提取 `result.output` 为 undefined向 worker 发送 `{}`。LLM 看不到工具输出困惑重试15 轮后被 BLOCKED。用户只看到 "Task blocked" 而没有文件。**根本原因是形状不一致——约 50% 的工具注册表通过 worker 路径被静默破坏。**
---
## 3. 真实用户测试报告
### 测试结果汇总
| 测试 | 命令 | 结果 | 关键观察 |
|------|------|------|----------|
| Test 1 | `air init` | **PASS** | 创建 6 个子目录 + project.jsonproject_id 自动生成 |
| Test 2 | `air doctor` | **PASS** | 5/6 检查通过project_structure 报 FAIL缺少 package.json/tsconfig.json标记为 fixable |
| Test 3 | `air ask 创建hello.txt` | **PASS** | 委托模式正常工作1 轮完成,文件内容正确 (HelloWorld, 10 bytes) |
| Test 4 | `air ask C++项目` | **部分通过** | main.cpp 和 CMakeLists.txt 创建成功,但 `cpp.build``shell.run` 报错LLM 却声称 "程序已成功编译" |
| Test 5 | `air run TUI` | **PASS** | TUI 渲染正常,面板和快捷键显示正确,输入 q 退出干净 |
| Test 6 | `air e2e` | **PASS** | 13/13 gates 全部通过 |
| Test 7 | `air history / session list` | **PASS** | 三个 session 被正确记录 |
### 用户最痛 3 个问题
1. **doctor 语义误导**: "All checks: FAIL" 用红色大字——但只是缺少 package.json 和 tsconfig.json 模板文件。新用户看到 FAIL 会以为产品坏了,其实项目完全正常工作。
2. **结果不可信——工具报错但 LLM 说成功**: Test 4 中 `cpp.build` 返回了 Error`shell.run` 返回了 `Error: undefined`,但最终输出却写着 "程序已成功编译并输出 Hello World"。用户分不清到底是真成功了还是 LLM 幻觉。**这是信任问题。**
3. **session/history 毫无辨识度**: `air history` 输出裸 session_id 数字加大小,不知道哪个 session 干了什么。用户做了 3 次 air ask回头想找之前的任务面对 3 个无区分的数字完全懵了。
### 用户体验评分: **5/10**
扣分项:
- 工具错误被吞掉(**-2 分**):信任问题,用户无法区分真实成功和幻觉
- doctor 诊断语义不准确(**-1 分**):把可修复警告当成硬失败
- session/history 不可辨识(**-1 分**):无法快速定位之前的任务
- 多轮交互体验存疑(**-1 分**
加分项: init 流程干净、TUI 渲染正常、e2e 全绿、响应速度快
---
## 4. QA 测试报告
### 测试矩阵
| Test | 描述 | 结果 | 严重级别 |
|------|------|------|----------|
| T1 | TypeScript 类型检查 | **PASS** | - |
| T2 | E2E Gates (13门) | **13/13 PASS** | - |
| T3 | 简单文件创建 | **PASS** (Worker 退出信号异常) | P1 |
| T4 | C++ AI 终端 (FR-017) | **PASS** (Worker 退出信号异常) | P1 |
| T5 | 追问上下文验证 | **FAIL** | **P0** |
### 详细测试分析
#### T3: 简单文件创建 — PASS (P1 警告)
- `hello.txt` 成功创建,内容 `HELLO`6 字节),分类正确为 `delegate`
- **警告**: Worker 输出 `[Worker] exited with code 0 (error): Unrecoverable error occurred`。Worker 以 exit code 0 退出但附加 "(error)" 标记——信号噪音导致诊断困难。
#### T4: C++ AI 终端 (FR-017) — PASS (P1 警告)
- 成功生成 `main.cpp`13824 字节,含 `#include``main()`)、`CMakeLists.txt``script.sh`
- 功能需求基本满足:代码具备 C++ 程序骨架。
- **警告**: 同样出现 Worker exit code 噪音。
#### T5: 追问上下文验证 — **FAIL** (P0)
- LLM 回答: **"抱歉,我目前无法直接访问您的本地文件系统,所以不知道您的项目里有哪些源代码文件。"**
- **根因**: `MainAgent.chat_with_llm()` 方法MainAgent.ts:102-122完全绕过 ContextAssembler。仅发送一条裸 system prompt `'You are AirCoding, an AI coding assistant...'`,没有注入项目根路径、文件列表、对话历史等任何上下文。
- **影响**: 所有问答类交互(占总交互的很大比例)都没有项目上下文感知能力。
### 问题分类
#### P0 — 阻断发布
1. **MainAgent.chat_with_llm 无 ContextAssembler 集成** (MainAgent.ts:102-122)
修复方向chat_with_llm 应接收 AssemblyContext 参数,先通过 ContextAssembler 组装上下文再发给 LLM。
#### P1 — 重要缺陷
2. **Worker 退出信号不一致** (T3/T4):
Worker 以 exit code 0 退出但附带 "(error)" 字符串——应排查 Worker 退出码逻辑。
3. **BuiltInToolRegistrar 结果形状不一致** (工程审计 P0):
18 个工具的返回形状使用 `content` 而非 `output`,导致 WorkerManager 收到空结果。
4. **shell.run 生成器未解包** (工程审计 P1)
#### P2 — 改进项
5. 无 workspace files 快照层ContextAssembler 缺少 project_files 提示层
6. Scheduler DISPATCHING 缺少 await (竞态)
7. classify_via_llm API 不匹配
8. history/session 输出缺乏可辨识性
### E2E Gates 补充建议
当前 13 个 gate 全部基于单元测试和静态检查,缺少以下端到端 gate:
| 优先级 | 建议 Gate | 检查内容 |
|--------|-----------|----------|
| **P0** | **Answer-Mode Context Gate** | 验证 chat_with_llm 回复包含项目文件信息 |
| **P0** | **Simple E2E Create Gate** | LLM 驱动的文件创建端到端 |
| **P0** | **Tool Output Shape Gate** | 验证所有 39 个工具的返回形状符合 ToolResultEnvelope |
| P1 | **Complex E2E Generate Gate** | 多文件代码生成端到端 |
| P1 | **Worker Exit Consistency Gate** | 验证 Worker exit code 0 不与 "(error)" 同时 |
| P1 | **Follow-up Context Gate** | 新建文件后追问,验证 Agent 感知已有文件 |
| P2 | **ContextAssembler Integration Gate** | 验证所有 Agent 路由经过 ContextAssembler |
---
## 5. 四视角交叉审计综合结论
### P0 问题汇总3 项,阻塞发布)
| # | 问题 | 来源视角 | 触发条件 | 影响范围 |
|---|------|----------|----------|----------|
| 1 | **MainAgent.chat_with_llm 无项目上下文** | QA + 架构师 + 用户 | 所有 answer 交互 | 用户追问项目状态时 LLM 100% 幻觉 |
| 2 | **BuiltInToolRegistrar 18 个工具结果形状不一致** | 工程师 + QA | Worker IPC 调用这些工具 | 50% 工具通过 worker 返回空结果 |
| 3 | **shell.run 生成器未解包** | 工程师 | 任何 shell.run 调用 | shell 命令 100% 失败 |
### P1 问题汇总5 项)
| # | 问题 | 来源视角 |
|---|------|----------|
| 4 | Worker 退出信号噪音 | QA + 架构师 |
| 5 | Scheduler MONITORING 竞态窗口 | 架构师 + 工程师 |
| 6 | classify_via_llm API 不匹配 | 工程师 |
| 7 | Scheduler DISPATCHING 缺少 await | 工程师 |
| 8 | 工具错误被吞掉 + false-positive 成功 | 用户 |
### P2 问题汇总5 项)
| # | 问题 | 来源视角 |
|---|------|----------|
| 9 | Architecture Designer 是死代码 | 架构师 |
| 10 | PermissionEngine 未在调用路径生效 | 架构师 |
| 11 | history/session 输出不可辨识 | 用户 |
| 12 | doctor 语义误导 (warn→FAIL) | 用户 |
| 13 | 资源泄漏 + 空 catch | 工程师 |
### 根因分析
本轮与前几轮审计相同的模式再次出现:
1. **E2E gates 框架盲区** — 13/13 gates pass 但真实场景 5/13 (38%) 核心功能失败。gates 检查代码质量tsc、depcruise、单元测试不检查功能可用性工具结果形状、LLM 上下文注入、Worker IPC 往返完整性)。
2. **集成测试仅覆盖 Happy Path** — 测试创建 hello.txt 验证了最简单场景,但未覆盖 C++ 多文件任务、shell 执行、追问上下文等复杂度递增的场景。
3. **组件间接口契约缺失** — BuiltInToolRegistrar 返回 `{ content }` vs WorkerManager 期望 `{ output }`,这种接口不一致在组件隔离开发时无法发现,只能在集成时暴露。缺少跨组件的 TypeScript 接口强约束。
4. **审计员不跑端到端** — 所有审计员检查了 MainAgent.ts 的方法签名、Chat 函数的类型正确性,但没有人实际问一句 "LLM 回到 '我没有文件系统访问' 合理吗?"
### 发布建议
**不建议发布 V1.0.0 Alpha**。3 个 P0 问题影响了核心体验链路:
- **P0-1**: 用户追问项目状态 → LLM 答"我无法访问文件系统"(每次触发)
- **P0-2**: Worker 调用 cpp.detect / doctor.run / project.scan 等 → 收到空结果 → LLM 困惑 → 任务假完成或失败
- **P0-3**: LLM 调用 shell.run → 永远返回 `undefined` → 编译/运行/测试全部失败
修复 P0 后,必须:
1. 将真实任务端到端集成测试加入 E2E gate suite
2. 统一工具结果形状为 contracts.ToolResultEnvelope (使用 `output` 字段)
3. MainAgent 注入 ContextAssembler 到所有路由
---
## 6. 修复优先级矩阵
| 优先级 | 数量 | 问题 |
|--------|------|------|
| **P0** | 3 | chat_with_llm 无上下文、工具结果形状不一致、shell.run 坏死 |
| **P1** | 5 | Worker exit 噪音、Scheduler 竞态、classify API、spawn await 缺、false-positive |
| **P2** | 5 | ArchDesigner 死代码、PermissionEngine 未生效、history 不可读、doctor 语义、资源泄漏 |
| **E2E gates 增强** | 6 | 新增 answer-mode context gate, simple E2E create gate, tool output shape gate 等 |
**总计**: 需修复 13 个代码问题 + 新增 6 个 E2E gate