# v3.0 vs HEAD 背靠背 Review — 司马懿

> **日期**: 2026-06-10 (v2)  
> **范围**: v3.0 tag → HEAD（6 commits, +1584/-134 行, 9 个文件）  
> **方法**: `git diff v3.0..HEAD` 逐文件逐行比对 + v3.0 源码 `git show v3.0:` 回溯验证  
> **独立判断**: 不参考庞统 review，独立产出后比对

---

## 总览

v3.0 → HEAD 的核心改动是 **Step 2-5 五层架构重构**：

| 层 | 新增/改动 | 说明 |
|---|---------|------|
| Protocol + Registry | `task_type_registry.py`（已有，未改） | `TaskTypeHandler` Protocol + `TaskTypeRegistry` |
| 基类 | `base_task_handler.py`（新增 +183） | `BaseTaskHandler` — crash/verify/mark/notify 统一流程 |
| Handler × 3 | `task_handler.py`（+378）、`mail_handler.py`（+210）、`toolchain_handler.py`（+277） | 各自实现 `build_prompt` / `verify_completion` / `post_complete` |
| 引擎接入 | `dispatcher.py`（-95/+58）、`spawner.py`（+38）、`ticker.py`（+31/-27） | `_mail_*` 硬编码 → `TaskTypeRegistry` 查表 |
| 设计文档 | `step5-impact-analysis.md`（+324）、`step5-audit-report.md`（+74） | 影响分析 + 双重审计 |

**核心结论**：架构方向正确，但 **handler 注册初始化缺失导致所有 handler 路径为死代码**，实际运行仍走 `_legacy_on_complete` 旧路径。旧路径中 review verdict 处理被删除，造成 **非 handler 项目的 review 流程失效**。

---

## Part A: v3.0 逻辑丢失检查

### 方法论

逐文件追踪 v3.0 中每个 `_mail` / `_task` / `project_id == "_mail"` 分支，验证 HEAD 中是否存在等价实现。分三层检查：
1. **功能等价**：新代码是否完整覆盖旧逻辑
2. **路径可达**：新代码是否会被实际执行（handler 注册？legacy fallback？）
3. **行为一致**：边界条件、异常处理是否等价

### 检查结果

#### A1 🔴 致命：dispatcher.py — review verdict 处理丢失

**v3.0 逻辑**（`dispatcher.py` L253-308 `_task_on_complete`）：
```python
if _is_review:
    if _task_db and outcome in ("completed", "session_revived"):
        # 读 verdict
        review = conn.execute(
            "SELECT verdict FROM reviews WHERE task_id=? ORDER BY created_at DESC LIMIT 1",
            (_task_id,)).fetchone()
        if review and review["verdict"] == "approved":
            _dispatcher._mark_task_status(_task_db, _task_id, "done")
        else:
            # 非 approved → @mention assignee + 保持 review
            bb.add_comment(_task_id, "daemon", f"@{assignee} 审查结论: {verdict_str}")
```

**HEAD 逻辑**（`dispatcher.py` L246-258 `_legacy_on_complete`）：
```python
def _legacy_on_complete(aid, outcome):
    if outcome in ROLLBACK_CURRENT_AGENT_OUTCOMES and _task_db:
        _dispatcher._rollback_current_agent(_task_db, _task_id, aid)
    if not _is_review:  # ← review 时整个 if 被跳过
        _dispatcher._task_auto_complete(_task_id, _task_db)
```

**分析**：
- `_legacy_on_complete` 在 `_is_review=True` 时**什么也不做**——无 verdict 读取、无 done 标记、无 @mention 通知
- `TaskHandler.handle_review_complete()` 方法有完整 verdict 处理，但 handler 未注册（见 A2），此代码不可达
- **影响**：所有非 handler 项目（`_general` 等）的 review agent 完成后，任务永远停在 `review` 状态

**补充**：rebuttal 路径不受影响——`_rebuttal_on_complete` 在 `ticker.py` L756-790 独立定义，直接读 verdict 并处理，不经过 `_legacy_on_complete`。

---

#### A2 🔴 致命：Handler 注册初始化缺失

**证据**：
```bash
$ grep -rn "TaskTypeRegistry.register" src/
# 零结果
```

`TaskTypeRegistry.register()` 在整个代码库中**从未被调用**。`TaskHandler` / `MailHandler` / `ToolchainHandler` 类已定义但从未实例化和注册。

**后果链**：
1. `TaskTypeRegistry.get_by_project()` 永远返回 `None`
2. 所有 `if handler:` 分支不进入 → 走 `else` / fallback 路径
3. `TaskTypeRegistry.virtual_projects()` 返回空列表 → `_mail` / `_toolchain` 不被 ticker 自动发现

