# Lane Worktree 物化与代码流转改造计划 本文档定义 `inbox v2` 中 `lane -> worktree -> runtime` 的代码流转改造方案。 目标很明确: - 保留 `lane` 级隔离执行能力 - 让下游 `lane` 能消费上游 `lane` 的真实代码产物 - 避免 worker summary 充当“伪代码同步” - 逐步把当前执行模型修正为“依赖图 = 代码图” 本文档按阶段拆分,便于逐步实现和回归。 ## 背景 当前系统已经把术语统一到 `lane`,但运行时还存在一个关键缺口: - `leader` 规划出 task DAG - 系统按 task 依赖自动派生 execution lanes - 每个 `lane` 都有独立 `worktree` 和 `podman` 容器 - 但跨 `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 API` 和 `Frontend 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 lane` 从 `main` 起步,产出基础脚手架代码快照。 2. `Backend API lane` 从 `Foundation Setup` 的代码快照起步,负责后端与 SQLite。 3. `Frontend App lane` 从 `Foundation 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。 ### 缺口 3:merge_request 模型未接入执行主路径 系统里虽然有 `merge_requests` 表和 API,但当前并没有把它们接入 `leaderloop` / `taskexec` 的主执行链路。 ### 缺口 4:lane 拆分策略过于宽松 当前 task DAG 会自动派生 lane,但不会约束: - 哪些任务必须共用 lane - 哪些任务值得独立 lane - 哪些节点根本不需要独立 worktree ## 目标架构 建议引入两个新模块和一个新的持久化记录层。 ### 模块 A:`lanesnapshot` 建议路径: - `inbox/internal/app/lanesnapshot/` 职责: - 检查 lane worktree 是否有代码变更 - 过滤不应纳入版本控制的运行时垃圾 - 生成 lane 的提交快照 - 把最新提交记录回 lane 元数据 它不负责: - 分配任务 - merge 上游 lane - 启动容器 ### 模块 B:`lanematerialize` 建议路径: - `inbox/internal/app/lanematerialize/` 职责: - 根据 task 依赖关系识别当前 task 的上游 lanes - 将上游 lane 的最新代码快照同步到当前 lane - 记录 merge / 物化结果 - 冲突时产生结构化阻塞信息 它不负责: - 选择哪个 task 该执行 - 自动 replan - worker prompt 组装 ### 模块 C:lane 同步记录 建议新增表: - `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` 如果 `Backend` 和 `Frontend` 都已经是从 `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 看不到上游代码”的基线案例 ### 阶段 1:lane 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-2` 中 `foundation` / `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 API` 和 `Frontend App` 的真实代码 - 回归时不再依赖 worker summary 重建实现 ### 阶段 3:阻塞与 replan 闭环 目标: - merge 冲突成为受控状态,而不是隐性失败 实现内容: - 统一 materialization failure 到 `blocked` - 增加 task event / message,向 leader 报告冲突 - leader 收到冲突后走 patch replan 验收标准: - 冲突 topic 会稳定停在 `blocked` - leader 能基于冲突信息重新编排,而不是盲目新起 lanes ### 阶段 4:lane 拆分规则收紧 目标: - 减少不必要的 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 来说,这不是优化,而是让系统终于按自己宣称的依赖关系去工作。