diff --git a/docs/design/20-issue-centric-orchestration.md b/docs/design/20-issue-centric-orchestration.md index 733cc42..ca5e4c6 100644 --- a/docs/design/20-issue-centric-orchestration.md +++ b/docs/design/20-issue-centric-orchestration.md @@ -1,9 +1,10 @@ --- title: "Issue-Centric Orchestration — Gitea Issue 替代黑板 DB 协作面" created: 2026-06-19 -version: v2.0 draft +version: v2.1 draft status: draft -changelog: v2.0 纳入姜维+司马懿 Review 反馈 + 庞统 Repository 模式修正 +changelog: v2.1 修正 M1(dispatcher 直接 SQL 声明)+ M2(Phase 格式)+ S1/S2(TaskAdapter 残留清理) +v2.0 纳入姜维+司马懿 Review 反馈 + 庞统 Repository 模式修正 v1.1 纳入姜维 Review 反馈 v1.0 初版 --- @@ -136,7 +137,7 @@ Gitea(协作介质,替代黑板 DB 协作面) ### 3.3 数据访问层改造:Repository 模式换底 -**设计原则**:不新建 task_state + TaskAdapter,而是改造现有 Repository(Queries/Blackboard 类)的实现。 +**设计原则**:改造现有 Repository(Queries/Blackboard 类)的实现,不新增中间层。 当前数据访问层已有 Repository 模式的基础——`Blackboard` 类和 `Queries` 类封装了所有数据访问,上层(dispatcher/spawner/ticker)通过方法调用(`queries.pending_dispatchable()`、`blackboard.get_task()`),不直接写 SQL。 @@ -150,7 +151,9 @@ Gitea(协作介质,替代黑板 DB 协作面) dispatcher → Queries(Gitea-backed) → Gitea API(协作数据)+ SQLite(执行状态) ``` -上层代码完全不用改。Queries 内部决定数据从哪来: +上层代码**基本**不用改。但有一个前置条件:dispatcher.py 中存在约 20 处直接操作 tasks 表的 SQL(绕过 Queries 类,如 `SELECT assignee FROM tasks`、`UPDATE tasks SET status=?`)。这些直接 SQL 需要先迁移到 Queries 方法调用,才能实现 Repository 换底。此项作为 Phase 1 的前置工作。 + +Queries 内部决定数据从哪来: | 数据类型 | 来源 | 方式 | |---------|------|------| @@ -178,7 +181,7 @@ CREATE TABLE task_state ( ); ``` -**和 task_state + TaskAdapter 的区别**:不新增表名(task_state 替代 task_state)、不新增 adapter 类。Repository 内部把 Gitea 数据 + 本地执行状态合并成 Task 对象返回。上层调用 `queries.get_task(issue_number)` 得到的 Task 对象和现在一模一样——有 title、有 description、有 status。 +**为什么不用 TaskAdapter**:Repository 内部已经把 Gitea 数据 + 本地执行状态合并成 Task 对象返回。上层调用 `queries.get_task(issue_number)` 得到的 Task 对象和现在一模一样——有 title、有 description、有 status。不需要额外 adapter 层。 --- @@ -273,13 +276,11 @@ webhook 可能丢失或延迟。ticker 保留原有逻辑,改为: - **缓存失效**: spawner 构建 prompt 时比对 `issue_updated_at` 和 Gitea API 的 Issue `updated_at`,不匹配才重新拉取(正常情况 Issue body 创建后不改,开销可忽略) - **推荐**: 方案 B + updated_at 校验 -**P2: dispatcher 的 `Task.from_row(row)` 返回的对象缺少字段** +**P2: Repository 内部数据合并** -当前 Task 对象有 30+ 个字段(title/description/priority/risk_level 等)。task_state 只存少量字段。dispatcher/dispatch 逻辑如果访问了 Task 对象的 title/description 字段,会取不到值。 +Queries 类内部改造——`get_task()` 方法从 Gitea API(或缓存)读 title/body,从 task_state 表读 status/retry_count,合并成 Task 对象返回。上层(dispatcher/spawner)无感知。 -- **方案 A(lazy load)**: Task 对象新增 `issue_data` 字段,首次访问 title/description 时从 Gitea API 或缓存加载 -- **方案 B(TaskAdapter,推荐 ✅)**: 新增 `TaskAdapter` 类,封装 task_state + Gitea Issue 数据的合并访问。调用方代码不用改,只改 adapter 内部实现。比 lazy load 字段更干净——合并逻辑集中在一处,而不是散落在 Task 对象的多个 property 中 -- **影响**: 需要检查 dispatcher 中所有访问 task.title/task.description 的地方 +这是标准的 Repository 模式——接口不变(`get_task(id)` 返回 Task 对象),实现换底(从 SQLite 单源改为 Gitea + SQLite 双源)。不新增 TaskAdapter 类——Queries 类本身就是 Repository,内部合并是职责内的事。 **P3: agent 的 prompt 中引用黑板 API 的地方需要改** @@ -355,12 +356,13 @@ agent 需要知道工作方式变了。新增一个通用 section(或加入现 | 阶段 | 内容 | 依赖 | |------|------|------| -| **Phase 0** | **前置:webhook 权限** — jiangwei-infra 升级为 repo admin,或主公手动配置 webhook | 设计 Review 通过 | -| Phase 0 | webhook 权限配置 + CI status webhook 验证(主公手动配 webhook;验证 Gitea CI status 变化是否触发 webhook) | 设计 Review 通过 | -| Phase 1 | task_state 表创建 + Repository 改造(Queries 类内部从 Gitea + SQLite 双源读) | Phase 0 |(Issue assigned → 建索引)+ **验证 Gitea CI status webhook 是否触发** | Phase 0 | -| Phase 2 | dispatcher/ticker 数据源从 tasks 表切换到 task_state + TaskAdapter 合并访问层 | Phase 1 | +| 阶段 | 内容 | 依赖 | +|------|------|------| +| Phase 0 | webhook 权限配置(主公手动配)+ CI status webhook 验证(确认 Gitea CI status 变化触发 webhook) | 设计 Review 通过 | +| Phase 1 | dispatcher.py 直接 SQL(约 20 处)迁移到 Queries 方法调用 + task_state 表创建 + Queries/Blackboard 内部改造(Gitea + SQLite 双源) | Phase 0 | +| Phase 2 | dispatcher/ticker 数据源从 tasks 表切换到 task_state | Phase 1 | | Phase 3 | spawner 读 Issue body 构建 prompt(替代读黑板 description)+ issue_updated_at 缓存失效机制 | Phase 2 | -| Phase 4 | prompt 改造(黑板 API → Gitea API)+ mention_queue 适配层(webhook payload → @mention 提取) | Phase 3 | +| Phase 4 | prompt 改造(黑板 API → Gitea API)+ mention_queue 适配(action_report body 标记约定) | Phase 3 | | Phase 5 | 验证 + 清理废弃的黑板协作面表 | Phase 4 | 每个 Phase 独立可验证,出问题可以回退。 @@ -376,5 +378,3 @@ agent 需要知道工作方式变了。新增一个通用 section(或加入现 | task_state 和 Gitea Issue 状态不一致 | 中 | ticker 定期校验(发现 Issue closed 但 index 未更新则修复) | | spawner 性能下降(Gitea API 调用) | 低 | 方案 B 缓存 Issue body,spawn 时不调 Gitea API | | 原 task 流程和新 Issue 流程共存期混乱 | 中 | 可以限定只在特定项目中启用 Issue 模式,逐步切换 | -| Gitea CI status 变化不触发 webhook | 中 | Phase 1 首先验证;如果不触发,ticker 兜底轮询 commit status API | -| webhook 管理权限不足 | 中 | Phase 0 前置解决:升级 jiangwei-infra 为 repo admin 或主公手动配置 |