**各路径受影响分析**：

| 路径 | dispatcher | spawner | ticker | 实际走什么 |
|------|-----------|---------|--------|----------|
| Mail `_mail` | `handler=None` → `_legacy_on_complete` | `handler=None` → 旧 `_build_mail_prompt` | `virtual_projects()` 空 → **_mail 不被 tick** | 旧路径（无 handler），但 **ticker 不扫描 _mail** |
| Task `_general` | `handler=None` → `_legacy_on_complete` | `handler=None` → BootstrapBuilder | 不涉及 handler | 旧路径，但 review 处理被删（A1） |
| Toolchain `_toolchain` | N/A | N/A | `virtual_projects()` 空 → **_toolchain 不被 tick** | **完全不可达** |

**⚠️ A2 导致 ticker 不再扫描 `_mail` 虚拟项目**，这是 v3.0 有、HEAD 丢失的行为——v3.0 中 `_mail` 硬编码在 ticker L218-229，HEAD 改为 `TaskTypeRegistry.virtual_projects()` 但注册为空。

**需要添加的初始化代码**（缺失）：
```python
# 应在 server.py 或 bootstrap.py 的启动流程中
from src.daemon.task_handler import TaskHandler
from src.daemon.mail_handler import MailHandler
from src.daemon.toolchain_handler import ToolchainHandler

TaskTypeRegistry.register(TaskHandler())
TaskTypeRegistry.register(MailHandler())
TaskTypeRegistry.register(ToolchainHandler())
```

---

#### A3 🟡 中等：dispatcher.py — 旧 `_mail_*` 方法成为死代码

**v3.0**：`_mail_auto_working` / `_mail_auto_complete` / `_mail_check_reply` / `_mail_revert_to_pending` 被 `dispatch()` 主流程调用。

**HEAD**：这些方法仍保留在 dispatcher.py 中（L628-860），但主流程已改走 handler 路径。由于 handler 未注册，主流程走 `_legacy_on_complete`（无 handler 分支），也不调用这些方法。

**结论**：方法体保留但无外部调用者，属于死代码。不影响当前运行（因为 `_legacy_on_complete` 有独立的 executor 逻辑），但增加维护混淆。

---

#### A4 🟢 低：dispatcher.py — spawn 失败回退等价

**v3.0**：`self._mail_revert_to_pending(task.id, db_path)` — 调独立方法。
**HEAD**：内联代码（L309-327），`BEGIN IMMEDIATE` + 状态检查 + `UPDATE ... SET status='pending'`。

**等价**：新版逻辑更通用（不限于 `_mail`，任何 handler 项目都可回退）。

---

#### A5 🟢 低：dispatcher.py — `_legacy_dispatch` 路径 handler 化

**v3.0**：`is_mail_legacy = project_id.get("project_id") == "_mail"`
**HEAD**：`handler_legacy = TaskTypeRegistry.get_by_project(project_id_legacy)`

**等价**：`handler_legacy` 为 None 时跳过 pre_spawn，与 v3.0 中 `is_mail_legacy=False` 行为一致。`_legacy_dispatch` 本身仅在 `router=None` 时触发，当前配置不会进入。

---

#### A6 🟢 低：spawner.py — prompt 构建双路径

**v3.0**：`if project_id == "_mail": return self._build_mail_prompt(...)` → 走 BootstrapBuilder。
**HEAD**：`handler = TaskTypeRegistry.get_by_project(project_id)` → `if handler: return handler.build_prompt(ctx)` → else 走 BootstrapBuilder。

**分析**：
- handler 未注册时，等价于 v3.0（走 BootstrapBuilder）
- handler 注册后，Task/Mail/Toolchain 走新 PromptSection 路径
- **注意**：新旧路径的 Skill 注入策略不同——旧路径（BootstrapBuilder）**全文注入** Skill，新路径（RoleSkillSection）只给**索引+引导语**。这可能导致 handler 注册后 Agent 行为变化

---

#### A7 🟢 低：spawner.py — `_build_api_section` success_status

**v3.0**：`success_status = '"done"' if project_id == "_mail" else '"review"'`
**HEAD**：`success_status = '"done"' if handler.target_success_status == "done" else '"review"'`

**等价**：handler 未注册时走 else 分支 → `'"review"'`，与 v3.0 非 mail 项目一致。

---

#### A8 🟡 中等：spawner.py — retry prompt 仍用硬编码

