Files
ai-workflow/docs/lane-worktree-materialization-plan.md
T

17 KiB
Raw Blame History

Lane Worktree 物化与代码流转改造计划

本文档定义 inbox v2lane -> worktree -> runtime 的代码流转改造方案。

目标很明确:

  • 保留 lane 级隔离执行能力
  • 让下游 lane 能消费上游 lane 的真实代码产物
  • 避免 worker summary 充当“伪代码同步”
  • 逐步把当前执行模型修正为“依赖图 = 代码图”

本文档按阶段拆分,便于逐步实现和回归。

背景

当前系统已经把术语统一到 lane,但运行时还存在一个关键缺口:

  • leader 规划出 task DAG
  • 系统按 task 依赖自动派生 execution lanes
  • 每个 lane 都有独立 worktreepodman 容器
  • 但跨 lane 的依赖目前只传递 worker summary,不传递代码

这会导致一个结果:

  • 调度层认为 Task B 依赖 Task A
  • 运行层却没有把 Task A 的代码产物同步给 Task B
  • Task B 只能在自己的空 worktree 里“重建”上游结果

这不是真正的依赖执行,而是“读摘要后重写”。

真实问题示例:todo-lane-smoke-2

todo-lane-smoke-2 的 task 图如下:

  1. Scaffold full-stack project structure
  2. Implement Todo API with SQLite
  3. Implement React Todo UI
  4. Integrate stack and verify runnable demo
  5. Todo demo ready for review

其依赖关系如下:

  • Scaffold full-stack project structure:根任务
  • Implement Todo API with SQLite:依赖 Scaffold
  • Implement React Todo UI:依赖 Scaffold
  • Integrate stack and verify runnable demo:依赖 Backend API + Frontend App
  • Todo demo ready for review:依赖 Integrate

当前系统会把它派生成 4 条 execution lanes

  • Foundation Setup
  • Backend API
  • Frontend App
  • Integration And Verification

问题在于:

  • Backend APIFrontend App 在各自 worktree 中写代码
  • Integration And Verification 也在自己的 worktree 中执行
  • 但它拿不到前两个 lane 的真实代码,只能拿到消息摘要

这意味着 Integration 不是在“上游代码之上做集成”,而是在“读了两段总结之后重新拼代码”。

总目标

实施完成后,系统应满足以下条件:

  • 每个代码型 lane 都有可复用的 git 产物,而不是只有未提交改动
  • 下游 lane 启动前可以显式物化上游 lane 的代码输入
  • lane 之间的依赖关系能在 git 历史中体现出来
  • merge 冲突会显式阻塞执行,而不是被摘要绕过
  • milestone / gate 不再滥用独立 worktree
  • lane 是“代码演进线”,不是“任意 task 容器”

术语

本文统一使用以下术语:

  • lane:执行泳道,代表一条相对连续的代码演进线
  • worktree:该 lane 对应的 git 工作目录
  • runtime:该 lane 对应的容器与 worker 进程
  • snapshot:某个 lane 在成功完成代码任务后的已提交 git 状态
  • materialization:将上游 lane 的代码输入同步到当前 lane

设计原则

1. 代码依赖必须用代码流转表达

只要下游 task 需要基于上游代码继续开发、联调、验证,就必须物化上游代码,而不是只传摘要。

2. lane 隔离要保留,但不能成为代码孤岛

lane 的价值是隔离并行开发,不是让每个 worker 在自己的平行宇宙里重写同一份实现。

3. 失败要显式

如果下游 lane 在物化上游代码时发生 merge 冲突,应显式标记 blocked,并触发 replan 或人工介入。

4. 优先 clean replacement,不做兼容分叉

不增加“新老同步方式同时存在”的运行时兼容逻辑。

应使用显式 schema / 数据迁移把新模型落下。

5. runtime 职责保持窄边界

  • workspaceruntime 负责 ensure worktree / container
  • taskexec 负责调度与状态推进
  • git 产物提交与代码物化应放在单独模块中

不要把代码同步逻辑散落到 handler、runtime、leader prompt 中。

非目标

本计划不包含以下内容:

  • 多机调度
  • 远程仓库 push / pull
  • GitHub / GitLab PR 集成
  • 二进制产物仓库
  • 通用 artifact storage
  • 对历史旧 topic 的运行时兼容兜底

理想工作流

todo-lane-smoke-2 举例,理想形态如下。

Lane 拆分

