# MIMO 2.5 Pro 系统详细设计全量交叉审查

Date: 2026-05-29
Reviewer: MIMO 2.5 Pro (single-model, independent pass)
Status: Full cross-verification of `system-detailed-design.md` against all frozen baselines, frozen overview, and internal architectural consistency
Scope: Coverage + consistency + architecture soundness audit

---

## 1. 审查方法

审查对象：`AirPlan/docs/architecture/system-detailed-design.md`（2033 行，23 节）

审查三维度：

1. **覆盖性**：基线/概要设计的每个 item 是否在详细设计中有对应项
2. **一致性**：详细设计内部是否存在矛盾、基线引用是否准确
3. **架构合理性**：类职责划分、依赖方向、边界执行是否合理，是否存在内在冲突

审查输入：

| 文档 | 角色 |
|---|---|
| `interface-contracts-v1.md` (23 节) | 接口契约 |
| `event-registry-v1.md` (55 durable + 7 ephemeral) | 事件注册表 |
| `db-schema-v1.md` (19 表, 18 个关闭枚举) | 数据库 Schema |
| `runtime-semantics-v1.md` (19 节) | 运行时语义 |
| `scheduler-state-machine-v1.md` (11 节) | 调度器状态机 |
| `main-agent-state-machine.md` | 主代理状态机 |
| `prompt-layering-v1.md` (L0-L9) | 提示分层 |
| `scope-escalation-v1.md` (13 节) | 作用域升级 |
| `security-model-v1.md` (8 PathRisk + 10 CommandRisk) | 安全模型 |
| `capability-trust-v1.md` | 能力信任 |
| `system-overview-design.md` (FROZEN, 1222 行) | 概要设计 |
| `DeepSeek系统详细设计审查.md` | 前一轮审查报告 |

方法：
- 逐契约接口字段比对
- 逐事件投影映射核对
- 逐表仓储核对
- 逐状态机转换核对
- PromptLayer 三方比对（contracts / prompt-layering / overview）
- 依赖方向一致性验证
- 内在冲突检测

---

## 2. 总体评估

### 2.1 评分

| 维度 | 得分 | 说明 |
|---|---|---|
| 契约覆盖 | 9.5/10 | 接口字段全覆盖，1 处 PromptLayerLevel 枚举与层名不完全对齐 |
| 事件覆盖 | 10/10 | 55 durable + 7 ephemeral 全覆盖 |
| DB Schema 覆盖 | 10/10 | 19 表全仓储 |
| 状态机覆盖 | 10/10 | 6 个状态机全覆盖 |
| 内在一致性 | 8.5/10 | 1 处真实内部矛盾（PromptLayer），1 处架构弱点（EventStore 错误隔离） |
| 架构合理性 | 9.5/10 | 边界清晰、职责分离良好、依赖方向正确 |
| 序列图覆盖 | 8.0/10 | 4 个关键序列覆盖，2 个可补充 |
| 可实现性 | 9.5/10 | 方法签名可直接编码，无歧义 |

**综合评分：9.4/10**

### 2.2 结论

详细设计是一个高质量的实现导向文档。架构边界清晰，依赖方向正确，类职责分离良好。发现了 **1 处真实内部矛盾** 和 **1 处架构弱点** 需要解决，但均不阻塞实现阶段——可以通过明确的设计决策澄清来修复。

---

## 3. P0 发现（0 项）

未发现 P0 项。

---

## 4. P1 发现（2 项）

### P1-01: PromptLayerLevel 枚举与 L0-L9 层名结构性不对齐

**严重度**：P1（真实内部矛盾，影响实现一致性）

**问题**：`interface-contracts-v1.md` §16 定义了 10 个 `PromptLayerLevel` 枚举值，`prompt-layering-v1.md` §2 定义了 L0-L9 共 10 个层名。概要设计 §13 已将 L0-L9 逐层与基线对齐。但三方存在结构性不匹配：

| L# | prompt-layering-v1 §2 | contracts §16 枚举值 | 对齐状态 |
|---|---|---|---|
| L0 | Runtime invariant | `runtime_invariant` | ✓ |
| L1 | Role / agent mode | `role` | ✓ |
| L2 | Safety and permission policy | **（无对应枚举值）** | ✗ |
| L3 | Project rules and user preferences | `project_rules` | ✓ |
| L4 | Architecture baseline and current plan | `architecture` | ✓ |
| L5 | Task specification and acceptance criteria | `task_spec` | ✓ |
| L6 | Relevant code / artifacts / evidence | `evidence` | ✓ |
| L7 | Recent conversation and decision context | `conversation` | ✓ |
| L8 | Tool result history / diagnostics | `tool_output` | ✓ |
| L9 | Immediate instruction | `user_override`（名字不同） | △ |
| — | （无对应层） | `system_debug` | ✗ |

