Commit 13000c553c25645361022f04741614567ff52368
1 parent
b65f384b
fix(coding): runBranchSetup 复用已存在分支时必须先合默认分支
缺陷:新建分支以默认分支为起点(createBranchFromPromptM),但复用已存在分支的 两条路径——主根 checkout(coding.mjs:2167 分支)与 lane worktree add(分支 2)—— 都不带任何同步动作。上一轮跑完遗留的功能分支遂停在原位,其后进入默认分支的 REQ 卡片 / migration / docs 增量对本轮全部不可见。 实测后果(xlyClaude15DDD 2026-07-20):module-CFG 停在旧点,spec 子代理报 「全仓 grep <req> 零命中」后照自身理解另实现了一套设计,直到 milestone merge 才以三文件内容冲突暴露,整轮返工。子代理并未跑偏——它被喂了残缺的世界。 修法:HEAD 确认后统一跑 syncBranchWithDefaultPromptM(lane / 主根共用)。 新建分支走到这里恒为 up-to-date,故可无条件执行、幂等。冲突时保留现场返回失败, 经 runAction 仲裁 halt 交人工——陈旧分支与默认分支真冲突意味着两边都动了同一处, 只有人能判断取舍;自动 abort 会抹掉这个信号,让下一轮再撞同一个坑。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Showing
1 changed file
with
36 additions
and
1 deletions
workflows/coding.mjs
| ... | ... | @@ -1517,6 +1517,34 @@ function createBranchFromPromptM(fromBranch, newBranch, c) { |
| 1517 | 1517 | ].join('\n') |
| 1518 | 1518 | } |
| 1519 | 1519 | |
| 1520 | +// syncBranchWithDefaultPromptM:把默认分支合进当前功能分支(幂等)。 | |
| 1521 | +// | |
| 1522 | +// 为什么必须有这一步:runBranchSetup 对**新建**分支以默认分支为起点(createBranchFromPromptM), | |
| 1523 | +// 但对**已存在**分支只做 checkout(主根)/ worktree add(lane 分支 2),二者都不带任何同步动作。 | |
| 1524 | +// 于是「上一轮跑完留下的功能分支」会停在它当时的位置,其后提交到默认分支的一切——新 REQ 卡片、 | |
| 1525 | +// 新 migration、docs 增量——对本轮**全部不可见**。子代理据残缺事实作业不会报错,只会自行发明 | |
| 1526 | +// 需求(实测:spec 阶段报「全仓 grep <req> 零命中」后照自己的理解另实现一套),到 milestone | |
| 1527 | +// merge 才以内容冲突暴露,此时整轮返工。故此步须在功能分支上作业**之前**执行。 | |
| 1528 | +// | |
| 1529 | +// 冲突处置:不 abort、不 stash——保留冲突现场返回失败,由 runAction 仲裁后 halt 交人工。 | |
| 1530 | +// 陈旧分支与默认分支真冲突意味着两边都动了同一处,只有人能判断取舍;自动 abort 会把这个 | |
| 1531 | +// 信号抹掉,让下一轮再次撞上同一个坑。 | |
| 1532 | +function syncBranchWithDefaultPromptM(branch, defaultBranch, c) { | |
| 1533 | + return [ | |
| 1534 | + `# 把默认分支 \`${defaultBranch}\` 合进功能分支 \`${branch}\`(幂等)`, | |
| 1535 | + microStepContract(c.root), | |
| 1536 | + '', | |
| 1537 | + `前置:确认 \`git -C ${c.root} rev-parse --abbrev-ref HEAD\` 等于 \`${branch}\`;不等则直接返回失败(error 写明实际分支),**绝不**自行切分支。`, | |
| 1538 | + `跑 \`git -C ${c.root} merge --no-edit ${defaultBranch}\`。`, | |
| 1539 | + '按结果分三种:', | |
| 1540 | + `1. 输出含 \`Already up to date\` → 分支本就包含默认分支全部提交,返回 \`{ "success": true, "detail": "up-to-date" }\`。`, | |
| 1541 | + `2. 合并成功(fast-forward 或产生合并提交)→ 返回 \`{ "success": true, "detail": "merged: <被合入的提交数,取 git -C ${c.root} rev-list --count ${branch}@{1}..${branch}>" }\`。`, | |
| 1542 | + `3. 冲突或其它失败 → **保留冲突现场**(绝不跑 \`merge --abort\` / \`reset\` / \`stash\`),返回 \`{ "success": false, "error": "merge conflict", "detail": "<git -C ${c.root} diff --name-only --diff-filter=U 的冲突文件清单>" }\`。`, | |
| 1543 | + '## 输出(ACTION_RESULT_SCHEMA)', | |
| 1544 | + '- 见上三种分支;`detail` 必填,供上层日志与人工诊断。', | |
| 1545 | + ].join('\n') | |
| 1546 | +} | |
| 1547 | + | |
| 1520 | 1548 | // ── lane 物理隔离基础设施(Phase C:worktree 生命周期 + migration 版本段 + lane 测试库)── |
| 1521 | 1549 | // 启用时机:Phase D 波次执行器在 ≥2 宽波次的前置串行段调用(读 maxV / 读 schema 基底 / 探测支持 / |
| 1522 | 1550 | // 建 lane),本阶段只提供确定性原语;串行 / 主根路径(c.lane == null)不触达其中任何一个,行为不变。 |
| ... | ... | @@ -2184,7 +2212,14 @@ async function runBranchSetup(module, c) { |
| 2184 | 2212 | } |
| 2185 | 2213 | if (head.branch !== branch) throw new Error(`HALT branchSetup-branch-mismatch ${branch}: ${ADJUDICATE_MAX} 轮后 HEAD 仍在 ${head.branch}`) |
| 2186 | 2214 | |
| 2187 | - log(`branch-setup: ${id} → ${branch}`) | |
| 2215 | + // 默认分支 → 功能分支同步(幂等)。新建分支走到这里恒为 up-to-date(起点就是默认分支); | |
| 2216 | + // 真正吃这一步的是**复用已存在分支**的两条路径——主根 checkout 与 lane worktree add—— | |
| 2217 | + // 它们此前不带任何同步,会让上一轮遗留的功能分支看不到其后进入默认分支的 REQ 卡片 / | |
| 2218 | + // migration / docs 增量,子代理据残缺事实自行发明实现,直到 milestone merge 才以冲突暴露。 | |
| 2219 | + // 冲突时保留现场 halt(见 prompt 说明),由人工判断取舍。 | |
| 2220 | + const sync = await runAction(g => syncBranchWithDefaultPromptM(branch, def.branch, c) + g, | |
| 2221 | + {site:`branchSetup-sync-default:${branch}`, grp:'Milestone', label: lbl('sync'), dec: c.decisions, root: c.root}) | |
| 2222 | + log(`branch-setup: ${id} → ${branch}(同步默认分支 ${def.branch}:${sync.detail || 'ok'})`) | |
| 2188 | 2223 | } |
| 2189 | 2224 | |
| 2190 | 2225 | // ---- runMilestone:原 milestonePrompt 的 6 步散文流程 → JS 编排 ---- | ... | ... |