integration-merge

把跨会话 / 跨 IDE 并行产出的 N 个砖头合流成可交付版本:6 项机械拒收门 → 按 DAG 分批合流(主干常绿)→ 装配验证(契约测试对真实实现重跑 + 挂载点测试)→ 语义验收(数据守恒 + 负向场景 + 关键路径 e2e)→ 失败隔离与逐片回滚 → 拼接报告。触发:"拼接"、"合并各窗口产出"、"集成合流"、"integration merge",或 delivery-slicing

SKILL.md

GitHub

集成合流(Integration Merge)

概述

目的:解决"多窗口并行做完了,拼起来却处处对不上"的问题——并行产出的合流不是"把文件放回一起",而是先机械拒收不合规的产出,再合流,再验证装配,最后做语义验收。

功能:

  • 6 项机械拒收门:越界 / 契约未改 / 依赖方向 / mock 残留 / 契约基线一致 / 桩残留——机械可判,不过即拒收该片
  • 分批合流:按依赖 DAG 层合入,每合一片主干保持可编译(常绿)
  • 装配验证:契约测试从"对 mock"切换为"对真实实现"重跑(强制)、挂载点测试由红转绿、集成点验证
  • 语义验收:契约 10 项对照 + 数据守恒质疑(流向/数量/内容/异常归宿/贯通)+ 负向场景 + 关键路径 e2e + 非功能行为
  • 失败隔离与逐片回滚:坏哪片退哪片,不阻塞其他片
  • 拼接报告:交付凭证 + 遗留项 + 交接

使用场景:

  • delivery-slicing 的砖头包(一批或多批)已完成,要把各窗口产出合成一个可交付版本
  • 用户在多个对话窗 / 多个 IDE 里手工并行做完,要统一验收
  • 拼接后发现"编译过了但行为不对",要定位是哪片与哪片对不上

定位

design-craft(架构 + 骨架)
        ↓
delivery-slicing(切砖头 + 定批次 + 自包含包)
        ↓
code-implement 并行窗口模式(各窗口只填实现体)
        ↓
integration-merge(本 skill:预检 → 合流 → 装配验证 → 语义验收 → 隔离回滚 → 报告)
        ↓
acceptance-verify(整体验收)/ implementation-report(归档)
  • 输入:N 个砖头包的产出(各分支 / 工作副本 / 独立目录)+ 骨架(桩 / 语义契约 / 挂载点 / mock 台账)+ 批次表与允许依赖矩阵
  • 输出:合入主干的可交付版本 + sub-requirements/INTEGRATION.md(拼接报告)
  • 边界:
    • 只管"怎么合、怎么验、坏了怎么退"
    • 不管"怎么切"(delivery-slicing)、"怎么实现"(code-implement)、"整体是否达标"(acceptance-verify)
    • 不改契约:发现契约有问题 → 报告并回 design-craft 修订(契约修订只在批次边界,且代价是砖头返工)

与 task-dispatch 的区别(别混用)

维度 task-dispatch 本 skill
场景 同一会话内,主 agent 派子 agent 跨会话 / 跨 IDE,无主 agent
协调方式 send_message 实时沟通 靠文件(砖头包 + 契约快照),Agent 之间不通信
合并方式 产出到隔离目录 → 主 agent 复制合并 各分支 / 工作副本 → 跨分支合流 + 拒收门
冲突防线 事后(合并时检测冲突) 事前 + 事后(预先目录互斥,事后 6 项拒收门 + 语义验收)
合并后的验证 编译 / 接口 / 导入校验 上述 + 契约测试重跑 + 语义验收 + 数据守恒

判定一句话:Agent 之间能不能互相发消息? 能 → task-dispatch;不能 → 本 skill。


核心原则

  1. 拒收门先行:预检不过不进合流。拒收一片的成本 ≪ 合进去再拆出来
  2. 拼接 ≠ 文件搬运:合流只占工作量的小头,验证与验收才是本体——"文件都回来了"不等于"功能对了"
  3. mock 的结果不作数:契约测试必须对真实实现重跑,禁止沿用各窗口"对 mock 全绿"的结论
  4. 契约是唯一真源:实现与契约不一致时以契约为准;发现契约本身有问题 → 报告,不就地改
  5. 主干常绿:每合一片就编译一次,编译不过立即停——否则后续片无法验证
  6. 失败隔离:坏哪片退哪片,不因一片阻塞其他片
  7. 语义冲突只能检测、且会漏:不假装零风险;检测手段做足,剩余风险写进报告交用户
  8. 不改上游:不在拼接期改 ownership / 契约 / 允许矩阵来"让问题消失"
  9. mock 替换是「接线」,不是「实现」:把 mock 换成真实实现属合法动作(跨分支场景下依赖方无法提前拿到对方代码,只能在此处接线)。但接线不得改变任何契约与行为——替换后若发现接口对不上,是拒收,不是就地适配
  10. 预检要前置到窗口自检:拒收门脚本应下发给各窗口,作为该片"完成定义"的一部分自行跑通——拼接期才首次发现越界,是切片流程的失败,不是拼接的失败
  11. 拼接健康度要回馈:拒收率 / 回滚率是切片质量的直接指标,必须记入报告并回到 delivery-slicing 作为下次切片的依据

工作流总览

阶段 0  拼接前置校验    → 能不能开始拼?(完成定义 / 基线一致 / 主干常绿 / mock 台账)
阶段 0.5 片级验收        → ★ 做没做对?(独立验收方逐片核验验收项,只判定不修改)
阶段 1  产出预检        → 规不规范?(6 项机械拒收门,不过即拒收该片)
阶段 2:分批合流        → 按 DAG 层合入,每片合完编译一次(主干常绿)
阶段 3:装配验证        → 契约测试对真实实现重跑 + 挂载点测试 + 集成点
阶段 4:语义验收        → 契约 10 项 + 数据守恒 + 负向场景 + 关键路径 e2e + 非功能
阶段 5:冲突与失败处理  → 机械可修 / 需报告 / 逐片回滚
阶段 6:拼接报告与交接

未得到用户对当前阶段的确认前,不进入下一阶段。

全量拼接 vs 部分批次拼接

不必等所有批次做完才拼——按层拼接是允许且推荐的(提前验证、提前交付部分价值):

