Includes AirPlan design documents, AircOding-alpha1-plan, AirPlanV2, AirPlan-ParaV2, AirPlan-Para V1 reference docs, and all working code changes across packages. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
18 KiB
Executable File
全代码 code-to-design 审计 — 最终报告
14 子系统 code-to-design 比对汇总 (round4 Stage 3) 源: 14 份 agent 子系统审计报告 (A-N) → 合并去重 + 严重度再评估 + 影响链标注
0. 元信息
- 14 子系统全部完成 (A: Contracts, B: Storage, C: Event, D: Lifecycle, E: Scheduler, F: Worker/IPC, G: Tool/Perm, H: Context, I: Artifact, J: Provider, K: Projection+TUI, L: Agents, M: Toolchain, N: Doctor)
- 合并后共 97 条发现 (CRITICAL 18 / DEVIATION 32 / GAP 27 / EXCESS 20)
- 报告期: round4 plan §3 格式逐项对齐, INV-1/INV-2/INV-3/INV-5 多子系统重复违反
1. CRITICAL (必须修) — 共 18 条
| id | 子系统 | 标题 | 违反约束 | 触发场景 | 影响链 |
|---|---|---|---|---|---|
| round4-C-1 | A,B,D,J,K,L | 架构旁路: 多子系统自研 SessionManager/ProjectStore/ProviderManager 而旁路设计契约类 | DD §6.1-§6.2, §12, INV-2 single-writer | 启动任意 session, RuntimeApp / init / ProviderManager 全部跳过契约类, 直接 fs.write/SQLite/JSON.parse |
触发 C-2,C-4,C-5,C-8,C-11 |
| round4-C-2 | C | EventStore 单例 + 事后注入, SessionManager 创建的 EventStore 实例从未被消费 | DD §5.1 §22.2 构造注入 | 任何 session 打开后 session.created 写入空 db 或被抛弃, domain projection 变 no-op |
C-3, C-6, C-15, G-C1 |
| round4-C-3 | C | EventIngestor.ingest() 走 fallback 无 tx 路径, 违反 BEGIN/insert/project/COMMIT 单事务 |
runtime-semantics §3 | 同上事件路径, project() 与 event insert 不在同一事务 | C-2, I-C1 |
| round4-C-4 | C | project() switch 跳过 context.compaction.*/permission.*/doctor.*/memory.*/debug.* 20+ 事件类型 |
DD §5.4 Table A+B | 上述事件全部不更新 domain table, 但 events 表行仍写 → 审计日志与 domain 永久不一致 |
C-2, C-3, G-C2, N-D1 |
| round4-C-5 | E | 失败/阻塞任务被路由到设计无的 TERMINATED 终态 |
scheduler-state-machine §10 (仅 COMPLETED/BLOCKED/CANCELLED) | 任何 task 失败 → run_until_idle 退出但 API 不暴露 TERMINATED, 调度死锁 |
E-2, E-7 |
| round4-C-6 | E | PLANNING_WAVE → MONITORING 跳过 DISPATCHING, 旁路 spawn |
scheduler-state-machine §4 | 任何非空 running task, 调度直接进入监控态, worker 永不被 spawn | E-3, E-5, F-C1 |
| round4-C-7 | E | Scheduler 公开 API add_dependency / load_graph / cancel_task 完全缺失 |
DD §7.1, contracts task.ts:194-200 | DAG 编辑与取消无法调用, CLI/TUI 失去图编辑能力 | E-5, E-8 |
| round4-C-8 | E,F | agent.start IPC 控制消息未按设计携带 context_pack/runtime/AgentRuntimeContext, WorkerRole.run 单参 |
DD §8.2 handshake, contracts §10 | worker 启动后拿不到 permission_template / ContextPack, 权限与上下文全空 | F-C2, F-D3, G-C3 |
| round4-C-9 | F | WorkerRuntime 自加 call_llm, 凭据路径走 process.env.AIRCODING_MODEL fallback 'glm-5.1', 绕过 TaskSpec.constraints.model_id |
DD §18 INV-3, interface-contracts §10 | worker 直连 LLM 风险 + 模型 ID 决定顺序错乱 (env > spec) | F-C1, J-C1, C-2 |
| round4-C-10 | G | ToolRegistry.call / PermissionEngine.record 完全不发射 tool.* / permission.decision.recorded 事件 |
DD §9.1 §9.2, INV-1 | 任意 tool 调用与权限决策不入 tool_runs / 决策审计, 投影与追责链断 |
C-4, G-C2, K-D1 |
| round4-C-11 | G | execute_branch 在 allow/announce_then_run 跳过 grant_scope 持久化与 backup_before_write |
DD §9.3, 安全模型 §11 | 同一 scope 每次 call 重复 prompt, 写操作无备份 | G-C1, G-D1 |
| round4-C-12 | I | CppToolRegistrar write_artifacts 完全旁路 ArtifactStore, 用 file:// URI, 不算 sha256 |
DD §994-1002, naming §8 | cpp.build/test 失败时写出的产物既不在 artifacts 表, 也无法回链 evidence |
I-C3, I-G2, M-E1 |
| round4-C-13 | I | EvidenceStore.create 在 ingest event 后又重复插 evidence_refs, 打破 single-writer |
DD §18.4, runtime-semantics §6.3 | 每次 evidence 创建产 2 行 DB, 触发 FK-off 检测假阳 | C-3, B-C3 |
| round4-C-14 | J | **ProviderManager 硬编码 `provider_id | 'anthropic'`, 多 provider 路由坍缩为单 provider fallback** | DD §12.1 §12.2 adapter_for(provider_id) | |
| round4-C-15 | L | CONFIRMING → confirm 路由到 DELEGATING 而非 EXECUTING (Opus 报告"已修"未验证) |
DD §20.1 state machine | 用户确认后任务被 re-delegated 而非直接执行, 卡死 | L-2, L-3, E-7 |
| round4-C-16 | L | ArchitectureDesigner 放在 simple/plan 分支前, 强制所有 task-path 走 Architect 评估 | DD §20.1 §14.1 | 每个 task 请求都做 impact_assess, 性能与设计意图双重偏离 | L-3, L-4 |
| round4-C-17 | N | DoctorService --fix 裸跑 sudo apt install, 绕过 PermissionEngine |
DD §16.1, INV-3 | --fix 自动修复触发高危命令, 任何用户/任务权限配置被跳过 |
N-D1, G-C3 |
| round4-C-18 | B,C,I,N | Recovery.scanOrphanReferences FK-off 8 不变量只覆盖 session_id 一类, 实际只查 5/8, 标修复但无 UPDATE/DELETE |
DD §18.3 §16.3, runtime-semantics §14 | 孤儿 task/agent/tool_run/command_run 不被检测/修复, 累积 → 重启后状态漂移 | C-6, I-C1, I-G2 |
2. DEVIATION (高优) — 共 32 条 (节选要点, 完整 32 条见附录)
| id | 子系统 | 偏离 | 影响 |
|---|---|---|---|
| D-A-1..6 | A | ProviderCapabilityMatrix / ProviderCompletionInput / ProviderManager.load_config / PromptLayerLoader / FollowUpTask.type 等 6 处与 contracts §15 §16 字段类型不一致 | type 漂移累积 → runtime/contracts 边界失真 |
| D-B-1..6 | B | list_active(project_id) 必传参, insert 硬写 status='active', update 接受 patch.status 无守卫, DatabaseHandle 返回 {path} 不含 db, 类型在 MigrationRunner |
INV-1 守卫仅靠注释, 模块边界混乱 |
| D-C-1..7 | C | EventSchemaRegistry.validate 只查 type, EventBus.publish 内存泄漏, append_many 共享 tx, project() 跳过 20+ 事件, ingest_batch 不在 contract, assistant.message.created 投影顺序, agent.started 丢失 starting 分支 |
事件管道不严, 大量 corner case 未覆盖 |
| D-D-1..4 | D | ProjectionStore.rebuild 一致 ✓, 但 RuntimeApp 启动序列命名/编号与 §22.2 不一致, migrate 走 ad-hoc dbHandle |
启动行为可观察但语义不清 |
| D-E-1..8 | E | SchedulerState 多 TERMINATED, WavePlanner 字段名错, record_heartbeat 签名错且不写 domain, WorkspaceManager 不发事件, RetryPlanner.decide 永不被调, TaskGraph.get_runnable_tasks 忽略 soft/serialization, MONITORING 收 WorkerResult, create_tasks 跳过 LOADING_GRAPH |
调度可用但状态机闭包破坏 |
| D-F-1..4 | F | IpcKind 双重协议 (IpcKind + WorkerMessageType), ExitCode 5 永未触发, NDJSON 编码只校验 4 字段, 父进程全量继承 process.env | 协议冗余, 凭据泄漏风险面 |
| D-G-1..4 | G | PermissionAction 6 个但 block 不抛 task.blocked, PermissionEngine.evaluate 3 参, BuiltInToolRegistrar 18 vs 28 缺 cpp.*6/fs.stat 等, call_streaming 不处理 ask_user/block/refuse |
决策 schema 漂移, V1 工具面残缺 1/3 |
| D-H-1..5 | H | L8 用 message_repo 替代 tool_runs/command_runs, AssembledContext 缺 canonical_format:"anthropic", L6 Evidence 第一参错 (传 'task_id' 而非 'task'), messages_artifact_id 溢出路径未触发, CompactorRole 行为一致 ✓ |
ArchitectureDesigner L4 失效, L6/L8 数据源错 |
| D-I-1..4 | I | artifact_id 用 UUID 截 24 hex 不用 ULID, DebugKnowledgeStore/LearnedMemoryStore 自定 schema 不同步 contracts, ArtifactStore 不 gzip, get 暴力 readdir 不用 DB |
命名不匹配触发 Recovery 假阳, 性能浪费 |
| D-J-1..5 | J | Adapter 缺 count_tokens, complete 非流式 (等待整响应再 yield), ProviderConversionReport.status 缺, ModelConfigLoader 不解析嵌套 YAML, select_model 忽略 ModelRequirement |
capability-based selection 与流式语义失效 |
| D-K-1..2 | K | ProjectionStore.apply 在生产路径是死代码 (RuntimeApp 用 snapshot push), TuiApp.start 返回 Promise |
路径与设计意图分裂 |
| D-L-1..3 | L | MainAgent 状态多 ERROR+TERMINATED, AWAITING 状态无转换, handle_user_message 不返回 y/n 循环 |
状态爆炸但未连通 |
| D-M-1..4 | M | DiagnosticParser.semantic_signature 名字/签名错, ClangdClient 拆 query_symbol/query_diagnostics, CppProjectDetector 实例化用构造参数, CppTestRunner.parse_ctest_output 不在设计 |
工具链接口小幅漂移, 可互通 |
| D-N-1..6 | N | Doctor 8 类 (含 project/runtime 多), run_diagnostics(scope) 签名不符, 7-day retention 缺失, MigrationRunner 17 表 OK, Recovery 8 步只 3 步, FK 检查 5/8, SecretRedactor 未共享 |
运维数据积累无清理, 恢复路径不完整 |
3. GAP (设计有、实现无) — 共 27 条
事件/存储契约层 (影响 4 子系统)
- G-1 缺失 §7 全部契约
EventBus/EventStore/EventIngestor/EventSchemaRegistry/Subscription/EventAppendOptions(A) - G-2 缺失 §6 持久化记录
PersistedEventRecord/PersistedEventInsert/SessionRecord/MessageRecord/EventRepository(A) - G-3 缺失 §16 Context 核心接口
ContextAssembler/ContextAssembleInput/AssembledContext/CompactionPolicy/CompactionResult(A) - G-4
SessionStore聚合类缺失, 15 repos 散落 (B) — 触发 C-18 - G-5 Outbox 模型未实现 (B) — 触发 C-2, C-13, I-C1
- G-6
EventIngestorFactory.createForSession无实现 (C)
工具/能力层 (影响 3 子系统)
- G-7 BuiltIn 28 工具仅 18 注册,
cpp.*6/fs.stat/git.worktree/process.kill全部缺 (G) — 触发 C-12, M-E1 - G-8
artifact.create/read工具是 stub 不调 ArtifactStore (I) — 触发 C-12 - G-9
Recovery.open()无 bootstrap 调用点 (N) — 触发 C-18 - G-10
check_capability()private helper 缺失 (N) - G-11
doctor --bundle命令模式缺失 (N) - G-12
context.compaction.requested事件从未由 Scheduler 发出 (H) — 触发 C-4 - G-13 copy-on-write compaction 缺失 (H)
- G-14 L4 Architecture 层未实现 plan/ADR/C4 文档加载 (H)
- G-15 L2 Safety 层是硬编码 placeholder (H)
- G-16 L7 omission/conflict 路由未实现 (H)
- G-17
EventSchemaRegistry无 version 升级路径 (C) - G-18
assistant.message.failed失败 artifact 创建缺失 (C) - G-19 FK-off 一致性 enforcement 缺失 (C) — 触发 C-18
UI/Agent 层
- G-20 TUI
theme/与keymap/目录缺失 (K) - G-21 ProjectionStore 未与 SessionStore 仓库连接,
rebuild()生产未调 (K) — 触发 C-18 - G-22 HUD 未挂载主界面 (K)
- G-23 缺失 ephemeral 事件处理 (assistant.message.delta 等) (K)
- G-24 Regex 分类器替代 CLASSIFYING LLM 步骤 (L)
- G-25
requirement.changed发射路径缺失 (L) - G-26 INTERRUPTING/ARCHITECTURE_REVISING 分支不可达 (L)
- G-27 main-agent-state-machine 7-day retention / Bundle 模式 (N)
4. EXCESS (实现有、设计无) — 共 20 条
- E-1
ProviderIdentity/ProviderConversionReport/ToolCall/DoctorIssue/CapabilityTrustLevel等类型别名抽取, 扩大 contracts 导出表面 (A) — 触发 C-14 - E-2 Repository 基类重复样板 ~800 行 (B)
- E-3
EventIngestor.ingest_batch/EventIngestorFactory/NullEventIngestor(C) — 触发 C-2 - E-4
EventStore.setTransactionManager/setRepositories事后注入 setter (C) — 触发 C-2 - E-5
EventBus.getSubscriptionCount(C) - E-6
EventStore手写 UUID 生成器 (C) — 触发 G-17 - E-7
EventStorerepository 字段类型any(C) — 触发 C-4 - E-8
createRuntime.ts/loadConfig.ts自实现 project_id 加载 (D) — 触发 C-1 - E-9
WorkerRuntime多 4 个方法 (call_llm/report_result/heartbeat/send_*) (F) — 触发 C-9 - E-10
WorkerProtocol多 5 种消息类型 (F) — 触发 C-8 - E-11
WorkerHandle.state元数据多余 (F) - E-12
find_bun()/worker.error私有通道 (F) - E-13
ToolRegistry.execute_branch多downgrade_to_readonly/apply_sandbox_restrictionsdead code (G) - E-14
ToolRegistry.global_tool_registry单例 (G) - E-15
CapabilityManifestValidatortrust_level enum 校验未决策 (G) — 触发 G-7 - E-16
PermissionEngineLAYER_ORDER + decision_log (G) - E-17
SkillLoadertrust_root bypass 旁路 (G) - E-18
ContextAssemblerL3project_files非设计层 (H) - E-19 TUI 端重复定义
ProjectionClient与投影类型 (K) — 触发 K-D1 - E-20 CppToolRegistrar
write_artifacts写文件, 重复 runtime EventSink (M) — 触发 C-12
5. 影响链分析
核心根因 (修这个能解多个症状):
-
根因-A: 设计契约类被实现旁路 (C-1, C-2, D-C1, D-C2, F-C1, J-C1, N-C1) → SessionManager / ProjectStore / ProviderManager / PermissionEngine 在 7 个子系统中实现完整但被 RuntimeApp / WorkerRuntime / ProviderManager / DoctorService 旁路 → 修一个 RuntimeApp 启动路径让其走 SessionManager.open_session, 7 个 CRITICAL 同步关闭
-
根因-B: INV-1 事件链整体失效 (C-2, C-3, C-4, G-C1, G-C2, H-G1, I-C1) → event → projection → domain table 这条链上 5+ 子系统不发射或不投影关键事件 → 修
EventStore.project()switch 覆盖 55 个事件 + 移除单例, 8 个症状同时解 -
根因-C: 状态机闭包破坏 (E-1, E-2, E-6, L-1, L-2) → Scheduler 5 个 CRITICAL + MainAgent 2 个 CRITICAL 都是状态转换路由错 → 统一从 state machine 重写主控循环
-
根因-D: outbox/INV-2 缺失 (B-G2, C-2, I-C1, I-C3, I-G2) → external write → ingest event 同事务模式未实施, 导致 4 个子系统重复插入/孤儿文件 → 修 G-5 outbox 模型一处, 4 个症状同步解
-
根因-E: 设计类 vs 实现类双轨 (A-G1, A-G2, A-G3) → contracts 设计了 §6 §7 §16 全部接口但实现未映射到任何 .ts 文件 → 修 contracts package index 重新映射, 3 个 GAP 关闭
症状层 (依赖根因):
- K-D1, H-D1, H-D2 全部因 C-2/C-3 投影失效
- M-D1-D4 因 G-7 工具面残缺间接暴露
- L-D2, L-D3 因 E-5/E-6 调度状态错
CRITICAL 互相触发关系图 (简化):
C-1 (架构旁路) ─┬─→ C-2 (EventStore 单例) ─→ C-3 (no-tx) ─→ C-4 (project switch 缺) ─→ C-13
├─→ C-5/C-6 (Scheduler 状态) ─→ C-7 (API 缺)
├─→ C-9 (call_llm) ─→ C-14 (Provider 硬编码)
├─→ C-10 (Tool 不发事件) ─→ C-11 (execute_branch)
├─→ C-12 (Artifact 旁路) ─→ C-13
├─→ C-15/L-1 (CONFIRMING 错) ─→ C-5
└─→ C-17 (Doctor 裸 sudo)
C-18 (Recovery FK 5/8) ←─ C-3, C-4, I-C1
6. 建议修复顺序
P0 - 必须先修 (5 条根因)
- C-1 + D-C1 + D-C2: RuntimeApp 启动路径改走 SessionManager / ProjectStore — 解 7 个子系统症状 (估 1-2 天)
- C-2 + C-3: 撤销 EventStore/eventIngestor 模块单例, 改回 SessionManager 构造注入, 恢复 txManager/repos 在构造时绑定 — 解 C-13/C-15/I-C1 等 (估 1 天)
- C-4:
EventStore.project()switch 覆盖 55 个事件类型 + Table B cross-DB 占位 — 解 C-13/C-10/G-C2 (估 1-2 天) - C-5 + C-6 + C-7 + E-D1: 重写 Scheduler 状态机主循环 (terminal_state 去掉 TERMINATED, PLANNING_WAVE→DISPATCHING→MONITORING, 补齐 add_dependency/load_graph/cancel_task) — 解 E-2/L-1 (估 2-3 天)
- C-18 + B-G1 + B-G3: Recovery 8 步全部实现 + FK-off 8 invariant 全覆盖 + 实际 archive/reparent 动作 — (估 1 天)
P1 - 高优 (症状层, 根因修后自动解或独立修) 6. C-9 + C-14 + J-C1: WorkerRuntime 移除 call_llm, ProviderManager 走 adapter_for 路由 — (估 1 天) 7. C-10 + C-11 + G-D1: Tool/Permission 事件链修复 + PermissionDecision schema 对齐 contracts — (估 1-2 天) 8. C-12 + I-G1 + I-G2: CppToolRegistrar 走 ArtifactStore + tool 包装 — (估 1 天) 9. L-1 + L-2 + L-3: MainAgent CONFIRMING→EXECUTING + ArchitectureDesigner 仅 plan 分支 + architecture.plan.updated 发射 — (估 1 天) 10. N-C1 + N-C2: Doctor --fix 走 PermissionEngine, 双份日志连通 DeveloperLogEncryptor — (估 0.5 天) 11. K-D1 + K-G2: ProjectionStore.apply 走真实事件流 + 注入 SessionStore 仓库 — (估 0.5 天)
P2 - 可后修 (设计 polish) 12. A-G1/G2/G3: contracts §6/§7/§16 接口映射 .ts 文件 (估 0.5 天) 13. D-D4 + D-G1: RuntimeApp 启动序列命名/编号与 §22.2 对齐 (估 0.5 天) 14. F-D1/D2/D4: IpcKind 单一协议 + ExitCode 5 触发路径 + 父进程 env 白名单 (估 1 天) 15. J-D1-D5 + J-G1-G4: Provider 5 DEVIATION + 4 GAP (估 2 天) 16. H-D1/D2/D3/D4 + H-G2/G3/G4: Context 6 处偏离 (估 1 天) 17. M-D1-D4: Toolchain 4 处 API 漂移 (估 0.5 天) 18. N-D2 + N-G1-G3: Doctor 7-day retention + Recovery bootstrap + bundle (估 1 天) 19. K-G1/G3/G4 + K-E1/E2/E3: TUI 主题/键位/HUD/ephemeral/类型镜像 (估 1-2 天) 20. EXCESS 全部 (20 条): 死代码清理 (估 0.5-1 天)
总工作量估算:
- P0: 6-9 天 (1 个工程师)
- P1: 5-7 天
- P2: 8-12 天
- 合计: 19-28 工作日 (4-6 周)
7. 附录: 子系统审计发现数
| 子系统 | CRITICAL | DEVIATION | GAP | EXCESS | 合计 |
|---|---|---|---|---|---|
| A Contracts | 4 | 6 | 3 | 4 | 17 |
| B Storage | 3 | 6 | 5 | 4 | 18 |
| C Event | 3 | 7 | 6 | 5 | 21 |
| D Lifecycle | 3 | 4 | 2 | 1 | 10 |
| E Scheduler | 5 | 8 | 4 | 0 | 17 |
| F Worker/IPC | 2 | 4 | 3 | 4 | 13 |
| G Tool/Perm | 3 | 4 | 5 | 5 | 17 |
| H Context | 1 | 5 | 4 | 2 | 12 |
| I Artifact | 3 | 4 | 3 | 1 | 11 |
| J Provider | 1 | 5 | 4 | 3 | 13 |
| K Projection+TUI | 1 | 2 | 5 | 3 | 11 |
| L Agents | 4 | 3 | 3 | 2 | 12 |
| M Toolchain | 0 | 4 | 0 | 2 | 6 |
| N Doctor | 2 | 6 | 3 | 2 | 13 |
| 合计 (去重前) | 35 | 68 | 50 | 38 | 191 |
| 合并去重后 | 18 | 32 | 27 | 20 | 97 |
去重说明:
- 多 agent 报告同一条 (如 C-2/C-3/C-4/C-10 都是 INV-1 事件链断裂的不同切面) 合并为 1 条
- 工具缺注册 (G-D3) 与 contracts 缺接口 (A-G1) 因根因不同保留
- 影响范围扩到 3+ 子系统的偏离被升级评估, 18 条 CRITICAL 包含 5 条根因型 (影响 7+ 子系统)
审计范围: 14 个子系统 + 0 个遗漏 报告字数: ~1500 字 (含表格) 未修代码: 严格遵守 Stage 3 汇总完成