保留 4 条 execution lanes,但语义要变:

  1. Foundation Setup lanemain 起步,产出基础脚手架代码快照。

  2. Backend API laneFoundation Setup 的代码快照起步,负责后端与 SQLite。

  3. Frontend App laneFoundation Setup 的代码快照起步,负责 React 前端。

  4. Integration And Verification lane 在开始执行前,先物化:

    • Foundation Setup
    • Backend API
    • Frontend App

    然后再做联调、启动脚本、验证、补丁修复。

  5. Todo demo ready for review 这是 milestone,不需要独立 worktree。

Git 视角下的理想状态

  • Foundation Setup lane 成功后,lane 分支上至少有一笔提交
  • Backend API lane 成功后,lane 分支上至少有一笔提交
  • Frontend App lane 成功后,lane 分支上至少有一笔提交
  • Integration 开始前,自己的 branch 已显式 merge 上游分支

换句话说,Integration 看到的应该是:

  • foundation commit
  • backend commit
  • frontend commit

而不是:

  • “Backend worker 说自己完成了”
  • “Frontend worker 说自己完成了”

当前缺口

缺口 1:代码没有被自动提交

当前 worker 执行成功后,代码通常还停留在未提交状态。

这会导致:

  • 上游 lane 没有稳定的可消费产物
  • 下游即使要 merge,也没有明确的输入 commit

缺口 2:下游 lane 没有物化步骤

当前 taskexec 在给 worker 分配任务前,不会把依赖 lanes 的代码同步进当前 lane。

缺口 3merge_request 模型未接入执行主路径

系统里虽然有 merge_requests 表和 API,但当前并没有把它们接入 leaderloop / taskexec 的主执行链路。

缺口 4lane 拆分策略过于宽松

当前 task DAG 会自动派生 lane,但不会约束:

  • 哪些任务必须共用 lane
  • 哪些任务值得独立 lane
  • 哪些节点根本不需要独立 worktree

目标架构

建议引入两个新模块和一个新的持久化记录层。

模块 Alanesnapshot

建议路径:

  • inbox/internal/app/lanesnapshot/

职责:

  • 检查 lane worktree 是否有代码变更
  • 过滤不应纳入版本控制的运行时垃圾
  • 生成 lane 的提交快照
  • 把最新提交记录回 lane 元数据

它不负责:

  • 分配任务
  • merge 上游 lane
  • 启动容器

模块 Blanematerialize

建议路径:

  • inbox/internal/app/lanematerialize/

职责:

  • 根据 task 依赖关系识别当前 task 的上游 lanes
  • 将上游 lane 的最新代码快照同步到当前 lane
  • 记录 merge / 物化结果
  • 冲突时产生结构化阻塞信息

它不负责:

  • 选择哪个 task 该执行
  • 自动 replan
  • worker prompt 组装

模块 Clane 同步记录

建议新增表:

  • lane_syncs

建议字段:

  • id
  • workspace_id
  • topic_id
  • downstream_lane_id
  • upstream_lane_id
  • task_id
  • upstream_commit
  • merge_commit
  • status
  • error_message
  • created_at
  • updated_at

用途:

  • 保证物化过程可观测
  • 避免重复 merge 同一输入时缺乏依据
  • 为 dashboard / 调试 / 重试提供基础数据

数据模型改造

阶段性最小变更

在现有 lanes 表上新增字段:

  • head_commit TEXT NOT NULL DEFAULT ''

说明:

  • 领域名词与底层表名现在都使用 lane / lanes
  • 先在现有 lanes 表上扩字段,避免一次性大迁移

后续可选扩展

如需更强的可观测性,可继续新增:

  • last_materialized_at
  • last_materialized_commit
  • last_sync_error

但这些不是第一阶段必需项。

关键执行点

1. 成功 task 完成后,自动生成 lane snapshot

建议接入点:

  • inbox/internal/app/taskexec/service.go
  • Complete(...) 主路径

顺序建议:

  1. worker 返回成功
  2. 宿主机确认 lane runtime 与 worktree 可访问
  3. lanesnapshot 检查并提交 worktree 代码
  4. 成功后才真正把 task 标成 succeeded
  5. 如果提交失败,则这次 run 视为失败或阻塞

原因:

  • 一旦 task 已被标成成功,但代码并未形成稳定快照,下游 lane 仍然无法消费
  • 所以“成功完成 task”的定义应当包含“代码产物已稳定落盘到 git”