**矛盾点**：
1. L2 "Safety and permission policy" 没有对应的 `PromptLayerLevel` 枚举值——但它是 prompt-layering-v1 定义的独立层
2. `user_override` 映射到 L9，但概要设计 §13 说 L9 = "Immediate instruction"，名字不一致
3. `system_debug` 枚举值没有对应的 L 层——DD §10.2 说"applied within L9 when present"，但这是一个缩写而非结构映射

**影响**：实现时 `ContextAssembler.load_layers()` 需要 10 个加载点，但 `PromptLayerLoader` 接口只有 4 个方法（`load_runtime_invariant`, `load_role`, `load_project_rules`, `load_task_context`）。L2 safety、L4 architecture、L6 evidence、L7 conversation、L8 tool_output、L9 immediate instruction 都没有明确的 loader 方法。

**修复建议**（需要设计决策）：
- 选项 A：在 contracts §16 添加 `safety_permission` 枚举值，将 `user_override` 改名为 `immediate_instruction`，删除 `system_debug` 或并入 L9
- 选项 B：保持枚举不变，在实现层将 L2 映射到 `runtime_invariant`（immutable=true），L9 由 `user_override` + `system_debug` 合并
- 选项 C：扩展 `PromptLayerLoader` 接口添加 L2/L4-L9 的显式加载方法

无论选哪个，需要一个明确的设计决策记录。

---

### P1-02: EventStore.project() 错误处理未定义

**严重度**：P1（架构弱点，影响运行时鲁棒性）

**问题**：DD §5.3 `EventStore.append()` 在事务内执行 `EventRepository.insert()` 和 `project(event, tx)`。但 `project()` 执行的是多行 domain update（如 `task.started` 需要更新 `tasks` 表 + 插入 `task_attempts` 行）。如果 `project()` 中间步骤失败，事务会回滚——但此时 `EventBus.publish()` 不会执行（正确行为），然而 **没有描述 `project()` 内部的错误语义**：

- 如果 `project()` 抛出异常，是整个 `append()` 回滚？（应该）
- 如果 domain update 因 FK-off 不一致失败（如引用了不存在的 `tasks.id`），错误如何传播？
- `project()` 是否有部分失败的恢复逻辑？

**影响**：在高并发或重启恢复场景下，如果 `project()` 的某一步 domain update 失败（如引用的 task 已被删除），整个事件追加会回滚——这是正确的原子行为，但 DD 没有显式描述这个错误路径。

**修复建议**：在 DD §5.3 或 §18.2 添加：`project()` 异常 → 事务回滚 → `EventBus.publish()` 不执行 → 返回 `AirError{kind: "system_error"}`。如果是因为 FK-off 不一致导致，记录到 developer log 并触发 `referential_check()`。

---

## 5. P2 发现（5 项）

### P2-01: DeepSeek 审查报告中的 3 项 P2 已验证

DeepSeek 审查报告的 3 项 P2 均确认属实：

| ID | DeepSeek 发现 | MIMO 验证 |
|---|---|---|
| DeepSeek P2-01 | PromptLayerLevel 枚举与 L0-L9 不完全 1:1 | 确认（已升级为 MIMO P1-01） |
| DeepSeek P2-02 | Architecture Designer gate 无独立序列图 | 确认，P2 |
| DeepSeek P2-03 | CLI catalog 命令类归属未指定 | 确认，P2 |

### P2-04: `agent.started` 投影映射措辞

DD §5.4 投影映射表中 `agent.started` 的域更新描述为 "insert `agents` (starting/running)"。这暗示 `project()` 可能选择 `starting` 或 `running`，但 event-registry §3.3 固定为 "insert `agents` row with `status = running` or `starting`"——具体选择哪个取决于调度器上下文（spawn 前 vs 握手后）。

建议：DD 应明确 `starting` 是初始状态，`running` 是握手完成后的状态（与 db-schema §10 agent status 一致）。当前描述可接受但含糊。

### P2-05: `WorkspaceManager` 与 `Scheduler` 状态机 MERGING 阶段的职责边界

DD §7.5 `WorkspaceManager.merge_workspace()` 和 DD §20.2 Scheduler 的 MERGING 状态都描述了合并逻辑。但 Scheduler 状态机的 MERGING 包含了冲突处理路由（trivial → repair/debugger, semantic → Reviewer/Architecture Designer, architecture → block, user → Main Agent）——这些是 Scheduler 级别的决策，而 `WorkspaceManager` 只负责 git 操作。

建议：明确 `WorkspaceManager` 返回 `MergeResult{status: success|conflict, conflict_files?, conflict_type?}`，Scheduler 根据 `conflict_type` 做路由决策。当前描述隐含了这个分工但没有显式标注。

---

## 6. 架构合理性分析

### 6.1 依赖方向

