Files
AirCoding/AirPlan/docs/architecture/opus4.7详细设计与UML审查.md
AirCoding 33a76a1ebc Move project from external drive to local NVMe
迁移路径: /run/media/airlongdian/EasyU/AirCoding -> /home/airlongdian/DataDevices/AirWorkSpace/AirCoding

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 09:51:49 +08:00

17 KiB
Executable File
Raw Permalink Blame History

Opus 4.7 系统详细设计与 UML 类图回归审查

Date: 2026-06-01 Reviewer: Claude Opus 4.7 (independent regression audit) Scope: 修复后回归审查 — 验证 P1×4 + P2×9 修复是否真正闭合,且未在修复过程中引入新偏差 Inputs:

  • 详细设计:system-detailed-design.md2264 行23 章节commit 543743b
  • 受冻结基线22 份基线 + 已冻结概要设计
  • 此前审查DeepSeek / MIMO 2.5 Pro / GPT-5.5 Pro / Opus 4.8 四轮审查 + 汇总

1. 审查方法

本次为回归审查,不重复覆盖性扫描,而是:

  1. P1×4 修复验证:检查每项修复是否真正落地、文字是否清晰、是否与基线一致
  2. P2×9 修复验证:同上,并特别检查"修复过程中是否引入新的偏离基线条款"
  3. 跨文档一致性DD 修复后是否仍与 contracts、event-registry、runtime-semantics、scope-escalation 等基线一致
  4. 新发现:审查过程中浮出的、之前轮次未发现的新问题

2. 总览结论

维度 状态
P1×4 修复闭合性 4/4 已闭合
P2×9 修复闭合性 ⚠ 9/9 文字已落地,但 3 项引入新基线偏离
新增 P0 0
新增 P1修复引入的回归 3
新增 P2 2
覆盖性 维持 100%
架构合理性 维持,无循环依赖
综合判定 CONDITIONAL PASS次轮 — 需收束 3 项 P1 回归

3. P1×4 修复验证

3.1 P1-01: Worker exit code 语义冲突 — 已闭合

检查项 结果
DD §8.1 与 baselineV1.md §8 对齐 ✓ 完全一致6 个 code 含义逐字对应)
overview §11 与 baselineV1 对齐 commit 8d9c420/453df09 中验证)
任务结果与 exit code 解耦说明 ✓ DD §8.1 末尾"Design decision"明确:任务 status 走 WorkerResult.statusexit code 仅表达进程协议层语义
表格格式与 baselineV1 一致

结论:完全闭合。无残留歧义。

3.2 P1-02: PromptLayerLevel 枚举与 L0-L9 不对齐 — 已闭合

检查项 结果
interface-contracts-v1.md §16 增加 "safety" 枚举值
11 个枚举值(含 system_debug)映射到 L0-L9 + 系统调试
DD §10.2 表 1枚举 → L# → loader正确显示 11 行
system_debug 注释"applied within L9 when present" ✓ 与 prompt-layering-v1 §2 注脚对齐

结论完全闭合。L0-L9 全部有显式枚举对应。

3.3 P1-03: EventStore.project() 错误处理未定义 — 已闭合

检查项 结果
DD §5.3 包含"Error handling for project()"块
异常 → 事务回滚 → EventBus.publish() 不触发
返回 AirError{kind: "system_error"}
FK-off 不一致触发 SessionStore.referential_check()

结论:完全闭合,并与 §4.3、§18.3 形成闭环。

3.4 P1-04: PromptLayerLoader 接口不完整 — 已闭合

检查项 结果
DD §10.2 第二张表L2/L4/L6/L7/L8/L9 → ContextAssembler 内部装配)
显式说明 PromptLayerLoader 只覆盖 L0/L1/L3/L5
Runtime rolesmain/architecture/scheduler不走 load_role() 的设计决策
与 §2"Worker AgentType vs. runtime roles"块互为印证

⚠ 次级发现L2 Safety 来源写为 PermissionEngine.current_profile(),但 interface-contracts-v1.md §13PermissionEngine 接口只声明 evaluate()record() 两个方法current_profile() 是基线之外的方法引用 → 见 §5.3 新发现 R1-01。


4. P2×9 修复验证