**v3.0**：`is_mail = project_id == "_mail"` → 用 `MAIL_RETRY_PROMPT` 模板。
**HEAD**：同样 `is_mail = project_id == "_mail"` 硬编码（L1128），未改走 handler。

**影响**：不影响功能（retry prompt 正确），但与设计文档 §6 不一致。属于 Step 5 未覆盖的遗留点。

---

#### A9 🟢 低：ticker.py — 虚拟项目扫描

**v3.0**：硬编码 `_mail` 扫描。
**HEAD**：`TaskTypeRegistry.virtual_projects()` 循环。

**分析**：逻辑正确，但注册为空时 `_mail` 不被扫描（见 A2）。注册后自动发现 `_mail` + `_toolchain`，比 v3.0 更可扩展。

---

#### A10 🟢 低：ticker.py — assignee 清空条件

**v3.0**：`if self._current_project_id == "_mail":` → 不清空 assignee。
**HEAD**：`handler = TaskTypeRegistry.get_by_project(...); if handler:` → 不清空。

**等价**：handler 未注册时，非 handler 项目正常清空 assignee。

---

#### A11 🟢 低：ticker.py — 跳过 claimed 状态

**v3.0**：`if project_id == "_mail":` → 跳过 claimed，直接 working。
**HEAD**：`handler = TaskTypeRegistry.get_by_project(project_id); if handler:` → 跳过。

**等价**。

---

#### A12 🟢 低：ticker.py — review dispatch 跳过

**v3.0**：`if project_id == "_mail": return []`
**HEAD**：`handler = TaskTypeRegistry.get_by_project(project_id); if handler: return []`

**等价**。

---

#### A13 🟢 低：ticker.py — 超时检查幻觉门控

**v3.0**：
```python
if self._current_project_id == "_mail":
    has_reply = self._mail_check_reply(task.id, db_path)
    if has_reply:
        ... # mark done
```

**HEAD**：
```python
handler = TaskTypeRegistry.get_by_project(self._current_project_id)
if handler and handler.check_completion(task.id, db_path):
    ... # mark done
```

**等价**：`MailHandler.check_completion` 内部调 `_check_reply`，查询语义与 v3.0 的 `_mail_check_reply` 完全一致（`SELECT id FROM tasks WHERE id != ? AND must_haves LIKE ?`）。

**缩进问题**：HEAD L1483 `if handler and handler.check_completion(...):` 后续 body 缩进 5 级（28 空格），与同级代码不一致。不影响运行，但增加维护混淆。

---

#### A14 🟢 低：ticker.py — startup recovery 虚拟项目列表

**v3.0**：`for virtual_id in ("_general", "_mail"):`
**HEAD**：`virtual_ids = ["_general"] + TaskTypeRegistry.virtual_projects()`

**等价**：注册为空时只有 `_general`，注册后自动包含 `_mail` + `_toolchain`。

---

### Part A 汇总

| 严重度 | 数量 | 项目 |
|--------|------|------|
| 🔴 致命 | 2 | A1 review verdict 丢失, A2 handler 未注册 |
| 🟡 中等 | 2 | A3 死代码未清理, A8 retry prompt 硬编码 |
| 🟢 低 | 10 | A4~A7, A9~A14 |

**A1+A2 联合根因分析**：

设计意图是 handler 注册后 review 走 `TaskHandler.post_complete` → `handle_review_complete`。但注册代码缺失导致：
1. 所有项目走 `_legacy_on_complete`（旧路径）
2. 旧路径中 review 处理被删除（信任 handler 会处理）
3. review agent 完成后无任何后续动作

**同时**，ticker 不再扫描 `_mail` 虚拟项目（原来硬编码扫描），`_mail` 项目的 pending 任务无人处理。

---

## Part B: 13 个重点专题设计-编码一致性

逐专题检查设计文档描述与 HEAD 代码的一致性。标记：
- ✅ 一致
- ⚠️ 设计已标注未实施/Phase N（不算差异）
- ❌ 设计承诺但代码不一致
- 🟡 部分一致

---

### B1: 专题 01 四相循环

**设计文档**：`01-four-phase-loop.md` — PRD Phase 1~4 完整实现方案

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B1-1 | §3.3 Spawn Prompt 框架（任务+约束+API+准则+完成标准） | BootstrapBuilder + PromptSection 实现 | ✅ |
| B1-2 | §3.4 @mention 通知机制 | `_process_mentions` + `mention_queue` | ✅ |
| B1-3 | §4 Review 机制（verdict → done/notify） | `TaskHandler.handle_review_complete`（handler 未注册）+ `_rebuttal_on_complete`（ticker 独立） | ⚠️ handler 路径不可达，但 rebuttal 路径完整 |

