diff --git a/docs/design/20-issue-centric-orchestration.md b/docs/design/20-issue-centric-orchestration.md index 861114d..87f81f6 100644 --- a/docs/design/20-issue-centric-orchestration.md +++ b/docs/design/20-issue-centric-orchestration.md @@ -1,8 +1,9 @@ --- title: "Issue-Centric Orchestration — Gitea Issue 替代黑板 DB 协作面" created: 2026-06-19 -version: v1.0 draft +version: v1.1 draft status: draft +changelog: v1.1 纳入姜维 Review 反馈(issue_updated_at 缓存校验、daemon_meta 改名、TaskAdapter、mention 适配层) --- # Issue-Centric Orchestration @@ -140,7 +141,9 @@ CREATE TABLE task_index ( branch TEXT, -- 功能分支名(如 fix/42-feature-a) status TEXT DEFAULT 'pending', -- daemon 内部状态 assignee TEXT, -- agent id(冗余,加速 dispatch 查询) - must_haves TEXT, -- JSON(daemon 元数据:event_type, steps 等) + daemon_meta TEXT, -- JSON(daemon 元数据:event_type, steps 等) + issue_body_cache TEXT, -- webhook 触发时缓存的 Issue body + issue_updated_at TEXT, -- Gitea Issue 的 last updated 时间戳,用于缓存失效判断 retry_count INTEGER DEFAULT 0, dispatch_count INTEGER DEFAULT 0, max_retries INTEGER DEFAULT 2, @@ -152,6 +155,10 @@ CREATE TABLE task_index ( **注意**: task_index 不存 title/description/labels——这些从 Gitea Issue 实时读。 +**缓存失效机制**: spawner 构建 prompt 时比对 `issue_updated_at` 和 Gitea API 的 Issue `updated_at`。不匹配说明 Issue body 被编辑过,重新拉取并更新缓存。正常情况下 Issue body 创建后不改,开销可忽略。 + +**字段命名说明**: `daemon_meta`(原 `must_haves`)存储 daemon 专用的元数据(event_type、steps 等),改名以避免和需求文档中的 must_haves 概念混淆。 + --- ## §4. 流程设计 @@ -239,14 +246,16 @@ webhook 可能丢失或延迟。ticker 保留原有逻辑,改为: 当前 spawner 从 SQLite 读 task description(微秒级)。改为从 Gitea API 读(毫秒级,HTTP 请求)。 - **方案 A**: 每次 spawn 时实时调 Gitea API。简单但慢 -- **方案 B**: webhook 触发时缓存 Issue body 到 task_index.must_haves 或单独字段。spawn 时从缓存读 -- **推荐**: 方案 B。webhook 触发时 daemon 已经有 Issue body(在 payload 中),直接缓存 +- **方案 B**: webhook 触发时缓存 Issue body 到 `task_index.issue_body_cache` + `issue_updated_at`。spawn 时从缓存读 +- **缓存失效**: spawner 构建 prompt 时比对 `issue_updated_at` 和 Gitea API 的 Issue `updated_at`,不匹配才重新拉取(正常情况 Issue body 创建后不改,开销可忽略) +- **推荐**: 方案 B + updated_at 校验 **P2: dispatcher 的 `Task.from_row(row)` 返回的对象缺少字段** 当前 Task 对象有 30+ 个字段(title/description/priority/risk_level 等)。task_index 只存少量字段。dispatcher/dispatch 逻辑如果访问了 Task 对象的 title/description 字段,会取不到值。 -- **方案**: Task 对象新增 `issue_data` 字段(lazy load),首次访问 title/description 时从 Gitea API 或缓存加载 +- **方案 A(lazy load)**: Task 对象新增 `issue_data` 字段,首次访问 title/description 时从 Gitea API 或缓存加载 +- **方案 B(TaskAdapter,推荐 ✅)**: 新增 `TaskAdapter` 类,封装 task_index + Gitea Issue 数据的合并访问。调用方代码不用改,只改 adapter 内部实现。比 lazy load 字段更干净——合并逻辑集中在一处,而不是散落在 Task 对象的多个 property 中 - **影响**: 需要检查 dispatcher 中所有访问 task.title/task.description 的地方 **P3: agent 的 prompt 中引用黑板 API 的地方需要改** @@ -261,6 +270,7 @@ PromptSection 中有多处 `POST localhost:8083/api/projects/.../tasks/.../comme 当前 @mention 通过黑板 `mention_queue` 表排队。改造后 @mention 通过 Gitea Issue/PR comment(webhook 自然触发)。但 mention_queue 的消费逻辑(ticker 扫描 → 通知 → agent 处理)需要适配。 - **方案**: mention_queue 保留,但数据来源从黑板 comment 改为 Gitea webhook payload +- **⚠️ 适配层**: Gitea webhook payload 中的 comment body 是完整 markdown 文本(不像黑板 comment 是结构化 JSON,有 comment_type、author 等字段)。mention_queue 消费侧需要适配:从 webhook payload 的 `comment.body` 中正则提取 @mention,而非 SQL WHERE 精确查询。这层适配在 Phase 4 mention 迁移时细化 - **影响**: ticker 中的 mention 处理逻辑需要适配 --- @@ -321,10 +331,11 @@ agent 需要知道工作方式变了。新增一个通用 section(或加入现 | 阶段 | 内容 | 依赖 | |------|------|------| -| Phase 1 | task_index 表创建 + webhook handler 适配(Issue assigned → 建索引) | 设计 Review 通过 | -| Phase 2 | dispatcher/ticker 数据源从 tasks 表切换到 task_index | Phase 1 | -| Phase 3 | spawner 读 Issue body 构建 prompt(替代读黑板 description) | Phase 2 | -| Phase 4 | prompt 改造(黑板 API → Gitea API) | Phase 3 | +| **Phase 0** | **前置:webhook 权限** — jiangwei-infra 升级为 repo admin,或主公手动配置 webhook | 设计 Review 通过 | +| Phase 1 | task_index 表创建 + webhook handler 适配(Issue assigned → 建索引)+ **验证 Gitea CI status webhook 是否触发** | Phase 0 | +| Phase 2 | dispatcher/ticker 数据源从 tasks 表切换到 task_index + TaskAdapter 合并访问层 | 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 5 | 验证 + 清理废弃的黑板协作面表 | Phase 4 | 每个 Phase 独立可验证,出问题可以回退。 @@ -335,8 +346,10 @@ agent 需要知道工作方式变了。新增一个通用 section(或加入现 | 风险 | 等级 | 缓解 | |------|------|------| -| Gitea API 不可用时 daemon 完全瘫痪 | 中 | webhook 触发时缓存 Issue body(P1 方案 B),减少运行时 Gitea API 依赖 | +| Gitea API 不可用时 daemon 完全瘫痪 | 中 | webhook 触发时缓存 Issue body + issue_updated_at 校验(P1 方案 B),减少运行时 Gitea API 依赖 | | Gitea webhook 丢失 | 低 | ticker 兜底扫描 | | task_index 和 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 或主公手动配置 |