ID 文字落地 内容质量 新偏离基线
P2-01 Architecture gate 序列图 ✓ §19.4 ✓ 完整
P2-02 CLI catalog 命令类归属 ✓ §17 ✓ 11 个 Command 类
P2-03 agent.started 投影措辞 ✓ §5.4 表 A → R1-02
P2-04 WorkspaceManager 职责矩阵 ✓ §7.5 ⚠ 引用错误 → R2-01
P2-05 §5.4 拆分两张表 ✓ §5.4 ✓ Table A/B 分离清晰
P2-06 memory.promoted 两相 ✓ §18.4 → R1-03
P2-07 docs task 闭合 ✓ §8.3
P2-08 AgentType vs runtime roles ✓ §2
P2-09 contracts 文件集冻结 ✓ §3 ⚠ → R2-02

整体:9/9 文字落地,但 3 项P2-03 / P2-04 / P2-06 / P2-09在修复过程中引入新偏离


5. 新发现(回归引入)

5.1 [R1-01] P1-04 副作用:PermissionEngine.current_profile() 不在基线 — P1

位置DD §10.2 "Design decision — Layer loading responsibility" 表L2 Safety 来源

问题

L2 Safety  →  PermissionEngine.current_profile() + ~/.air/permissions.yaml + project permissions

interface-contracts-v1.md §13PermissionEngine 接口仅声明:

export interface PermissionEngine {
  evaluate(context: PermissionRequestContext): Promise<PermissionDecision>
  record(decision: PermissionDecision, context: PermissionRequestContext): Promise<PermissionRecordResult>
}

current_profile() 是详细设计层引入的方法名,没有对应的契约方法。这违反了 DD §0 "does not introduce new public contracts" 的约束。

根因P1-04 修复时为给 L2 Safety 找一个明确来源,引用了一个并不存在的方法名。

建议处理

  • 选项 A把来源改为"PermissionEngine 内部状态(实现细节)+ ~/.air/permissions.yaml 文件 + 项目权限配置",避免点名一个不存在的方法
  • 选项 BPermissionEngine 契约中加 current_profile() 方法 → 需要 ADR 并修改 contracts §13违反"基线冻结"约束)
  • 推荐:选项 A

预计工作量5 分钟(文字调整)


5.2 [R1-02] P2-03 副作用:agent.started 引入"同事件内分阶段更新"概念,超出基线 — P1

位置DD §5.4 Table A 中 agent.started

当前文字

insert `agents` row with `status='starting'` upon spawn intent, then update to
`status='running'` on the same event's commit when WorkerProcess handshake has
succeeded (`workers` ack); domain row carries final state at commit time

问题:这段话描述了"同一个事件提交过程中先 starting 再 running"的语义,事件投影在一次事务内对同一行做 insert+update。

event-registry-v1.md §3agent.started 的定义是:

Domain update: insert `agents` row with `status = running` or `starting`.

即基线明确"插入时 row 的 status 等于 runningstarting 其一"不是两步。状态从 startingrunning 的过渡由独立事件 / 后续状态机决定(参见 DD §20.4 中 starting ──ready──▶ running,但 baseline 并未对应 "ready" 持久事件)。

把握手成功"在同一事件提交时"反映到 row 上,事实上无法实现 — 因为 agent.started 事件已经在 WorkerManager.spawn 完成 handshake 之前或之后就已经被持久化。

根因P2-03 旧文字"insert agents (starting/running)"措辞被认为"含糊",修复时反而引入了一个违反事件原子性的描述。

建议处理:恢复为符合基线的清晰版本:

| `agent.started` | insert `agents` row with `status = 'starting'` (initial spawn)
or `status = 'running'` (if handshake completed before the event is emitted);
final transition `starting → running` is recorded via the implicit state
machine in §20.4 without a dedicated durable event |

预计工作量5 分钟


5.3 [R1-03] P2-06 副作用:memory.promoted 引入 phase 字段,扩展基线 payload — P1

位置DD §18.4 "memory.promoted two-phase semantics" 表

当前文字

| Phase | Payload marker                                              |
| Intent     | phase: "intent",  no artifact_ref/memory_id yet       |
| Completion | phase: "committed", includes artifact_ref / memory_id |

问题event-registry-v1.md §3MemoryPromotedPayload 定义为:

interface MemoryPromotedPayload {
  candidate_id: string
  target_ref: string
  promoted_by: "user" | "curator" | "system"
  summary: string
}

没有 phase 字段。P2-06 修复引入的"intent vs committed"两相是 DD 层对 outbox 模型的额外扩展,事实上在基线中是通过单一 memory.promoted 事件 + 上下游推断完成的runtime-semantics §6.4 直接说"session event records completed promotion and target ref",即单事件即为完成态)。

