160 lines
6.7 KiB
Markdown
160 lines
6.7 KiB
Markdown
|
|
# contracting-guide.md(给人看的:契约治理与落地指南)
|
|||
|
|
|
|||
|
|
本文档面向人类(架构/平台/DevOps/测试/协作负责人),用于说明如何将契约成熟度与门禁策略落地到实际工程中。
|
|||
|
|
|
|||
|
|
> 编码智能体必须遵守的硬规则见项目根目录 `agents.md` 与 `spec/contracting.md`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 目标
|
|||
|
|
|
|||
|
|
- 降低 AI 开发过程中的需求偏移(通过可执行门禁约束)
|
|||
|
|
- 支持多窗口并行:调用方先行、提供方后补实现
|
|||
|
|
- 降低跨模块联调成本:契约成为单一可信源(SSOT)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. OpenAPI 拆分与职责
|
|||
|
|
|
|||
|
|
- `openapi.provider.yaml`
|
|||
|
|
- 描述“本模块对外提供什么能力”
|
|||
|
|
- 由提供方维护并对其实现负责
|
|||
|
|
|
|||
|
|
- `openapi.deps.yaml`
|
|||
|
|
- 描述“本模块依赖外部什么能力”(调用方需求侧契约)
|
|||
|
|
- 由调用方先起草(draft),用于生成 mock / sdk
|
|||
|
|
- 提供方后续可认领实现或提出映射/替代方案
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 契约成熟度(L0-L3)如何在团队中使用
|
|||
|
|
|
|||
|
|
建议把 `info.x-contract-level` 当作“里程碑标签”,在代码评审/门禁中用于决策,而不是装饰。
|
|||
|
|
|
|||
|
|
- L0:允许快速并行启动(mock 驱动)
|
|||
|
|
- L1:允许调用方完成主流程开发(sdk/调用可稳定)
|
|||
|
|
- L2:允许提供方实现进入可合并门槛(契约测试可跑)
|
|||
|
|
- L3:允许进入兼容治理与长期演进阶段(deprecate / examples / changelog)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 门禁落地点(实现建议)
|
|||
|
|
|
|||
|
|
> 裸 git 场景下,推荐以服务端 hooks 作为最终防线。
|
|||
|
|
|
|||
|
|
### 4.1 git hooks
|
|||
|
|
|
|||
|
|
- 本地 hooks(可选):`pre-commit` / `pre-push`
|
|||
|
|
- 目的:快速反馈,减少无效 push
|
|||
|
|
- 注意:可被跳过,不能作为最终门禁
|
|||
|
|
|
|||
|
|
- 服务端 hooks(推荐):
|
|||
|
|
- `pre-receive` / `update`
|
|||
|
|
- 用于 main 分支硬门禁:不符合规则直接拒绝
|
|||
|
|
- `post-receive`
|
|||
|
|
- 触发构建、测试、契约校验
|
|||
|
|
- 通过后执行自动合并(若你们实现了 auto-merge 流程)
|
|||
|
|
|
|||
|
|
### 4.2 构建阶段(mvn verify)
|
|||
|
|
|
|||
|
|
建议在构建阶段串联以下检查:
|
|||
|
|
- openapi 解析与 lint
|
|||
|
|
- openapi diff(breaking change 检测)
|
|||
|
|
- provider 契约校验(响应符合 schema)
|
|||
|
|
- 需求追踪校验(AC 引用未断裂)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 推荐的软/硬门禁策略
|
|||
|
|
|
|||
|
|
- feature 分支:软门禁
|
|||
|
|
- 允许并行推进、允许契约处于 L0/L1
|
|||
|
|
- 但不允许自动合并进入 main
|
|||
|
|
|
|||
|
|
- main 分支:硬门禁
|
|||
|
|
- 至少要求 provider 达到 L2
|
|||
|
|
- 契约测试与 diff 检查必须通过
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. Git Cadence(提交节奏)与 Hooks 门禁(落地建议)
|
|||
|
|
|
|||
|
|
本节用于将 `agents.md` 中的“提交与同步(Git Cadence)”规则落到工程实现(裸 Git/中央仓库)。
|
|||
|
|
|
|||
|
|
### 6.1 提交节奏(建议与约束)
|
|||
|
|
|
|||
|
|
- **提交粒度(推荐与 `agents.md` 一致)**:
|
|||
|
|
- `spec/<module>/` 下的规范文件变更必须**单独 commit**(Spec-only commit),不要与实现代码混在同一提交。
|
|||
|
|
- 实现代码按 `spec/<module>/tasks.md` 的**子任务完成**为粒度提交。
|
|||
|
|
|
|||
|
|
- **必须提交的触发点**(满足任一,且必须通过最小自测):
|
|||
|
|
- 任何 `spec/<module>/` 规范文件发生变更。
|
|||
|
|
- 任一 `spec/<module>/tasks.md` 子任务完成(从 ⏳/🔄 → ✅)。
|
|||
|
|
- 触发 `docs/session-handoff-protocol.md` 的阈值并准备会话接续前。
|
|||
|
|
|
|||
|
|
- **最小自测(与 `agents.md` 对齐)**:
|
|||
|
|
- 能编译/构建通过。
|
|||
|
|
- 单元测试通过。
|
|||
|
|
- 至少一条契约校验或接口冒烟通过(与本次变更相关)。
|
|||
|
|
|
|||
|
|
- **提交信息要求**:
|
|||
|
|
- commit message 必须包含 `[AC-...]`,便于需求追踪与门禁脚本校验。
|
|||
|
|
|
|||
|
|
### 6.2 hooks 分层:feature 软门禁 / main 硬门禁
|
|||
|
|
|
|||
|
|
> 原则:feature 分支尽量给快速反馈;main 分支必须可验收、可回滚、可自动合并。
|
|||
|
|
|
|||
|
|
#### 6.2.1 feature 分支(软门禁)
|
|||
|
|
|
|||
|
|
建议做(可在本地 `pre-commit/pre-push` 或服务端提示性检查):
|
|||
|
|
- commit message 包含 `[AC-...]`
|
|||
|
|
- OpenAPI 变更时:
|
|||
|
|
- YAML 可解析
|
|||
|
|
- `info.x-contract-level` 存在且为 L0-L3
|
|||
|
|
- provider: `operationId` 唯一
|
|||
|
|
|
|||
|
|
允许:
|
|||
|
|
- `openapi.deps.yaml` 处于 L0/L1,用于 Mock/SDK 并行开发。
|
|||
|
|
- provider 实现处于 L0/L1(但仅限 feature,不得进入 main 的自动合并路径)。
|
|||
|
|
|
|||
|
|
#### 6.2.2 main 分支(硬门禁)
|
|||
|
|
|
|||
|
|
建议在服务端 `pre-receive/update` 中强制:
|
|||
|
|
- Provider 契约成熟度门槛:`openapi.provider.yaml >= L2`
|
|||
|
|
- 契约测试通过(Provider 响应符合 OpenAPI schema)
|
|||
|
|
- OpenAPI diff 检查通过(无未声明 breaking change)
|
|||
|
|
- 需求追踪检查通过(AC 引用未断裂)
|
|||
|
|
|
|||
|
|
### 6.3 推荐的实现位置(Gitea 避坑建议)
|
|||
|
|
|
|||
|
|
> **重要:Gitea 环境下的 Hooks 优先级与冲突处理**
|
|||
|
|
|
|||
|
|
- **优先使用 Gitea 分支保护(Branch Protection)**:
|
|||
|
|
- 进入 `仓库设置 -> 分支 -> 保护分支(main)`。
|
|||
|
|
- 勾选 `禁止直接推送`:这是实现“禁推 main”最稳定、最标准的方式。
|
|||
|
|
- 勾选 `允许由 PR 合并`:确保协作流程通畅。
|
|||
|
|
- **避坑提示**:不要在服务端 `pre-receive` 钩子中一刀切地通过 `refs/heads/main` 拒绝所有更新。因为 Gitea 服务端的 PR 合并操作也会触发此钩子,导致 PR 无法合入。
|
|||
|
|
|
|||
|
|
- **服务端 Hooks(pre-receive)职责收敛**:
|
|||
|
|
- 仅用于做“极轻量”的全局硬约束(如文件大小、非 utf-8 检查)。
|
|||
|
|
- 不建议在 hook 里跑 Maven/JDK 等重型构建,否则会严重拖慢 push 速度并导致超时。
|
|||
|
|
|
|||
|
|
- **Gitea Actions / CI(推荐的门禁位置)**:
|
|||
|
|
- 这是落地“provider >= L2”和“契约测试”的最佳位置。
|
|||
|
|
- 将校验脚本(如 `scripts/check-openapi-level.sh`)集成进 Action。
|
|||
|
|
- 在保护分支设置中勾选 `要求通过状态检查后才允许合并`。
|
|||
|
|
- **环境搭建详见**:`docs/setup-gitea-actions-gate.md`(包含新环境部署、Runner 配置与离线环境优化)。
|
|||
|
|
- **离线 Checkout 实战经验**:在无法访问 GitHub 的环境下,不应使用 `actions/checkout`,应通过 `git clone` 结合环境变量(优先 `GITHUB_`,fallback `GITEA_`)实现离线拉取。若遇到 `refusing to fetch into branch` 错误,应确保不直接 fetch 到本地 `main` 分支,而是使用 `refs/remotes/origin/main` 作为引用基准。
|
|||
|
|
- **本地 JAR 依赖自动化**:对于无法通过中央仓库获取的本地 JAR,应在 CI 的测试步骤前通过 `mvn install:install-file` 自动安装到 Runner 容器的本地仓库,以确保 `mvn test` 能够顺利通过且无路径警告。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 检查清单(适合做成脚本/CI step)
|
|||
|
|
|
|||
|
|
- OpenAPI 可解析
|
|||
|
|
- `info.x-contract-level` 存在且合法
|
|||
|
|
- provider operationId 唯一
|
|||
|
|
- AC 追踪一致性(x-requirements 或 traceability 表)
|
|||
|
|
- 合并门槛:provider >= L2
|
|||
|
|
- breaking change 检测:无未声明破坏性变更
|