- review-v3-vs-head-pangtong.md → archive-3.0/ - review-v3-vs-head-simayi.md → archive-3.0/ - step5-audit-report.md → archive-3.0/ - step5-impact-analysis.md → archive-3.0/ - §20 新增 §19 审查与验证历史(关键发现+修复状态汇总)
12 KiB
Step 5 引擎接入 — 影响分析与逐点对照
方法论
逐行审查 dispatcher.py / spawner.py / ticker.py 中所有 is_mail / _mail / project_id == "_mail" 分支,
对照 handler 实现,确认每个特殊处理的去向。
一、dispatcher.py(985 行)
1.1 Guardrail 跳过(L127-129)
is_mail = project_config.get("project_id") == "_mail" if project_config else False
if self.guardrails and not is_mail:
violations = self.guardrails.check_task(task)
特殊处理:Mail 不做 guardrail 检查。
Handler 覆盖:设计文档 D6 "skip_guardrail 从接口删除,guardrail 自己判断"。Step 5 改为:if self.guardrails and handler is None(无 handler 时走 guardrail),或者用 handler.virtual_project 判断。handler 存在时跳过 guardrail。
改动:is_mail → TaskTypeRegistry.get_by_project(project_id) is not None
1.2 Mail on_checks_passed(L194-213)
on_checks_passed = None
_mail_marked_working = False
if is_mail and db_path:
def _mail_on_checks_passed():
nonlocal _mail_marked_working
if not _disp._mail_auto_working(_task_id, _mail_db):
raise RuntimeError("mail_auto_working_failed")
_mail_marked_working = True
on_checks_passed = _mail_on_checks_passed
特殊处理:Mail spawn 前通过 on_checks_passed 回调标 working,标记成功后才 spawn,spawn 失败回退。
Handler 覆盖:MailHandler.pre_spawn 调用 _auto_mark_working,和 _mail_auto_working 逻辑完全一致。
改动:
on_checks_passed改为调用handler.pre_spawn(task_id, db_path)_mail_marked_working标记保留,用于 Exception 回退
1.3 Mail on_complete(L224-238)
if is_mail:
def _mail_on_complete(aid, outcome):
_dispatcher._mail_auto_complete(_task_id, aid, _mail_db, _must_haves, outcome=outcome)
on_complete = _mail_on_complete
特殊处理:Mail on_complete 调用 _mail_auto_complete(含 inform/request 分支、幻觉门控、重试 3 次、失败通知)。
Handler 覆盖:MailHandler 使用基类 post_complete 统一流程(crash→verify→mark→notify)。但现有 _mail_auto_complete 有几个细节差异需要注意:
| 现有逻辑 | Handler 覆盖 | 差异 |
|---|---|---|
| request 无回复 → 重试 3 次标 failed | on_failure 标 failed + notify | ⚠️ 缺少 3 次重试 |
| inform 只在特定 outcome 标 done | verify 始终返回 True → 基类标 done | ✅ 简化了,合理 |
| 标 done 重试 3 次 | _mark_task_status 单次 | ⚠️ 缺少重试 |
| notify_mail_failed | on_failure 中调用 notify_mail_failed | ✅ 一致 |
⚠️ 关键发现:现有代码标状态时有 重试 3 次 机制(防止 DB 锁),handler 的 _mark_task_status 只做一次。需要把重试逻辑补到 _mark_task_status 或在 handler 层加。
改动:on_complete 改为调用 handler.post_complete(task_id, agent_id, outcome, db_path)
1.4 Task on_complete(L241-310)
else:
def _task_on_complete(aid, outcome):
# #07.2: crash 回退
if outcome in ROLLBACK_CURRENT_AGENT_OUTCOMES and _task_db:
_dispatcher._rollback_current_agent(_task_db, _task_id, aid)
if _is_review:
if outcome in ("completed", "session_revived"):
# 读 verdict → approved 标 done / 非 approved @mention assignee
else:
logger.warning("review agent outcome=%s, NOT marking done", outcome)
else:
# executor: 三信号验证 → 标 review
_dispatcher._task_auto_complete(_task_id, _task_db)
特殊处理清单:
- #07.2 crash 回退:executor 和 review 都回退 current_agent → assignee
- review 分支:outcome 必须是 "completed" 或 "session_revived" 才走 verdict 读取
- review verdict 读取:approved → done,非 approved → @mention assignee + 保持 review
- review @mention:通过 Blackboard.add_comment,comment_type="review"
- executor 分支:走 _task_auto_complete → 三信号验证 → review
Handler 覆盖:
- crash 回退:✅ BaseTaskHandler.post_complete 第一步
- review verdict:⚠️ TaskHandler.handle_review_complete 存在但未被 dispatcher 调用。现有 dispatcher 直接在闭包里做了,不走 handler。
- @mention:⚠️ handler 用
conn.execute("INSERT INTO comments")直接插入,dispatcher 用Blackboard.add_comment(会做更多处理,如 comment_type="review") - executor 三信号:✅ TaskHandler.verify_completion
⚠️ 关键发现:
- dispatcher 的 review @mention 用
bb.add_comment(..., comment_type="review"),handler 直接 INSERT 不带 comment_type。需要修复 handler。 - dispatcher 对 review outcome 有白名单检查(只处理 "completed"/"session_revived"),handler 的 post_complete 没有 outcome 白名单——crash 已在基类处理,其他 outcome 都会走 verify。
- dispatcher review 非 approved 时保持 review 状态,handler 的 handle_review_complete 标回 working。这是行为差异。
改动:需要先修复 handler 的 review 分支,再替换 on_complete。
1.5 Mail spawn 失败回退(L355-358)
except Exception as e:
if _mail_marked_working:
self._mail_revert_to_pending(task.id, db_path)
特殊处理:spawn 失败(subprocess 启动失败)回退 working → pending。
Handler 覆盖:❌ handler 没有这个。这是 dispatcher 级别的异常处理,和 handler 无关。但 toolchain 也需要类似逻辑。
改动:保留在 dispatcher 中,改为 _mail_marked_working → handler_marked_working。
1.6 Legacy dispatch(L584-660)
is_mail_legacy = project_config.get("project_id") == "_mail"
if is_mail_legacy:
if not self._mail_auto_working(task.id, db_path_legacy):
return error
特殊处理:legacy 路径(router=None 时触发)也有 mail 特殊处理。
Handler 覆盖:同 1.2/1.3,用 handler 替代。
改动:同样用 handler.pre_spawn 和 handler.post_complete 替代。
1.7 现有 Mail 辅助方法(L658-870)
_mail_auto_working / _mail_revert_to_pending / _mail_auto_complete / _mail_check_reply
改动:Step 5 不删这些方法(安全起见保留,标记 deprecated),只改调用方。确认稳定后再删。
二、spawner.py(1704 行)
2.1 _build_prompt 中的 mail 分支(L282-284)
if project_id == "_mail":
return self._build_mail_prompt(task_id, title, description, must_haves, agent_id)
特殊处理:Mail 用专用精简模板。
Handler 覆盖:MailHandler.build_prompt 通过 PromptComposer 拼 3 个 section。
改动:查注册表 → handler.build_prompt(context)。需要构建 PromptContext 传入。
2.2 _build_api_section(L321-325)
success_status = '"done"' if project_id == "_mail" else '"review"'
特殊处理:Mail 的 success_status 是 done。
Handler 覆盖:已由 handler 的 PromptSection 处理(TaskApiSection hardcode review,MailApiSection 不含 status 回写指令)。
改动:如果 handler 存在,跳过 _build_api_section(handler.build_prompt 已包含)。
2.3 classify_outcome 中的 handler 调用
spawner 在 classify_outcome 后调 on_complete(outcome)。on_complete 是 dispatcher 传入的闭包。
改动:on_complete 闭包改为调用 handler.post_complete。spawner 本身不直接查注册表。
三、ticker.py(1897 行)
3.1 虚拟项目扫描(L218-229)
mail_db = Path(self.registry.root) / "_mail" / "blackboard.db"
if mail_db.exists() and "_mail" not in active_projects:
pr = await self._tick_project("_mail", {...})
特殊处理:_mail 硬编码扫描。
Handler 覆盖:TaskTypeRegistry.virtual_projects() 返回 ["_toolchain", "_mail"]。
改动:循环 TaskTypeRegistry.virtual_projects() 替代硬编码。_toolchain 如果也需要 ticker 扫描就自动发现。但需确认 _toolchain 是否需要 ticker——当前 toolchain 任务创建和完成都在 toolchain_routes.py 中处理,可能不需要 ticker 扫描。
3.2 _transition_status 中 mail assignee 不清空(L953-960)
if new_status == "pending":
if self._current_project_id == "_mail":
# Mail 的 assignee 是收件人,永不清空
conn.execute("UPDATE tasks SET status=?, updated_at=? WHERE id=?", ...)
else:
conn.execute("UPDATE tasks SET status=?, assignee=NULL, ...", ...)
特殊处理:Mail 重置到 pending 时不清空 assignee(assignee 是收件人)。
Handler 覆盖:❌ handler 不管 ticker 的状态转换逻辑。这是 ticker 内部逻辑。
改动:用 TaskTypeRegistry.get_by_project(project_id) 判断替代硬编码。
3.3 Mail 跳过 claimed 状态(L1029-1043)
if project_id == "_mail":
conn.execute("UPDATE tasks SET current_agent=? WHERE id=?", ...)
# 跳过 claimed,直接 working
特殊处理:Mail 不走 claimed 中间态(已在 dispatcher 中标 working)。
Handler 覆盖:handler.pre_spawn 的 _auto_mark_working 跳过了 claimed。
改动:用 handler 判断替代硬编码。
3.4 _dispatch_reviews 跳过 mail(L1304)
if project_id == "_mail":
return []
特殊处理:Mail 不走 review 流程。
Handler 覆盖:MailHandler.target_success_status = "done",不走 review。但 ticker 的 _dispatch_reviews 是看项目级。
改动:用 handler 判断。
3.5 Mail 幻觉门控兜底(L1474-1492)
if self._current_project_id == "_mail":
has_reply = self._mail_check_reply(task.id, db_path)
if has_reply:
# working → done
特殊处理:Ticker 超时检查时,如果 mail 有回复,标 done 而非 failed。
Handler 覆盖:❌ handler 的 check_completion 只返回 bool,不做状态标记。
改动:调用 handler.check_completion 替代 _mail_check_reply。状态标记逻辑保留在 ticker 中。
3.6 _mail_check_reply(L1555-1575)
和 dispatcher 版本一致。
改动:用 handler.check_completion 替代。
3.7 虚拟项目 init + recovery 扫描(L1625-1643)
for virtual_id in ("_general", "_mail"):
...
# _mail 项目不清空 assignee
改动:virtual_projects() + _general 硬编码。
四、Handler 缺陷(需在 Step 5 前修复)
| # | 缺陷 | 影响 | 修复方案 |
|---|---|---|---|
| H1 | BaseTaskHandler._mark_task_status 无重试 | DB 锁时标状态失败,任务卡住 | 加 3 次重试(和 dispatcher 现有行为一致) |
| H2 | TaskHandler.handle_review_complete 中 @mention 不带 comment_type="review" | review comment 无类型标记 | INSERT 加 comment_type |
| H3 | dispatcher review 非 approved 保持 review 状态,handler 标 working | 行为差异 | handler 改为保持 review 状态(和 dispatcher 一致) |
| H4 | dispatcher review outcome 有白名单("completed"/"session_revived"),handler 无 | crash 之外的异常 outcome 也会走 verify | handler 的 post_complete 已在基类处理 crash,其余 outcome 走 verify 是合理的 |
H3 最关键——dispatcher review 非 approved 保持 review 状态(等 assignee 自己处理),handler 标 working 会触发 ticker 重新 dispatch executor,这不是预期行为。
五、改动策略
不删旧代码,只改调用方:
- dispatcher 中 is_mail → handler 判断,on_checks_passed/on_complete → handler.pre_spawn/post_complete
- spawner 中 _build_prompt → handler.build_prompt
- ticker 中虚拟项目扫描 → registry.virtual_projects(),mail 特殊判断 → handler 判断
- 旧方法(_mail_auto_working 等)标记 @deprecated 保留,不删
先修 handler 缺陷(H1-H3),再改引擎。