# 规范驱动 + 接口先行(SDD + API-First)实战流程 Runbook(从 0 到可合并) 本文档用于复盘并固化一次完整的“从初始化规范体系 → 落地 Gitea 门禁 → 实际业务跑通(以 ai-robot 多渠道改造为例)”的全流程。 目标:换环境/换人/换模型后,可以按此 SOP 复现同样的协作链路,并在后续迭代中持续优化。 --- ## 0. 核心原则(务必先读) 1. **SSOT(单一可信源)优先**:以 `spec//requirements.md` + OpenAPI 契约为准,任何实现必须可追溯到 AC。 2. **Consumer-first 并行**:依赖契约由调用方先写 `openapi.deps.yaml`,提供方后补实现并以 provider-driven 校验对齐。 3. **分支治理**:`main` 禁止直接 push,仅允许 PR 合并;feature 分支允许并行与草案(L0/L1)。 4. **门禁物理化**:规则必须进入 Actions/脚本,否则只停留在“口头约束”。 5. **长任务可接续**:满足阈值即启用 `docs/session-handoff-protocol.md`,并维护 `docs/progress/...`。 --- ## 1. 仓库文档分层(最终形态) - 方法论(详细、指导生成规范):`docs/spec-product-zh.md` - AI 入口硬规则(极简、命令式):`agents.md` - AI 契约硬规则(L0-L3、门禁、自检):`spec/contracting.md` - 人类落地指南(hooks/CI/操作细节):`docs/contracting-guide.md` - 会话接续协议(复杂任务强制):`docs/session-handoff-protocol.md` - Gitea Actions 门禁落地手册:`docs/setup-gitea-actions-gate.md` --- ## 2. Gitea(Docker)落地门禁:一次性 checklist > 若是新环境,从这里开始。 ### 2.1 分支保护(必须) 在 Gitea 仓库:`设置 -> 分支 -> 保护分支(main)` - [ ] 禁止直接推送 main - [ ] 禁止强制推送(force push) - [ ] 禁止删除 main > 经验:不要用 `pre-receive` 一刀切拒绝 `refs/heads/main`,否则 PR 合并也会被拒绝。 ### 2.2 启用 Actions + Runner(必须) - 在 Gitea `app.ini` 中启用: ```ini [ACTIONS] ENABLED = true ``` - 启动 runner(内网环境用宿主机内网 IP,不要用 127.0.0.1 / host.docker.internal): ```bash docker run -d --name gitea-act-runner --restart always \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /data/act_runner:/data \ -e GITEA_INSTANCE_URL="http://:" \ -e GITEA_RUNNER_REGISTRATION_TOKEN="" \ -e GITEA_RUNNER_NAME="runner-1" \ gitea/act_runner:latest ``` ### 2.3 离线环境必做(避免访问 GitHub) - workflow **不要**使用 `actions/checkout@v3`。 - 使用离线 checkout(仓库内 workflow 已实现): - 优先 `GITHUB_*` 变量,fallback `GITEA_*` 变量 - `git clone "$SERVER_URL/$REPO_NAME.git" .` + `git checkout "$COMMIT_SHA"` ### 2.4 Required Checks(必须) - 首次运行 workflow 后,在保护分支启用状态检查。 - 推荐 job 名称: - 轻量门禁:`contract-level-check` - 全量门禁:`sdd-full-gate` > 注意:Gitea 通常需要 **至少跑过一次 Actions** 才能在 UI 中选择/识别状态检查项。 --- ## 3. 规范生成(文档阶段)SOP(强模型执行) > 目标:把需求与契约先做对,再进入编码。 ### 3.1 分支策略(文档与代码共存) - 若“旧代码在 master,新规范在 main”,且历史不相关: - 推荐创建 feature 分支后合并: ```bash git checkout master git checkout -b feat/ git merge main --allow-unrelated-histories ``` - 若出现 untracked 覆盖:先提交 checkpoint(保护性提交)再 merge。 ### 3.2 生成顺序(每次只生成 1 个文件) 严格按顺序: 1) `spec//requirements.md` 2) `spec//openapi.deps.yaml` 3) `spec//openapi.provider.yaml` 4) `spec//design.md` 5) `spec//tasks.md` 每生成 1 个文件: - 人类审阅通过后,做 **spec-only commit**(只提交该文件)。 --- ## 4. 编码执行(实现阶段)SOP(弱模型可执行) > 目标:按 `tasks.md` 原子任务执行,降低长上下文导致的偏移。 ### 4.1 进入编码前必须读取 - `agents.md` - `spec/contracting.md` - `spec//requirements.md` - `spec//openapi.provider.yaml` / `openapi.deps.yaml` - `spec//design.md` - `spec//tasks.md` ### 4.2 提交节奏(Git Cadence) - `spec//` 变更:必须单独 commit - 实现代码:按 tasks 子任务完成提交 - commit message:必须包含 `[AC-...]` ### 4.3 多窗口并行(推荐分工) - 窗口 A:基础设施 + DTO + 配置 + DB - 窗口 B:渠道适配层(Adapter/Factory/Controller) - 窗口 C:路由层 + 会话管理 - 窗口 D:AI client + Resilience + fallback - 窗口 E:集成测试/回归 合并策略:各窗口在同一 feature 分支上串行提交(避免互相覆盖),或各自分支最后 rebase 合并。 ### 4.4 契约与实现双向对齐(L2 升级两步走) 当实现接近完成,准备进入可合并状态时: 1. **第一步:描述型升级**。AI 仅修改 `openapi.provider.yaml` 将等级提升至 L2,补充代码已实现的约束(描述、示例、错误结构)。执行 spec-only commit。 2. **第二步:实现约束对齐**。AI 根据 L2 契约中的 `required`、`enum`、`format` 等硬约束,同步补齐代码中的 `@Valid` 校验注解、枚举处理及单测。 --- ## 5. 最终集成与收网 SOP ### 5.1 契约与实现双向对齐(L2 升级两步走) 当实现接近完成,准备进入可合并状态时: 1. **第一步:描述型升级**。AI 仅修改 `openapi.provider.yaml` 将等级提升至 L2,补充代码已实现的约束(描述、示例、错误结构)。执行 spec-only commit。 2. **第二步:实现约束对齐**。AI 根据 L2 契约中的 `required`、`enum`、`format` 等硬约束,同步补齐代码中的 `@Valid` 校验注解、枚举处理及单测。 ### 5.2 合拢动作 1. **本地汇总**:将所有并行窗口的分支/提交合并至主功能分支。 2. **一致性自检**:确认 `spec/` 文档与 `src/` 实现 100% 对齐(AC 追踪、契约等级、任务勾选)。 3. **推送 PR**:推送到远端并发起向 `main` 的 PR。 4. **门禁验收**:观察 `sdd-full-gate` 状态。 - 若 `Commit Message Check` 失败:补充 `[AC-...]` 或 `[TASK-...]` 标注。 - 若 `AC Traceability Check` 失败:修正需求引用或代码注释。 5. **合并合拢**:Checks 全绿后执行合并,并同步本地 `main` 分支。 --- ## 6. 自动化门禁(Actions 脚本)说明 ### 5.1 当前已落地的脚本 - OpenAPI 等级门禁:`scripts/check-openapi-level.sh` - AC 追踪门禁:`scripts/check-traceability.sh` - OpenAPI Breaking change(最小版):`scripts/check-openapi-diff.sh` ### 5.2 常见报错与处理 - `provider contract-level must be >= L2`:提升 `openapi.provider.yaml` 到 L2 - `No module named yaml`:workflow 会尝试安装 PyYAML,失败则跳过 YAML parse check - `Cannot ping Gitea instance`:runner URL 不可用,换宿主机内网 IP - `cloning https://github.com/actions/checkout`:workflow 仍在用 checkout action,需改离线 checkout --- ## 7. 需求迭代与生命周期管理 SOP > 目标:确保功能演进过程中,规范文档同步滚动且历史可追溯。 ### 7.1 迭代模式选择 - **微调模式**:直接在现有 `requirements.md` 追加 AC,ID 保持连续(如 `AC-AISVC-21`)。 - **特性模式**:在 `spec//` 下新增 `requirements-.md`,适用于独立大特性。 - **重构模式**:建立新模块目录(如 `spec/ai-service-v2/`),适用于架构级变更。 ### 7.2 迭代执行步骤 1. **增量 Scoping**:分析新需求对现有 AC 的影响,明确是否涉及破坏性变更。 2. **版本滚动**:修改任一规范文件时,必须同步更新 Frontmatter 中的 `version`(如 `0.1.0 -> 0.2.0`)。 3. **任务追加**:新任务作为 `tasks.md` 的新 Phase(如 `Phase 6`),严禁删除已完成任务的历史。 4. **契约先行**:若涉及接口变动,必须先更新 `openapi.provider.yaml` 到 L0/L1,再写实现代码。 --- ## 8. 维护与迭代建议 - 每次重大变更后更新: - `docs/setup-gitea-actions-gate.md` - 本文档(Runbook) - 逐步增强门禁:OpenAPI 专业 diff、契约测试(schema 校验)、最小自测强制化(runner 预装 Maven/JDK)