---

### B2: 专题 02 Main Session + Delegation

**设计文档**：`02-main-session-delegation.md`

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B2-1 | §3.1 投递到 Main Session | `use_main_session=True` 参数 | ✅ |
| B2-2 | §3.3 续杯机制 | `use_main_session=True` + session 复用 | ✅ |
| B2-3 | §4.3 消息优先级与中断策略 | 无优先级队列 | ⚠️ 设计描述但未标注 Phase |
| B2-4 | §4.4 Subagent 背压控制 | 无显式背压，靠 counter 间接控制 | ⚠️ |

---

### B3: 专题 03 Prompt 进化

**设计文档**：`03-prompt-evolution.md` — 从 SOP 到任务式指挥

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B3-1 | §3.1 广播认领模板改写 | PromptSection 组装（新路径）+ BootstrapBuilder（旧路径） | ✅ |
| B3-2 | P6 反静默降级 | 无 `scope-reduction-detection` 自动机制 | ⚠️ 设计原则，未强制实施 |
| B3-3 | P7 经验闭环 | 无 IMPROVE 阶段自动触发 | ⚠️ |

---

### B4: 专题 04 黑板协作模型

**设计文档**：`04-blackboard-collaboration-model.md`

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B4-1 | §3.1 assignee 降级为显示字段，路由走 @mention | `router.py` L160-166 仍有 assignee 快速路径 | ⚠️ 设计说 Phase 1 双轨并行，Phase 2 废弃。当前停在 Phase 1 |
| B4-2 | §3.2 @mention 语义增强 | `mention_queue` + `comment_type` 已实现 | ✅ |
| B4-3 | §3.3 多人协作 `co_assignees` | 数据库无此字段 | ⚠️ Phase 3 |
| B4-4 | §3.4 output↔comment 关联 | 无关联字段 | ⚠️ Phase 2 |
| B4-5 | §3.5 层级查询 API | `parent_task` 支持 | ✅ |

---

### B5: 专题 05 上下文四层架构

**设计文档**：`05-context-layers.md`

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B5-1 | L0 铁律层 | workspace 文件注入（SOUL.md/IDENTITY.md 等） | ✅ |
| B5-2 | L1 角色层 | SOUL.md / IDENTITY.md | ✅ |
| B5-3 | L2 引擎注入层 | BootstrapBuilder 实现 | ✅ |
| B5-4 | L3 被动参考层（wiki knowledge） | 无 `_inject_wiki_knowledge` | ⚠️ 设计标注为 Phase 2 |

---

### B6: 专题 06 PM2 Crash 恢复

**设计文档**：`06-pm2-crash-recovery.md`

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B6-1 | §4.1 总体流程 `_startup_recover` | ticker.py L1614 有启动恢复 | ✅ |
| B6-2 | §4.2 claimed 状态恢复 | ✅ | ✅ |
| B6-3 | §4.2 working 状态恢复 `_recover_working_task` | ✅ | ✅ |
| B6-4 | §4.2 review 状态恢复 `_recover_review_task` | ✅ | ✅ |

---

### B7: 专题 07 Spawner Acquire-First

**设计文档**：`07-spawner-acquire-first.md` — #07.1 已实施, #07.2 已实施

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B7-1 | Phase 0 Pre-acquire 修复 | spawner.py L499-512 | ✅ |
| B7-2 | Phase 1 Counter acquire | spawner.py L516-521 | ✅ |
| B7-3 | Phase 2 Session check | spawner.py L523-568 | ✅ |
| B7-4 | Phase 2.5 假死修复 | spawner.py L557-568 | ✅ |

---

### B8: 专题 08 Classify Outcome 优化

**设计文档**：`08-classify-outcome-optimization.md` — 已实施 ✅

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B8-1 | A0-A17 判定树 | `_classify_outcome` 方法 | ✅ |
| B8-2 | A9 api_error 特殊路径 | `api_retry_count` | ✅ |
| B8-3 | A14-A17 可恢复 retry + cooldown 60s | `cooldown_seconds` + `set_cooldown` | ✅ |

---

### B9: 专题 09 Rebuttal + Goal Gate

**设计文档**：`09-rebuttal-and-goal-gate.md`

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B9-1 | §2.1 Rebuttal 自动化（review 非 approved → @mention assignee） | `review.py RebuttalManager` + `ticker.py _rebuttal_on_complete` | ✅ |
| B9-2 | §2.1 防止无限循环（max 2 轮） | `RebuttalManager.MAX_ROUNDS = 2` | ✅ |
| B9-3 | §2.2 目标一致性 Gate | 无自动 goal gate 检查 | ⚠️ 设计为 Agent 端行为，非 Daemon 侧 |