此外DD §18.4 也对 debug.record.created 同样应用了 phase 字段("the same two-phase pattern (intent → committed) with payload field phase"),同样不在 event-registry-v1.mdDebugRecordCreatedPayload中。

根因GPT-5.5 Pro 的原 P2-06 关注点是"outbox intent/completion 阶段不清"。修复时为了在 DD 层明确区分,新增了 phase 字段。但契约层从未声明这个字段,且 baseline runtime-semantics §6.4 实际上认为 memory.promoted 是单事件、完成态语义。

建议处理:去掉 phase 字段引入,改用"两个事件"或"前置 candidate + 单完成事件"叙述:

**`memory.promoted` outbox flow**(不引入新 payload 字段):

1. `memory.candidate.created` 已持久化(已存在事件)
2. 决定 promote 后,业务侧执行外部 store 写入
3. 写入成功后发出 `memory.promoted` —— 这就是基线说的"completed promotion"
4. 写入失败:发出 `memory.archived` 或回退到一个新的 candidate运行时不发未完成的 `memory.promoted`

如果未来需要严格的 outbox intent应通过 ADR 引入新事件类型,而非给现有事件增加 payload 字段。

debug.record.created:基线 runtime-semantics §6.3 说"intent/completion event",但实际 payload 是单一 schema建议同样不引入 phase,而是依赖 debug.record.created + debug.record.failed(如果未来加入)形成 outbox。

预计工作量15 分钟


5.4 [R2-01] P2-04 副作用DD §7.5 引用 "overview §10.5" 不正确 — P2

位置DD §7.5 "Responsibility split — Scheduler vs. WorkspaceManager"

当前文字**Responsibility split — Scheduler vs. WorkspaceManager** (overview §10.5, scheduler-state-machine §4/§MERGING)

问题system-overview-design.md §10.5 是 "Direct mode",不包含 workspace 职责描述。workspaces 描述实际位于 overview §10.3 (Scheduler state machine, 含 "workspace assignment", "workspace merge and conflict handling")。

根因P2-04 修复时引用错章节号。

建议处理:把 (overview §10.5, scheduler-state-machine §4/§MERGING) 改为 (overview §10.3, scheduler-state-machine §4/§MERGING)

预计工作量1 分钟


5.5 [R2-02] P2-09 副作用file-set 决策中存在 self-contradicting 描述 — P2

位置DD §3 "Frozen file-set decision (P2-09)" 块

当前文字

For V1.0.0 Alpha, the canonical contracts package file set is exactly the 16 files listed above

问题

  1. 上方 ASCII 列表中实际上是 15 个文件ids/error/event/runtime/ipc/task/worker-result/tool/permission/artifact/evidence/project/provider/ui/capability/platform = 16让我数一遍ids, error, event, runtime, ipc, task, worker-result, tool, permission, artifact, evidence, project, provider, ui, capability, platform = 16数对了。

  2. 但紧接着的 file-mapping 表说"context.ts symbols → runtime.ts + dedicated context.ts only if needed (otherwise inlined in runtime.ts)"以及"dedicated doctor.ts only if file size warrants split"等条目,实际允许额外文件。这与"exactly the 16 files listed above"自相矛盾。

  3. "no new .ts files are added in the contracts package without an ADR" 是好的硬约束,但表中的"only if needed"放宽了它。

根因P2-09 修复想同时表达"主体冻结" + "极少数情况可拆分",但语言模糊。

建议处理:明确两层:

  • 冻结16 个必有文件
  • 可选:context.ts / doctor.ts / knowledge.ts / diagnostics.ts 在出现明确大小/分层需求时可以追加,追加同时需要更新 code-view §3 + ADR

或更严格:彻底冻结到 16 个,不预留追加口子。

预计工作量5 分钟


6. 重新验证未受影响的领域