```text
contracts → (none)
llm → contracts
toolchain-cpp → contracts
tui → contracts
runtime → contracts, llm (facade only)
cli → contracts, runtime, tui, llm, toolchain-cpp
workers → contracts + WorkerRuntime IPC (no direct runtime import)
```

**评估**：完全正确。`contracts` 是叶节点，`cli` 是根节点，`runtime` 依赖 `llm` 但仅通过 facade（`ProviderManager` 接口），`workers` 通过 IPC 间接依赖 `runtime`（不直接 import）。这个依赖方向避免了循环依赖，允许各包独立编译。

### 6.2 职责分离

| 组件 | 职责 | 边界 | 评估 |
|---|---|---|---|
| EventIngestor | 事件入口 | 不创建 scheduler/permission/memory 决策 | ✓ 正确隔离 |
| EventStore | 持久化事件 + 投影 | 不直接暴露 EventBus | ✓ 正确（投影在事务内，发布在事务后） |
| EventBus | 实时发布/订阅 | 不是恢复源 | ✓ 正确 |
| SessionStore | 聚合所有仓储 | 不含调度/权限/投影策略 | ✓ 正确（code-view §9） |
| Scheduler | 编排服务 | 不是编码代理 | ✓ 正确（scheduler-state-machine §intro） |
| ToolRegistry | 工具调用 | 所有 side effect 必须经过 PermissionEngine | ✓ 正确（contracts §23） |
| PermissionEngine | 权限决策 | 不绕过 credential/system-sensitive override | ✓ 正确 |
| TUI | UI 渲染 | 只依赖 ProjectionClient/contracts | ✓ 正确（contracts §23） |
| ContextAssembler | 上下文组装 | 不自行压缩 | ✓ 正确（概要设计 §13） |

**评估**：所有组件的职责边界与基线一致。没有发现职责泄漏或边界违反。

### 6.3 状态机一致性

6 个状态机之间的交互路径：

| 源状态机 | 目标状态机 | 事件/数据流 | 一致性 |
|---|---|---|---|
| Main Agent → Scheduler | DELEGATING → SCHEDULING | `task.created` | ✓ |
| Scheduler → Worker | DISPATCHING → worker spawn | `agent.start` IPC | ✓ |
| Worker → Scheduler | worker.return → COLLECTING_RESULTS | `worker.result` IPC | ✓ |
| Scheduler → Architecture Designer | architecture-sensitive review | `architecture.impact.completed` | ✓ |
| Architecture Designer → Scheduler | impact assessment done | Scheduler consumes impact | ✓ |
| Main Agent ← Scheduler | progress/blocked/complete | `task.progress/blocked/completed` events | ✓ |
| EventBus → ProjectionStore | all events | subscribe/apply | ✓ |
| ContextAssembler → Scheduler | `compaction_requested` | Scheduler creates compact task | ✓ |

**评估**：所有状态机交互路径的事件名称、方向和触发条件一致。没有发现状态机之间的死锁或悬空事件路径。

### 6.4 事务语义一致性

关键事务边界：

| 操作 | 事务范围 | 后置操作 | 一致性 |
|---|---|---|---|
| EventStore.append | event insert + domain projection | EventBus.publish (after commit) | ✓ |
| ArtifactStore.create | temp→rename→DB record | event ingest | ✓ |
| Task.start | task.started event + tasks update + task_attempts insert | agent.started event | ✓ |
| Compaction | summary.created event + summaries insert | context.compaction.completed | ✓ |
| Cross-DB write (outbox) | session event → external DB → completion event | recovery on restart | ✓ |

**评估**：所有事务边界遵循 runtime-semantics §3 规则（durable event + domain update 同事务，EventBus 发布在事务后）。

---

## 7. 与 DeepSeek 审查的交叉验证

| 发现 | DeepSeek 判定 | MIMO 判定 | 差异 |
|---|---|---|---|
| PromptLayerLevel 结构性不对齐 | P2 | **P1** | MIMO 升级：这不是"措辞差异"而是真实内部矛盾，影响实现一致性 |
| Architecture gate 无独立序列图 | P2 | P2 | 一致 |
| CLI catalog 类归属 | P2 | P2 | 一致 |
| EventStore.project() 错误处理 | **未报告** | **P1** | MIMO 独立发现 |
| agent.started 投影措辞 | **未报告** | P2 | MIMO 独立发现 |
| WorkspaceManager/Scheduler 职责边界 | **未报告** | P2 | MIMO 独立发现 |

**差异分析**：DeepSeek 将 PromptLayer 问题标记为 P2，理由是"DD §10.2 正确记录了此映射"。MIMO 认为这是 P1，因为虽然 DD 记录了差异，但没有给出明确的解决决策——实现时仍然面临"枚举值和层名不完全对应"的问题，而这个差异发生在两个已冻结的基线之间（contracts 和 prompt-layering），属于需要明确澄清的架构级问题。