---

### B10: 专题 10 T3 需求探索 + 黑板展示

**设计文档**：`10-t3-requirement-exploration-and-blackboard-display.md`

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B10-1 | A2 需求探索过程写黑板 comments | 后端支持 `comment_type` | ✅ |
| B10-2 | A3 TaskModal 实时刷新 | SSE `comment_added` / `checkpoint_resolved` | ✅ |
| B10-3 | D1 砍掉 AI 摘要 | 黑板直投前端 | ✅ |
| B10-4 | D2 SSE 只做通知 | 前端按需拉数据 | ✅ |

---

### B11: 专题 11 上下文四层重设计

**设计文档**：`11-context-layers-redesign.md`

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B11-1 | §2.3 L2 操作规范型 6 个 Skill 全文注入 | `BootstrapBuilder` 有 `ROLE_SKILL_MAP` + `_read_skill` 全文注入 ✅；`task_handler.py RoleSkillSection` 只给索引+引导语 ⚠️ | 🟡 **双路径并存**，策略矛盾 |
| B11-2 | §2.3 `handoff.schema.json` | 不存在 | ⚠️ Phase 3 |
| B11-3 | §2.3 `review_protocols/` 目录 | 不存在，但 `review-quality` Skill 文件存在 | ⚠️ 设计文档 §三归属表已改归类为 L3 Skill |
| B11-4 | §6 Phase 3 Step 6-8 BootstrapBuilder 改造 | 已完成（ROLE_SKILL_MAP + _read_skill） | ✅ |
| B11-5 | §2.3 token 预算 ~600 tokens | bootstrap.py 有 warn 但不截断 | 🟡 有告警无硬限制 |

**B11 关键发现**：新旧路径的 Skill 注入策略矛盾——
- 旧路径（BootstrapBuilder）：**全文注入** Skill（`_read_skill` 读文件全文）
- 新路径（RoleSkillSection）：**只给索引**（"请用 read 工具读取 SKILL.md"）
- 设计文档 §2.3 要求 "A 类 Skill 全文注入"
- handler 注册后会从旧路径切换到新路径，导致 **Skill 从全文注入降级为索引提示**

这是一个 **隐性回归**：注册 handler 后 Agent 获取的操作规范信息量大幅减少。

---

### B12: 专题 12 Pipeline 设计

**设计文档**：`12-pipeline-design.md`

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B12-1 | §3 Pipeline 注册表 | 不存在 | ⚠️ 设计 §9 标注 Phase 2 |
| B12-2 | §4 路由逻辑 task_type | router.py 无 task_type 路由 | ⚪ |
| B12-3 | §8 PipelineRegistry | 不存在 | ⚪ |
| B12-4 | §10.1 task_type 默认值改 None | `blackboard_routes.py` 已为 None（v3.0 已修） | ⚪ **已实施** |
| B12-5 | §10.2 广播计数器修正 | `_broadcast_tracker` + `BroadcastRound` 已实现 | ⚪ **已实施** |

**B12 结论**：Pipeline 主体未实施符合设计路线图（Phase 2），但 §10 Phase 1 的两个 bug fix 明确标注为"立做"却未执行。

---

### B13: 专题 13 工具链与开发工作流

**设计文档**：`13-toolchain-and-dev-workflow.md`

| # | 设计要求 | 代码现状 | 判定 |
|---|---------|---------|------|
| B13-1 | §16 工具链事件中枢 | `toolchain_handler.py` + `toolchain_templates.py` | ✅ |
| B13-2 | Gitea webhook 处理 | 5 模板 + 去重 | ✅ |
| B13-3 | CI 前缀 `[CI]` | ✅ | ✅ |

---

### Part B 汇总

| 判定 | 数量 | 主要项目 |
|------|------|---------|
| ✅ 一致 | 21 | B1-1, B1-2, B2-1/2, B3-1, B4-2/5, B5-1/2/3, B6-1~4, B7-1~4, B8-1~3, B9-1/2, B10-1~4, B11-4, B13-1~3 |
| 🟡 部分一致 | 3 | B11-1 双路径策略矛盾, B11-5 token 预算无硬限制 |
| ⚠️ 设计标注未实施 | 10 | B1-3（handler 不可达）, B2-3/4, B3-2/3, B4-1/3/4, B5-4, B9-3, B11-2/3 |
| ❌ 设计承诺未交付 | 0 | — |

---

## Step 5 审计报告偏差项验证

