From c19286eb5b128b08f040567016ab3dffb9d4dd8a Mon Sep 17 00:00:00 2001 From: claude_dev Date: Thu, 25 Jun 2026 07:45:26 +0800 Subject: [PATCH] =?UTF-8?q?[moz]=20docs(=C2=A722):=20v1.5=20=E9=87=87?= =?UTF-8?q?=E7=BA=B3=E5=8F=B8=E9=A9=AC=E6=87=BF=20S1-S4+P1-P3=20=E5=AE=A1?= =?UTF-8?q?=E6=9F=A5=E5=BB=BA=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/design/22-end-to-end-flow.md | 95 ++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 14 deletions(-) diff --git a/docs/design/22-end-to-end-flow.md b/docs/design/22-end-to-end-flow.md index 42dc2fc..0b949a4 100644 --- a/docs/design/22-end-to-end-flow.md +++ b/docs/design/22-end-to-end-flow.md @@ -1,9 +1,10 @@ --- title: "End-to-End Flow — 端到端任务流程设计" created: 2026-06-22 -version: v1.4 +version: v1.5 status: draft -changelog: v1.4 §22.6/§22.8 设计补足:基础设施排除、定向讨论简化为单spawn自主模式、迁移策略、TC数据源/round_count分流通透 +changelog: v1.5 采纳司马懿 S1-S4+P1-P3:判断逻辑补 infrastructure 分支、flow/discuss deprecated、定向讨论 fallback、task_state.status 完整生命周期、parent_status 查表不硬编码 + v1.4 §22.6/§22.8 设计补足:基础设施排除、定向讨论简化为单spawn自主模式、迁移策略、TC数据源/round_count分流通透 v1.3 §22.6 重构为「所有 TC 流程第一步走 Discuss」+ §22.8 TC Round Review Gitea 适配设计 v1.2 §22.3/§22.4 更新 Phase 1 为 ✅ 已实现(PR #124) v1.1 补充轻量路径设计(§22.6)、数据流澄清(§22.7)、修正设计原则3、统一Phase编号、Phase 1标注 @@ -292,7 +293,8 @@ issue_assigned: ``` parent Issue 创建 ├─ 有 flow/direct label?→ Direct 路径(→ Phase 2,跳过讨论) - ├─ 有 assignee?→ 定向 Discussion(assignee + reviewer 讨论) + ├─ 有 type/infrastructure label?→ Direct 路径(→ executor,运维排障) + ├─ 有 assignee(非 infrastructure)?→ 定向 Discussion(assignee 自主模式) └─ 无 assignee(默认)→ 广播 Discussion(所有空闲 agent) ``` @@ -322,6 +324,21 @@ Issue assigned webhook - 广播讨论:assignee=None → ticker 归入 broadcast_tasks → 广播所有空闲 agent - 定向讨论:assignee=该 agent → ticker 归入 deterministic_tasks → 确定性路由 spawn 单人 +### 定向讨论 fallback(assignee 无响应) + +> **v1.4 补充(司马懿 S4)**:广播讨论有「3 轮无 taker → 升级庞统」机制,定向讨论也需要 fallback。 + +单 spawn assignee 后,如果 assignee NO_REPLY 或 session 超时: + +``` +ticker 定期 check(复用现有 broadcast _broadcast_tracker 机制) + → discussion task 仍 pending/working 且超过 3 轮 check 未终态 + → 升级庞统(escalated 状态) + → 庞统判断:重新分配 / 转为广播讨论 / 直接关闭 +``` + +复用现有 `_broadcast_tracker` 的 `round_number >= 3 → escalated` 逻辑,不引入新机制。 + ### 广播讨论流程(无 assignee) ``` @@ -337,7 +354,7 @@ Issue opened webhook | 路径 | 适用场景 | 示例 | |------|---------|------| -| 广播讨论 | 需求不明确、跨模块协作、无人认领 | 新功能设计、架构变更 | +| 广播讨论 | 需求不明确、跨模块协作、涉及 3+ agent、无人认领 | 新功能设计、架构变更 | | 定向讨论 | 需求明确但需要方案确认 | 有明确 assignee 的 Issue | | Direct | 改 typo、改配置值等极小改动 | `flow/direct` label | @@ -366,6 +383,8 @@ Discussion 进行中,如果所有 agent 都认为任务足够简单只涉及 `_ACTION_HINTS` / YAML steps / `ToolchainContextSection` 中的 `issue_assigned` 相关逻辑**保留**(infrastructure/flow-direct 还用),新增 `issue_review_discussion` action_type。 +> **`flow/discuss` label deprecated**:v1.2 曾设计 `flow/discuss` label(强制 Discussion 即使有 assignee),v1.4 废弃。所有有 assignee 的 Issue(非 infrastructure)默认走定向讨论,无需显式 label。Gitea 上 `flow/discuss` label(id=101)保留但不影响路由。 + ### 实现方案 **toolchain_routes.py**: @@ -473,17 +492,65 @@ task_state 表创建前,`_check_round_complete` 仍扫 `tasks.parent_task`。 ### task_state.status 更新机制 -> **v1.4 补充**:当前 `_ensure_task_state` 只做 `INSERT OR IGNORE`,status 初始为 `pending`,后续没有任何代码更新。需补充。 +> **v1.4 补充(司马懿 S3)**:当前 `_ensure_task_state` 只做 `INSERT OR IGNORE`,status 初始为 `pending`,后续没有任何代码更新。需补充。 -**更新来源**:Gitea Issue closed webhook → 更新 `task_state.status = 'done'` +**状态生命周期**: -``` -_handle_issues: action == "closed" - → UPDATE task_state SET status='done', updated_at=datetime('now') - WHERE issue_number = ? +| 状态 | 触发来源 | 更新位置 | +|------|---------|----------| +| `pending` | `_ensure_task_state` 初始插入 | `toolchain_routes.py` assigned 分支 | +| `done` | Gitea Issue closed webhook | `toolchain_routes.py` closed 分支 | +| `failed` | executor task 验证失败且未重试 | `toolchain_handler.py` `post_complete` → `_update_task_state_status()` | + +**关键路径说明**: + +1. **sub Issue 创建** → `_ensure_task_state` 写入 `status='pending'` +2. **sub Issue 对应的 executor task 完成** → ToolchainHandler 通过 @mention 指引 agent 创建 PR(含 `Closes #N`)→ PR 合并时 Gitea 自动关闭 Issue → webhook `issues/closed` → 更新 `status='done'` +3. **executor task 失败** → `ToolchainHandler.post_complete()` 中检测 verify 失败且 retry_count 达上限 → 调用 `_update_task_state_status(issue_number, 'failed')` + +**`post_complete` 何时触发**:spawner 完成 session 后(agent exit),ticker 在下个 tick 检测到 session 终态 → 调用 `handler.post_complete(task_id, agent_id, outcome, db_path)`。此时 handler 可以: +- 检查 verify 结果 +- 如果 failed 且不可 retry → 查 task_state 找到对应 issue_number → 更新 status='failed' + +**新增方法**: + +```python +# toolchain_handler.py +def _update_task_state_status(self, issue_number: int, status: str): + """更新 task_state.status(executor 失败时调用)""" + tc_db = _toolchain_db_path() + conn = get_connection(tc_db) + try: + conn.execute( + "UPDATE task_state SET status=?, updated_at=datetime('now') " + "WHERE issue_number=?", + (status, issue_number) + ) + conn.commit() + finally: + conn.close() ``` -后续如需更精细状态(failed/retry),通过 ToolchainHandler.post_complete 补充更新。 +**toolchain_routes.py closed 分支补充**: + +```python +elif action == "closed": + # 更新 task_state status='done' + tc_db = _toolchain_db_path() + conn = get_connection(tc_db) + try: + conn.execute( + "UPDATE task_state SET status='done', updated_at=datetime('now') " + "WHERE issue_number=?", + (issue_number,) + ) + conn.commit() + finally: + conn.close() + # ... 现有通知逻辑 +``` + +> **注意**:`get_tc_subtask_summary` 中的 `all_terminal` 只依赖 `done` 和 `failed` 两种终态。`pending`/`working` 计入 `other`,确保未完成的 sub 不会误触发 round review。 ### 分流方案(全链路) @@ -580,7 +647,7 @@ TC 版本的 Round Review prompt。核心区别: 1. **Handler 分流**:`_check_round_complete` 通过 `TaskTypeRegistry.get_by_project(project_id)` 判断。普通项目(无 handler)走 `_build_review_prompt`(黑板版本不变) 2. **数据隔离**:TC review 读 `task_state` 表 + Gitea API;黑板 review 读 `tasks` 表 + `outputs` / `comments` 表 3. **prompt 隔离**:TC prompt 只含 Gitea API 指引;黑板 prompt 只含黑板 API 指引 -4. **`_dispatch_reviews` 已有先例**:L1379 `if handler: return []` 已经用 Handler 分流跳过 handler 项目的 review 流程 +4. **Handler 分流模式已在 `_dispatch_reviews` 中验证可行**:L1379 `if handler: return []` 用 Handler 分流跳过 handler 项目的 PR Review 流程,TC Round Review 采用相同模式 ### 实现方案 @@ -599,7 +666,7 @@ def get_tc_subtask_summary(tc_db: Path, parent_issue: int) -> Optional[dict]: conn = get_connection(tc_db) try: parent_row = conn.execute( - "SELECT round_count FROM task_state WHERE issue_number = ?", + "SELECT round_count, status FROM task_state WHERE issue_number = ?", (parent_issue,) ).fetchone() if not parent_row: @@ -615,7 +682,7 @@ def get_tc_subtask_summary(tc_db: Path, parent_issue: int) -> Optional[dict]: summary = { "parent_id": str(parent_issue), - "parent_status": "done", # TC 路径 parent 是 Gitea Issue + "parent_status": parent_row["status"], # 从 task_state 读取实际状态 "round_count": parent_row["round_count"], "total": 0, "done": 0, "failed": 0, "cancelled": 0, "other": 0, }