模式 条件 要求
全量拼接 所有批次完成 默认模式
部分批次拼接 第 N 层全部完成,且该层砖头不依赖任何未完成的后续层 报告中显式标注"部分拼接(第 N 层)",并列出未并入的片与原因

判据:查允许依赖矩阵——若该层任一砖头对未完成层有真实依赖(非 mock*),则不能部分拼接(合进来也跑不通)。

快速通道

满足全部条件时不走本 skill,直接顺序实施或人工核对:

  • 只有 1 片(无并行,谈不上拼接)
  • 各片之间零共享面(目录完全不相干且无契约关系)——此时"拼接"退化为合并分支
  • 无 git 且无独立工作副本(无法做越界与基线校验)

触发快速通道时输出判定理由,并至少保留阶段 1 的越界检查 + 阶段 3 的编译验证(这两项即使简化场景也不能省)。


阶段 0:拼接前置校验

拼接能不能开始——不是"片做完了就能拼"。

# 检查项 不合格时的处理
0 预检脚本已在各窗口自跑通过(6 项拒收门 + 越界检查,见阶段 1) 未自跑的片先跑一遍——拼接期才首次发现越界是切片流程的失败
1 该批砖头全部达到完成定义(本砖头组契约测试绿 + 片级验收测试绿 + 未越界 + slice.md 状态已更新) 未达标的片拒收,其余可继续。注意:完成定义是窗口自证——功能维度的确认在阶段 0.5
1b verify/run.sh 本身合格(含必备四项:契约测试 + 越界检查 + 异常路径 + 桩残留自检) 缺项 → 该片的"绿"不可信,先补脚本重跑(宽泛的自测脚本等于没测)。缺「桩残留」尤其危险:它恰好是测试覆盖不到的那部分
2 各片 contract_base 一致(= 实现的是同一版契约;code_base 允许因分批而各不相同,见 delivery-slicing 阶段 3.2b) 不一致 → 先按 delivery-slicing 三·3.3 重新对齐到最新契约再拼,否则新旧契约混用
3 骨架自冻结后未被再修订(比对基准 = sub-requirements/INDEX.md 记录的骨架 commit;若有修订,受影响片必须已重新对齐并重跑契约测试) 未重新对齐的片拒收
4 主干可编译(常绿未被破坏) 先修主干,再谈拼接
5 各片产出可收集(分支 / 工作副本 / 独立目录可达) 不可达的片跳过并记录
6 mock 台账齐备(哪些 mock 要替换为真实实现、替换成什么) 无台账 → 拼接后无法确认残留,先补台账
7 骨架期的数据走向预演测试齐备(tests/data-flow/) 缺 → 阶段 4 的贯通检查要现场重造,成本高且易漏;先补

输出格式

🚪 拼接前置校验
━━━━━━━━━━━━━━━━

| # | 检查项 | 结论 | 证据 |
|---|--------|------|------|
| 1 | 完成定义 | ✅ 3/3 | 各包 verify/run.sh 全绿(日志路径) |
| 2 | 契约基线一致 | ⚠️ SR-03 落后 | SR-03 的 `contract_base` a1b2c3d;骨架当前 a1b2c3e |
| 3 | 骨架未再修订 | ✅ | 骨架 commit 未变 |
| 4 | 主干可编译 | ✅ | `make build` 通过 |
| 5 | 产出可收集 | ✅ | branch/A、branch/B、branch/C |
| 6 | mock 台账 | ✅ | 2 项:汇率查询 → SR-05;通知发送 → SR-07 |

判定:✅ 可拼接 / ⚠️ 有条件拼接(列出需先处理的项) / ❌ 不可拼接

【⚠️ 处理】SR-03 需先重新对齐到 a1b2c3e 并重跑契约测试,通过后并入

阶段 0.5:片级验收(拼接前的门)

目的:拼之前确认"每片真的做对了"——而不是"窗口说完成了"。

为什么必须有这一关

现状 问题
窗口的完成定义是自证(自己跑 verify/run.sh、自己更新状态标记) 没人有权说"不算"
片做错要到拼接期才暴露 拼接期是全局验证,症状会与其他片混在一起,定位成本高
窗口自己写验收断言 自己出题自己答(不是恶意,是自然倾向——照着自己实现的样子写宽松断言)

执行

项 规定
执行者 独立验收方——不是该片的实现窗口(推荐另一个子 agent / 另一窗口 / 用户)
输入 该片 slice.md 的验收标准表(外部给定)+ tests/{SR-XX}/ + 需求侧验收项
判据 逐条核验验收项;命令 + 期望输出对齐;测不出来标 ⚪
节奏 逐片进行(可并行——各片互不依赖)

三条铁律(方法 SSOT 在 acceptance-verify 的「片级验收模式」,不自造第二套验收方法)

  1. 验收项先锁定:slice.md 的验收项在打包时已定稿,执行中不得改判据(测不出来标 ⚪,不删项、不放宽)
  2. 断言锚定验收项、不锚定实现:先读验收项再设计验证动作;不读实现再反推断言(写成"一定能过"的断言 = 自欺欺人)
  3. 只判定不修改:验收方不改任何产品代码;不达标 → 退回该片,由实现窗口修

预期先声明:每条验收项执行前先写下"应该是什么结果"——跑完再定结论会让一切"通过"。

与阶段 1 的分工

阶段 管什么
0.5 片级验收 做没做对(功能维度:验收项是否达成)
1 产出预检 规不规范(边界维度:越界 / 契约未改 / 依赖方向 / mock 残留 / 契约基线)

降级路径(无独立验收方时)

单人单机场景:

  • 至少做到「验收项外部给定(非窗口自拟)」+ 用户抽查
  • 报告中显式声明"未独立验收"——不假装验过

输出格式

✅ 片级验收
━━━━━━━━━━━━━━━━

执行者:{独立验收方} | 方式:逐片

| 砖头 | 验收项 | 命令 | 预期 | 实际 | 判定 |
|------|--------|------|------|------|------|
| SR-01 | 能导出 CSV 且金额准确 | pytest tests/SR-01/ -k csv | 绿 | 绿 | ✅ |
| SR-01 | 异常路径 | pytest tests/SR-01/ -k error | 绿 | 绿 | ✅ |
| SR-02 | 导出文件格式正确 | ... | 绿 | ❌ 空文件未报错 | ❌ **退回** |

