--- title: "ToolchainHandler 强约束设计" created: 2026-06-13 version: v1.0 status: draft --- # ToolchainHandler 强约束设计 > **状态**: 草案 > **作者**: 庞统(副军师)🐦 > **日期**: 2026-06-13 > **定位**: 让 toolchain 事件走已有的 ToolchainHandler(§14 设计),并在 ToolchainHandler 中加入 L2 引擎层的强约束(输入/执行/输出),取代 §16 权宜方案中走 MailHandler inform 的路径 > **前置文档**: §14 TaskTypeRegistry + Handler 架构、§13 工具链与开发流程设计 > **推翻文档**: 原 §17 action Mail 类型设计(`17-action-mail-type.md`) --- ## §1. 问题陈述 ### 1.1 现状 ToolchainHandler 已完整实现并注册(`src/daemon/toolchain_handler.py`,`virtual_project="_toolchain"`)。但实际的 toolchain 事件流从未走过 ToolchainHandler: | 环节 | 设计(§14) | 实际(§16 权宜) | |------|------------|----------------| | 创建 task | `project_id="_toolchain"` + `task_type="toolchain"` | `project_id="_mail"` + `task_type="mail"` | | 写入 DB | `_toolchain/blackboard.db` | `_mail/blackboard.db` | | 路由 handler | ToolchainHandler | MailHandler | | 完成验证 | verify action output | inform 始终通过 | **根因**:§16 设计 toolchain 事件中枢时,没有用 ToolchainHandler,而是通过 `_send_mail`(`src/api/toolchain_routes.py` L203)创建 `task_type="mail"` + `type=inform"` 的 task。§16 D1 决策"不做第三种 task 类型"是基于权宜方案做的——但 §14 早已设计了 ToolchainHandler 作为独立的 task 类型,只是没有接线。 ### 1.2 后果 所有 toolchain 事件走了 MailHandler 的 inform 路径: 1. MailHandler 的 inform PromptSection 说"已阅即可"、"不要执行任何状态转换命令"——Agent 收到 Review 驳回通知后当纯通知处理就 done 了 2. verify_completion 对 inform 始终返回 `VerifyResult(True)`——没有任何验证 3. 流程断链:Review 驳回 → Agent 不修 → 永远卡在驳回状态;CI 失败 → Agent 不修 → 永远卡在失败状态 ### 1.3 主公要求 > "输入,执行过程和输出都要能确保流程的顺利执行,以及业务内容的承载" > "L2 引擎这一层的 toolchain 必须是强约束的" > "不强约束总是断链" ### 1.4 方向 **不是给 Mail 加类型,而是让 toolchain 事件回归 ToolchainHandler**。ToolchainHandler 已有独立的 DB、独立的 PromptSection、独立的 verify 逻辑。需要做的是: 1. 新增 `_send_toolchain_task` 函数,创建 `project_id="_toolchain"` + `task_type="toolchain"` 的 task 2. 强化 ToolchainHandler 的三个 PromptSection,实现 L2 引擎层的三层强约束 3. 强化 verify_completion,从"任意 comment ≥20 字符"升级为"action_report comment 存在" --- ## §2. 三层强约束总览 主公要求的"输入、执行过程和输出"三层,对应 ToolchainHandler 的三个核心环节: ``` ┌─────────────────────────────────────────────────────────┐ │ ToolchainHandler 强约束 │ │ │ │ ┌─── 输入约束 ───┐ ┌─── 执行约束 ───┐ ┌─── 输出约束 ──┐ │ │ │ │ │ │ │ │ │ │ │ must_hives JSON │ │ PromptSection │ │ verify_ │ │ │ │ 携带结构化字段 │→ │ 强语气+Red Flag│→ │ completion │ │ │ │ │ │ │ │ │ │ │ │ ToolchainContext│ │ ToolchainCon- │ │ action_report│ │ │ │ Section 渲染 │ │ straintsSection│ │ comment 检查 │ │ │ │ 编号步骤列表 │ │ 必须执行 │ │ │ │ │ │ │ │ │ │ on_failure: │ │ │ │ │ │ │ │ 标failed+通知│ │ │ └────────────────┘ └────────────────┘ └──────────────┘ │ │ │ │ 数据流: webhook → _send_toolchain_task → _toolchain DB │ │ → spawner (ToolchainHandler.build_prompt) │ │ → Agent 执行 → comment (action_report) │ │ → verify_completion → done / failed │ └─────────────────────────────────────────────────────────┘ ``` | 层 | 目标 | 机制 | 防什么 | |----|------|------|--------| | **输入约束** | Agent 收到的不是一句话摘要,而是结构化的编号步骤 + 事件上下文 | must_hives JSON(event_type, action_type, steps, context)+ ToolchainContextSection 渲染 | 防"Agent 不知道该做什么" | | **执行约束** | Agent 知道必须执行,不会自合理化跳过 | ToolchainConstraintsSection 强语气"必须执行" + Red Flags 表 | 防"Agent 当纯通知忽略" | | **输出约束** | Agent 执行后有可验证的产出 | verify_completion 检查 action_report comment | 防"Agent 假装执行" | --- ## §3. 输入约束(Agent 收到什么) ### 3.1 must_hives JSON 结构 toolchain task 的 `must_hives` 字段携带完整的结构化信息: ```json { "event_type": "review_result", "action_type": "review_result", "steps": [ "合并 PR(Gitea API: POST /repos/{repo}/pulls/{pr_number}/merge)", "提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/{task_id}/comments,comment_type=action_report)" ], "context": { "pr_number": 42, "repo": "sanguo/sanguo_moziplus_v2", "pr_title": "feat: add login page", "result": "APPROVED", "reviewer": "simayi-challenger", "review_body": "代码质量良好,可以合并" }, "from": "system", "source": "webhook" } ``` 字段说明: | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `event_type` | string | ✅ | 事件类型,用于 ToolchainContextSection 模板选择 | | `action_type` | string | ✅ | 动作分类,用于步骤选择和日志统计 | | `steps` | string[] | ✅ | 结构化编号步骤列表,渲染到 Prompt 中 | | `context` | object | ❌ | 事件上下文数据(PR 号、仓库名、review 意见等) | | `from` | string | ✅ | 来源标识(`system` / webhook) | | `source` | string | ❌ | 来源类型(`webhook`) | ### 3.2 ToolchainContextSection 渲染增强 现有 `ToolchainContextSection` 使用模板引擎渲染事件信息。增强后必须包含三部分内容: **Part 1:事件类型 + 事件上下文**(现有,保留) 通过 `toolchain_templates.py` 的模板引擎渲染,展示事件的核心信息(PR 标题、审查结果、CI 错误摘要等)。 **Part 2:结构化编号步骤**(新增,从 must_hives 的 `steps` 字段读取) ```markdown ### 必须执行的步骤 1. 合并 PR(Gitea API: POST /repos/sanguo/sanguo_moziplus_v2/pulls/42/merge) 2. 提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks//comments,comment_type=action_report) ``` **Part 3:事件专属 action 指引**(新增,按 action_type 选择) 每种事件类型有对应的 action 指引文本,以"你收到一个需要执行动作的事件"开头,明确告诉 Agent 这不是纯通知。 渲染逻辑伪代码: ```python class ToolchainContextSection: def render(self, context: PromptContext) -> str: # Part 1: 事件信息(现有模板引擎) event_text = render_template(context.event_type, ...) # Part 2: 结构化步骤(新增) steps = context.action_steps # 从 PromptContext 获取 steps_text = "" if steps: lines = ["", "### 必须执行的步骤", ""] for i, step in enumerate(steps, 1): lines.append(f"{i}. {step}") steps_text = "\n".join(lines) # Part 3: action 指引(新增) action_hint = self._get_action_hint(context.action_type) return f"{action_hint}\n\n{event_text}{steps_text}" def _get_action_hint(self, action_type: str) -> str: hints = { "review_result": "你收到一个 Review 结果通知,这是一个需要你执行动作的事件(不是纯通知)。", "review_request": "你收到一个 Review 请求,这是一个需要你审查并提交 Review 的事件。", "ci_failure": "你收到一个 CI 失败通知,这是一个需要你修复失败测试的事件。", ... } return hints.get(action_type, "你收到一个工具链事件,这是一个需要你执行动作的事件。") ``` ### 3.3 与 §13 §15.5 强约束模板的关系 §13 §15.5 定义了 6 个流程强约束 Mail 模板,每个模板包含编号步骤和 Gitea API 调用指令。这些模板内容**不变**,但承载方式变了: | 维度 | §16 权宜方案 | 本设计 | |------|------------|--------| | 模板渲染为 | Mail task 的 description | toolchain task 的 description(ToolchainContextSection 模板引擎) | | 步骤固化在 | description 纯文本中 | must_hives JSON `steps` 字段 + PromptSection 渲染 | | Agent 是否能看到步骤 | 受 MailHandler inform prompt 干扰("已阅即可") | ToolchainHandler prompt 强化("必须执行") | --- ## §4. 执行约束(Agent 知道必须做) ### 4.1 ToolchainConstraintsSection 强化 现有的 `ToolchainConstraintsSection` 有 5 条约束,但语气不够强,且缺少防自合理化机制。改写为: ```markdown ## 硬约束(必须遵守) ⚠️ 以下是强制要求,不是建议或参考。违反任何一条都会导致任务失败。 ### 1. 必须按步骤执行 - 检查上方"必须执行的步骤"列表 - 逐条执行每个步骤,不可跳过 - 不要只读不做——这不是纯通知 ### 2. 必须提交 action report - 执行完所有步骤后,必须提交 action report - 提交方式:POST comment(comment_type='action_report') - 报告内容:简要描述你执行了什么操作、结果如何 - ⚠️ 不提交 action report 的任务会被标记为 failed ### 3. 不要执行任何状态转换命令 - 不要手动标 working/done/review/failed,系统会自动处理 ### 4. 不需要回复 - action report 就是你的完成凭证 - 不要发送 Mail(飞鸽传书),你的所有操作在 toolchain 流程内完成 ### 5. 所有协作通过 Gitea 完成 - 如果遇到问题需要其他角色支持,在关联的 PR/Issue 上创建 comment @对方 - 不要使用 Mail API(飞鸽传书)发送消息 - 你的所有操作都在 toolchain 流程内,通过 Gitea 留痕 ### Red Flags(如果脑海中出现以下想法,说明你错了) | Agent 想法 | Red Flag 驳回 | |------------|--------------| | "这个通知看看就行了" | ❌ 错!这是 action 指令,必须执行步骤列表中的每一项 | | "我不需要做任何事" | ❌ 错!检查"必须执行的步骤"列表,每一步都要执行 | | "先放着等会处理" | ❌ 错!立即执行,不要推迟 | | "我已经知道了" | ❌ 知道不等于执行。执行步骤 + 提交 action report 才算完成 | | "步骤太多了,选几个做就行" | ❌ 错!必须逐条执行,不可跳过 | | "这个步骤不适用于当前情况" | ❌ 如果确实不适用,在 action report 中说明原因,但其他步骤必须执行 | ``` ### 4.2 Red Flags 表设计原理 参考 Superpowers 模式的 Red Flags 防 self-rationalization 机制: **问题**:LLM Agent 面对需要执行动作的 prompt 时,常见的 self-rationalization 模式: 1. **降级处理**:把 action 当 inform 处理("这个通知看看就行了") 2. **推迟执行**:识别到需要执行但不执行("先放着等会处理") 3. **部分执行**:选择性跳过步骤("选几个做就行") 4. **认知混淆**:知道但没行动("我已经知道了") **解法**:提前列出这些 self-rationalization 模式,在 Agent 的 prompt 中以"Red Flag"表格形式呈现。当 Agent 的推理过程中出现这些模式时,表格中的"驳回"语句会激活,阻止 Agent 继续沿错误路径推理。 **来源**:Superpowers 框架的"Pre-commitment + Red Flag"模式。预先承诺一个规则,然后列出违反规则的常见借口,让 Agent 在推理时就识别出自己的 self-rationalization。 ### 4.3 强语气设计 | 语气级别 | 用词 | 效果 | 使用场景 | |---------|------|------|---------| | **强制** | "必须"、"不可跳过"、"强制要求" | Agent 无法自合理化跳过 | 步骤执行、action report 提交 | | **禁止** | "不要"、"违反会"、"failed" | Agent 不会越界 | 状态转换、发送 Mail | | **提醒** | "⚠️" | 视觉强调 | 关键约束前缀 | **避免的用词**:"建议"、"如需"、"可以考虑"、"参考"、"推荐"——这些词在 Agent 的推理中会被解读为"可选"。 ### 4.4 ToolchainApiSection 调整 现有的 `ToolchainApiSection` 指示 Agent 标 done,但强约束设计中 done 由 verify_completion 自动触发。调整: ```markdown ## API 操作指令 项目 ID: `_toolchain` 任务 ID: {task_id} ### 完成后必须提交 action report 执行完所有步骤后,必须提交 action report: ```bash curl -s -X POST "http://localhost:8083/api/projects/_toolchain/tasks/{task_id}/comments" \ -H "Content-Type: application/json" \ -d '{"author": "{agent_id}", "comment_type": "action_report", "body": "简要描述你执行了什么操作及结果"}' ``` ⚠️ 不提交 action report 的任务会被标记为 failed。 ### 提交产出 如有产出(如 review 结果、修复方案),提交到任务 outputs: ```bash curl -s -X POST "http://localhost:8083/api/projects/_toolchain/tasks/{task_id}/outputs" \ -H "Content-Type: application/json" \ -d '{"content": "<你的产出内容>", "type": "text"}' ``` ``` ### 需要其他角色支持时 如果在执行过程中需要其他角色协助(如缺数据、需要审批等),在关联的 PR/Issue 上创建 comment @对方: ```bash curl -s -X POST "http://192.168.2.154:3000/api/v1/repos/{repo}/issues/{pr_number}/comments" \ -H "Authorization: token " \ -H "Content-Type: application/json" \ -d '{"body": "@{agent-id} 需要你的支持:{描述问题}"}' ``` ⚠️ 不要使用 Mail API(飞鸽传书)。所有协作通过 Gitea 留痕。 **变化**:移除了"手动标 done"的 curl 示例(done 由 verify 自动处理),替换为 action report 提交指引。 --- ## §5. 输出约束(Agent 执行后怎么验证) ### 5.1 verify_completion 设计 **D17-1: verify_completion 采用 action_report comment 机制** 现有逻辑:检查 output 或 comment(任意 comment 长度 ≥20 字符)→ 通过。 问题:Agent 可以随便写一条 comment 就通过验证,无法确认是否真正执行了步骤。 新逻辑:检查 `comment_type='action_report'` 的 comment 是否存在。 ```python def verify_completion(self, task_id: str, db_path: Path) -> VerifyResult: """检查 action report(精确验证)""" try: conn = get_connection(db_path) try: # 1. 优先检查 action_report comment report_row = conn.execute( "SELECT id FROM comments WHERE task_id=? " "AND comment_type='action_report' LIMIT 1", (task_id,) ).fetchone() if report_row: return VerifyResult(True, "has_action_report", "action_report found") # 2. fallback:检查 output(向后兼容) output_count = conn.execute( "SELECT COUNT(*) FROM outputs WHERE task_id=?", (task_id,) ).fetchone()[0] if output_count > 0: return VerifyResult(True, "has_output", f"output_count={output_count}") # 3. fallback:检查有实质内容的 comment(向后兼容) comment_count = conn.execute( "SELECT COUNT(*) FROM comments WHERE task_id=? " "AND author != 'system' AND LENGTH(body) >= 20", (task_id,) ).fetchone()[0] if comment_count > 0: return VerifyResult(True, "has_comment", f"comment_count={comment_count}") return VerifyResult(False, "no_action", "no action_report, no output, no valid comment") finally: conn.close() except Exception as e: logger.error("Toolchain %s: verify error: %s", task_id, e) return VerifyResult(False, "verify_error", str(e)) ``` **验证优先级**: 1. `action_report` comment(首选——精确验证 Agent 执行了步骤) 2. output(fallback——Agent 可能通过 outputs API 提交了产出) 3. 有实质内容的 comment(fallback——向后兼容现有行为) 保留 fallback 层次是为了平滑过渡:改造初期 Agent 可能还不习惯提交 action_report,fallback 避免"改造后所有 task 都 failed"的问题。 ### 5.2 on_failure 处理 **设计原则**:toolchain 事件全生命周期在 toolchain 流程内闭环,不走 Mail API。失败本身按错误类型分类,路由到不同的 Gitea 管理动作。 #### 错误分类三分路 | 错误类型 | 例子 | 处理方式 | 管道 | |---------|------|---------|------| | **业务失败** | verify 不过(no action_report)、Agent 忽略步骤 | 在关联 PR/Issue 上创建 comment @原始 assignee | Gitea webhook → §25 @mention → toolchain task | | **系统失败** | spawner crash、timeout、max_retries、业务失败连续 3 次 | 创建 Gitea Issue 指派 pangtong-fujunshi | Gitea webhook → issue_assigned → toolchain task | | **基础设施失败** | Gitea API 不可用、网络不通 | `_send_toolchain_task` 直接创建 toolchain task 指派 jiangwei-infra | toolchain 内部直接创建 | 三条路全在 toolchain 流程内,Mail 完全不参与。 #### 防递归保护 基础设施失败创建的 toolchain task(action_type=infrastructure_failure),其 verify_completion 始终返回 `VerifyResult(True)`,不再触发 on_failure。 #### 完整设计 三分路的详细设计见 §6.4(基础设施 Issue 转交流程)和 toolchain_handler.py 实现(`_handle_infrastructure_failure` / `_classify_failure`)。 #### 首次 steps 分支指引 三分路是 verify 失败后的兜底机制。此外,ci_failure 和 deploy_failure 的首次 toolchain task steps 中**已包含分支指引**——agent 在执行过程中自行判断失败原因,如果是基础设施问题则直接创建 Issue 指派 jiangwei-infra(见 §6.4)。三分路作为第二道防线,覆盖 agent 未正确判断或未执行分支的情况。 ### 5.3 action_report comment 格式 Agent 提交的 action_report comment: ```json { "comment_type": "action_report", "author": "zhangfei-dev", "body": "已修复 CI 失败:修正 import 错误(src/api/routes.py L23),push 到 feat/issue-42 分支。CI 已自动重跑。" } ``` **comment body 要求**: - 简要描述执行了什么操作 - 如有修改,说明修改的文件和大致内容 - 如有外部验证(CI 重跑、Review 提交),说明状态 ### 5.4 防虚假报告 Agent 可能写了 action_report 但没真做。缓解机制: 1. **后续事件链自然暴露**:CI 不会通过、Reviewer 不会收到 Review、部署不会成功 2. **action_report 可审计**:庞统可以查看 action_report 内容和实际 Gitea 状态是否一致 3. **验证目标定位**:verify 的首要目标是防止 Agent"没看到/忽略了"(占 90% 的失败场景),不是防止恶意行为(<10%) --- ## §6. 场景 steps 定义 ### 6.1 完整场景对照表 | 场景 | action_type | 走向 | steps | 说明 | |------|------------|------|-------|------| | Review APPROVED → PR 作者 | review_result | toolchain | 2 步 | 合并 PR + 提交 report | | Review REQUEST_CHANGES → PR 作者 | review_result | toolchain | 4 步 | 修改代码 + push + 等 Review + report | | Review 请求 → reviewer | review_request | toolchain | 4 步 | 读 diff + 审查 + 提交 Review + report | | Review 有新提交 → reviewer | review_updated | toolchain | 4 步 | 读 diff + 检查修改 + 提交 Review + report | | Review 评论 → PR 作者 | review_comment | toolchain | 3 步 | 查看评论 + 响应(修改/回复)+ report | | CI 失败 → PR 作者 | ci_failure | toolchain | 3 步 | 查 CI 日志 + 分支判断(代码问题自己修 / 基础设施问题提 Issue 给姜维)+ report | | Issue 指派 → 开发者 | issue_assigned / infrastructure_failure | toolchain | 6 步(编码)或 4 步(运维) | 按 label 分流:type/infrastructure → 运维排查;其他 → 创建分支 + 编码 + push + CI + PR + report | | 部署失败 → 运维 | deploy_failure | toolchain | 3 步 | 查日志 + 分支判断(代码/配置问题自己修 / 基础设施问题提 Issue 给姜维)+ report | | @mention → 被@者 | mention | toolchain | 按 guidance | 按 mention 模板的 response_guidance + report | | PR 合并 → PR 作者 | review_merged | toolchain | 0 步 | 纯通知,走 _send_toolchain_task(steps 为空,verify 始终通过) | **D17-2: 所有 toolchain 场景走 ToolchainHandler** ### 6.2 各场景 steps 详细定义 #### Review APPROVED → PR 作者 ``` event_type: review_result action_type: review_result steps: 1. 合并 PR(Gitea API: POST /repos/{repo}/pulls/{pr_number}/merge) 2. 提交 action report(POST .../comments, comment_type=action_report) context: pr_number, repo, pr_title, result=APPROVED, reviewer, review_body ``` #### Review REQUEST_CHANGES → PR 作者 ``` event_type: review_result action_type: review_result steps: 1. 按审查意见逐条修改代码 2. push 到原分支 → CI 自动跑 3. CI 通过后等重新 Review 4. 提交 action report context: pr_number, repo, pr_title, result=REQUEST_CHANGES, reviewer, review_body ``` #### Review 请求 → reviewer ``` event_type: review_request action_type: review_request steps: 1. 读取 PR diff(Gitea API: GET /repos/{repo}/pulls/{pr_number}.diff) 2. 按审查清单审查(参考 code-review Skill) 3. 提交 Review(Gitea API: POST /repos/{repo}/pulls/{pr_number}/reviews)— APPROVE 或 REQUEST_CHANGES 4. 提交 action report context: pr_number, repo, pr_title, pr_author, branch, risk_level, changed_files ``` #### Review 有新提交 → reviewer ``` event_type: review_updated action_type: review_updated steps: 1. 读取 PR diff(Gitea API: GET /repos/{repo}/pulls/{pr_number}.diff) 2. 重点检查上次 Review 意见的修改部分 3. 提交 Review(Gitea API: POST /repos/{repo}/pulls/{pr_number}/reviews) 4. 提交 action report context: pr_number, repo, pr_title, pr_author, new_sha, reviewer ``` #### CI 失败 → PR 作者 ``` event_type: ci_failure action_type: ci_failure steps: 1. 查看完整 CI 日志(PR 页面或 Gitea Actions 页面) 2. 根据 CI 日志判断失败原因类型: a. 代码问题(lint/test 失败)→ 修复失败的测试 → push 到原分支 → CI 自动重跑 b. 基础设施问题(runner 环境/Python/venv/Gitea/网络故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见 §6.4),label 必须包含 type/infrastructure 3. 提交 action report — 报告中说明判断的原因类型和执行的操作 context: pr_number, repo, branch, error_summary ``` **分支设计说明**:原设计假设"CI 失败 = 代码问题",steps 只有"修测试 + push"一条路径。实际运行中发现 CI 失败可能是 runner 环境故障(如 ensurepip 失败),agent 判断为基础设施问题后不知道该做什么。现在 steps 中明确两条分支,agent 自行判断后走对应路径。 #### Issue 指派 → 开发者 ``` event_type: issue_assigned 或 infrastructure_failure action_type: issue_assigned 或 infrastructure_failure steps(按 label 分流): # 默认路径(编码任务): 1. 创建分支 fix/{issue_number}-{brief} 2. 编码 + 写 UT 3. push → 等 CI 4. CI 通过后创建 PR(Gitea API: POST /repos/{repo}/pulls) 5. 等 Review 6. 提交 action report # type/infrastructure label 路径(运维任务): 1. 根据 Issue body 中的错误来源和日志片段排查问题 2. 修复基础设施问题(如修复 CI runner 环境、恢复网络、重启服务等) 3. 修复后在 Issue 上 comment 说明修复方式和结果 4. 提交 action report context: issue_number, repo, issue_title, labels, issue_body, brief ``` **label 分流说明**:issue_assigned handler 检查 label 中是否包含 `type/infrastructure`。如果是,走运维排查 steps(event_type 设为 infrastructure_failure,verify 始终 auto-pass 防递归);否则走编码 steps。 #### 部署失败 → 运维 ``` event_type: deploy_failure action_type: deploy_failure steps: 1. 检查 deploy 日志 2. 根据 deploy 日志判断失败原因类型: a. 代码/配置问题(rsync 路径错、依赖缺失、启动失败)→ 修复 → 重新部署 b. 基础设施问题(Gitea 不可用、网络不通、磁盘满、SSH 故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见 §6.4),label 必须包含 type/infrastructure 3. 提交 action report — 报告中说明判断的原因类型和执行的操作 context: repo, commit_sha, reason ``` #### @mention → 被@者 ``` event_type: mention action_type: mention steps: 1. 按 mention 模板中的 response_guidance 执行 2. 提交 action report context: source_type, source_url, commenter, content_snippet, intent_hint, response_guidance ``` #### PR 合并 → PR 作者 ``` event_type: review_merged action_type: review_merged steps: [] # 无步骤,纯通知 verify: 始终通过(inform 语义,无需 action_report) context: pr_number, repo, pr_title, pr_author, merged_by ``` **特殊处理**:review_merged 的 verify_completion 始终返回 `VerifyResult(True)`。这是唯一的纯通知场景,Agent 只需阅读即可。 ### 6.3 PR 合并通知为何也走 ToolchainHandler **设计原则**:toolchain 和 Mail 完全分离。所有工具链事件(包括纯通知)都走 ToolchainHandler + _toolchain DB。 **为什么 PR 合并通知不走 _mail**: - toolchain 事件的完整生命周期应在同一个 DB(_toolchain)中追溯 - 前端展示统一(Toolchain Tab),不需要跨 _mail 和 _toolchain 两个 Tab 查看同一类事件 - Mail 只服务 Agent 间点对点通信(inform / request),不服务工具链事件 **实现差异**:review_merged 的 verify_completion 始终通过(`VerifyResult(True)`),不需要 action_report。这是 ToolchainHandler 内部的语义区分,不影响 MailHandler。 **spawn 说明**:review_merged 仍会触发 spawn(Agent 只需阅读通知),verify auto-pass 后标 done。未来可优化为 ticker 直接 auto-done 跳过 spawn。 ### 6.4 基础设施 Issue 转交流程 当 ci_failure / deploy_failure 的 agent 在调查后发现失败原因是基础设施问题(非代码问题),需要创建 Gitea Issue 指派 jiangwei-infra。 #### Issue 提在哪里 **根据问题来源决定**——哪个仓库的 CI/部署失败了,Issue 就提到那个仓库。CI runner 是全局共享的(一个 Mac mini),但 Issue 挂在触发的仓库最自然。如果 runner 故障影响多个仓库,各仓库会各自触发 ci_failure task,姜维看到任何一个 Issue 就能定位全局问题。 #### Issue 格式规范 ```markdown ## 问题描述 <简要描述问题现象> ## 错误来源 - 仓库: - PR/Commit: <链接> - CI/Deploy run: ## 日志关键片段 ``` <错误日志摘要,不需全文,但要让排查者看到关键信息> ``` ## 判断依据 <为什么判断为基础设施问题而非代码问题> ``` **必填字段**:问题描述、错误来源(含链接)、日志片段、判断依据。Issue body 不完整会导致姜维无法高效排查。 **label 要求**:必须包含 `type/infrastructure`,用于 issue_assigned handler 分流(见下)。 #### issue_assigned handler label 分流 当 Gitea Issue 指派触发 webhook 时,issue_assigned handler 检查 label: | label 包含 type/infrastructure | event_type | steps | |---|---|---| | 是 | infrastructure_failure | 运维排查:根据 Issue body 排查问题 → 修复 → Issue comment 说明修复方式 → action report | | 否 | issue_assigned | 编码:创建分支 → 编码 → push → CI → PR → 等 Review → action report | 基础设施路径的 verify 始终 auto-pass(防递归,已有逻辑覆盖)。 ⚠️ **label 分流当前为设计目标**,toolchain_handler.py 尚未实现 issue_assigned 的 label 检查。当前只有 `_handle_infrastructure_failure`(verify 失败时)创建 infrastructure_failure task。issue_assigned handler 的 label 分流在后续代码 PR 中实现。 ⚠️ **label 预创建**:使用前需确认仓库中已创建名为 `type/infrastructure` 的 label。sanguo_moziplus_v2 仓库已创建(ID=98)。其他仓库使用前需先创建。 #### API 指令位置 Issue 创建的 API 调用方式(curl 示例)统一在 ToolchainApiSection 中,与 action_report / comment 指引并列。steps 指令中不重复 API 调用方式,只描述"做什么"。 #### Red Flags 补充 硬约束 Red Flags 表新增一条: | Agent 想法 | Red Flag 驳回 | |---|---| | "CI/部署失败不是我代码的问题,我什么也不用做" | ❌ 错!即使是基础设施问题,你也必须创建 Issue 指派 jiangwei-infra(body 含错误来源链接 + 日志 + 判断依据),并在 action report 中说明。不能只报告"不是我的问题"就完事 | --- ## §7. _send_toolchain_task 函数设计 ### 7.1 函数定义 新增 `_send_toolchain_task` 函数(`src/api/toolchain_routes.py`),与 `_send_mail` 并列。两个函数各司其职: | 函数 | 用途 | project_id | task_type | DB | |------|------|-----------|-----------|-----| | `_send_mail` | Agent 间点对点通信(inform / request) | `_mail` | `mail` | `_mail/blackboard.db` | | `_send_toolchain_task` | 工具链动作事件(需 Agent 执行步骤) | `_toolchain` | `toolchain` | `_toolchain/blackboard.db` | ```python def _toolchain_db_path() -> Path: """获取 Toolchain 数据库路径,确保目录存在。""" root = get_data_root() db = root / "_toolchain" / "blackboard.db" db.parent.mkdir(parents=True, exist_ok=True) init_db(db) return db def _send_toolchain_task( to_agent: str, title: str, description: str, event_type: str, action_type: str, steps: list[str], context_data: dict | None = None, source: str = "webhook", ) -> str: """创建 Toolchain Task 并写入 _toolchain DB。 Args: to_agent: 收件人 Agent ID title: 任务标题 description: 任务描述(模板渲染后的事件信息) event_type: 事件类型(review_result / ci_failure / ...) action_type: 动作分类(用于步骤选择和日志统计) steps: 结构化编号步骤列表 context_data: 事件上下文数据(PR 号、仓库名等) source: 来源标识 Returns: 创建的 Task ID """ if to_agent not in AGENT_IDS: logger.warning("Unknown agent: %s, skipping toolchain task", to_agent) return "" task_id = f"tc-{int(datetime.now().timestamp() * 1000)}" must_hives = json.dumps({ "event_type": event_type, "action_type": action_type, "steps": steps, "context": context_data or {}, "from": "system", "source": source, }, ensure_ascii=False) task = Task( id=task_id, title=title, description=description, assignee=to_agent, assigned_by="system", must_haves=must_hives, task_type="toolchain", status="pending", ) bb = Blackboard(_toolchain_db_path()) bb.create_task(task) logger.info( "Toolchain task sent: %s → %s [%s] action_type=%s", title[:40], to_agent, task_id, action_type, ) return task_id ``` ### 7.2 各 handler 调用改造 `toolchain_routes.py` 中各 handler 从调用 `_send_mail` 改为调用 `_send_toolchain_task`。 以 `_handle_pr_opened` 为例(改造后): ```python async def _handle_pr_opened(payload: Dict[str, Any]) -> None: """PR opened → 通知 simayi-challenger(走 ToolchainHandler)。""" pr = payload.get("pull_request") repo = _repo_fullname(payload) pr_number = pr.get("number", 0) pr_title = pr.get("title", "") # ... 获取文件列表、风险级别(现有逻辑不变) text = render_template("review_request", {...}) title = f"Review 请求: {pr_title} ({repo}#{pr_number})" _send_toolchain_task( to_agent="simayi-challenger", title=title, description=text, event_type="review_request", action_type="review_request", steps=[ f"读取 PR diff(Gitea API: GET /repos/{repo}/pulls/{pr_number}.diff)", "按审查清单审查(参考 code-review Skill)", f"提交 Review(Gitea API: POST /repos/{repo}/pulls/{pr_number}/reviews)— APPROVE 或 REQUEST_CHANGES", f"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks//comments,comment_type=action_report)", ], context_data={ "pr_number": pr_number, "repo": repo, "pr_title": pr_title, "pr_author": pr_author, "branch": branch, "risk_level": risk_level, }, ) ``` ### 7.3 handler 改造对照表 | handler 函数 | 新 action_type | 新调用 | |-------------|---------------|--------| | `_handle_pr_opened` | review_request | `_send_toolchain_task(...)` | | `_handle_pull_request_review` (APPROVED/REQUEST_CHANGES) | review_result | `_send_toolchain_task(...)` | | `_handle_pr_synchronize` | review_updated | `_send_toolchain_task(...)` | | `_handle_pull_request_review` (COMMENTED) | review_comment | `_send_toolchain_task(...)` | | `_handle_issue_comment` (CI failure) | ci_failure | `_send_toolchain_task(...)` | | `_handle_issues` (assigned) | issue_assigned | `_send_toolchain_task(...)` | | `_handle_pr_closed` (merged) | review_merged | `_send_toolchain_task(...)`(纯通知,steps 为空,verify 始终通过) | | `_send_deploy_failure_mail` | deploy_failure | `_send_toolchain_task(...)` | | `_send_mention_mails` | mention | `_send_toolchain_task(...)` | ### 7.4 _send_mail 不参与任何 toolchain 事件 `_send_mail` 函数只服务一个场景:**Agent 间点对点通信**(inform / request)。 **toolchain 事件完全不经过 Mail**: - 事件投递:`_send_toolchain_task`(不是 `_send_mail`) - 失败处理:Gitea PR comment / Gitea Issue / `_send_toolchain_task`(三分路) - PR 合并通知:`_send_toolchain_task`(review_merged,steps 为空) Mail 和 toolchain 是两套完全独立的系统,各自有独立的 DB、Handler、PromptSection。 --- ## §8. spawner / PromptContext 改动 ### 8.1 PromptContext 新增字段 ```python @dataclass class PromptContext: # ... 现有字段不变 ... # toolchain 专用(增强) event_type: str = "" event_data: Dict = field(default_factory=dict) action_type: str = "" # 新增:动作分类 action_steps: list = field(default_factory=list) # 新增:结构化步骤列表 ``` ### 8.2 spawner 解析 must_hives 增强 `spawner.py` 中 handler 路径的 PromptContext 构造,需要从 must_hives JSON 中提取 action 字段: ```python handler = TaskTypeRegistry.get_by_project(project_id) if handler: meta = json.loads(must_haves) if must_haves else {} from_agent = meta.get("from", "") mail_type = meta.get("performative", meta.get("type", "")) # 注:toolchain task 的 mail_type 为空(不走 MailHandler),保留字段兼容 MailHandler # 新增:toolchain 字段提取 event_type = meta.get("event_type", "") event_data = meta.get("context", {}) action_type = meta.get("action_type", "") action_steps = meta.get("steps", []) ctx = PromptContext( task_id=task_id, title=title, description=description or "", must_haves=must_haves or "", project_id=project_id, agent_id=agent_id, role=spawn_type, spawn_type=spawn_type, from_agent=from_agent, mail_type=mail_type, event_type=event_type, event_data=event_data, action_type=action_type, action_steps=action_steps, ) return handler.build_prompt(ctx) ``` --- ## §9. DB 隔离设计 ### 9.1 两套独立 DB **D17-5: _mail 和 _toolchain DB 隔离**(§14 原设计) ``` ~/.sanguo_projects/sanguo_moziplus_v2/data/ ├── _mail/ │ └── blackboard.db # MailHandler 管理 ├── _toolchain/ │ └── blackboard.db # ToolchainHandler 管理 └── projects/ └── ... ``` 隔离理由: 1. §14 L41 明确:`_toolchain` 有独立 DB,和 `_mail` 隔离 2. 不同 task_type 的 task 互不干扰 3. 前端展示独立(Toolchain Tab vs 飞鸽传书 Tab) 4. 数据量可控(toolchain 事件多但每个 task 生命周期短) ### 9.2 comments 表 CHECK 约束 **D17-3: comments 表 CHECK 约束处理** `_toolchain/blackboard.db` 的 comments 表需要支持 `action_report` 类型的 comment。 现有 CHECK 约束(`db.py`): ```sql CHECK (comment_type IN ( 'general','handoff','observation','review', 'rebuttal','rebuttal_response','debate_argument', 'debate_rebuttal','debate_judgment' )) ``` **方案 A(推荐)**:去掉 CHECK 约束。CHECK 在 SQLite 中仅文档作用,应用层已做校验。去掉后未来新增 comment_type 不需要 migration。 **方案 B**:新增 `action_report` 到 CHECK 约束枚举。需要 migration(SQLite 重建表)。 推荐方案 A——直接去掉 CHECK,在应用层(ToolchainApiSection + comments API)校验 comment_type 合法性。 ### 9.3 ticker 扫描 ticker 需要扫描 `_toolchain` 虚拟项目。当前 ticker 通过 `TaskTypeRegistry.virtual_projects()` 自动发现已注册的虚拟项目,ToolchainHandler 已注册 `virtual_project="_toolchain"`,无需额外改动。 --- ## §10. 影响范围 涉及的文件(开发目录 `~/.openclaw/sanguo_projects/sanguo_moziplus_v2/`): | 文件 | 改动类型 | 说明 | |------|---------|------| | `src/daemon/toolchain_handler.py` | 修改 | ToolchainContextSection 加 steps 渲染 + action_hint;ToolchainApiSection 改为 action_report 指引;ToolchainConstraintsSection 加 Red Flags;verify_completion 改用 action_report | | `src/api/toolchain_routes.py` | 修改 | 新增 `_toolchain_db_path()` + `_send_toolchain_task()`;所有 handler(含 PR merged)改为调用 `_send_toolchain_task` | | `src/daemon/spawner.py` | 修改 | handler 路径 PromptContext 构造时提取 `action_type`、`action_steps` 字段 | | `src/daemon/prompt_composer.py` | 修改 | PromptContext 新增 `action_type`、`action_steps` 字段 | | `src/blackboard/db.py` | 修改 | comments 表 CHECK 约束处理(去掉 CHECK 或加 action_report) | ### 改动量估算 | 文件 | 改动量 | 风险 | |------|--------|------| | `src/daemon/toolchain_handler.py` | ~120 行 | 中(核心逻辑变化 + on_failure 三分路) | | `src/api/toolchain_routes.py` | ~120 行 | 中(新增函数 + 8 个 handler 改造) | | `src/daemon/spawner.py` | ~8 行 | 低(纯新增字段提取) | | `src/daemon/prompt_composer.py` | ~3 行 | 低(dataclass 新增字段) | | `src/blackboard/db.py` | ~5 行 | 低(CHECK 约束处理) | | **总计** | **~256 行** | | --- ## §11. 向后兼容 ### 11.1 Mail 系统不受影响 | 场景 | 影响 | |------|------| | Agent 间手动发 inform Mail | ✅ 无影响 | | Agent 间手动发 request Mail | ✅ 无影响 | | MailHandler 的 verify / on_failure | ✅ 无影响 | | `_send_mail` 函数 | ✅ 保留不变(只服务 Agent 间通信,不服务任何 toolchain 事件) | ### 11.2 _mail DB 中已有的 toolchain task 改造前创建的 toolchain task 存在于 `_mail/blackboard.db` 中(task_type=mail, type=inform)。改造后: - 这些旧 task 继续由 MailHandler 管理(inform 始终通过验证) - 不需要 migration——旧 task 自然 done / 过期清理 - 新 task 创建在 `_toolchain/blackboard.db` 中 ### 11.3 ToolchainHandler 的 fallback verify 改造后 verify_completion 保留了三层 fallback: 1. action_report comment(首选) 2. output(fallback) 3. 有实质内容的 comment(fallback) 这意味着即使 Agent 初期不习惯提交 action_report,只要有 output 或实质 comment 仍能通过验证。平滑过渡。 ### 11.4 PromptContext 新增字段 `action_type` 和 `action_steps` 使用 `field(default_factory=list/str)`,不传时为空/[]。现有 PromptContext 构造不受影响。 ### 11.5 comments 表 CHECK 约束 如果选择"去掉 CHECK"方案,对现有数据无影响——现有 comment_type 值在应用层仍被校验。如果选择"加 action_report"方案,需要 migration。 --- ## §12. 设计决策记录 ### D17-1: verify 采用 action_report comment 机制 **决策**:verify_completion 优先检查 `comment_type='action_report'` 的 comment 是否存在,替代现有"任意 comment ≥20 字符"逻辑。保留 output 和实质 comment 作为 fallback。 **讨论的替代方案**: - A(外部状态检查):太复杂,每个 action_type 需要不同检查逻辑,耦合 Gitea API - B(始终通过):等于 inform,失去意义 - C(只查 action_report,无 fallback):改造初期过于激进 **理由**:action_report comment 机制最简单且与现有架构一致。保留 fallback 确保平滑过渡。Agent 如果写了 report 但没执行,后续事件链(CI 不会通过、Reviewer 不会收到 Review)会自然暴露问题。 ### D17-2: 所有 toolchain 场景走 ToolchainHandler **决策**:全部 10 种 toolchain 场景走 ToolchainHandler(`_send_toolchain_task`),包括 PR 合并通知(review_merged)。Mail 不服务任何 toolchain 事件。 **理由**: - toolchain 事件的完整生命周期应在同一个 DB(_toolchain)中追溯 - 前端展示统一(Toolchain Tab),不需要跨 _mail 和 _toolchain 两个 Tab - Mail 只服务 Agent 间点对点通信(inform / request),不服务工具链事件 - review_merged 的 verify_completion 始终通过,不需要 action_report ### D17-3: comments 表 CHECK 约束处理 **决策**:推荐去掉 comments 表的 comment_type CHECK 约束,在应用层校验。或新增 action_report 到 CHECK 枚举。 **理由**:SQLite CHECK 约束修改需要重建表(CREATE → COPY → DROP → RENAME),migration 成本高。CHECK 仅文档作用,去掉不影响功能。 ### D17-4: 推翻 §16.0 D1"不做第三种 task 类型" **决策**:推翻 D1。toolchain 事件不再走 MailHandler(mail + inform),改走 ToolchainHandler(toolchain)。 **理由**: - D1 基于权宜方案——当时 ToolchainHandler 还没接线 - §14 早已设计 ToolchainHandler 作为独立 task type,有自己的 DB、PromptSection、verify 逻辑 - 不强约束总是断链——主公明确要求 L2 引擎层必须是强约束 - MailHandler 的 inform 语义("已阅即可")和 toolchain 事件的期望行为("必须执行步骤")根本矛盾 - ToolchainHandler 不需要 Mail 的回复机制(request),也不应该被 inform 的"已阅即可"语义覆盖 ### D17-5: _mail 和 _toolchain DB 隔离 **决策**:toolchain task 写入 `_toolchain/blackboard.db`,不写入 `_mail/blackboard.db`。 **理由**: - §14 L41 原设计 - 不同 task_type 的 task 互不干扰 - 数据生命周期不同(toolchain task 短生命周期,mail 可能需要长期保留线程) - 前端展示独立 ### D17-6: action_report 作为唯一的新 comment_type **决策**:只引入 `action_report` 一个新 comment_type,不为每种 action_type 定义不同的 comment_type。 **理由**: - 统一简化了 verify 逻辑(只查一种 type) - action_type 的区分在 must_hives JSON 中已有 - comment body 内容可以自由描述具体执行了什么 ### D17-7: ToolchainApiSection 移除"手动标 done"指引 **决策**:ToolchainApiSection 不再指示 Agent 手动标 done,改为指示提交 action_report。done 由 verify_completion 通过后自动触发。 **理由**: - Agent 手动标 done 和 verify_completion 的 done 可能冲突 - action_report + verify 是更可靠的完成路径 - 减少 Agent 需要执行的 API 操作(从"标 done + 提交产出"简化为"提交 action_report") --- ## §13. 实施计划 ### Step 1:基础设施(prompt_composer + spawner + db) | 子步骤 | 文件 | 内容 | 风险 | |--------|------|------|------| | 1a | `prompt_composer.py` | PromptContext 新增 `action_type`、`action_steps` 字段 | 极低 | | 1b | `spawner.py` | handler 路径提取 `action_type`、`action_steps` | 极低 | | 1c | `db.py` | comments 表 CHECK 约束处理 | 低 | ### Step 2:ToolchainHandler 强化 | 子步骤 | 文件 | 内容 | 风险 | |--------|------|------|------| | 2a | `toolchain_handler.py` | ToolchainContextSection 加 steps 渲染 + action_hint | 低 | | 2b | `toolchain_handler.py` | ToolchainApiSection 改为 action_report 指引 | 低 | | 2c | `toolchain_handler.py` | ToolchainConstraintsSection 加 Red Flags 表 | 低 | | 2d | `toolchain_handler.py` | verify_completion 改用 action_report(保留 fallback) | 中 | | 2e | `toolchain_handler.py` | on_failure 三分路重写(业务→PR comment / 系统→Gitea Issue / 基础设施→toolchain task) | 中 | ### Step 3:toolchain_routes 改造 | 子步骤 | 文件 | 内容 | 风险 | |--------|------|------|------| | 3a | `toolchain_routes.py` | 新增 `_toolchain_db_path()` + `_send_toolchain_task()` | 低 | | 3b | `toolchain_routes.py` | 所有 handler(含 PR merged)改为调用 `_send_toolchain_task` | 中 | ### Step 4:测试 + 验证 | 子步骤 | 内容 | |--------|------| | 4a | 单元测试:ToolchainContextSection steps 渲染 | | 4b | 单元测试:verify_completion action_report 检查 + fallback | | 4c | 单元测试:_send_toolchain_task 写入 _toolchain DB | | 4d | 集成测试:webhook → toolchain task → Agent → action_report → done | | 4e | 回归测试:_mail 路径不受影响(inform/request 不变) | | 4f | 回归测试:PR merged 走 _send_toolchain_task(review_merged,verify 始终通过) | --- ## §14. 风险评估 | 风险 | 概率 | 影响 | 缓解措施 | |------|------|------|----------| | Agent 不提交 action_report | 中 | 高 | Prompt 强约束 + Red Flag 表 + verify 失败 → on_failure 三分路(PR comment @assignee / Gitea Issue @pangtong / toolchain task @jiangwei)+ fallback(output/comment) | | Agent 提交虚假 action_report | 低 | 中 | 后续事件链自然暴露(CI 不通过、Reviewer 收不到 Review) | | Agent 混淆 toolchain 和 mail 语义 | 低 | 低 | ToolchainContextSection 明确告知"这是需要执行动作的事件" | | _toolchain DB 未初始化 | 低 | 中 | `_toolchain_db_path()` 中调用 `init_db()` 确保目录和表存在 | | ticker 不扫描 _toolchain | 低 | 中 | TaskTypeRegistry.virtual_projects() 已自动发现 | | handler 改造遗漏 | 中 | 低 | 逐个 handler 审查 + 集成测试覆盖 | | steps 内容不完整或不准确 | 中 | 低 | 代码审查 + 从 §13 §15.5 已有模板提取 steps | --- ## §15. 优秀实践参考 ### 15.1 §13 §15.5 流程强约束模板 §13 §15.5 已定义 6 个强约束模板,每个包含编号步骤、Gitea API 调用指令、时限要求。本设计在此基础上: - 将步骤从模板纯文本提取到 must_hives JSON 的 `steps` 字段(结构化、可编程化) - 通过 ToolchainHandler 的 PromptSection 强约束确保 Agent 知道必须执行 - 用 action report(执行凭证)替代邮件回复(更适合自动化验证) ### 15.2 Superpowers: Red Flags 表 Superpowers 使用 Red Flags 表防止 Agent self-rationalization。本设计在 ToolchainConstraintsSection 中增加 Red Flag 示例(如"这个通知看看就行了"→ ❌ 错!),防止 Agent 将 action 降级为 inform 处理。 ### 15.3 §14 Handler 架构 §14 定义了 TaskTypeRegistry + Handler 架构,ToolchainHandler 已实现并注册。本设计是"给 ToolchainHandler 接线 + 强化约束"——不是新建一套系统,而是让已有的系统按设计意图运转。 ### 15.4 Hermes: "Keep calling tools until complete AND verified" Hermes 的验证理念:执行和验证不可分割。本设计中 verify_completion 的 action_report 检查就是这个理念的体现——不是检查 Agent"说了什么",而是检查 Agent"产出了什么执行凭证"。 --- ## §16. 未来演进 ### 16.1 外部状态验证(增强) 未来可选择性增加某些 action_type 的外部状态验证作为补充: - `review_request`:检查 PR 是否有新的 Review - `ci_failure`:检查 PR 是否有新 push - `issue_assigned`:检查是否有关联 PR 创建 这是可选增强,在 action_report 之上叠加更精确的验证。 ### 16.2 steps 动态化 当前 steps 在 `_send_toolchain_task` 调用时硬编码。未来可以根据事件内容动态生成 steps(如根据 CI 失败的具体测试文件给出修复建议)。 ### 16.3 超时检测 参考 §15.4 的超时处置机制: - toolchain task 创建后 N 小时内无 action_report → ticker 重发提醒 - 超时严重时 spawn 庞统介入 当前由 verify_completion 的 fail → on_failure → notify 机制处理。 --- ## §17. 审查检查清单 - [ ] §1 问题陈述是否准确(ToolchainHandler 未接线,toolchain 事件走了 MailHandler inform) - [ ] §2 三层强约束设计是否完整(输入/执行/输出) - [ ] §3 输入约束:must_hives JSON 结构 + ToolchainContextSection 渲染增强 - [ ] §4 执行约束:Red Flags 表设计是否覆盖常见 self-rationalization 模式 - [ ] §5 输出约束:action_report verify 机制 + fallback 设计 - [ ] §6 场景 steps 定义是否完整(9 种 action 场景 + 1 种纯通知场景 review_merged) - [ ] §7 _send_toolchain_task 函数设计是否正确 - [ ] §8 PromptContext / spawner 改动是否和 §14 架构一致 - [ ] §9 DB 隔离是否符合 §14 原设计 - [ ] §10 影响范围是否完整 - [ ] §11 向后兼容是否充分 - [ ] §12 设计决策 D17-1 ~ D17-7 是否合理 - [ ] §13 实施计划是否可行(4 步渐进)