docs(§20): 纳入姜维 Review 反馈 v1.1
CI / lint (pull_request) Successful in 13s
CI / test (pull_request) Successful in 28s
CI / frontend (pull_request) Successful in 12s
CI / notify-on-failure (pull_request) Successful in 0s

- task_index 加 issue_updated_at + issue_body_cache 字段
- must_haves 改名 daemon_meta(避免概念混淆)
- P2 推荐 TaskAdapter 替代 lazy load
- P4 补充 mention 解析适配层说明
- 新增 Phase 0 前置(webhook 权限)
- Phase 1 加 CI status webhook 验证
- 风险表补充 CI status 不触发 + 权限不足两项
This commit is contained in:
cfdaily
2026-06-19 21:21:46 +08:00
parent ea04b4c483
commit b6e58a164c
+23 -10
View File
@@ -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, -- JSONdaemon 元数据:event_type, steps 等)
daemon_meta TEXT, -- JSONdaemon 元数据: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 或缓存加载
- **方案 Alazy load**: Task 对象新增 `issue_data` 字段,首次访问 title/description 时从 Gitea API 或缓存加载
- **方案 BTaskAdapter,推荐 ✅)**: 新增 `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 commentwebhook 自然触发)。但 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 bodyP1 方案 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 bodyspawn 时不调 Gitea API |
| 原 task 流程和新 Issue 流程共存期混乱 | 中 | 可以限定只在特定项目中启用 Issue 模式,逐步切换 |
| Gitea CI status 变化不触发 webhook | 中 | Phase 1 首先验证;如果不触发,ticker 兜底轮询 commit status API |
| webhook 管理权限不足 | 中 | Phase 0 前置解决:升级 jiangwei-infra 为 repo admin 或主公手动配置 |