[Feature] 需求间阻塞依赖:定时派发只认领依赖已完成的需求,按优先级排序,上游完成自动放行

オープン
#393 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
22/100
issue の種類
機能追加
明瞭さ
おおむね明確
活発さ
活発
技術スタック
github, go
領域
api, backend, databases

調査の方向性

Start with the scheduler path: execute() and matchingIssues() in internal/schedule/service.go, the candidate ordering from Issues() in internal/repo/issues.go, and the Issue type in internal/domain/issue.go. Also read internal/httpapi/dispatch.go and internal/tracker/github.go. Done means the acceptance checklist in the issue passes, including readiness and cycle-detection unit tests and a migration under migrations/.

索引モデルが issue の本文から書いたものです。

説明

背景与借鉴来源

需求一多,AI 自动认领就会遇到顺序问题:B 需求必须等 A 合入才能做,但调度器不知道,照样把 B 派给 Agent,结果要么在旧代码上实现、要么和 A 冲突,最后只能人工撤回。主流「给 Agent 用的任务系统」都把需求间的阻塞依赖 + 只派发就绪项当作核心能力:

项目 规模/活跃度(2026-11-13) 相关能力
steveyegge/beads ~28.7k stars,当天有提交,v1.3.4(2026-11-04) 依赖图驱动的 Agent 任务记忆:bd dep add B A(A 阻塞 B),bd ready 只列出没有未关闭阻塞项的任务,bd ready --claim 原子认领;A 关闭后 B 自动解除阻塞。依赖分阻塞型(blocks/parent-child/waits-for)和非阻塞型(related/discovered-from),见 Dependencies 文档
MrLesk/Backlog.md ~7.4k stars,11-11 有提交,v1.55.3 面向 AI 助手的任务看板,任务支持 dependencies,详情页同时显示「我在等谁」和「谁在等我」
eyaltoledano/claude-task-master ~28.4k stars 任务带 dependencies,next 命令只返回依赖已完成、按优先级排序的下一项
GitHub Issues — 原生已支持 issue 的 blocked by / blocking 关系和 sub-issues(REST /issues/{n}/dependencies/blocked_by,GraphQL issueDependenciesSummary)

共同做法:依赖关系存在任务上;调度/认领只看「就绪」集合;上游完成自动放行下游;界面能看见卡在谁身上。

LoopForge 现状与不足

  1. 需求之间没有依赖字段。 internal/domain/issue.go 的 Issue 只有 SOPBindings[].DependsOn(internal/domain/issue_sop.go),那是同一个需求内多条 SOP 泳道之间的先后,不能表达「需求 #12 要等需求 #9 完成」。
  2. 定时派发不看依赖和优先级。 internal/schedule/service.go 的 execute() → matchingIssues() 只按项目、状态、来源筛选;可派发判断只有 IssueHasTask/DeliveryLocked/已关闭/AutomationState=ignored,以及集成分支阻塞(guard,按仓库)。候选顺序来自 IssuesRepo.Issues()(internal/repo/issues.go)按 Number 倒序,即最新的需求最先派,Issue.Priority 不参与;MaxDispatch 名额可能被新的、低优先级、或依赖没完成的需求占掉。
  3. blocked 状态只是手工/失败标记。 internal/httpapi/dispatch.go 里 run 启动失败会把需求置为 blocked,但没有「被谁阻塞」的数据,上游完成后也不会自动恢复。
  4. 外部来源的依赖关系丢失。 internal/tracker/github.go 同步 GitHub issue 时只取标题/正文/状态,GitHub 原生的 blocked-by、sub-issue 关系没有带进来(TAPD、工蜂同理)。

建议方案

  1. 数据模型:Issue 增加 BlockedBy []string(同项目内需求 ID);读取时反查生成 Blocks(谁在等我),不重复存。基线变更按 AGENTS.md 规范写 migrations/NNN_issue_dependencies.sql,如需单独关系表放在 IssuesRepo。
  2. 就绪判定(domain 层纯函数,便于测试):IssueReady(issue, lookup):所有 BlockedBy 都已完成(Completed(),或 DeliveryMRState 为 merged/integrated,可配置哪个算完成)才算就绪;阻塞项被取消/删除时视为解除并记一条 IssueOperation。新增/修改依赖时检测环,有环直接拒绝。
  3. 定时派发:schedule.Service.execute 在筛 eligible 时跳过未就绪需求,并把原因写进 job.Blockers(如「#12 等待 #9 完成」),与现有集成阻塞一起在任务结果里展示;候选排序改为「优先级 → 创建时间早的先派」,可在 ScheduleJob 上保留按编号倒序的旧行为开关。
  4. 手动派发:dispatchIssue 对未就绪需求返回 409 并列出阻塞项;提供 force 参数让有权限的人显式越过,记操作日志。
  5. 自动放行:上游需求完成或 MR 合入时,下游需求在下一次调度扫描中自然进入就绪集合;可选:此时给下游负责人发一条通知(复用 internal/notification)。
  6. 外部同步(可分期):GitHub 同步时读取 issue 的 blocked-by 关系,映射为 BlockedBy(两端都已同步进 LoopForge 才建立);TAPD/工蜂后续按各自 API 补。
  7. 界面与 API/MCP:需求详情显示「等待中 / 阻塞了」两个列表,可增删依赖;需求列表支持「仅就绪」筛选;平台 MCP 增加查询就绪需求和维护依赖的工具,方便澄清/拆分类 SOP 拆出子需求时直接写上先后关系。

验收标准

  • 可以在需求上添加/删除「被阻塞于」关系,接口和 UI 都能用;自依赖和成环被拒绝并给出明确提示。
  • 定时任务扫描时,依赖未完成的需求不会被派发,任务结果里能看到「#X 等待 #Y」的原因;上游完成后,下一轮扫描能自动派发下游。
  • 定时任务候选按优先级从高到低派发,同优先级先建先派;MaxDispatch 名额不被未就绪需求占用。
  • 手动派发未就绪需求默认被拒绝(409 + 阻塞清单),带 force 可越过并在需求操作记录里留痕。
  • 上游需求被取消/删除时,下游不会永久卡住(自动解除并记录)。
  • 需求详情能同时看到「等待中」和「阻塞了」;需求列表可筛选「仅就绪」。
  • domain 就绪判定、环检测、schedule 跳过与排序逻辑有单元测试;新增表/列有对应 migrations/ 脚本,不在启动路径里做迁移。
  • (可选,分期)GitHub 同步能带入原生 blocked-by 关系。
主要言語
Go
スター
141
フォーク
28
平均マージ
1日 15時間
マージ済み PR(30日)
113

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

Tencent/LoopForge のほかの issue

Tencent/LoopForge の issue をすべて見る

似ている issue

Go の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。