---

## 8. 覆盖性检查

### 8.1 契约接口字段抽样

| 接口 | 基线字段数 | DD 覆盖数 | 缺失 |
|---|---|---|---|
| TaskSpec | 9 fields | 9 | 0 |
| WorkerResult<T> | 12 fields | 12 | 0 |
| IpcEnvelope<T> | 9 fields | 9 | 0 |
| PermissionDecision | 7 fields | 7 | 0 |
| AirError | 11 fields | 11 | 0 |
| ProviderCapabilityMatrix | 10 fields | 10 | 0 |
| CapabilityManifestV1 | 13 fields | 13 | 0 |
| DebugRecord | 10 fields | 10 | 0 |
| LearnedMemory | 9 fields | 9 | 0 |
| Diagnostic | 14 fields | 14 | 0 |

**10/10 接口字段完整性抽样全部通过。**

### 8.2 事件投影映射核对

55 个持久化事件逐一对比 event-registry §3 的 Domain update 描述。全部 55/55 覆盖且域更新描述准确。

### 8.3 DB Schema 表核对

19 张表（db-schema §2-§18 + §20.1-§20.2）逐一对比 DD §4.3 仓储清单 + §11.3 项目级 DB Store。19/19 全覆盖。

### 8.4 禁止路径核对

10 条 contracts §23 禁止路径逐一对比 DD §2 + §18.5。10/10 全覆盖。DD 额外添加 1 条 C4 规则（runtime → TUI import）。

---

## 9. 与前轮审查的一致性

| 维度 | DeepSeek | MIMO 2.5 Pro |
|---|---|---|
| P0 | 0 | 0 |
| P1 | 0 | 2 |
| P2 | 3 | 5 |
| 综合评分 | 9.6/10 | 9.4/10 |
| 新发现 | — | P1-02, P2-04, P2-05 |

**一致性结论**：两轮审查在 P0 层面一致（0 项）。MIMO 发现了 DeepSeek 未报告的 P1 级 EventStore 错误处理问题，并将 PromptLayer 结构性矛盾从 P2 升级为 P1。

---

## 10. 门禁判定

| 条件 | 状态 |
|---|---|
| P0 = 0 | PASS |
| P1 ≤ 2（均有明确修复路径）| PASS |
| 契约覆盖 100% | PASS |
| 事件覆盖 100% | PASS |
| DB Schema 覆盖 100% | PASS |
| 状态机覆盖 100% | PASS |
| 禁止路径全执行 | PASS |
| 架构无循环依赖 | PASS |
| 职责分离无泄漏 | PASS |
| 状态机交互无死锁 | PASS |
| 事务语义一致 | PASS |

**门禁结果：PASS（附 2 项 P1 修复建议）**

详细设计可以进入实现阶段，但建议在实现开始前明确 P1-01（PromptLayer 设计决策）和 P1-02（EventStore 错误路径文档化）。

---

## 11. P1 修复建议

### P1-01 修复路径

需要一个设计决策（ADR 或详细设计补充）：

**推荐方案 B**：保持枚举不变，在实现层建立映射：

```text
L0 → runtime_invariant (immutable=true)
L1 → role (immutable=true)
L2 → (safety layer loaded by ContextAssembler as a runtime_invariant variant with immutable=true, 
      source from ~/.air/permissions.yaml + project permissions)
L3 → project_rules
L4 → architecture (loaded from plan/todo/ADR context)
L5 → task_spec
L6 → evidence (loaded from artifacts/diagnostics/evidence_refs)
L7 → conversation (loaded from messages/summaries)
L8 → tool_output (loaded from recent tool_runs/command_runs/diagnostics)
L9 → user_override + system_debug (merged, highest priority non-immutable layer)
```

PromptLayerLoader 接口扩展为：

```text
load_safety_policy(): PromptLayer        // L2
load_architecture_context(refs): PromptLayer[]  // L4
load_evidence_context(refs): PromptLayer[]      // L6
load_conversation(session_id): PromptLayer[]    // L7
load_tool_output(recent_runs): PromptLayer[]    // L8
load_immediate_instruction(): PromptLayer       // L9
```

### P1-02 修复路径

在 DD §5.3 或 §18.2 补充：

```text
EventStore.append error semantics:
  - project() 内部异常 → 整个事务回滚
  - EventBus.publish() 不执行（正确：post-commit only）
  - 返回 AirError{kind: "system_error", message: "event projection failed"}
  - 如果是因为 FK-off 不一致（如引用不存在的 task_id）：
    - 记录到 developer log
    - 触发 SessionStore.referential_check()
    - Scheduler 将受影响的 task 标记为 interrupted/blocked
  - 不会部分投影：SQLite 事务保证原子性
```