【处置】
- ❌ 片 → **退回该片**(由实现窗口修,验收方不动手)
- ⚪ 测不出来 → 进「需补验清单」,**不降级为通过**

判定:✅ 全部通过,进入阶段 1 / ⚠️ 有条件(列出 ⚪ 项)/ ❌ 有片退回

【降级声明】(如有)本次未使用独立验收方,验收由 {谁} 执行 —— **未独立验收**

阶段 1:产出预检(6 项机械拒收门)

逐片检查,任一不过即拒收该片。全部项均为机械可判,应做成脚本(见 reference.md)。

门 检查内容 判定方式 不过的含义
① 越界 改动是否全落在该包 ownership.md 的独占写内 git diff --name-only {code_base}..HEAD ⊄ 独占写 侵占了他人独占区 → 必然冲突
② 契约未改 contract/ 与接口目录是否零 diff git diff {code_base}..HEAD -- contract/ {接口目录} 为空 契约已漂移 → 其他片全部作废
③ 依赖方向 是否有禁止的真实依赖(新砖头之间) 扫 import / require 构造实际依赖图,与允许矩阵比对 破坏"砖头不互相依赖"的设计
④ mock 残留 生产代码路径是否引用 mock 模块 扫 .delivery/mocks/ 之外的代码是否引用 mock mock 带上线 = 经典事故
⑤ 契约基线 该片的契约快照是否与主干当前契约一致 比对包内 contract/BASE(=contract_base)与 INDEX.md 记录的骨架当前 commit 契约基线不一致 → 该片是对旧契约实现的,与其他片对不上
⑥ 桩残留 生产路径是否仍抛 NotImplemented / 留有桩标记 扫全生产路径(不限测试覆盖范围),模式 = STUB_PATTERN 漏实现的接口调用即抛异常,且契约测试未必覆盖到

① / ② 用 code_base,⑤ 用 contract_base——两者不可混用。分批时它们是不同的 commit(见 delivery-slicing 阶段 3.2b):code_base 是"这片的改动从哪算起"(第 N 批 = 上批合入后),contract_base 是"这片实现的是哪版契约"。混用会让门① 或门⑤ 必然误报一处。

⑥ 与 ④ 的区别:④ 扫的是"测试替身被带上线"(mock),⑥ 扫的是"接口没被实现"(桩)。两者都不产生编译错误,都可能逃过测试——④ 逃过是因为"没人测生产路径",⑥ 逃过是因为"这段代码没被任何测试跑到"。

⑥ 必须独立扫描、不得依赖测试结果:契约测试只覆盖"有测例的接口";漏实现的恰是没被覆盖的那些。grep 级扫描(如 grep -rn "raise NotImplementedError\|NotImplemented\|TODO(骨架)" src/)比"跑一遍测试看绿不绿"可靠得多。语言无 NotImplemented 机制时,改为扫骨架期注入的桩标记(由 design-to-code 统一生成,见其并行路线差异表)。

预检输入的来源(防止第三份真相)

拒收门的判定输入必须从砖头包读取,不得手抄:

输入 唯一真源 禁止
独占写路径 各包 ownership.md 的机器可读块 ❌ 手抄进脚本配置
代码基线 code_base 各包 ownership.md 机器可读块的 code_base(门①② 用) ❌ 凭记忆填 / ❌ 与 contract_base 混用
契约基线 contract_base 各包 contract/BASE(门⑤ 用) ❌ 凭记忆填 / ❌ 拿 code_base 顶替
允许依赖矩阵 sub-requirements/INDEX.md(或独立矩阵文件) ❌ 手工重建
mock 清单 MOCK_LEDGER.md ❌ 口头确认

脚本配置是从砖头包生成的,不是手写的。手抄 = 制造第三份真相,不同步时预检结论直接失真。

依赖方向检查的误报处理

③ 依赖方向 最容易误报(注释里提到路径、测试文件引用对方、字符串常量撞名):

  • 优先用静态分析工具(import-linter / dependency-cruiser / ArchUnit)构造真实依赖图;grep 只是无工具时的近似
  • grep 近似时排除注释与测试目录
  • 误报走人工复核后放行,并记入报告——不静默放过,也不因误报白耗一轮拒收

输出格式

🔍 产出预检(6 项拒收门)
━━━━━━━━━━━━━━━━

| 砖头 | ① 越界 | ② 契约未改 | ③ 依赖方向 | ④ mock 残留 | ⑤ 契约基线 | ⑥ 桩残留 | 判定 |
|------|-------|-----------|-----------|------------|-----------|---------|------|
| SR-01 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 接收 |
| SR-02 | ❌ 2 文件 | ✅ | ✅ | ⚠️ 1 处 | ✅ | ❌ 3 处 | **拒收** |
| SR-03 | ✅ | ❌ 1 文件 | ✅ | ✅ | ✅ | ✅ | **拒收** |

【拒收明细】
- SR-02:越界 `src/user/service.py`(不在独占写内);mock 残留 `src/order/export/csv.py:42`;
  桩残留 `src/order/export/xlsx.py:88`(`exportXlsx` 未实现)、`...:102`、`...:147` —— **该接口契约测试未覆盖,靠扫描才发现**
- SR-03:修改了 `contract/rate.py`(契约禁止改动)

【处理选项】
- 越界:要求该片回退越界改动后重新提交(不代为修改)
- 契约改动:报告并回 design-craft 评估——**不得就地接受**
- mock 残留:可机械替换的自动修(记入报告),需业务判断的退回该片
- 桩残留:**退回该片补齐实现**(不代为实现);若该接口本次确实不实现 → 回骨架评估是否该从契约移除(不许留悬空桩上线)

拒收片不进入合流;其余片继续。

★ 拒收门自身需要被验证(首次实战的硬教训)

拒收门是机械检查,但它自己也会错 —— 且错了会产生最危险的后果:让正确的流程被判定为失败(或反过来假绿)。

实战记录:某次真实拼接中,6 门在首次使用时就暴露 4 处自身缺陷:

