Files
AirCoding/集成测试阶段opus审查结果.md
AirCoding 5e282a39b4 feat(round2+round3): 完整实现 A/B/C/D 主线 + round3-F/H 修复
Round2 主线:
- A: 事件落库地基 (RuntimeApp EventStore 单例 + 14 repo wiring)
- B: 执行体对齐 (read-before-edit, verification-before-completion)
- C: 界面对齐 (@opentui/solid, 删除 runtime 依赖)
- D: 经验闭环 (ExperienceMiner, DebuggerRole, CompactorRole)

Round2 补充修复:
- fail-on-missing 反作弊门禁
- projection-store-apply.test.ts 补写
- 3个空壳测试转行为 (evidence-store, recovery-impl, knowledge-store)
- ask 项目根支持 AIRCODING_PROJECT_ROOT
- Worker 事件契约修复 (task.attempt.started → checkpoint)

Round3-F: cpp 工具切换
- 删除 BuiltInToolRegistrar cpp.* 闭包
- 接入 toolchain-cpp 真实 CppToolRegistrar
- canonical envelope {status/output/metadata}
- ExecutorRole system prompt 对齐新工具名

Round3-H: Doctor 5 类报告
- toolchain (cmake/ninja/cppcheck/clangd/g++)
- display (X11/Wayland + ImageMagick)
- network (internet connectivity)
- provider (api_key/base_url/model/connectivity)

Secret 脱敏:
- 状态交接.md: sk- → \${OPENAI_API_KEY}
- .gitignore: 添加 .air/ .claude/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 16:13:16 +08:00

19 KiB
Executable File
Raw Blame History

集成测试阶段 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 可发布带条件
  • QA5 条新增 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 askCLI 进程内自带 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-312EventStore.ts:492-935RuntimeApp.ts:80-84(只 setTransactionManager INV-1 运行时整体失效FR-004 不成立domain 表永远为空SQLite 不是事实源
ARCH-P0-2 task.created 从不发出Scheduler.create_tasks() 注释称发出但函数体只加内存 TaskGraph 节点,无 ingest Scheduler.ts:65-78L76 注释谎称)对比 Scheduler.ts:149 task.started 确实 ingest tasks 表无 pending 行task.started 投影 update 不存在的行rebuild_from_db 永远查不到任务
ARCH-P0-3 TUI 非 OpenTUI,是手写 ANSI 转义渲染器;@opentui/* 零依赖零引用 TuiApp.tsx:27-310tui/package.json 无 opentui 违反 baseline §3/§18 + 需求约束 #3 + FR-016任务 #158 标记 completed 与事实不符
ARCH-P0-4 ProjectionStore 运行时从不被事件驱动apply() 运行路径零调用run.ts 手工构造假 snapshot run.ts:59-72run.ts:170-183EventBus→ProjectionStore 无订阅 违反 baseline §18 + INV-5 + FR-016TUI 状态与 DB 可任意不一致
ARCH-P0-5 air ask 旁路整个调度/Worker 架构,自带内联执行循环 ask.ts:71-78ask.ts:82-215 FR-007/FR-008 在主力 demo 命令上不成立;两套执行语义割裂

P1 问题表

# 问题 证据
ARCH-P1-1 ArchitectureDesigner 发出事件 session_id:'' 必抛错被 .catch(()=>{}) 吞掉 ArchitectureDesigner.ts:59-73EventIngestor.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:48RuntimeApp.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 任务被调度机当成 COMPLETEDPLANNING_WAVE 算 remaining=pending+runningfailed 不计入 → COMPLETEDREPAIRING_OR_CONTINUING 的 if(failed>0){} 是空壳retry_planner 从未调用 Scheduler.ts:117-122,358-368grep 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-142WorkerManager.ts:339-362main.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-197ExecutorRole.ts:292ask.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-257Scheduler.ts:177,193AgentMonitor.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-49RuntimeApp.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-119ask.ts:13,43
ENG-P2-5 process.kill 工具无权限门perms 全 false可 kill 任意 PID BuiltInToolRegistrar.ts:118-120,190-201
ENG-P2-6 空 catch 吞错 ContextAssembler.ts:127run.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 与行式 > 提示符混在同一 stdoutworker 运行时刷屏交错。
  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=01.2s 增量编译(未 clean rebuild
air e2e 14/14 passed4.9s 见逐 gate 评估
release --dry-run 3/3 — READY8.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.ts5 条)——质量最高:

Gate 判定
1 tool 用 output 非 content 真实调用工具断言 output 存在/content undefined
2 shell.run finalcall+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.ts3 条)——全部源码字符串断言,不执行 run 命令,仅防回退快照。

仍缺失的关键 gate

# 缺失项 风险
G1 Worker 真实 spawn + IPC round-tripworker-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 无真实集成 gateQA

与前几轮对比

维度 前几轮 第一轮修复后(本轮实测)
工具契约 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 repocreate_tasks 真正 ingest task.created。P0-1/P0-2
  2. 修复失败处理Scheduler PLANNING_WAVE 终态区分 failed接线 RetryPlannerrun_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 / 真编译 / 真事件落库)仍是发布前硬缺口。


审计模型: Opus4 子代理并行) 审计时间: 2026-06-08 仓库状态: 源码未改动(只读审计)