# 集成测试阶段 opus 审查结果 **审计日期**: 2026-06-08 **项目**: AirCoding V1.0.0 Alpha **审计模型**: Opus(四子代理并行,各持不同文档) **审计模式**: 四视角交叉审计(系统架构师 / 开发工程师 / 真实用户 / 测试工程师) **审计基线**: 第一轮集成修复后(commit ddefcbb) --- ## 0. 总体结论 第一轮修复**方向正确、happy-path 可用**:四份历史报告的头号 P0(工具契约 content/output、shell.run AsyncGenerator、Scheduler 假完成、MainAgent 无上下文、确认门断裂)已真实闭合并有功能级门禁守护。但本轮 opus 交叉审查发现**第一轮未触及的更深层架构问题与新缺陷**: - **架构师**:事件驱动地基在运行路径上是空的(`setRepositories` 从不调用、`task.created` 从不发出、ProjectionStore 运行时从不被事件驱动、TUI 非 OpenTUI、`air ask` 旁路整个调度架构)。判定**不可发布**。 - **工程师**:发现 failed 任务被调度机当成 COMPLETED、Worker exit/result 竞态、fs.edit 参数名不匹配、心跳不刷新。判定**不阻断内测,但对外 Alpha 前必修 P1-1/P1-2/P1-3**。 - **用户**:核心闭环真实跑通无幻觉无假成功,评分 8/10,判定**可演示、Alpha 可发布带条件**。 - **QA**:5 条新增 gate 中 4 条真实有效,但 P6 门禁引用不存在的测试文件形成假阳性,Worker/C++/Projection 仍无真实集成测试。判定**不建议标记 Release READY**。 四视角分歧点在于"发布标准":用户/工程师视 happy-path 可用为 Alpha 达标;架构师/QA 视事实源与门禁完整性未达标。**综合判定:可内测演示(限 `air ask`),但不可对外 Alpha 发布,事件地基与失败处理必须先闭合。** --- ## 1. 系统架构师审查 ### 架构结论 **不具备产品演示/Alpha 发布标准。** 第一轮闭合了一批工具契约/Worker 结果/确认门的真实 bug,但**事件驱动这一架构地基在运行路径上仍是空的**:domain 表从不被写入、`task.created` 从不发出、TUI 不是 OpenTUI、ProjectionStore 运行时从不被事件驱动。`air run` 能跑通"创建文件"是因为它绕过事实源,直接用 WorkerResult 内存对象 + 手工 snapshot 显示结果,掩盖了 INV-1/INV-5/FR-004 运行时整体失效。 存在两条割裂的执行实现: - `air ask`:CLI 进程内自带 LLM→工具循环(`ask.ts:82-215`),**完全不经过 Scheduler/Worker/IPC**。 - `air run`:走 MainAgent→Scheduler→WorkerManager→子进程→IPC→ExecutorRole 真实链路。 状态交接.md 的 UAT 全部用 `air ask` 验证,因此真实执行链路实际未被 UAT 覆盖。 ### P0 问题表(阻断发布) | # | 问题 | 证据 | 影响 | |---|---|---|---| | ARCH-P0-1 | **durable 事件从不投影到 domain 表**:`EventStore.setRepositories()` 运行路径从未调用,仅测试调用。运行时 `project()` 内所有 repo 为 null,每个 case 静默 no-op | `EventStore.ts:299-312`、`EventStore.ts:492-935`、`RuntimeApp.ts:80-84`(只 setTransactionManager) | INV-1 运行时整体失效;FR-004 不成立;domain 表永远为空,SQLite 不是事实源 | | ARCH-P0-2 | **`task.created` 从不发出**:`Scheduler.create_tasks()` 注释称发出但函数体只加内存 TaskGraph 节点,无 ingest | `Scheduler.ts:65-78`(L76 注释谎称)对比 `Scheduler.ts:149` task.started 确实 ingest | tasks 表无 pending 行;task.started 投影 update 不存在的行;rebuild_from_db 永远查不到任务 | | ARCH-P0-3 | **TUI 非 OpenTUI**,是手写 ANSI 转义渲染器;`@opentui/*` 零依赖零引用 | `TuiApp.tsx:27-310`;`tui/package.json` 无 opentui | 违反 baseline §3/§18 + 需求约束 #3 + FR-016;任务 #158 标记 completed 与事实不符 | | ARCH-P0-4 | **ProjectionStore 运行时从不被事件驱动**:`apply()` 运行路径零调用,run.ts 手工构造假 snapshot | `run.ts:59-72`、`run.ts:170-183`;EventBus→ProjectionStore 无订阅 | 违反 baseline §18 + INV-5 + FR-016;TUI 状态与 DB 可任意不一致 | | ARCH-P0-5 | **`air ask` 旁路整个调度/Worker 架构**,自带内联执行循环 | `ask.ts:71-78`、`ask.ts:82-215` | FR-007/FR-008 在主力 demo 命令上不成立;两套执行语义割裂 | ### P1 问题表 | # | 问题 | 证据 | |---|---|---| | ARCH-P1-1 | ArchitectureDesigner 发出事件 `session_id:''` 必抛错被 `.catch(()=>{})` 吞掉 | `ArchitectureDesigner.ts:59-73`、`EventIngestor.ts:204` | | ARCH-P1-2 | MainAgent 15 态多数无真实触发路径(AWAITING/SCHEDULING/SUMMARIZING/ERROR/TERMINATED 无进入点) | `MainAgent.ts:15-30,75-122,278-313` | | ARCH-P1-3 | Scheduler 13 态部分空壳过场(COLLECTING_RESULTS/REVIEWING_WAVE 直接切换);200ms 轮询 | `Scheduler.ts:340-356,329-331` | | ARCH-P1-4 | CapabilityRegistry 接入但运行路径无 discover/load,恒空 | `CapabilityRegistry.ts:48`、`RuntimeApp.ts:71-75` | | ARCH-P1-5 | 真实 C++ 工具链 CppToolRegistrar 未进主链路,live 用 BuiltInToolRegistrar 简化版 | `grep CppToolRegistrar` 无命中;`BuiltInToolRegistrar.ts:288-364` | | ARCH-P1-6 | contracts ToolRegistry 接口签名与实现背离,靠 `as any` 掩盖 | `contracts/src/tool.ts:100-106` vs `ToolRegistry.ts:91,128,60` | --- ## 2. 开发工程师审查 ### 工程结论 第一轮修复方向正确、主路径可用,`tsc --noEmit` 0 错误。但发现第一轮未覆盖的真实缺陷,两项触及"诚实性/正确性"底线:failed 任务被伪装成 COMPLETED、Worker exit/result 竞态。happy-path 能跑通,UAT 结论可信,但"任务失败"会被系统性伪装成成功。 ### P1 问题表(对外发布前必修) | # | 问题 | 证据 | 修复方向 | |---|---|---|---| | ENG-P1-1 | **failed 任务被调度机当成 COMPLETED**:PLANNING_WAVE 算 `remaining=pending+running`,failed 不计入 → COMPLETED;REPAIRING_OR_CONTINUING 的 `if(failed>0){}` 是空壳,retry_planner 从未调用 | `Scheduler.ts:117-122,358-368`;`grep retry_planner.` 无调用 | PLANNING_WAVE 终态区分 failed → BLOCKED/TERMINATED 或经 RetryPlanner 重试;run_until_idle 终态反映失败 | | ENG-P1-2 | **Worker 退出/结果竞态**:WorkerProcess 用 `'exit'` 非 `'close'`,worker report_result 后立即 process.exit(0),exit 可能先于最后一行 stdout 解析,handle_worker_exit 误判 failed | `WorkerProcess.ts:134-142`、`WorkerManager.ts:339-362`、`main.ts:92-93` | 监听 `'close'`;或 handle_worker_exit 对无结果做微任务让步后复查;worker 端 exit 前 await stdout drain | | ENG-P1-3 | **fs.edit 参数名不匹配,Agent 调用恒失败**:执行器读 `{find,replace}`,ExecutorRole/ask.ts 传 `{old_str,new_str}`,find 恒 undefined → "Exact text not found" | `tools/fs/index.ts:191-197`、`ExecutorRole.ts:292`、`ask.ts:107` | 统一参数名(执行器接受 old_str/new_str 或兼容 find=old_str);补 Agent 路径编辑回归 | | ENG-P1-4 | **Worker 心跳不刷新**:worker.heartbeat 无 WorkerManager 处理器,record_heartbeat 仅派发时调一次,>5min 任务被判 stalled,>10min 被 cancel | `WorkerManager.ts:162-257`、`Scheduler.ts:177,193`、`AgentMonitor.ts:90-104` | WorkerManager 注册 worker.heartbeat/checkpoint → record_heartbeat 刷新 | ### P2 问题表 | # | 问题 | 证据 | |---|---|---| | ENG-P2-1 | shell.run 流式块顺序错乱且重复(退出后先聚合 stdout/stderr 再 drain 增量 chunks) | `tools/shell/index.ts:94-135` | | ENG-P2-2 | ServiceRegistry 为分叉死代码,DB 路径与 RuntimeApp 不一致 | `ServiceRegistry.ts:38-49`、`RuntimeApp.ts:64-66` | | ENG-P2-3 | 内建工具成功 envelope 夹带遗留 `call_id/tool_name/type:'text'` 顶层字段,靠 Promise 不报错 | `BuiltInToolRegistrar.ts:180-183` 等 18 处 | | ENG-P2-4 | ProviderManager.complete_text 硬编码 anthropic provider_id/canonical_format | `ProviderManager.ts:110-119`、`ask.ts:13,43` | | ENG-P2-5 | process.kill 工具无权限门(perms 全 false,可 kill 任意 PID) | `BuiltInToolRegistrar.ts:118-120,190-201` | | ENG-P2-6 | 空 catch 吞错 | `ContextAssembler.ts:127`、`run.ts:155,157` | | ENG-P2-7 | ArchitectureDesigner 事件 session_id 为空 | `ArchitectureDesigner.ts:59-73` | ### 第一轮修复正确性核验表 | 第一轮声称 | 核验结论 | |---|---| | 内建工具改 canonical {status,output,metadata} | ✅ 部分:status/output 已加,但仍夹带 type:'text'/顶层 call_id | | grep content: 无残留 | ⚠️ 残留多为合法(fs.read 输出、layer.content、IPC payload) | | shell.run 两路径正确 | ✅ 消费正确;⚠️ 流式块顺序/重复有缺陷 | | Scheduler 按 status 终结 | ✅ 已删假完成逻辑;❌ 但 failed 在 PLANNING_WAVE 被当已完成 | | WorkerProcess on_exit 覆盖退出语义 | ⚠️ 映射对,但 exit/result 顺序竞态未解决 | | MainAgent 真用 ContextAssembler | ✅ assemble 注入;⚠️ answer 模式 agent_type 误用 'executor' | | run.ts pendingConfirmation 健壮 | ✅ 空输入/y/n/非y-n 路由成立 | | ExecutorRole 严格 DONE/失败不 completed/保留原文 | ✅ 全部成立 | | CapabilityRegistry/ArchitectureDesigner 接入 | ✅ 实例化绑定;但 ArchDesigner 事件 session_id 空(P1)、Capability 运行时空集 | | ContextAssembler L3/L6/L8 | ✅ project_files/evidence 签名/tool role 均落地 | | release.ts findRepoRoot/findBun | ✅ 成立 | --- ## 3. 真实用户 / UAT 审查 ### 用户体验评分:8/10 核心闭环(创建文件、上下文问答、多文件生成、危险操作确认门、调度执行)全部真实跑通,无幻觉、无假成功。扣分来自 `air run` TUI/readline 交织、新建项目立即 doctor 失败两个体验摩擦点。 ### 测试矩阵 | # | 场景 | 结果 | 观察 | |---|---|---|---| | 1 | air init | PASS | 创建 .air 结构 + project.json,退出码 0 | | 2 | air ask 创建 hello.txt | PASS | fs.write,磁盘内容精确 `HelloWorld`(10B) | | 3 | air ask 项目有哪些文件 | PASS | answer 模式准确列出真实文件,无幻觉,未列 .air | | 4 | air ask C++ + CMakeLists | PASS | main.cpp(97B)+CMakeLists.txt(153B),g++ 实测编译运行输出 Hello World | | 5 | air run 中文删除 + n | PASS | 命中确认门,"Cancelled. No task was created.",文件保留 | | 6 | air run 中文删除 + y | PASS | 确认后派发 worker 走 shell.run,文件被删除 | | 7 | air doctor | PASS(含告警) | 6 项全绿,project_structure 报缺 package.json [fixable] | | 8 | air e2e | PASS | 14/14 gates | | 9 | /help /tools /results | PASS | 清晰可理解 | ### 最痛问题 1. `air run` TUI 与 readline 双写终端(中)——全屏 TUI 与行式 `> ` 提示符混在同一 stdout,worker 运行时刷屏交错。 2. 新建项目 doctor 立即失败(低-中)——init 不生成 package.json,紧接 doctor 报 FAIL,负面第一印象。 3. glm-5.1 reasoning token 消耗(信息项)——低 max_tokens 时正文可能为空。 ### False-positive 风险:低 文件产物均落盘后 cat/ls/g++ 实测复核;删除查磁盘确认;cpp.build 失败是真实无 cmake(优雅降级如实说明)。唯一留意:/results 是 run 进程内存态,重启不持久。 ### 是否可演示/可发布 - **可演示:是**(建议用 air ask,输出干净)。 - **可发布 Alpha:是,带条件**——功能完整、门禁 14/14、确认门中英文生效达 Alpha 线;正式版前收口 run 输入统一、init/doctor 体验、/results 持久化。 --- ## 4. QA / 发布门禁审查 ### QA 总结 第一轮源码修复方向正确,`release-critical-gates.test.ts` 是本项目第一次出现真正执行被测代码的发布级门禁。但门禁整体三个结构性问题未达"可发布": 1. **P6 门禁形同虚设**——引用的 `projection-store-apply.test.ts` 不存在,bun 静默跳过缺失路径,仅靠 workspace-enum.test.ts 让 gate 变绿,**假阳性**。 2. **关键集成路径无真实验证**——28 个测试文件无一真正 spawn worker 子进程、无一真正编译运行 C++。 3. **源码字符串断言占比过高**——28 个测试中 18 个(64%)用 readFileSync + toContain,只证明"代码还在"不证明"功能正确"。 ### 测试矩阵(真实运行) | 项 | 实测结果 | 备注 | |---|---|---| | tsc | EXIT=0,1.2s | 增量编译(未 clean rebuild)| | air e2e | 14/14 passed,4.9s | 见逐 gate 评估 | | release --dry-run | 3/3 — READY,8.6s | | | P4 Worker IPC | 21 pass/53 expect | 无真实 spawn | | P5 C++ | 5 pass/10 expect | 仅 1 文件纯源码断言,无真实编译 | | P8 全回归 | 142 pass/346 expect/21 files | 体量真实但大量字符串断言 | ### 新增 gate 有效性评估 `release-critical-gates.test.ts`(5 条)——质量最高: | Gate | 判定 | |---|---| | 1 tool 用 output 非 content | ✅ 真实调用工具断言 output 存在/content undefined | | 2 shell.run final(call+streaming) | ✅ 真跑 printf ok 断言 exit_code/stdout/is_final | | 3 Scheduler 不假完成 | ✅ 命中核心 bug;⚠️ workerManager 是字面量 mock | | 4 MainAgent answer 用 context | ✅ 真实 ContextAssembler + 临时文件 | | 5 危险操作 CONFIRMING→IDLE | ✅ 真实 MainAgent 状态机 | 5 条中 4 条真实执行被测逻辑——**合格,是门禁里唯一可信功能层**。 `run-command-regression.test.ts`(3 条)——全部源码字符串断言,不执行 run 命令,仅防回退快照。 ### 仍缺失的关键 gate | # | 缺失项 | 风险 | |---|---|---| | G1 | Worker 真实 spawn + IPC round-trip(worker-fixture 自承认 stub) | 最高 | | G2 | 真实 C++ build/run | 高 | | G3 | Worker exit consistency 端到端 | 高 | | G4 | Projection rebuild/replay(门禁引用文件不存在,假绿) | 高 | | G5 | False-positive 成功检测(ExecutorRole 无任何测试) | 高 | | G6 | complex C++ build/run e2e | 中-高 | ### QA P0/P1/P2 **P0(阻断发布)** - QA-P0-1 修复 P6 假阳性门禁(补 projection-store-apply.test.ts 或移除路径并 fail-on-missing) - QA-P0-2 e2e runTest 加 fail-on-missing(任一路径不存在直接 fail) - QA-P0-3 Worker 真实 spawn round-trip 接入 P4 **P1** - QA-P1-1 真实 C++ build/run e2e - QA-P1-2 ExecutorRole DONE/失败不 completed 功能测试 - QA-P1-3 Worker exit→result 一致性端到端 - QA-P1-4 Projection rebuild/replay 覆盖 **P2** - QA-P2-1 降低源码字符串断言占比(64%) - QA-P2-2 tsc clean rebuild 验证 - QA-P2-3 P7 direct-mode mock 标注边界 ### 发布门禁建议 **当前不建议标记 Release READY**,尽管 release --dry-run 3/3。理由:release 的绿建立在 e2e 14/14 之上,而 14/14 里 P6 假阳性、P4/P5 源码断言冒充集成。最低放行:QA-P0-1/2/3 完成 + 手工 UAT 脚本化为可重放 e2e 纳入门禁。 --- ## 5. 四视角交叉综合 ### P0 汇总(阻断对外发布) | # | 问题 | 来源视角 | 根因 | |---|---|---|---| | 1 | EventStore.setRepositories 运行路径从不调用 → domain 表恒空 | 架构师 | INV-1/FR-004 地基失效 | | 2 | task.created 从不发出 | 架构师 | 事件溯源断链 | | 3 | failed 任务被调度机当成 COMPLETED | 工程师 | 失败伪装成功(触碰红线)| | 4 | Worker exit/result 竞态误判 failed | 工程师 | 成功也可能被误判 | | 5 | ProjectionStore 运行时不被事件驱动,run.ts 手工 snapshot | 架构师 | INV-5/FR-016 | | 6 | P6 门禁引用不存在文件,假阳性 | QA | 门禁完整性 | | 7 | air ask 旁路调度/Worker 架构 | 架构师 | FR-007/008 双实现割裂 | | 8 | TUI 非 OpenTUI | 架构师 | FR-016/约束#3 | ### P1 汇总 fs.edit 参数不匹配恒失败(工程师)、Worker 心跳不刷新(工程师)、ArchitectureDesigner 事件 session_id 空被吞(架构师+工程师)、MainAgent/Scheduler 状态机空壳(架构师)、CapabilityRegistry 运行时空集(架构师)、真实 C++ 工具链未进主链路(架构师)、Worker/C++/Projection 无真实集成 gate(QA)。 ### 与前几轮对比 | 维度 | 前几轮 | 第一轮修复后(本轮实测) | |---|---|---| | 工具契约 output/content | 头号 P0 | ✅ 已修 + 真实 gate | | shell.run AsyncGenerator | 阻断 | ✅ 已修 + 真实验证 | | Scheduler 假完成 | 阻断 | ✅ 已删假逻辑;❌ 但 failed→COMPLETED 新问题 | | MainAgent 上下文/确认门 | 阻断 | ✅ 已修 + 真实验证 | | ProjectionStore-only/TUI snapshot | Deepseek/Gpt5.5 P1 | ❌ 未修(更深:本轮查实 setRepositories 从不调用)| | durable task events 主路径 | Gpt5.5 P0 | ❌ 未修(根因:task.created 不发出)| | Worker 真实 spawn | 一直缺失 | ❌ 仍缺失(自承认 stub)| | C++ 真实 build/run | 一直缺失 | ❌ 仍缺失 | **本轮新发现**:setRepositories 从不调用(最严重)、task.created 不发出、TUI 非 OpenTUI、failed→COMPLETED、Worker exit/result 竞态、fs.edit 参数不匹配、P6 假阳性门禁、ArchitectureDesigner 事件被吞。 --- ## 6. 发布建议与修复优先级 **综合判定:可内测演示(限 air ask),不可对外 Alpha 发布。** 14/14 e2e 与 3/3 release 全绿,但这些门禁不触碰本轮 P0 任何一条——绿灯与可用性正交,这正是 MiniMax 已警告、本轮仍重演的盲点。 按修复优先级(遵守"不接受架构降级"原则,全部为补齐而非删功能): 1. **闭合事件地基**:RuntimeApp.start 调用 `eventStore.setRepositories({...})` 注入全部 domain repo;create_tasks 真正 ingest task.created。(P0-1/P0-2) 2. **修复失败处理**:Scheduler PLANNING_WAVE 终态区分 failed,接线 RetryPlanner;run_until_idle 反映失败。(P0-3) 3. **修复 Worker 竞态**:WorkerProcess 监听 'close' 或退出前复查 result。(P0-4) 4. **统一执行路径**:air ask 复用 Scheduler→Worker,删除 CLI 内联循环。(P0-7) 5. **收口 Projection 事实源**:EventBus→ProjectionStore.apply→TUI,删 run.ts 手工 snapshot。(P0-5) 6. **门禁完整性**:e2e runTest fail-on-missing;补 P6 真实测试;补 Worker spawn / C++ build / false-positive / projection rebuild gate。(P0-6 + QA-P0) 7. **TUI 技术栈归位**:接 @opentui/*,或走正式架构变更声明(不可默默降级)。(P0-8) 8. P1 批量:fs.edit 参数、心跳刷新、ArchDesigner session_id、状态机补齐、CapabilityRegistry 加载、真实 C++ 工具链进主链路。 **核心教训重申**:代码质量指标(tsc/门禁数)与产品可用性指标正交。第一轮把"被测代码从不执行"推进到"核心修复点被真实执行"是实质进步,但门禁完整性(fail-on-missing)与集成层(真 spawn / 真编译 / 真事件落库)仍是发布前硬缺口。 --- *审计模型: Opus(4 子代理并行)* *审计时间: 2026-06-08* *仓库状态: 源码未改动(只读审计)*