--- name: contract-first description: >- 分前端/后端(或多个服务)多端开发的项目,用 CONTRACT.md 指向的唯一机器契约,各端只照它各做各的,防止字段漂移导致集成时白屏。支持单会话多 agent 和多终端各自跑两种模式。只要项目有前后端/多服务、接口字段老对不上、各端联调卡住、某端改了字段忘了通知别人、或前端为渲染一个页面要调一堆接口拼数据,就用这个 skill,哪怕用户没明说"契约"。这套方法论的学名是消费者驱动契约(Consumer-Driven Contracts, CDC)/ 契约测试。中文触发:契约式开发、接口契约、前后端协作、多终端协作、防字段漂移、接口对不上、联调、API 契约、字段命名不一致、集成白屏、唯一真相源、契约测试、CDC。English triggers: contract-first development, consumer-driven contracts, contract testing, API contract, frontend backend collaboration, multi-terminal, prevent field drift, provider verification. metadata: origin: ECC --- # 契约优先(Contract-First / Consumer-Driven Contracts) 多端并行开发的项目(前端 + 后端,或再加多个服务),最容易炸在"连接"那一刻: > 后端把 `userName` 改成 `user_name`,忘了通知前端。两边各自"自测通过",一集成——白屏。**两份文档各自为真,合起来是假的。** **契约优先**把接口当成一份**唯一机器契约**(由 `CONTRACT.md` 登记入口):所有数据接口只定义一次,各端照它各做各的,谁都不许私自偏离。它和 `living-docs-governance` 是姊妹篇——那套防"项目文档"漂移,这套防"端与端之间的接口"漂移。 > 学名:这套就是 **消费者驱动契约(Consumer-Driven Contracts, CDC)/ 契约测试(contract testing)**。"消费方需求先行"=CDC 核心;"后端写返回符合契约的测试"=提供者验证(provider verification);标杆工具是 Pact,契约规格常用 OpenAPI/Swagger。 ## 什么时候启用 - 项目分前端 + 后端(或多个服务),且各端可能**并行**开发。 - 接口字段老对不上:`userName` vs `user_name`、类型不符、枚举值不一致。 - 某端为渲染一个页面要调 5 个接口拼数据。 - 某端改了接口忘了通知别人,集成时才发现。 **不要**用在只有单端、不存在跨端集成的项目上——那时退化成单层,用 `living-docs-governance` 即可。接口少、单人、不会漂移时也别上,过度工程化。 ## 两种协作模式(关键:选对你的现实) 这套契约协作有两种落地方式,纪律一致、组织方式不同: ### 模式 A — 单会话多 agent(中心化派活) 一个支持多 agent 的会话里,契约拥有者**派出**前端 / 后端(及更多服务工人)并行干活,最后由它集成对账。Claude Code 可使用 `contract-director`、`frontend-dev`、`backend-dev`;Codex 可由当前 agent 持有契约并使用内置 worker,任务提示中明确端别、文件所有权和“只读契约”的边界。适合一人一个会话内推进、需要实时编排时。 ### 模式 B — 多终端各自跑(去中心化,契约当异步媒介)⭐ 更贴近真实团队 终端1 跑前端、终端2 跑后端、终端N 跑某个服务,**各端完全独立、上下文隔离**,**没有一个活的主任在线派活**。协调的唯一媒介就是那份 `CONTRACT.md` 文件: - "主任"在这里**退化成"契约拥有者"**——就是定契约、有权改契约那个人/终端(很可能是你本人或某个指定终端),不是实时调度器。 - 各端要改接口时,不存在"喊一个在线 agent",而是**提一条"契约变更请求"**:写进约定位置(如 Issue,或 `PROJECT_LOG.md` 追加一条 `contract-request`),由契约拥有者评估后更新契约,各端再各自重新拉取对齐。 - 适合双终端/多终端、多人、跨时区——这才是大多数真实前后端团队的样子。 **两种模式的铁律完全相同**:接口只在 `CONTRACT.md` 指向的机器契约定义一次;各端只读不改;要改接口必须先改契约,绝不在实现里私自偏离。 > 宿主适配:Claude Code 的 `/contract` 与自定义 agents 是交互适配层;Codex / ChatGPT 直接调用 `$contract-first` 并由当前 agent 执行同一流程。没有可用子 agent 时退化为顺序执行,不得因此跳过契约前置、提供方验证或集成对账。 ## 三条核心纪律 ### 1. 契约是唯一真相源,只有一个拥有者,且分两层 **将协作约定与机器定义分开,字段只保留一个来源**: - **入口与协作层**(`CONTRACT.md`):登记机器契约路径、版本/hash、拥有者、生成/校验命令和兼容策略;不手抄字段表。 - **机器定义层**:沿用项目已有 OpenAPI / JSON Schema / GraphQL / protobuf。HTTP 项目无现有契约时可用 `templates/openapi.example.json`;方法、路径、字段、类型、错误响应只在机器契约定义,重复类型用引用复用。 跨接口字段约束通过机器契约的公共 schema 或类型定义复用。所有接口只在 `CONTRACT.md` 指向的机器契约定义**一次**,各端只读;改契约的权力归**契约拥有者**(模式 A 是 director,模式 B 是指定的人/终端)。要改接口 → 提契约变更请求 → 拥有者改契约 → 各端再对齐。**绝不在实现里单方偏离契约**——这是头号集成杀手。 ### 2. 消费方需求先行(CDC 核心:别让提供方拍脑袋定) 接口是给消费方(如前端)用的,**先看消费方渲染/使用需要什么**,再定接口形状,而不是照着数据库表结构透传。定契约时优先问: - 这个页面/调用方实际需要哪些字段?一次请求能不能拿全? - 字段类型有没有坑?(19 位商品 ID 必须 `string`,用 `number` 会截零;金额用 `number` 保留 2 位;状态用枚举别用裸字符串) - 分页、错误码、空值怎么约定? ### 3. 让契约机器可校验,谁偏离谁先红 - 机器契约必须能被对应格式的标准工具直接解析和校验;JSONC 响应示例、Markdown 字段表与内部 DTO 不能替代 schema。`CONTRACT.md` 使用 `templates/CONTRACT.example.md` 只登记权威入口。 - 消费方拿它**生成类型和 mock**(提供方没好也能先把界面跑起来)。 - 提供方拿它写**"返回必须符合契约"的校验测试**(即 provider verification)——提供方改实现不小心偏离了,**自己的测试先红,炸在自己这边,炸不到别人**。 ## 工作流程 > 模式 A 由 `contract-director` 串起全流程;模式 B 下每端在自己终端各做第 1、2、4 步,第 3 步(定契约)和第 5 步(对账)由契约拥有者做。 1. **先反问消歧义,再定契约。** 定契约前,就模糊点反问消费方(字段语义、类型、空值怎么传、枚举到底有哪几个),把歧义消灭在动手前(借 Spec Kit 的 `/clarify` 思路)。然后按"消费方需求先行"更新唯一机器契约,并在 `CONTRACT.md` 登记入口和版本(模板见 `templates/CONTRACT.example.md`)。**契约必须前置**——绝不先写实现、再从代码事后导出契约,那样契约永远滞后、必然漂移。 2. **各端以契约为强制起点开发。** 每端读取机器契约对应段、只读不改。每个接口任务**第一步就是读 `CONTRACT.md` 及其机器契约**,不是凭记忆;复杂改动先声明"我打算怎么对齐契约",审过再写代码——在偏离前就拦下来。 3. **要改接口 → 提契约变更请求。** 不在实现里偷改。模式 A 回报 director;模式 B 写进约定位置(Issue 或 `PROJECT_LOG.md` 的 `contract-request`),由契约拥有者裁决后更新契约。破坏性变化必须同时写明兼容期、消费者迁移顺序、回滚条件和不可逆部分;缺失时不进入实现。 4. **本端自检。** 消费方回查所有用到的字段是否都在契约里;提供方跑契约校验测试。 5. **集成对账。** 逐字段核对:提供方返回 vs 契约、消费方用到的字段 vs 契约、字段名大小写/枚举值是否一致。对不上 → 指出哪边偏离、让其修正;若契约本身不合理 → 契约拥有者改契约再让各端对齐。 6. **记账。** 契约有变更 → 往 `PROJECT_LOG.md` 追加一行 `## [日期] contract | 改了什么接口、为什么`(与 `living-docs-governance` 共用同一本流水账)。 ## 例子 - **字段名漂移**:前端按契约用 `userName`,后端数据库列叫 `user_name`。后端在接口层做映射,对外一律按契约 `userName`,集成对得上。 - **多终端不用互等**:契约先定好,前端在终端1按契约造 mock 把整个下单页跑通,后端在终端2按契约写实现 + 校验测试,两边并行、互不打扰,联调时一次对齐。 - **多终端改字段**:终端1 前端发现少个字段,不去打断终端2,而是在契约"待定变更"区写一条请求;契约拥有者评估后更新 `CONTRACT.md`,两个终端各自重新拉取对齐。 ## 相关 - `contract-director`(契约拥有者/对账)、`frontend-dev` / `backend-dev`(各端工人)—— 执行这套方法论的 agent,两种模式通用。 - `living-docs-governance` skill —— 防项目文档漂移的姊妹篇;两套共用一本 `PROJECT_LOG.md`。 ## 角色边界与执行证据 - 契约拥有者只维护契约、处理变更请求、按已选择模式分工与集成,不实现业务代码;派工注明文件所有权,各端不得回退其他协作者的改动。 - 消费方只写分配的消费方目录;提供方只写分配的提供方目录。两者均只读契约,变更请求写到约定的 Issue/LOG,不越权编辑契约入口的“待定变更”区。 - 消费方从同一机器契约生成或校验类型和 mock;没有提供方时可先做契约已定义范围内的页面,不能把新猜测字段塞入 mock 当真。 - 提供方验证真实序列化响应,覆盖字段改名、大整数 ID、空值、枚举和错误结构;内部 DTO 或状态码为 200 不是足够证据。 - 用 `test-collaboration` 将契约格式、消费者、提供者、真实联调四层证据关联到同一 TEST-ID 和契约版本;未跑真实联调时标缺口。 - 模板参考 `tests/test_contract_template.py` 只证明模板格式和响应约束,不证明用户项目已经生成类型、实现服务或完成联调。