2. 下游 task 被 claim 前,先做 lane materialization

建议接入点:

  • inbox/internal/app/taskexec/service.go
  • ClaimNext(...) 主路径

顺序建议:

  1. 找到当前 lane 中下一个 ready task
  2. 识别其依赖 tasks
  3. 推导依赖 tasks 所属的上游 lanes
  4. lanematerialize 将上游 lane commits 同步到当前 lane
  5. 同步成功后再真正 claim task
  6. 如冲突,则不 claim,改为 blocked

原因:

  • worker 启动时就应该处于“已拿到所有上游代码输入”的环境
  • 不要把 merge 责任甩给 worker

3. workspaceruntime 不做业务同步

workspaceruntime 继续只负责:

  • ensure repository
  • ensure worktree
  • ensure container
  • stop container

不要把以下逻辑塞进去:

  • 依赖 lanes 分析
  • 自动 commit
  • 自动 merge
  • 冲突策略判断

推荐 merge 策略

第一版建议使用最朴素、最可审计的策略:

  • 上游 lane 产物必须先成为 git commit
  • 下游 lane 物化时使用显式 git merge
  • 保留 merge commit,不做 squash

原因:

  • 依赖关系能在历史中直接看见
  • 调试时容易定位是哪条 lane 带进来的改动
  • 比起复制文件或 patch 应用,git merge 更符合当前 worktree 模型

合并顺序

建议按依赖拓扑顺序进行 merge。

Integration And Verification 为例,建议顺序:

  1. Foundation Setup
  2. Backend API
  3. Frontend App

如果 BackendFrontend 都已经是从 Foundation 分化出来的,并且各自分支历史完整,也可以只 merge 最终两个分支,由 git 自动通过共同祖先处理基础提交。

第一版不要求做最优优化,要求的是语义正确和行为稳定。

冲突处理

发生冲突时:

  • 停止当前 materialization
  • 记录 lane_syncs.status = failed
  • task 标记为 blocked
  • lane 可标记为 blocked
  • 通过 message 或 task event 通知 leader

不要做以下行为:

  • 自动硬解冲突
  • 静默 fallback 为“只读摘要继续执行”
  • 自动丢弃上游改动

lane 拆分策略建议

除了代码流转,lane 数量本身也要更收敛。

应当独立 lane 的情况

  • 明确并行价值高
  • 文件边界清晰
  • 预期实现时间较长
  • 失败隔离有意义
  • 产物可以作为其他 lane 的明确输入

应当共用 lane 的情况

  • 前后两个 task 本质上是同一条连续实现链
  • 第二个 task 高度依赖第一个 task 的局部未抽象代码
  • 拆开后只会制造频繁 merge 和冲突

不应拥有独立代码 lane 的情况

  • milestone
  • gate
  • 单纯汇报 / 审阅 / 总结型节点

分阶段实施

阶段 0:基线梳理与命名统一

目标:

  • 明确以 lane 为统一术语
  • 建立当前缺口的自动化验证样例

实现内容:

  • 文档统一使用 lane
  • todo-lane-smoke-2 这类场景补回归测试描述
  • 梳理现有旧命名残留,不要求立刻全量改名

验收标准:

  • 团队对外讨论统一使用 lane
  • 有一份可复现“下游 lane 看不到上游代码”的基线案例

阶段 1lane snapshot 落地

目标:

  • 成功的代码型 task 必须沉淀为 lane 分支上的 commit

实现内容:

  • lanes 表新增 head_commit
  • 新增 lanesnapshot 模块
  • 在 task 成功完成路径中自动:
    • 检查 worktree dirty 状态
    • 执行 git add
    • 执行 git commit
    • 写回 head_commit

建议约束:

  • 只对 execution / verification 这类代码型 task 做 snapshot
  • milestone / gate 不生成代码提交

验收标准:

  • todo-lane-smoke-2foundation / backend / frontend 成功后,各自 lane 均有非空 head_commit
  • worktree 不再只停留在未提交改动

阶段 2:下游 lane materialization

目标:

  • 下游 lane 能在 worker 执行前拿到上游 lane 的真实代码输入

实现内容:

  • 新增 lanematerialize 模块
  • 新增 lane_syncs
  • ClaimNext(...) 中对 candidate task 执行 materialization
  • materialization 成功后才 claim task

验收标准:

  • Integration And Verification 在执行前能看到 Backend APIFrontend App 的真实代码
  • 回归时不再依赖 worker summary 重建实现