`step5-audit-report.md` 列出 6 项偏差（D1-D6）。逐项验证 HEAD 代码：

| # | 审计描述 | HEAD 实际状态 | 判定 |
|---|---------|-------------|------|
| D1 | pre_spawn 返回值未检查 | **已修复**：`if not _handler.pre_spawn(...): raise RuntimeError("handler_pre_spawn_failed")` | ✅ 已修 |
| D2 | PromptContext 缺少 from_agent/mail_type | **已修复**：spawner L289-296 从 must_haves JSON 提取 | ✅ 已修 |
| D3 | inform outcome 白名单缺失 | 未修复。但影响极小——CRASH_OUTCOMES 由基类处理，剩余异常 outcome 罕见 | 🟢 可接受 |
| D4 | retry prompt 仍用 `is_mail` 硬编码 | **未修复**：spawner L1128 仍硬编码 `is_mail = project_id == "_mail"` | 🟡 遗留 |
| D5 | _check_reply 语义差异 | **已修复**：MailHandler._check_reply 用 `SELECT id FROM tasks WHERE id != ? AND must_haves LIKE ?`，与 v3.0 一致 | ✅ 已修 |
| D6 | 标 done 重试机制 | **已修复**：`BaseTaskHandler._mark_task_status` 有 3 次重试 | ✅ 已修 |

**结论**：D1/D2/D5/D6 已在后续 commit 修复，D3 可接受，D4 是遗留项。

---

## 与庞统 Review 的背靠背比对

| 维度 | 司马懿 | 庞统 | 差异分析 |
|------|--------|------|---------|
| **致命问题** | A1 review verdict 丢失 + A2 handler 未注册 | 仅 #1 review verdict 丢失 | **关键差异**：庞统未将 handler 未注册列为致命问题。庞统认为 `_legacy_on_complete` 仍可运行所以只关注 review 路径。但我认为 **ticker 不再扫描 `_mail`** 是 v3.0 有、HEAD 丢失的行为，这比 review 路径更严重——Mail 系统完全停止工作 |
| **_mail tick 丢失** | 明确指出 A2 导致 ticker 不扫描 `_mail` | 未提及 | 庞统漏检了 `virtual_projects()` 返回空时 `_mail` 不被 tick 的后果 |
| **Skill 注入降级** | B11-1 发现新旧路径策略矛盾 | 未提及 | 庞统未分析 handler 注册后 Skill 注入策略的变化 |
| **D1/D2/D5 修复状态** | 验证了审计报告的修复项 | 未验证 | 庞统的 review 早于修复 commit |
| **专题覆盖范围** | 13 个全覆盖 | 13 个全覆盖 | 一致 |
| **D4 retry 硬编码** | A8 独立发现 | B4 独立发现 | 独立确认 |

---

## 建议优先级

| 优先级 | 项目 | 说明 |
|--------|------|------|
| **P0** | A2 handler 注册初始化 | 添加 `TaskTypeRegistry.register()` 启动代码。**这是所有 handler 路径的前提** |
| **P0** | A1 review verdict 处理 | P0 修复后自然恢复（`TaskHandler.handle_review_complete` 生效）。**但如果不想立即注册 handler**，需先在 `_legacy_on_complete` 中恢复 review verdict 逻辑作为 interim fix |
| **P1** | B11-1 Skill 注入策略对齐 | 注册 handler 后 RoleSkillSection 只给索引——需确认这是有意降级还是遗漏。如果是遗漏，RoleSkillSection 应全文注入 |
| **P1** | A8 retry prompt handler 化 | spawner L1128 `is_mail` 硬编码改走 handler |
| **P2** | A3 死代码清理 | `_mail_auto_working` / `_mail_auto_complete` 等方法在 handler 注册后确认不再需要再删除 |
| ~~P2~~ | ~~B12-4/5~~ | ~~已验证 v3.0 tag 时已修复，不需要再改~~ |
| **P3** | ticker.py L1483 缩进对齐 | 风格问题 |

---

## Cross-Check：庞统 Review 逐项验证

对庞统 `review-v3-vs-head-pangtong.md` 的每个发现，独立验证：**是不是真问题？根因对不对？修复方案对不对？**

---

### Part A 逐项验证

#### 庞统 #1 🔴 review verdict 丢失

**庞统判定**：致命。"仅影响非 handler 项目（_general）"。

**我的验证**：

1. **是致命问题** ✅ —— `_legacy_on_complete` 在 `_is_review=True` 时确实什么都不做。