维度 状态
22 份基线契约覆盖 100%
55 个 durable + 7 个 ephemeral 事件覆盖 100%
19 张 DB 表的 Repository 覆盖 100%
6 个状态机覆盖 100%main agent, scheduler, task, agent, workspace, capability
10 条 forbidden edge §2 显式继承,禁止路径无破口
8 个 UML 类图 全部存在22.1-22.8
5 个序列图(含 P2-01 新增 gate 5/5
5 项 traceability 矩阵 5/5
依赖方向 无循环
事务语义 project + publish 时序正确

7. UML 类图回归审查

8 个 Mermaid 类图全部存在且语法可解析,无新偏差。需要补充指出:

  • §22.1 EventSource.kind:枚举 "main"|"architecture_designer"|"scheduler"|"agent"|"tool"|"system" 现与 §2 "runtime role" 表协同P2-08 修复正确指向 event.ts)。✓
  • §22.3 Scheduler vs WorkspaceManager 关系:图中 Scheduler --> WorkspaceManager 已暗示策略/机制层级,但未引入 P2-04 矩阵中的"Scheduler 拥有 conflict resolution policy"语义。建议是否在图旁加注 "Scheduler owns policy; WorkspaceManager owns mechanism"。
  • §22.5 WorkerRole 继承5 个 Role 类全部出现P2-07 引入的 docs TaskType 通过复用 ExecutorRole,类图无需新增节点 — ✓ 与文字一致。
  • §22.7 ContextAssembler vs PromptLayerLoader:图中 ContextAssembler --> PromptLayerLoader 是单向依赖,符合 P1-04 / P2-08 决策。建议补充 ContextAssembler --> PermissionEngine(用于 L2 Safety 加载)— 但若采纳 R1-01 选项 A此依赖也应消失。

8. 门禁判定

条件 状态
P0 = 0 PASS
契约覆盖 100% PASS
事件覆盖 100% PASS
DB Schema 覆盖 100% PASS
状态机覆盖 100% PASS
禁止路径全执行 PASS
架构无循环依赖 PASS
职责分离无泄漏 PASS
此前 4 处 P1 已闭合 PASS
此前 9 处 P2 文字已落地 PASS
修复未引入新偏离基线 FAIL3 处 P1 回归 + 2 处 P2 回归)

门禁结果CONDITIONAL PASS次轮


9. 修复优先级建议

优先级 Finding 建议处理 工作量
P1 R1-01 PermissionEngine.current_profile() 不在契约 改写 L2 Safety 来源描述 5 min
P1 R1-02 agent.started 同事件内 starting→running 违反事件原子性 恢复为基线允许的"starting OR running" 5 min
P1 R1-03 memory.promoted 引入未冻结 phase payload 字段 移除 phase 字段,回归基线 outbox 单事件叙述 15 min
P2 R2-01 §7.5 "overview §10.5" 引用错误 改为 §10.3 1 min
P2 R2-02 §3 file-set 表内 self-contradicting 明确"16 必有 + 可选追加(需 ADR"或彻底冻结 5 min

总预计工作量30 分钟


10. 多模型审查累积视角

轮次 模型 主要贡献 累积 P0 累积 P1 累积 P2
R1 DeepSeek 全量覆盖性 0 0 3
R2 MIMO 2.5 Pro 内在一致性 0 2 5
R3 GPT-5.5 Pro 基线冲突检测 0 2 (新) 4 (新)
R4 Opus 4.8 验证 + 根因 + 建议 0 2 (确认) 5 (确认)
R5 Opus 4.7(本次回归) 修复闭合性 + 回归引入检测 0 3 (新回归) 2 (新回归)

累积说明

  • R1R4 发现的 P1×4 + P2×9 已全部文字闭合commit 453df09 + 543743b
  • R5 发现修复过程引入新偏离基线的 3 P1 + 2 P2需要再迭代一次

11. 最终结论

11.1 修复有效性

  • P1×4 修复4/4 全部文字闭合,质量良好。其中 P1-04 副作用引入 R1-01。
  • P2×9 修复9/9 全部文字闭合,但 P2-03 / P2-06 / P2-09 引入新偏差P2-04 含小引用错误。

11.2 详细设计当前状态

  • 从覆盖性 / 架构合理性 / 状态机一致性看:详细设计仍然 PASS
  • 从契约/事件 payload 不变性看:当前版本存在 3 处契约/payload 越界引用R1-01 ~ R1-03

11.3 建议

短迭代修复30 分钟以内) 收束 3 P1 + 2 P2然后可以正式冻结详细设计、进入实现阶段。

不建议在不解决 R1-01 ~ R1-03 的情况下开始实现:

  • R1-01 会让 ContextAssembler 实现时找不到 current_profile() 方法
  • R1-02 会让 EventStore 实现者误以为 agent.started 投影需要做两次 status 更新
  • R1-03 会让消息处理代码尝试读不存在的 event.payload.phase 字段

11.4 最终判定

CONDITIONAL PASS (R5) — 详细设计相比 R4 后版本仍然满足覆盖性与结构正确性,但修复过程引入了 3 处契约 / payload 越界条款,需要在冻结/实现前 30 分钟内修正。


End of regression audit.