Files
sanguo_moziplus_v2/docs/design/22-end-to-end-flow.md
T
cfdaily d2e449bca8
CI / lint (pull_request) Failing after 32s
CI / test (pull_request) Has been skipped
CI / frontend (pull_request) Has been skipped
CI / notify-on-failure (pull_request) Successful in 2s
[moz] docs(§22): v1.1 轻量路径设计 + 数据流澄清 + 编号修正
2026-06-22 20:28:44 +08:00

406 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "End-to-End Flow — 端到端任务流程设计"
created: 2026-06-22
version: v1.1
status: draft
changelog: v1.1 补充轻量路径设计(§22.6)、数据流澄清(§22.7)、修正设计原则3、统一Phase编号、Phase 1标注
v1.0 初版
---
# End-to-End Flow — 端到端任务流程设计
> 本文档描述一个任务从发起到结束的**完整系统行为链路**。
> §21 各章节按功能点分章,本文档把它们串成一条端到端流程。
> 每个 Phase 标注:触发源、daemon 函数、prompt 来源、agent 行为、留痕位置。
---
## §22.1 流程总览
```
Phase 0: 庞统创建 parent Issue(无 assignee, 有 type/* label
↓ webhook: issues/opened
Phase 1: Discussion 广播(所有空闲 agent
↓ agent 在 Gitea Issue comment 讨论 → 创建 sub Issueassign 自己)
Phase 2: sub Issue assigned → executor 分派
↓ webhook: issues/assigned
Phase 3: 编码 + PR + CI
↓ webhook: pull_request/opened → CI 自动触发
↓ CI 通过 → 等 Review / CI 失败 → agent 修复 → 重跑
Phase 4: Review(司马懿)
↓ APPROVED → 通知 agent 合并 / REQUEST_CHANGES → agent 修改 → 回 Phase 3
Phase 5: Merge + sub Issue 自动关闭
↓ webhook: pull_request/closed(merged)
Phase 6: Round Review(庞统三问)
↓ GOAL_ACHIEVED → 关闭 parent / 需要新轮 → 创建新 sub → 回 Phase 2
Phase 7: parent Issue 关闭
↓ webhook: issues/closed
```
**核心设计原则**
1. **协作面是 Gitea**Issue/PR comment),不是黑板 DB
2. **每个 Phase 有明确的前置条件和产出**,前一步未完成则后续不触发
3. **webhook 和 ticker 协同**——webhook 负责事件感知和 task 创建,ticker 负责广播调度(Phase 1)和聚合检测(Phase 6
4. **agent 在 Gitea 留痕**Issue comment、PR、Review),黑板 DB 只存 daemon 内部状态
---
## §22.2 阶段详解
### Phase 0: parent Issue 创建
| 维度 | 内容 |
|------|------|
| **触发** | 庞统(或用户)在 Gitea 创建 parent Issue |
| **条件** | 无 assignee + 有 `type/*` label |
| **daemon 函数** | `_handle_issues``toolchain_routes.py`),opened 分支 |
| **daemon 行为** | 检测无 assignee + 有 type/* label → 创建 toolchain task`assignee=None`, `action_type=issue_discussion`)写入 `_toolchain` DB |
| **agent 行为** | 无(此阶段不 spawn agent |
| **产出** | `_toolchain` DB 中一条 pending task |
**webhook 流转**
```
Gitea: Issue created (no assignee, label type/feat)
→ webhook: issues/opened
→ daemon: _handle_issues → action="opened"
→ 非部署失败 + 无 assignee + 有 type/* label
→ _send_toolchain_task(to_agent=None, action_type="issue_discussion")
```
---
### Phase 1: Discussion 广播
| 维度 | 内容 |
|------|------|
| **触发** | ticker 30s 扫到 Phase 0 创建的 pending task |
| **daemon 函数** | `ticker._dispatch_pending``dispatcher.decide``_broadcast_claim`。⚠️ 当前 broadcast 使用 claim prompt(黑板 API)而非 discussion promptP0 修复后改为 discussion broadcast |
| **daemon 行为** | assignee=None → router 返回 mode=delegate → ticker 归入 broadcast_tasks → 广播给所有空闲 agent |
| **prompt 来源(设计期望)** | `discussion prompt`(§13.2):你是谁 + 你必须做什么(4 维度)+ Gitea API + Boids 行为准则 |
| **agent 行为(设计期望)** | 每个 agent 在 **Gitea Issue** comment(角色名开头,4 维度回应);需要参与的 agent 创建 sub IssueGitea APIassign 自己);在 parent Issue comment 注册 sub |
| **产出** | parent Issue 上有所有 agent 的讨论 commentGitea 上有若干 sub Issue |
**discussion prompt 核心(§13.2**
```
你被 spawn 来参与 Gitea Issue 讨论。
## 讨论主题
{parent Issue body 全文}
## 你是谁
你是 {agent_id}{display_name}),角色是 {role},能力是 {capabilities}
## 你必须做什么(每个 agent 必须 comment
1.【定位】这个需求和你有什么关系?
2.【建议】你对实现方案有什么建议?
3.【认领】如果你需要参与,创建 sub Issue 并在 parent comment 注册:
POST /repos/{repo}/issues
title: "[moz][sub][parent #{N}] 任务名"
body: "Parent: #{N}\nDepends: #M\n## 任务\n..."
assignees: ["{你的 agent_id}"]
4.【风险】如果发现风险或不合理假设,直接提出
## Comment 格式
[角色名] 你的观点
## APIGitea
- 读 Issue: GET /repos/{repo}/issues/{N}
- 写 comment: POST /repos/{repo}/issues/{N}/comments
- 创建 sub Issue: POST /repos/{repo}/issues
```
**Phase 1 的结束条件**(⚠️ 设计目标,检测逻辑待实现):
- 所有被广播的 agent 都已 comment(或 NO_REPLY)——daemon 需维护"已回复 agent"集合,当前无此机制
- 至少有一个 agent 创建了 sub Issue
- 如果没有任何 agent 创建 sub Issue → ticker 升级庞统(3 轮无 taker 机制)
---
### Phase 2: sub Issue assigned → executor 分派
| 维度 | 内容 |
|------|------|
| **触发** | agent 在 Phase 1 创建 sub Issue 时 assign 自己 → Gitea 发 `issues/assigned` webhook |
| **daemon 函数** | `_handle_issues``toolchain_routes.py`),assigned 分支 |
| **daemon 行为** | 解析 type/* label → 确定 business_type → 从 `toolchain-templates.yaml` 获取 steps → 创建 toolchain task`action_type=issue_assigned`)→ ticker dispatch |
| **prompt 来源** | `ToolchainHandler.build_prompt`(通过 PromptComposer 拼装 sections |
| **agent 行为** | 建分支 `{type}/{sub_issue_number}-{brief}` → 编码 → 写测试 → 创建 PR(body 含 `Closes #N` + `Parent #M` |
| **产出** | Gitea 上有 PR + 分支有代码 |
**steps 来源(`config/toolchain-templates.yaml`**
```yaml
issue_assigned:
feat:
steps:
- "理解需求(Issue body"
- "git checkout -b feat/{issue_number}-{brief}"
- "编码 + 写 UT"
- "文档同步检查"
- "git push + 创建 PRbody 含 Closes #{issue_number}"
- "等 Review"
```
---
### Phase 3: 编码 + PR + CI
| 维度 | 内容 |
|------|------|
| **触发** | agent 创建 PR → webhook `pull_request/opened` → CI 自动触发 |
| **daemon 函数(PR opened** | `_handle_pull_request` → 创建 `review_request` task → 通知司马懿 |
| **daemon 函数(CI** | CI 结果通过 Gitea comment 反馈 → `_handle_issue_comment` CI 路径 |
| **CI 通过** | 等待 ReviewPhase 5 |
| **CI 失败** | 创建 `ci_failure` task → 通知 agent 修复 |
| **agent promptCI 失败时)** | `ToolchainHandler.build_prompt`action_type=ci_failuresteps 含 CI 日志查看 + 根因判断 + 修复 |
| **产出** | CI 通过的 PR |
---
### Phase 4: Review(司马懿)
| 维度 | 内容 |
|------|------|
| **触发** | `review_request` task 被 ticker dispatch 给司马懿 |
| **daemon 函数** | ticker spawn 司马懿 → 司马懿通过 Review API 提交 verdict → webhook `pull_request_review``_handle_pull_request_review` |
| **prompt 来源** | `ToolchainHandler.build_prompt`action_type=review_request |
| **Review APPROVED** | 创建 `review_result_approved` task → 通知 agent 合并 |
| **Review REQUEST_CHANGES** | 创建 `review_result_request_changes` task → 通知 agent 修改 → agent push 同分支 → CI 重跑 → 回 Phase 3 |
| **产出** | Gitea Review 记录 |
---
### Phase 5: Merge + sub Issue 关闭
| 维度 | 内容 |
|------|------|
| **触发** | agent merge PR |
| **daemon 函数** | Gitea 自动关闭 sub IssuePR body 含 `Closes #N`)→ webhook `pull_request/closed(merged)``_handle_pull_request` closed 分支 |
| **daemon 行为** | 创建 `review_merged` task → 通知 agent(纯通知);ToolchainHandler verify: auto-pass |
| **产出** | sub Issue closed + 分支自动删除 |
---
### Phase 6: Round Review(庞统三问)
| 维度 | 内容 |
|------|------|
| **触发** | daemon 检测 parent Issue 下所有 sub Issue 终态(done/closed |
| **daemon 函数** | `ticker._check_round_complete` 扫描 parent/sub 映射 → 所有 sub 终态 → spawn 庞统 |
| **prompt 来源** | `ticker._build_review_prompt`(三问框架) |
| **agent 行为** | 庞统通过 Gitea API 读 parent Issue body + 所有 sub Issue comments/outputs → 三问评估 |
| **GOAL_ACHIEVED** | 庞统关闭 parent Issue → Phase 7 |
| **需要新轮** | 庞统创建新 sub Issues → 回 Phase 2 |
| **产出** | parent Issue closed 或新一轮 sub Issues |
**三问框架**
```
1. Goal 还清晰吗?(是否有 goal drift)
2. 成果物覆盖 goal 了吗?(逐条检查验收标准 + docs/design 同步确认)
3. 下一轮需要做什么?(创建新 sub / 标记完成 / 调整方向)
```
---
### Phase 7: parent Issue 关闭
| 维度 | 内容 |
|------|------|
| **触发** | 庞统关闭 parent Issue |
| **daemon 函数** | webhook `issues/closed``_handle_issues` closed 分支 |
| **daemon 行为** | 创建 `issue_closed` task → 通知(纯通知,auto-pass |
| **产出** | parent Issue closed,全流程结束 |
---
## §22.3 Prompt 模板对照表
| Phase | prompt 用途 | 设计指定的模板来源 | 当前实际来源 | 一致? |
|-------|-----------|----------------|------------|-------|
| 1 Discussion | 广播讨论 | discussion prompt(§13.2Gitea API | claim prompt`_build_claim_prompt`,黑板 API | ❌ |
| 2 Executor | 编码执行 | `ToolchainHandler.build_prompt` + YAML steps | 同设计 | ✅ |
| 3 CI 失败 | 修复 CI | `ToolchainHandler.build_prompt` ci_failure | 同设计 | ✅ |
| 4 Review | 审查 PR | `ToolchainHandler.build_prompt` review_request | 同设计 | ✅ |
| 5 Merge | 合并通知 | `ToolchainHandler.build_prompt` review_merged | 同设计 | ✅ |
| 6 Round Review | 庞统三问 | `ticker._build_review_prompt` | 同设计 | ✅ |
| 7 Issue closed | 关闭通知 | `ToolchainHandler.build_prompt` issue_closed | 同设计 | ✅ |
**唯一偏差在 Phase 1**discussion 设计了完整的 prompt(§13.2),但 ticker 从未调用它。
---
## §22.4 当前实现差距
| Phase | 实现状态 | 差距描述 |
|-------|---------|---------|
| 0 parent Issue 创建 | ✅ 已实现 | PR #113 `_handle_issues` opened 分支,无 assignee + type/* label → toolchain task |
| 1 Discussion 广播 | ❌ **未实现** | ticker broadcast 只有 `_build_claim_prompt`(黑板 API,认领模式),没有 discussion broadcastGitea API,讨论模式)。`_build_discussion_prompt` 存在于 spawner 中但 ticker 从未调用。agent 收到的是"认领并执行"而不是"讨论后创建 sub" |
| 2 sub Issue → executor | ⚠️ 部分 | assigned 路径 + YAML steps 已实现(PR #107),但因为 Phase 1 断裂,agent 不会创建 sub Issue,走不到此阶段 |
| 3 PR + CI | ✅ 已实现 | toolchain handler 正常处理 PR opened + CI 失败 |
| 4 Review | ✅ 已实现 | Review 请求 + Review 结果通知正常 |
| 5 Merge + sub 关闭 | ⚠️ 部分 | merge 通知正常。但 agent 创建的 PR body 不含 `Closes #N`(因为走的是 claim prompt 不是 executor promptprompt 中没有 Closes #N 约束) |
| 6 Round Review | ❌ 未适配 | `_check_round_complete` 扫黑板 `parent_task` 字段,不扫 Gitea parent/sub Issue 映射。没有 sub Issue 就检测不到 |
| 7 parent Issue 关闭 | ✅ 已实现 | PR #113 issue_closed auto-pass |
---
## §22.5 差距优先级排序
| 优先级 | 差距 | 影响范围 | 修复建议 |
|--------|------|---------|---------|
| **P0** | Phase 1 discussion broadcast | **核心断裂**。整个 Gitea Issue 流程退化成黑板 claim 模式 | ticker `_broadcast_claim` 中判断 `action_type=issue_discussion` → 调用 discussion promptGitea API 版本)而非 claim prompt |
| **P1** | Phase 5 PR body Closes #N | sub Issue 不自动关闭 | Phase 2 executor prompt 中已有 Closes #N 约束(YAML steps),Phase 1 修好后自然解决 |
| **P2** | Phase 6 Round Review Gitea 适配 | 无法触发庞统三问 | `_check_round_complete` 改为扫 Gitea parent/sub Issue 映射,详见 §22.7 数据流设计 |
**关键结论**:P0 是唯一阻断点。修好 Phase 1 discussion broadcast 后,Phase 2-5 自然走通(已实现),Phase 6-7 后续跟进。
---
## §22.6 轻量路径设计(Direct Assignment
> 不是所有任务都需要 Discussion 广播。需求明确、单一执行者的任务应跳过 Phase 0/1 直接进入 Phase 2。
### 路径决策矩阵
| 条件 | 路径 | 流程 |
|------|------|------|
| Issue 无 assignee + type/* label | **Discussion 路径**(默认) | Phase 0 → 1 → 2 → … |
| Issue 有 assignee | **Direct 路径** | → Phase 2(跳过 Phase 0/1 |
| Issue 有 `flow/direct` label | **强制 Direct** | → Phase 2(即使无 assigneedaemon 自动 assign |
| Issue 有 `flow/discuss` label | **强制 Discussion** | Phase 0 → 1 → 2 → …(即使有 assignee |
### 判断逻辑
```
parent Issue 创建
├─ 有 flow/discuss label?→ Discussion 路径(Phase 0 → 1
├─ 有 flow/direct label?→ Direct 路径(daemon 自动 assign → Phase 2
├─ 有 assignee?→ Direct 路径(→ Phase 2
└─ 无 assignee(默认)→ Discussion 路径(Phase 0 → 1
```
优先级:`flow/*` label > assignee > 默认行为。
### 适用场景
| 路径 | 适用场景 | 示例 |
|------|---------|------|
| Discussion | 需求不明确、需要多角色讨论、跨模块协作 | 新功能设计、架构变更、涉及 3+ agent 的任务 |
| Direct | 需求明确、单一执行者、小范围改动 | Bug 修复、文档更新、配置调整、单人任务 |
### Discussion 路径中的降级
Discussion 进行中,如果所有 agent 都认为任务足够简单只涉及一个角色,任何 agent 可以在 comment 中建议:
```
@pangtong-fujunshi 建议直接指派 @agent-id,理由:...
```
庞统判断后创建 sub Issue 直接 assign → 该 agent 跳过讨论直接进入 Phase 2。
### Direct 路径跳过的 Phase
| Phase | 是否跳过 | 原因 |
|-------|---------|------|
| Phase 0parent Issue 讨论 task | ✅ 跳过 | 不创建 discussion task |
| Phase 1Discussion 广播) | ✅ 跳过 | 不广播,不打扰其他 agent |
| Phase 2assigned → executor | ❌ 直接进入 | 起点 |
### 对现有代码的影响
当前 `_handle_issues` 已有两个分支:
- `opened`(无 assignee + type/* label)→ discussion task ← Discussion 路径 ✅
- `assigned`(有 assignee)→ executor task ← Direct 路径 ✅
**轻量路径的后端已实现**。需要补充的是:
1. `flow/direct``flow/discuss` label 的识别逻辑(`toolchain_routes.py` `_handle_issues` opened 分支)
2. Discussion prompt 中告知 agent 可以建议 direct assignment(降级机制)
---
## §22.7 数据流设计澄清
> 本文档涉及两个数据源(黑板 DB 和 Gitea Issue),parent/sub 映射的数据流必须明确。
### 当前状态 vs 设计目标
| 数据 | 当前存储 | §20/§21 设计目标 | 差距 |
|------|---------|-----------------|------|
| 协作面(title/body/comment | 黑板 DB tasks/comments 表 | Gitea Issue/PR | ❌ Phase 1 断裂导致 agent 用黑板 API |
| parent/sub 映射 | `tasks.parent_task`(黑板字段) | `task_state.parent_issue`(新表) | ❌ task_state 表不存在 |
| 执行状态 | 黑板 DB tasks.status | task_state.status | ❌ task_state 表不存在 |
| 成果物 | 黑板 DB outputs 表 | git commit + PR | ⚠️ 需 prompt 引导 |
### parent/sub Issue 映射数据流(设计)
```
Agent 在 Phase 1 创建 sub Issue:
POST /repos/{repo}/issues
title: "[moz][sub][parent #{N}] 任务名"
assignees: ["{agent_id}"]
Gitea webhook: issues/opened (with assignee)
daemon: _handle_issues → assigned 分支
→ 解析标题 [parent #{N}] → 提取 parent_issue_number
→ 写入 task_state (issue_number, parent_issue=N, status='pending')
ticker: _check_round_complete
→ SELECT DISTINCT parent_issue FROM task_state WHERE parent_issue IS NOT NULL
→ 对每个 parent_issue: SELECT status FROM task_state WHERE parent_issue=?
→ 全部终态 → spawn 庞统 review
```
### 前置条件
1. **task_state 表创建**:§20 设计了 DDL 但未实现。需要先建表:
```sql
CREATE TABLE task_state (
issue_number INTEGER PRIMARY KEY,
repo TEXT,
parent_issue INTEGER,
status TEXT DEFAULT 'pending',
action_type TEXT,
retry_count INTEGER DEFAULT 0,
dispatch_count INTEGER DEFAULT 0,
round_count INTEGER DEFAULT 0,
created_at TEXT,
updated_at TEXT
);
CREATE INDEX idx_task_state_parent ON task_state(parent_issue);
```
2. **parent_issue 解析**daemon 在 `_handle_issues` 中解析标题 `[parent #{N}]` 模式,写入 `task_state.parent_issue`(§21 §14b L920 已有此设计)。
3. **_check_round_complete 改造**:从扫 `tasks.parent_task`(黑板)改为扫 `task_state.parent_issue`toolchain DB)(§21 §16.2 L1148 已有此设计)。
### 混合期处理
task_state 表创建前,`_check_round_complete` 仍扫 `tasks.parent_task`。两种数据可以共存:
- **黑板路径**Phase 1 断裂时):agent 通过黑板 API 认领 → `tasks.parent_task` 有值
- **Gitea 路径**Phase 1 修复后):agent 创建 sub Issue → `task_state.parent_issue` 有值
`_check_round_complete` 需要同时扫两个源,直到黑板路径完全废弃。
### 各 Phase 数据读写汇总
| Phase | daemon 写 | daemon 读 | agent 读 | agent 写 |
|-------|----------|----------|----------|----------|
| 0 | toolchain DB: task(pending, action_type=issue_discussion) | Gitea webhook payload | — | — |
| 1 | toolchain DB: broadcast log | toolchain DB: pending tasks | Gitea Issue body | Gitea Issue comment + sub Issue |
| 2 | toolchain DB: task(pending, action_type=issue_assigned) | Gitea webhook payload, toolchain-templates.yaml | Gitea Issue body | git branch + PR |
| 3 | toolchain DB: task(review_request/ci_failure) | Gitea webhook (PR opened, CI status) | Gitea PR + CI logs | git push (修复) |
| 4 | toolchain DB: task(review_result_*) | Gitea webhook (pull_request_review) | Gitea PR diff + files | Gitea Review API |
| 5 | toolchain DB: task(review_merged) | Gitea webhook (PR closed/merged) | — | — |
| 6 | task_state: round_count++ | task_state: parent_issue + sub status | Gitea parent Issue body + sub Issue comments | Gitea Issue comment(三问结论)+ 关闭/创建 Issue |
| 7 | toolchain DB: task(issue_closed) | Gitea webhook (issues/closed) | — | — |