2. **"仅影响非 handler 项目" — 表述不准确**。实际情况更复杂：
   - `_general` 项目确实受影响（走 `_legacy_on_complete`）
   - 但 `_mail` / `_toolchain` 不受影响，**不是因为"handler 正确处理"**，而是因为它们**根本不走 review 流程**（ticker 中 `_dispatch_reviews` 对 handler 项目 `return []`）
   - 庞统说"handler 项目（_mail/_toolchain）的 review 由 TaskHandler.post_complete 正确处理"——**这个说法有误导性**。TaskHandler 不是 `_mail`/`_toolchain` 的 handler，它们各自的 handler（MailHandler/ToolchainHandler）没有 `handle_review_complete` 方法。它们不走 review 是因为设计上就不走。

3. **庞统的修复方案有隐藏缺陷**。庞统说"让非 handler 项目也走 TaskHandler（注册 `_general` 到 TaskTypeRegistry）"。但 `TaskTypeRegistry.get_by_project()` 匹配的是 `handler.virtual_project`，而 TaskHandler 的 `virtual_project = None`。所以：
   - `get_by_project("_general")` → 遍历所有 handler，检查 `h.virtual_project == "_general"` → TaskHandler 的 `virtual_project` 是 `None` → **不匹配** → 返回 `None`
   - 即使注册了 TaskHandler，`_general` 项目仍然走 `_legacy_on_complete`
   - 庞统的修复方案需要**额外改 TaskHandler.virtual_project 或 registry 匹配逻辑**，但他没指出这一点

**结论**：问题是真的，严重度判定正确。但影响范围描述和修复方案都不完整。

---

#### 庞统 #2 🟢 旧 `_mail_*` 方法保留

**庞统判定**：正常重构，方法体保留标记为 deprecated。

**我的验证**：

1. **方法体确实保留** ✅（dispatcher.py L628-860）
2. **但"标记为 deprecated"不对**——代码中没有 `@deprecated` 装饰器或注释。这些方法就是安静地躺在那里，没有任何标记告诉维护者"别用了"
3. **我标 🟡 中等而非 🟢**的原因：无 deprecated 标记 + 主流程不再调用 = 未来维护者容易误用

**结论**：问题不大，但庞统多给了信息（"标记为 deprecated"）——代码中实际没有标记。

---

#### 庞统 #3 🟢 spawn 失败回退

**庞统判定**：逻辑改进。

**我的验证**：✅ 确认等价，新版更通用。

---

#### 庞统 #4-5 🟢 spawner prompt/api_section

**庞统判定**：等价实现。

**我的验证**：✅ 确认等价。

---

#### 庞统 #6 🟢 ticker `_mail` → `virtual_projects()`

**庞统判定**：正常重构，可扩展。

**我的验证**：**这是庞统最大的漏检**。

庞统只看了代码方向（硬编码 → 注册表），**没有检查注册表是否为空**。

实际运行时 `TaskTypeRegistry.virtual_projects()` 返回空列表 → `_mail` 不被 ticker 扫描。这是一个 **v3.0 有、HEAD 丢失的行为**——v3.0 中 `_mail` 硬编码在 ticker L218-229，HEAD 中完全消失。

后果：所有 Mail 任务的 pending → claimed → working 流程中断，整个飞鸽传书系统停止工作。

这不是"正常重构"，是**致命回归**。

---

#### 庞统 #7-8 🟢 ticker check_reply / dispatch_reviews

**庞统判定**：等价实现。

**我的验证**：✅ 确认等价。但 #7 说"缩进正确"——实际 ticker.py L1483 有缩进不一致（28 空格 vs 同级 24 空格），不影响运行但增加维护混淆。

---

### Part B 逐专题验证

#### 专题 01-03：无分歧

庞统的检查和我的结论一致。设计原则未强制实施属于正常。

---

#### 专题 04：庞统更严格

庞统把 B4-3（co_assignees）和 B4-4（output↔comment）标 ❌，我标 ⚪（Phase 2/3）。

庞统的判定更严格——"设计了但没实现就是不一致" vs 我的"设计自身标注了 Phase，未实施是预期的"。两种视角都有道理，**不算错误**。

---

#### 专题 05：判定标准差异

庞统把 B5-4（L3 wiki 知识注入）标 ❌。我标 ⚪（Phase 2）。

同专题 04，判定标准差异。

---

#### 专题 06：庞统更细致

庞统多了 B6-5"设计提到 7 个恢复方法只看到 2 个公开方法"——这是一个合理的疑问，我没有提出。

---

#### 专题 07-10：无分歧

---

#### 专题 11：庞统全标 ❌ 是错的