缺陷类型 现象 后果
解析被注释截断 机器可读块的列表项中间夹了一行注释,正则 (?:\s*-\s*[^#\n]+)+ 遇 # 即终止 → 注释后的项被静默丢弃 门① 把已授权的文件判为"越界"
口径过时 门② 仍用 diff {code_base}..{branch},而分支已 merge 主干 → 主干上的流程修补被算成"契约被改" 误报
扫描范围过宽 门⑥ 扫全仓,而片分支上同时存在两片的桩(骨架含全部桩) 本片被判出另一片的桩残留(实测 19 条)
检查目标定义含混 interface 被填成"接口相关文件",而门② 对它的语义是"零 diff" → 桩文件必然被改 门② 对每一片都必然误报

强制要求(接线/出包时逐条落实):

☐ 1. 用【已知有问题的样本】跑一遍门 → 确认它【能报错】(而不是一路放行)
☐ 2. 用【已知干净的样本】跑一遍门 → 确认它【不误报】
☐ 3. 解析机器可读块后【断言关键字段非空】—— 空值 = 解析失败,必须显式报错,不得静默跳过
☐ 4. 扫描类门的【范围】必须与语义一致("本片残留" ≠ "全仓残留")

越界检查的正确口径(不要用 diff {code_base}..HEAD)

❌ git diff --name-only {code_base}..{branch}
   窗口为拿包修补会 merge 主干 → HEAD 含【主干的流程修补】,
   而主干修补可能触及任意文件 → 被算成"该片的改动" → 误报

✅ git log --no-merges --name-only --format= {主干分支}..{branch}
   = 该分支【独有、且非合并】的提交所触及的文件

为什么这条特别隐蔽:误报取决于主干修补恰好落在谁的独占写里 —— 落在你范围内 → 误报长得像真改动,你不会怀疑检查;落在范围外 → 才会触发怀疑。 同一套检查,一片踩到、一片没踩到,其中一次是运气。

推论(检查的设计要求):报错信息要带足上下文(来源提交 / 归属),让人能判断 "这条是否可能属于我" —— 最危险的误报是长得像真问题的那一种, 因为受害者会去**"修"它**(改自己的代码或放宽检查),而不是怀疑检查本身。

三条易错的技术细节(都属"会静默出错")

项 要求 不做的后果
非 ASCII 路径 解析 git 路径输出时加 -c core.quotePath=false git 默认输出带引号的八进制转义("sub-requirements/SR-01-\345…")→ ^sub-requirements/ 之类前缀匹配全部失效,流程产物被误判为越界
编译命令 必须验证它真的覆盖目标文件(如 tsc -p X --noEmit --listFiles | grep -c {目标目录} 应 > 0) 用错 tsconfig(include 不含目标目录)→ 退出码 0 但零覆盖(假绿)
桩残留扫描 扫工作区文件系统(grep -rn),不是 git grep git grep 只扫已跟踪文件,而实现期的桩正是新建未提交的 → 扫描恒为空 → 假绿(比不扫更危险:它给出"已检查且通过"的错误结论)

阶段 2:分批合流

合流顺序

按依赖 DAG 层合入:被依赖的先合。顺序错会导致后续片编译不过。

第 1 层(无前置)→ 逐个合入 → 每合一片编译一次
        ↓
第 2 层(依赖第 1 层)→ 逐个合入 → 每合一片编译一次

合流方式

情况 方式 要求
有 git 分支合流(merge / cherry-pick) 保留历史,冲突可见;不使用 squash(丢失逐片可追溯性)
无 git 文件搬运 + 前后哈希校验 记录每片搬了哪些文件、哈希是否与产出一致

主干常绿(硬规则)

每合一片,立刻编译/类型检查一次。

合入 SR-01 → 编译 ✅ → 合入 SR-02 → 编译 ❌ → 停止
                                              │
                                    ┌─────────┴─────────┐
                                    ▼                   ▼
                          定位是 SR-02 自身问题   还是与 SR-01 的
                          (回阶段 1 复核)       接口不匹配(报用户)

编译不过不得继续合下一片——带着编译错误往后走,后面每一片都无法验证。

编译失败时的默认动作:先撤回该片合入,恢复主干常绿,再定位。

情况 处理
默认 撤回该片(git revert / 反向搬运)→ 主干恢复可编译 → 再定位
例外(可就地修) 确认为琐碎且不涉及契约与依赖方向的改动(如格式、import 顺序)→ 可就地修 + 记入报告
归属不明 不就地改,按上表流程撤回后定位(避免"改到能过"掩盖真问题)

为什么默认撤回:主干带着错误时,问题归因会失真(分不清是这片的问题还是前一片遗留)。恢复常绿是继续工作的前提。

输出格式

🔗 分批合流
━━━━━━━━━━━━━━━━

第 1 层 [SR-01, SR-02]
  ├─ SR-01 合入 ✅ → 编译 ✅
  └─ SR-02 合入 ✅ → 编译 ✅

第 2 层 [SR-03]
  └─ SR-03 合入 ✅ → 编译 ✅

合并冲突:0 处(目录互斥生效,符合预期)

阶段 3:装配验证

合流成功 ≠ 能跑。本阶段验证"装配正确"。

分层测试期望值(全流程判别标准,各相关文档必须一致;本阶段看"拼接期"列):

测试组 落盘位置 骨架期 窗口期(本砖头) 拼接期
契约测试 · 各组 tests/contract/{SR-XX}/ 红 本组绿 / 他组不跑 全组绿
片级验收测试 tests/{SR-XX}/ 红 绿 绿
数据走向预演(全 mock → 真实实现) tests/data-flow/ 绿 绿 绿
挂载点测试 tests/mount/ 红 红(预期) 绿
# 验证项 做法 通过标准
1 契约测试对真实实现重跑 全量各组(tests/contract/*/)一起跑——窗口期只跑过本组,他组在此首次与真实实现对接 全绿
2 数据走向预演测试对真实实现重跑(★ 复用,不是重新设计) 骨架期(delivery-slicing 阶段 0.5)已写好的 tests/data-flow/ 测试,把 mock 换成真实实现重跑——同一组断言,只换实现 全绿
3 挂载点测试 跑骨架期产出的挂载点测试(tests/mount/,骨架期应为红) 由红转绿
4 编译 / 类型检查 语言工具链 零错误
5 集成点验证 识别跨砖头调用,逐一验证签名与返回一致 零偏差
6 依赖方向复检 合流后重扫依赖图(合流可能引入间接依赖) 与允许矩阵一致

第 1 项是强制项:各窗口"对 mock 全绿"只是形状验证。不重跑 = 用假绿当交付凭证。此项不过,不得进入阶段 4。 第 2 项为什么是"复用"而非"重新设计":骨架期那组断言就是"这条数据链应该长什么样"的正式声明——拼接期另起一套必然漏(人只会照着现状写)。复用还顺带省掉整块 e2e 设计工作。

输出格式

📐 装配验证
━━━━━━━━━━━━━━━━

✅ 契约测试(对真实实现):{N}/{N} 通过(对照各窗口"对 mock"结果,无退化)
✅ 挂载点测试:红 → 绿(N 个挂载位全部接通)
✅ 编译 / 类型:零错误
✅ 集成点验证:零偏差(N 个跨砖头调用)
✅ 依赖方向复检:与允许矩阵一致

判定:✅ 装配正确 / ❌ {列出失败项,转阶段 5}

★「对真实实现重跑」≠「把测试指向真实端点」

单窗口期因另一片未完成而红的用例,必须在装配期对真实实现重跑(不得沿用 mock 下的结果)—— 但这还不够。

实战教训:

mock 只兑现「事件类型与顺序」,不兑现真实延迟 / 真实分块形态 / 缓冲行为 / 数据质量。 若只是把测试指向真实端点,仍然可能全绿但没测到那条路径。

必须额外构造「能命中未覆盖分支」的真实数据:

数据特征 命中的分支 为什么 mock 测不出
分块边界不对齐帧边界 跨块缓冲 分块恰好整帧 → 该分支永不执行(测试参数把分支变成了不可达)
多字节字符(中文 / emoji) 不完整 UTF-8 序列的保留(decode(v, {stream:true})) 纯 ASCII 没有多字节边界问题
大 payload / 慢上游 背压、超时、中断 mock 立即返回

两条要求:

1. 重跑时记录「相比 mock 期【多覆盖了哪条路径】」,而不是只报"又全绿了一次"
2. 若某条被测路径在 mock 下【不可能执行】,明确标注它是本期新增覆盖

推广(易被忽视的覆盖维度):测试参数本身是覆盖率的一部分。 任何"为了让测试稳定"而调成整数值的参数(分块大小 / 批量大小 / 超时), 都应先确认它没有同时把某个分支变成不可达。

阶段 4:语义验收

这是唯一无法静态保证的环节——编译过、类型对、契约测试绿,行为仍可能不一致。

裁剪原则(工作量兜不住时怎么办)

全做最稳,但大需求下四组全量可能超过并行省下的时间。允许裁剪,但必须分级并声明:

级别 范围 可否裁剪
必做 ① 全部跨砖头契约的 10 项对照 ② 改动点所在数据链路的守恒三问 ③ 与本次改动相关的负向场景 ④ 关键路径 e2e ❌ 不得裁剪
可裁剪 与本次改动无关的数据链路、低风险场景、非关键路径、非功能项 ✅ 可裁剪,须在报告写明裁掉了什么

裁剪的判定依据(不是凭感觉):

  • 该数据链路是否被任一砖头触碰过?(grep 改动面 → 未碰则可裁)
  • 该场景是否在语义契约里被承诺过?(承诺过则必做)
  • 该路径是否是本次需求的主路径?(是则必做)

裁剪必须留痕:报告「未覆盖风险」章节逐条列出裁掉的项目,不写等于给了用户虚假的完整保证。

A. 契约 10 项逐条对照

对每个跨砖头契约,逐项问"两边的假设一致吗":

项 拼接时的典型冲突
前置条件 一方在对方未初始化时就调用
后置条件 一方按时间序、一方按 ID 序 → 分页错乱
空值策略 一方判 null、一方判 [] → 空数据被当异常
错误语义 一方抛异常、一方返回错误码 → 上层捕获不到
单位与精度 一方传分、一方按元 → 金额差 100 倍
时间语义 时区差 8 小时 / 时间戳差 1000 倍
幂等性 重试导致重复扣款 / 重复建单
并发安全 双方都以为独占 → 竞态、双写
事务边界 事务内发消息 → 消息先于数据落库
副作用 双方各发一次消息 → 下游重复处理

B. 数据守恒质疑(拼接必做)

先看骨架期的成果再动手:阶段 3 第 2 项已经把 tests/data-flow/ 的断言对真实实现跑过一遍了。本组要做的不是重跑,而是补它覆盖不到的部分——先列出骨架期已覆盖的链路与断言,只对未覆盖的做人工质疑。骨架期预演在数据走向上的作用是"把检查前移",不是"让这里省事"。

某片的改动可能让数据悄悄变了形状或数量——git 不冲突、编译不报错。逐问检查:

问 拼接时的问题
流向 数据到消费方的路径有没有因某片改动而改变?有没有不在 diff 可见范围内的消费方?
数量 到达消费方时数量有静默增减吗?(过滤 / 去重 / JOIN / 异常吞批)
内容 字段 / 精度 / 格式到达消费方还是原样吗?序列化层会不会静默丢字段?
异常归宿 异常处理点的数据去哪了?(重试 / 死信 / 补偿 / 上抛 / 静默丢弃)静默丢弃即缺陷
贯通(新增数据) 某片新增的字段 / 事件 / 接口,另一端接住了吗?逐跳走完链路
反向消费 某片新增的产出有人消费吗?还是死字段?

判定:任一问命中变化 → 逐消费方做效果等价性判定——消费方拿变化后的数据产生的效果与原来一致吗?不一致且影响重大(报表失真 / 告警漏报 / 资金偏差 / 不可逆丢失)→ 阻断交付。

C. 负向场景(mock 覆盖不到的部分)

风险提示(用 mock 并行的代价):凡有片依赖 mock 完成,其"与对方的真实对接"是在拼接期第一次发生。因此阶段 3 的契约测试重跑失败概率显著偏高,属预期而非异常。失败后按原则 9 处理——拒收该片,不就地适配;若多片同时失败,考虑该依赖本就该串行(记入拼接健康度,回馈切片)。

Mock 天然返回理想结果,以下必须用真实实现跑:

  • 依赖方失败 / 超时 / 部分成功
  • 返回空 / 返回脏数据 / 极值
  • 重试与幂等(重复调用是否产生副作用)
  • 并发调用(两片同时触发同一资源)

D. 端到端与非功能

  • 关键路径 e2e:从入口到终态走通(跨砖头的完整链路,不是各片自己的局部测试)
  • 性能:跨砖头调用是否引入明显退化(单看每片都正常)
  • ★ 非功能预算对账:拿骨架第 10 项定稿的预算分配表逐片对账——各片实测 vs 分到的预算,再加总对照需求总指标 (这是唯一能抓「各片各自达标、整体不达标」的环节。没有预算表就无法对账 → 记入"未覆盖风险"并在回馈里要求下次补上;有预算表但环境测不出(无大数据量 / 无并发条件)→ 同样记入未覆盖风险,措辞为「预算已定义但未验证」,不许因为"表上有数"就当已达标)
  • 事务与副作用时机:跨砖头的副作用顺序是否符合契约
  • 横切约定贯通性:一次请求能否用 trace / 请求 ID 串起多片日志(断链 = 第 10 项没落实)、时区与精度基准是否一致、错误码是否落在各自分配号段内(撞码不报错,只会让调用方走错分支)

输出格式

🔎 语义验收
━━━━━━━━━━━━━━━━

A 契约 10 项:✅ N 个契约全对照 / ⚠️ {列出不一致项}
B 数据守恒:✅ 6 问全过 / ⚠️ {命中的问 + 消费方 + 效果等价性判定}
C 负向场景:✅ N 个场景通过 / ❌ {失败场景}
D 端到端:✅ 关键路径 N 条通 / ❌ {失败路径}
     非功能:性能无退化 / 事务与副作用时机符合契约

【裁剪声明】本次裁掉了:{列出未覆盖的数据链路 / 场景 / 路径 + 裁剪依据}
             (未裁剪时写"无裁剪")

判定:✅ 通过 / ⚠️ 有条件通过(列条件) / ❌ 不通过

【⚠️/❌ 项处理】见阶段 5

阶段 5:冲突与失败处理

分档处置

档 类型 处理 谁来做
A 机械可修 越界但可回退的改动、mock 残留替换、格式类偏差 自动修 + 记入报告 本 skill
B 需报告 契约被改、依赖方向违规、签名偏差(说明骨架有问题)、语义不一致 报用户裁定,不自行改契约 用户 / 回 design-craft
C 逐片回滚 该片语义验收不过且短期修不好 退该片,其余继续 本 skill 执行 + 用户确认

逐片回滚机制

某片不合格
  │
  ├─ 有 git:revert 该片合入 commit(或丢弃其分支)
  ├─ 无 git:按合流记录反向搬运,哈希校验还原
  │
  ├─ 回滚后立刻编译(主干恢复常绿)
  ├─ 检查其他片是否依赖它:
  │     ├─ 无依赖 → 其余片照常验收
  │     └─ 有依赖(允许矩阵出边)→ 依赖它的片一并回滚,或改为对 mock 验证
  └─ 记入报告:回滚了哪片、原因、后续如何处理(重做 / 拆小 / 串行补)

关键约束:

  • 回滚不得静默:每片回滚都必须写进报告并告知用户
  • 不因一片阻塞全局:其余片继续验收,不进入"等它修好"的空转
  • 回滚后主干必须仍可编译——否则等于把整个拼接退回原点

回滚 → 重做闭环(回滚不是终点)

回滚只完成"止损"。必须再决定这片如何回到交付,否则它会在报告里永远悬着("回滚了 1 片"没有下文)。三条路径由用户裁定:

路径 何时用 操作
A 原片重做 问题局部、契约无需改 在原独立工作副本里修 → 重跑 verify → 重新走阶段 0.5 片级验收 + 阶段 1 预检(不得跳过——它是二次提交,不是延续上次)
B 拆小重做 一片太大 / 边界不清导致出错 回 design-craft 5.5.1 重新划分(L2 划分修订 → 骨架全废重出)→ 走完整链路
C 串行补做 与其他片耦合超出预期、不适合并行 按 plan-track 在主干上串行做(不建包、不建批次),做完按常规提交

共同要求:

  • 重做片不得复用原「已完成」状态:slice.md 状态重置为 待开始,时间戳处记「重做(第 N 次)」
  • 重做的基线 = 当前主干(不是原基线 commit),且契约测试必须对手上的真实实现重跑
  • B / C 属划分变更 → 其他砖头的边界约定可能同时失效 → 必须重新核对所有未开工 / 在跑的片的 ownership(合并两片会让原互斥校验全部作废)
  • 同一片最多重做 2 次:第 3 次仍不过 → 问题不在实现层(是划分或契约错)→ 转 B 或 C,不要在原路径上继续耗

判断 A / B / C 的一句话:契约没变 → A;边界不对 → B;耦合超预期 → C。

降级验证的状态归属(易漏)

某片因依赖方被回滚而"改为对 mock 验证"时,它不能算完成:

项 规定
状态标记 slice.md 与 INDEX.md 标 「降级验证」,不标「已完成」
交付资格 不计入本次交付——它验的是形状,不是真实对接
补验时机 依赖方重新并入后,必须重跑契约测试(对真实实现),通过才转「已完成」
报告 「未覆盖风险」章节必须列明哪些片处于降级验证状态

把降级验证当完成 = 用假绿充当交付凭证,与原则 3 冲突。

输出格式

🛠️ 冲突与失败处理
━━━━━━━━━━━━━━━━

A 机械可修:2 项(已修)
  - SR-02 越界 2 文件 → 已回退越界 hunk
  - SR-02 mock 残留 1 处 → 已替换为真实实现

B 需报告:1 项(等裁定)
  - SR-03 修改了 contract/rate.py → 契约变更须回 design-craft 评估;
    影响面:依赖汇率的 SR-05 需重新对齐

C 逐片回滚:1 片
  - SR-04 语义验收不通过(单位不一致:分 vs 元)
  - 已回滚(commit {hash}),主干编译 ✅
  - 依赖检查:SR-06 依赖 SR-04 → 一并回滚,改为对 mock 验证
  - 后续建议:SR-04 与 SR-06 合并为一片重做(口径需在骨架层统一)

阶段 6:拼接报告与交接

报告落盘

sub-requirements/INTEGRATION.md,必含:

章节 内容
拼接范围 参与片 / 批次 / 各片 code_base 与 contract_base
预检结果 6 项拒收门逐片结论 + 拒收明细
合流记录 合流顺序、合并冲突、编译结果、合入 commit
装配验证 契约测试重跑结果(对照各窗口 mock 结果)、挂载点测试、集成点
语义验收 A/B/C/D 四组结论 + 裁剪声明 + 未过项
处置记录 机械修复 / 待裁定 / 回滚(含原因与后续)
未覆盖风险 逐条列出(写法见下)
产物归属核对 双向校验结果:产品测试都在版本控制里(防误忽略)/ 脚手架都没进版本控制(防漏忽略)——命令与输出见 delivery-slicing「测试与脚手架的归属」
拼接健康度 拒收率 / 回滚率 / 桩残留数 + 归因(回馈切片)
周期对比 串行预估 vs 实际耗时 + 用户人工动作次数(写法见下)
后续 整体验收 / 归档 / 需返工的片

未覆盖风险怎么写(不许写空话)

❌ 反例:"可能存在未知风险"、"建议后续关注"——等于没写。 ✅ 正例:逐条对应具体来源:

来源 要写的具体内容
被裁剪的项 裁掉了哪条数据链路 / 哪个场景 / 哪条路径 + 依据
造不出的场景 哪些负向场景因环境限制没能构造(如无法制造并发、无脏数据)
未测的环境 哪些环境没覆盖(大数据量、多实例、特定时区/语言)
未验的契约项 10 项里哪些项无法验证(如幂等性需业务侧配合)
降级验证的片 哪些片处于「降级验证」状态,尚未对真实实现验证
无 git 场景 越界/基线靠人工核对,可靠性下降的具体范围

拼接健康度(回馈切片)

拒收率与回滚率是切片质量的直接指标,必须记录并回到 delivery-slicing:

指标 计算 含义
拒收率 拒收片数 / 总片数 高 → 切片时 ownership 或契约定义不准
回滚率 回滚片数 / 总片数 高 → 骨架有缺口,或该依赖本不该并行
契约改动次数 拼接期发现的契约缺口数 > 0 → 冻结点过早或语义契约没填全
mock 失败率 契约测试(对真实实现)首次重跑失败的比例 高 → mock 降级判断过于乐观(判据 1–5 需收紧)

归因建议(写进报告,供下次切片参考):

  • 拒收集中在越界 → ownership 粒度过粗或目录归属调研不足
  • 回滚集中在语义 → 语义契约 10 项没填全,或该依赖属实现级而非接口级
  • mock 失败率高 → 该依赖的可行性判据(尤其是"对方是改造现有逻辑")判轻了
  • 桩残留数 > 0 → 片级"完成"定义没落实(slice.md 第 6 项验收未跑),或骨架预演的"预期红"被误解

周期对比(唯一能判断"这套流程值不值"的证据)

本方案的目标是缩短交付周期。不记这一节,跑十次也攒不出"它到底有没有用"的证据。

项 数据来源 怎么记
串行预估 INDEX.md(切片时记的) "若串行做,预计 X 天"(粗估即可)
实际总耗时 冻结点日期 → 拼接完成日期 由 INDEX.md 时间戳列算出
骨架耗时 5.5.1 开工 → 阶段 0 核验通过 骨架是前置成本,必须单列——否则它吃掉并行收益时看不出来
并行段耗时 第 1 批开工 → 末批完成 与"串行做这些片"对比
集成耗时 拼接开始 → 报告出具 这是并行的代价
用户人工动作次数 实际发生 建副本 / 粘 handoff / 配环境 / 收片 / 验收 / 拼接,逐项计数

报告里必须给一句结论(不许含糊,按下列格式):

周期对比:串行预估 8 天 | 实际 6.5 天(骨架 1.5 + 并行 3 + 集成 2) 净收益 1.5 天,用户人工动作 ~18 次 结论:✅ 本次值得 / ⚠️ 勉强(收益被骨架成本吃掉)/ ❌ 不值(同类需求下次建议串行)

归因(把这次的数字变成下次的判据):

现象 归因 下次调整
骨架耗时远超预估 接口多 / 语义契约复杂 / 挂载点多 修正本项目"骨架成本占比"的经验值(delivery-slicing 快速通道里的 30%–50%)
并行段没省下时间 片太少 / 依赖太重 / 窗口等阻塞 提高并行门槛(如 ≥3 片 → ≥4 片)
集成耗时占比高 拒收率高 / 语义冲突多 加强 L0/L1,或减少片数
用户动作太多成瓶颈 片数过多 降低并行度

首次使用必然"不值"(无基线、不熟练)。判断应以第 2–3 次的数字为准;第 1 次的数字主要用于校准。

交接

✅ 集成合流完成
━━━━━━━━━━━━━━━━

参与片:N(接收 X / 拒收 Y / 回滚 Z)| 批次:M
装配验证:✅ 通过(契约测试对真实实现 N/N)
语义验收:✅ 通过 / ⚠️ 有条件通过(列条件)
主干状态:可编译 ✅ | 合入 commit:{hash}

【未覆盖风险】{明确列出本次识别不了的部分,交用户判断}

🚀 后续行动选择
1. 🧪 整体验收(acceptance-verify,按需求级验收指标逐条核验)
2. 📝 实现总结(implementation-report,记录最终效果与偏差)
3. 🔁 回设计(语义冲突暴露了骨架缺口 → 回 design-craft 修契约)
4. ⏭️ 结束(保留报告)

请选择 [1/2/3/4]:

与相邻 skill 的边界

skill 关系
delivery-slicing 上游。它的砖头包(ownership / contract 快照 / 允许矩阵 / mock 台账)是本 skill 拒收门的判定依据;本 skill 不自造第二套标准
code-implement 上游。并行窗口模式的"完成定义"是准入条件;本 skill 不合格时退回该片重做
design-craft 旁路(仅修订契约时)。发现契约本身有问题 → 回它修订(契约修订只在批次边界,代价是砖头返工)
task-dispatch 不同场景:它管同一会话内子 agent 并行;本 skill 管跨会话 / 跨 IDE 手工并行的合流
acceptance-verify 下游。本 skill 验"拼对了吗";它验"达到需求指标了吗"。两者不替代
code-review 互补:它看 diff(局部 + 增量),本 skill 看合流后的整体装配与语义
e2e-testing 本 skill 阶段 4D 的取证手段(关键路径真实链路验证)
debug 语义验收不通过、需要运行时证据定位时转它取证

需求管理集成

项目配置了 .requirements/config 时,阶段 6 落盘后注册:

req update {REQ-NNN} \
  --docs add sub-requirements/INTEGRATION.md,slice \
  --changelog "完成集成合流(接收 X / 拒收 Y / 回滚 Z)"
产出物 存储路径 docs 类型
拼接报告 sub-requirements/INTEGRATION.md slice

反模式

  • ❌ 把拼接当文件搬运 → "文件都回来了"不等于"功能对了";验证与验收才是本体
  • ❌ 跳过拒收门直接合流 → 越界与漂移的产出合进来,问题在验收期才暴露,那时更难定位是哪片
  • ❌ 沿用各窗口"对 mock 全绿"作交付凭证 → 假绿;契约测试必须对真实实现重跑
  • ❌ 带着编译错误继续合下一片 → 后续每片都无法验证,错误归因失真
  • ❌ 就地改契约让问题消失 → 契约是唯一真源;改动须回 design-craft,且代价是砖头返工
  • ❌ 就地改 ownership / 允许矩阵 → 改上游适配现状 = 双源漂移,下次切片全错
  • ❌ 一片不合格就全线等待 → 应逐片回滚,其余继续
  • ❌ 静默回滚 → 每片回滚必须报告;用户不知道就等于没发生
  • ❌ 跳过语义验收(A/B/C/D)直接交付 → 编译过、测试绿、行为错,是最贵的失败形态
  • ❌ 假装语义风险为零 → 报告必须写明未覆盖风险,不写等于给用户虚假保证
  • ❌ 用本 skill 处理同一会话内的子 agent 产出 → 那是 task-dispatch 的场景,机制不同
  • ❌ 手抄 ownership.md 内容到预检脚本配置 → 制造第三份真相,不同步时预检结论直接失真;配置须从砖头包生成
  • ❌ 预检脚本不下发到窗口、只在拼接期跑 → 越界到拼接期才首次发现,是切片流程的失败,不是拼接的失败
  • ❌ 依赖检查误报就直接拒收 → 注释/测试文件撞名必然误报;应先排除后人工复核
  • ❌ 编译失败就地"改到能过" → 掩盖真问题、让分支与主干不一致;默认先撤回再定位
  • ❌ 把「降级验证」当完成 → 验的是形状不是真实对接,等于假绿充当交付凭证
  • ❌ 语义验收裁剪不留痕 → 报告写"可能存在未知风险"等于没写;须逐条列出裁掉了什么
  • ❌ 不做拼接健康度归因 → 拒收/回滚率是最有价值的切片反馈,丢了下次还会犯同样的错
  • ❌ 只扫 mock 残留、不扫桩残留 → 漏实现的接口(NotImplemented 未替换)调用即抛异常;契约测试恰好没覆盖到就抓不住,必须独立机械扫描
  • ❌ 拿"测试全绿"当桩残留的证明 → 契约测试只跑有测例的接口;漏实现的恰是没被覆盖的那些(⑥ 号门必须独立于测试结论)
  • ❌ 回滚完就结案(不写重做路径) → "回滚了 1 片"没有下文 = 交付里少了一块;必须给 A 原片重做 / B 拆小重做 / C 串行补做,由用户裁定
  • ❌ 重做片复用原「已完成」状态、或沿用原基线 → 它是二次提交:状态重置、基线取当前主干、片级验收 + 预检必须重走(不得跳过)
  • ❌ 同一片在实现层反复重做超过 2 次 → 问题不在实现层(是划分或契约错),应转 B/C,别在原路径上耗
  • ❌ 不记周期 → 本方案的目标是缩短周期;不记就永远无法判断是否达成,也无法把经验变成判据
  • ❌ 把拒收门当成"接上就可靠" → 它自己也会错:首次实战暴露 4 处(解析被注释截断 / 口径过时 / 扫描范围过宽 / 检查目标含混),每一处都会让正确的流程被判定为失败。接线后必须用「已知有问题」+「已知干净」两个样本各跑一遍
  • ❌ 越界检查用 diff {code_base}..{branch} → 分支 merge 过主干时,主干修补会被算成该片的改动;正确口径 = 该分支独有且非合并的提交
  • ❌ interface 里填"接口相关文件" → 门② 对 interface 的语义是零 diff;桩文件(实现体必然要改)列进去 → 每片都必然误报。只填形状 SSOT
  • ❌ 桩残留扫描用 git grep → 它只扫已跟踪文件,而实现期的桩恰是新建未提交的 → 扫描恒为空(假绿),比不扫更危险
  • ❌ 解析 git 路径输出不加 core.quotePath=false → 非 ASCII 路径变成带引号的八进制转义 → 所有前缀匹配失效(流程产物被误判越界)
  • ❌ 编译命令不验证覆盖范围 → tsc -p 用错 tsconfig 会退出码 0 但零覆盖,验收项形同虚设
  • ❌ 装配期只"把测试指向真实端点"就宣称重跑完成 → mock 不兑现真实分块 / 多字节 / 延迟;必须构造能命中未覆盖分支的数据,并记录"多覆盖了哪条路径"

更多资源

  • 预检脚本模板、拒收门判定细则、冲突分档处置、语义审查清单完整版、mock 台账模板、逐片回滚流程、完整示例,参见 reference.md
  • 上游:delivery-slicing(砖头包 / 契约快照 / 允许矩阵 / mock 台账)、code-implement(并行窗口模式)
  • 下游:acceptance-verify(整体验收)、implementation-report(归档)
  • 取证:e2e-testing(关键路径)、debug(语义问题定位)