阶段 3:阻塞与 replan 闭环

目标:

  • merge 冲突成为受控状态,而不是隐性失败

实现内容:

  • 统一 materialization failure 到 blocked
  • 增加 task event / message,向 leader 报告冲突
  • leader 收到冲突后走 patch replan

验收标准:

  • 冲突 topic 会稳定停在 blocked
  • leader 能基于冲突信息重新编排,而不是盲目新起 lanes

阶段 4lane 拆分规则收紧

目标:

  • 减少不必要的 lane / worktree / container 增生

实现内容:

  • 调整 leader prompt 与 lane 派生规则
  • 倾向于把连续实现链保留在同一 lane
  • 仅在明确并行或集成汇聚点时拆新 lane
  • milestone / gate 不派生代码 lane

验收标准:

  • 类似 todo-lane-smoke-2 的 topic 中,lane 数量与实际代码边界一致
  • 不再出现“为了一个收口任务额外生成空 lane”的情况

阶段 5:可观测性与回收策略

目标:

  • 让 lane 运行时资源与代码同步状态都可追踪、可回收

实现内容:

  • dashboard 展示:
    • head_commit
    • 最新 materialization 状态
    • lane sync 历史
  • topic 完成后可选执行:
    • 停止 lane runtime
    • 延迟回收容器
    • 延迟清理 worktree

说明:

  • 本阶段是运维优化,不阻塞前四阶段主路径落地

验收标准:

  • topic 完成后不再长期残留无意义运行中的 lane runtime
  • 调试时能直接看到 lane 的代码输入输出链路

需要修改的主要模块

必改

  • inbox/internal/app/taskexec/service.go
  • inbox/internal/store/sqlite/taskexec_store.go
  • inbox/internal/store/sqlite/migrations/
  • inbox/internal/domain/lane/

新增建议

  • inbox/internal/app/lanesnapshot/
  • inbox/internal/app/lanematerialize/
  • inbox/internal/domain/lanesync/
  • inbox/internal/store/sqlite/lane_syncs_store.go

暂不建议承载业务逻辑的模块

  • inbox/internal/app/workspaceruntime/
  • inbox/internal/httpapi/
  • inbox/internal/app/leaderloop/

这些模块可以消费结果,不应承担主要 git 业务逻辑。

测试建议

单元测试

  • snapshot 成功创建提交
  • worktree 无变化时不重复提交
  • materialization 能识别依赖 lanes
  • materialization 在冲突时稳定失败并写入 blocked

集成测试

todo-lane-smoke-2 类型流程验证:

  1. Foundation Setup 成功后生成 commit
  2. Backend API / Frontend App 都从基础快照继续开发
  3. Integration 在启动前合并上游代码
  4. milestone 自动完成且不新建代码 lane

回归重点

  • 不能破坏当前单 lane 串行执行
  • 不能让 gate / milestone 意外触发 git commit
  • 不能把未提交脏状态错误标记成“已可下游消费”

开放问题

1. 自动提交的粒度

第一版建议:

  • 每个成功 task 最多生成一笔提交

不建议第一版支持:

  • 一个 task 内自动切多笔提交

2. merge 粒度是按 task 还是按 lane

第一版建议按 lane 的最新成功快照物化。

原因:

  • 实现简单
  • 与当前 runtime 粒度一致
  • 更符合“lane 是代码演进线”的模型

3. 是否必须使用 merge request 模型

第一版不必强制接入 merge_requests

建议先把:

  • 真实 commit 产物
  • lane materialization
  • 冲突阻塞

这三个核心闭环做完。

之后再决定是否把 merge_requests 升级成:

  • lane 间同步记录
  • 人工审批面板
  • 最终 topic 合并机制

最小可上线版本

如果只做最小闭环,建议范围如下:

  1. lanes.head_commit
  2. 成功 task 后自动提交
  3. ClaimNext 前 merge 上游 lane commits
  4. merge 冲突时标记 blocked

做到这一步,系统就已经从“摘要依赖”升级成“代码依赖”。

结论

这次改造的本质,不是“再加一个 merge 功能”,而是修正整个 lane 执行模型的语义:

  • 上游 lane 的产物应该是代码快照
  • 下游 lane 的输入应该是上游代码状态
  • worker summary 应回归为编排证据,而不是代码同步手段

todo-lane-smoke-2 这样的 DAG 来说,这不是优化,而是让系统终于按自己宣称的依赖关系去工作。