庞统 B11-1 说"BootstrapBuilder 只注入通用 prompt，无 skill 全文注入"。

**我验证了代码**：
```python
# bootstrap.py L29
ROLE_SKILL_MAP = {
    "executor": "blackboard-executor",
    "reviewer": "blackboard-reviewer",
    ...
}

# bootstrap.py L68-72
skill_name = self.ROLE_SKILL_MAP.get(role)
if skill_name:
    skill_content = self._read_skill(skill_name)  # 读全文
    if skill_content:
        sections.append(skill_content)
```

**BootstrapBuilder 有 Skill 全文注入**。庞统说"无 skill 全文注入"与代码不符。他可能只看了 `task_handler.py` 的 RoleSkillSection（确实只给索引），没有看 `bootstrap.py` 的旧路径。

**实际情况**：双路径并存。旧路径（BootstrapBuilder）全文注入，新路径（RoleSkillSection）只给索引。handler 注册后从旧路径切换到新路径，Skill 信息量降级。这才是真正的问题。

---

#### 专题 12：我之前的 B12-4/5 判定有误

我在 Part B 中说"B12-4 task_type 默认值仍为 `\"coding\"`"和"B12-5 广播计数器 retry_count 不递增"是 Phase 1 承诺未交付。

**cross-check 时我重新验证了代码**：

- **B12-4**：`blackboard_routes.py` L138 已是 `body.get("task_type", None)`，**默认值已经是 None**。v3.0 tag 中也是 None。设计文档 §10.1 的 bug fix 可能在 v3.0 之前就修了，或者设计文档基于旧版本写的。**不是问题**，我之前的判定有误。

- **B12-5**：`ticker.py` 中 `_broadcast_tracker` + `BroadcastRound` + `round_number >= 3` 升级庞统的机制已实现。`mark_mention_retry` 有 `retry_count = retry_count + 1`。设计 §10.2 描述的问题已在 v3.0 或更早修复。**不是问题**，我之前的判定有误。

庞统对专题 12 的判定（"设计文档 §9 自身标记为待实现"）比我准确。

**修正我的报告**：Part B 中 B12-4 和 B12-5 应从 ❌ 改为 ⚪（设计自标 Phase 2，主体未实施是预期的）。

---

#### 专题 13：无分歧

---

### 庞统未引用 Step 5 审计报告

庞统的 review 完全没引用 `step5-audit-report.md`（v3.0..HEAD diff 中新增的文件）。这意味着 D1/D2/D5 的修复状态未经庞统验证。我逐项验证了 D1/D2/D5 **已修复**，D4 **未修复**（retry 硬编码），D3 **可接受**，D6 **已修复**。

---

### 庞统漏检的额外行为回归

handler 未注册还导致一个庞统完全没提到的问题：

**guardrail 回归**。v3.0 中 dispatcher L127-128：
```python
is_mail = project_config.get("project_id") == "_mail" if project_config else False
if self.guardrails and not is_mail:
```

HEAD dispatcher L128-131：
```python
handler = TaskTypeRegistry.get_by_project(project_config.get("project_id", "") ...)
is_handler_task = handler is not None
if self.guardrails and not is_handler_task:
```

handler 未注册 → `is_handler_task = False` → **`_mail` 项目也要过 guardrail 检查了**。v3.0 中 `_mail` 是跳过 guardrail 的。这可能导致某些 Mail 任务被 guardrail 拦截。

---

### Cross-Check 总结

| 维度 | 庞统 review 质量 |
|------|-----------------|
| **致命问题发现** | 发现 A1 ✅，漏检 A2（handler 注册 + ticker 不可达 + guardrail 回归）❌ |
| **根因分析** | A1 根因正确。修复方案不完整（没指出 TaskHandler.virtual_project=None 导致注册也匹配不到 `_general`） |
| **Part B 专题覆盖** | 13/13 全覆盖 ✅ |
| **Part B 事实准确性** | B11 "无 skill 全文注入"与代码不符 ❌。B12 比我准确 ✅ |
| **Part B 多给信息** | #2 说"标记为 deprecated"但代码无标记 ⚠️ |
| **Part B 更严格处** | B04-3/4 标 ❌（合理），B06-5 恢复方法数量疑问（合理） |
| **审计报告验证** | 未引用，未验证 D1-D6 修复状态 |
| **遗漏的行为回归** | guardrail 对 `_mail` 的回归 |

**我的自我修正**：B12-4/5 判定有误，应改为 ⚪。v3.0 tag 时这两个问题已修复，设计文档描述的是更早期的问题。

---

*— 司马懿 仲达，质量总监 🗡️*
