2026-06-15-frontend-overlap-jsdom.md
8.22 KB
前端 jsdom-only 重叠编排 — 实施计划(待评审)
目标:让前端不依赖后端的工作(骨架 + spec + plan + jsdom 驱动的组件代码)与后端波次循环并发, 把所有依赖后端的工作(e2e tdd 任务、e2e verify、静态 review→req-done、行为门、测试闸、里程碑) 延后到后端全部完成之后。这是前后端重叠唯一安全的形态——重叠期前端只跑代码 + jsdom(无栈、无固定 端口、无 DB),不碰后端 lane 的端口/库,补 8/9/10 不变量全部保住。
总开关
parallel.frontendOverlap(缺省 false,完全回退现行串行终波)。一切失败 fail-open 降级现行路径, 绝不因重叠机制新增 halt 点。
一、现状与目标流程
现状(runModule(frontend-phase),终波宽 1 主根,依赖全部后端):
branchSetup → skeleton → featureLoop(frontend: 逐FE spec→plan→tdd(jsdom+e2e)→verify(unit+e2e)→review→req-done)
→ behaviorGate → testGate(frontend) → report → milestone
目标(frontendOverlap 开启时):
Phase 1(重叠,与后端波次并发,跑在前端 worktree):
branchSetup(fe) → skeleton → 逐FE [ spec → plan → tdd(仅 jsdom 任务) → verify(仅 vitest) → tag fe-code-done/<FE> ]
↑ 不打 req-done(e2e+review 未做)
─── 屏障:等后端全部 done(后端波次循环结束) ───
Phase 2(后端 done 后,前端分支并入已完成的 default,主根跑全栈):
逐FE [ tdd(仅延后的 e2e 任务) → verify(unit+e2e) → review → tag req-done/<FE> ]
→ behaviorGate → testGate(frontend) → report → milestone
二、改动清单(函数级)
1. 新增执行序拆分(核心)
-
runFrontendPhase1(feModule, feCtx):branchSetup + skeleton +featureLoopFE(items, 'jsdom', feCtx)。 -
runFrontendPhase2(feModule, c):featureLoopFE(items, 'e2e', c)+ behaviorGate + testGate + report + milestone。 - 现行
runModule的前端段(3078–3096)在 frontendOverlap 关时一字不动;开时改走上面两段。
2. featureLoop 拆 mode(最小侵入:加形参,不动串行语义)
- 现
featureLoop(items, phase, c)内部按 FE 链已抽出共用闭包(isDone/ensureSpec/runPlanStage/runImplChain/tagDone)。 - 新增
feStage参数('jsdom'|'e2e'|'all',缺省'all'=现行):-
jsdom:spec→plan→runImplChain(jsdom)→tag fe-code-done(不 review、不 req-done)。 -
e2e:入口 dedup 读fe-code-done(必须已存在,否则回退 all)→runImplChain(e2e)→review→tag req-done。 -
all:现行完整链。
-
3. tddPrompt(id, phase, planPath, c, feStage='all')
- 新增
feStage:-
jsdom:只处理 plan 中测试先行类型 = jsdom的任务;e2e 任务显式跳过并记账(输出 deferred 列表); FeStub→真组件替换(554)在此完成(组件由 jsdom 任务建出)。测试命令只用frontend.test_command(vitest), 绝不触发pnpm e2e:ci/ Playwright。 -
e2e:只处理= e2e的任务(jsdom 已在 phase1 绿);e2e 基线约束(551)照旧。 -
all:现行文案,一字不动。
-
- 「c 为末位参数」的第三个 opts 特例(先例 deriveSpecPrompt
{batch}/ reviewWithFixLoop{flipDocs08})。
4. verifyPrompt(id, phase, implSummary, specPath, round, c, feStage='all')
-
jsdom:只跑 unit(vitest),不跑 e2e;红则 halt。 -
e2e/all:现行 unit+e2e(595),一字不动。
5. 新增中间 tag fe-code-done/<FE>
- 语义:phase1 完成(组件代码 + jsdom 绿)。
createFeCodeDoneTagPromptM+ check 复用checkReqDoneTagPromptM同构。 - resume 真值链:
fe-code-done/<FE>存在 → phase1 跳过该 FE;req-done/<FE>存在 → phase2 跳过。 二者皆缺 → phase1 重跑该 FE。
6. 主循环并发点(while (remaining.length) 段)
- frontendOverlap 开 且 存在 frontend-phase 模块时:
- 从波次图剔除 frontend-phase(
todo/remaining仅后端;frontend 不再经 annotateDeps 硬依赖)。 const [beResults, fe1] = await Promise.allSettled([ 后端波次循环(), runFrontendPhase1(feModule, feCtx) ])- 两者独立 try/catch,互不 break:前端 phase1 halt 不停后端,反之亦然(各自结构化 halted 入 results)。
- 屏障后:仅当后端全部 done 且 phase1 全部 fe-code-done →
runFrontendPhase2。 - 后端有 halt/pending → phase2 不跑(e2e 需完整后端);phase1 产物(fe-code-done)已落 tag,resume 续跑。
- 从波次图剔除 frontend-phase(
- frontendOverlap 关 → 现行路径(frontend-phase 留在波次图当终波),零改动。
7. worktree / 分支隔离(重叠期)
- phase1 跑在前端专属 worktree(分支
frontend-phase,路径<ROOT>-lanes/frontend-phase同 lane 命名族); 与后端主根/lane 的 git index 互不干扰。phase1 不 merge、不 milestone → 不取 withMainRootLock。 - phase1→phase2 边界:后端已全部 milestone 到 default。phase2 起手 merge default → frontend-phase
(把完成的后端代码并进前端树,e2e 才打得到真后端)。路径互斥(
frontend/vsbackend/)→ 冲突概率极低; 冲突按现行 milestone merge 同口径「留树 halt 给人工」。phase2 完成后照现行 runMilestone 合回 default。
8. 开关透传 + 入口
-
coding-start/SKILL.md步骤 4 的parallel不传frontendOverlap(与 features 闸同纪律:留作显式评估开关, 收益验证通过后才一行加上)。文档补一句逃生口说明。 - README 阶段 B 同步一句。
三、不变量与安全性
| 不变量 | 是否保住 | 依据 |
|---|---|---|
| 补 8/10 行为门/骨架 lane DB 注入豁免 | ✅ | 重叠期前端只跑 jsdom(无 DB);行为门仍在 phase2 后端 done 后、主根、无后端 lane 时跑 |
| 补 9 起栈互斥(固定端口) | ✅ | 重叠期前端不起栈不占端口;phase2 全栈门在后端 lane 全清后跑 |
| fail-open 不新增 halt 点 | ✅ | frontendOverlap 失败/关 → 现行终波路径;phase1 halt 不停后端 |
| req-done 语义(静态过) | ✅ | 仍在 phase2 review 后打;phase1 用独立 fe-code-done
|
| resume 经 tag 续跑 | ✅ | fe-code-done + req-done 双 tag 链 |
四、风险
- 契约漂移返工:前端对 docs/05 写代码,后端编码期若偏离契约 → 错误拖到 phase2 的 e2e/行为门才暴露、返工。 (任何重叠固有代价;用户已接受「先把能做的做了」。)
- 任务分类错配:plan 把 e2e 任务误标 jsdom → phase1 误跑 e2e 触后端。缓解:tddPrompt jsdom 模式硬禁 Playwright/e2e 命令,命中即 halt(不静默放行)。
- 组件依赖后端类型:前端应只依赖 docs/05 契约类型,不依赖后端代码。若个别 FE 的 jsdom 测试隐性需要真后端 → 该 FE 的该任务在 phase1 红 → 按 tdd 账本上限 halt(结构化),phase1 跳过它、其余 FE 照常,resume 续跑。
- phase1→phase2 merge 冲突:路径互斥,概率极低;冲突走现行 milestone 同口径 halt。
五、验证
- coding.mjs 无法
node --test:纯函数/流程以.tmp/临时脚本 stub agent/parallel/phase/log 跑确定性断言 (①overlap 关=现行终波 ②overlap 开+后端全 done+phase1 全 fe-code-done→phase2 跑 ③后端 halt→phase2 不跑、 phase1 tag 保留 ④phase1 halt 不停后端 ⑤tddPrompt jsdom 模式不含 e2e 命令字样)。即跑即删不入库。 -
node lib/check-workflow-syntax.mjs workflows/coding.mjs必过。
六、落地顺序(建议分提交)
- tddPrompt / verifyPrompt 加 feStage(纯 prompt,行为默认不变)+ fe-code-done tag builder。
- featureLoop 加 feStage 分流 + runFrontendPhase1/2 拆分(overlap 关时等价现行)。
- 主循环并发点 + worktree 隔离 + phase1→phase2 merge。
- coding-start/README 开关透传(不默认开)。
- 临时脚本验证 + 语法门。
待你确认:范围是否就按以上五类改动?有无要砍/加的?确认后我从第 1 步开始实现,每步过语法门。