c1d49adb62
build / build (push) Successful in 53s
工单 #6。三个会话(架构/开发/验收)在同一仓库串行协作时缺一份可核对的 书面契约,口头约定会漂移:状态标签命名不统一(仓里还留着 status/working)、 快照 tag 被当正式版本用、验收拿开发总结当结论。 本文件把契约写死:角色边界、main 单线串行、六个状态名与 blocked 要素、 快照 tag snapshot/vX.Y.Z 与正式版本 vX.Y.Z 分线、不可变与回退规则、 开发与验收交接模板、关单条件、安全边界。 为什么快照不能沿用 vX.Y.Z:make verify 里的 check_changelog --tags 会对每个 正式 tag 断言其提交内 CHANGELOG 顶部版本一致;在临时仓库实测正式 v0.1.1 与 v0.1.2 都判红,而 snapshot/v0.1.1 被归为非正式 tag 通过。故快照改用 snapshot 前缀,正式版本仍走单独批准与 CHANGELOG 流程。 范围:仅新增这一个文档,不改 CHANGELOG 与 CI。 验证:make verify 15 项全 success(档案 local,退出码 0)。
160 lines
9.8 KiB
Markdown
160 lines
9.8 KiB
Markdown
# 三 Agent 交接闭环工作流(架构 / 开发 / 验收)
|
||
|
||
> 适用仓库:`Weknora/knowledge-governance`(默认分支 `main`)。
|
||
> 本文件是**交接契约**,不是介绍:它规定角色边界、状态机、版本口径与交接证据格式,
|
||
> 供三个独立会话(架构 / 开发 / 验收)在同一仓库上串行协作时逐条核对。
|
||
> 依据:工单 `#6` 的「文档内容合同」8 条(正文=目标与范围,评论=证据,commit/tag=版本)。
|
||
|
||
## 0. 与工单合同条目的对应(便于独立验收逐条核对)
|
||
|
||
| 合同条目 | 本文位置 |
|
||
|---|---|
|
||
| 1 三角色职责 | §1 |
|
||
| 2 main 单线、串行修改 | §2 |
|
||
| 3 六个状态名、标签互斥、blocked 要素 | §3 |
|
||
| 4 每轮可交接的修改链路(自测→commit→快照 tag→推送→核实→review) | §4、§5 |
|
||
| 5 不可变与回退规则 | §5 |
|
||
| 6 开发/验收交接模板 | §6 |
|
||
| 7 关单条件 | §7 |
|
||
| 8 安全与边界 | §8 |
|
||
|
||
## 1. 三角色职责
|
||
|
||
| 角色 | 能做 | 不能做 |
|
||
|---|---|---|
|
||
| **架构** | 需求、设计、把目标/范围/验收标准写成工单;维护工单正文与验收矩阵;写设计文档 | 不写业务代码、不改测试/依赖/构建配置、不推送、不启动其他 Agent |
|
||
| **开发** | **唯一**可以改业务代码、测试、依赖、迁移、构建配置与项目文档的角色;自测、commit、打快照 tag、推送 main 与 tag | 不设置 `accepted`、不关单、不改验收标准、不部署 |
|
||
| **验收** | 独立复核差异与版本信息,逐项判定 PASS/FAIL/BLOCKED;通过后置 `accepted` 并关单 | 不修复代码(发现问题置 `rework` 并把问题列清)、不自行 `checkout`/`reset` |
|
||
| **prototype(UI)** | **仅**当工单涉及 UI 原型时介入,产出可打开的原型与交互证据 | 不参与非 UI 任务,不代替开发提交业务代码 |
|
||
|
||
角色约束是**流程约束**,不是技术 ACL 隔离:本机共用 Gitea 管理员凭据,谁也拦不住谁越权,
|
||
所以每个角色都要靠"读回核实"而非"相信对方自述"来交付。
|
||
|
||
## 2. main 单线、单仓库串行
|
||
|
||
- 只使用 `main` 一条线:**不创建分支、不建 worktree、不走 PR、不做合并**(通用引擎规范里 PR 是可选姿态,
|
||
本仓沿用"以直推为主"的口径)。
|
||
- 同一仓库的代码修改**串行**:一个工单在主开发阶段只由一个开发会话持有。
|
||
- **review 期间开发停止修改代码**:工单进入 `status:review` 后,除按 `rework` 要求修复外不再改动。
|
||
- 切换现场前先取证:`git status --short --branch`、`git worktree list`、`git rev-parse origin/main`。
|
||
工作区不干净、或存在不属于本工单的改动时**不得混入**,安全处理不了就置 `status:blocked`。
|
||
- 别人的 feature 分支与成果原样保留:不 `reset`、不 `stash`、不 cherry-pick、不清理旧分支/worktree/tag。
|
||
|
||
## 3. 工单状态机
|
||
|
||
六个完整状态名,**互斥**,同一工单最多一个状态标签:
|
||
|
||
```
|
||
status:ready → status:developing → status:review → status:accepted
|
||
↑ │
|
||
└── status:rework ─┘ status:blocked(可从中途进入,解除后回原状态)
|
||
```
|
||
|
||
| 标签 | 含义 | 进入条件(缺一不可) |
|
||
|---|---|---|
|
||
| `status:ready` | 设计完成、用户已批准开发 | 用户明确批准;范围与验收标准写明 |
|
||
| `status:developing` | 开发已领取并在实施 | 评论记录工单号、起始 SHA |
|
||
| `status:review` | 已交付待独立验收 | commit/tag/推送/远端核实/交接证据齐全 |
|
||
| `status:rework` | 验收失败 | 验收列出明确不通过项(不授权扩范围) |
|
||
| `status:accepted` | 指定版本通过验收待核实交付 | 验收矩阵逐项通过,结论绑定 tag + 完整 SHA |
|
||
| `status:blocked` | 受阻停手 | 有原因、处理人、解除条件、原状态;解除后**恢复原状态** |
|
||
|
||
- `Closed` 是 **Issue 状态**,不是标签:通过验收后由验收移除状态标签并关闭。
|
||
- 未批准的工单保持 Open 且**不打** `status:ready`。
|
||
- 标签 ID **按仓库实时读取**(`GET /api/v1/repos/{owner}/{repo}/labels`),不跨仓库复用 ID。
|
||
- ⚠️ Gitea 1.26.2 实测:`PATCH /issues/{n}` 带 `labels` 返回 201 **却不改任何标签**(静默无效);
|
||
替换标签必须用 `PUT /issues/{n}/labels`,且每次写完 `GET /issues/{n}` **读回核验**。
|
||
- ⚠️ 本仓历史遗留标签 `status/working`(`/` 而非 `:`)不符合本约定,遇到时应归一为 `status:developing`。
|
||
|
||
## 4. 快照 tag 与正式版本分线
|
||
|
||
**两种版本语义必须分开**,混用会让 CI 变红或让快照被误当发布。
|
||
|
||
| | 快照(开发交付用) | 正式版本(发布用) |
|
||
|---|---|---|
|
||
| 命名 | `snapshot/vX.Y.Z` | `vX.Y.Z` |
|
||
| 类型 | **注释 tag**(`git tag -a`) | **注释 tag**(`git tag -a`) |
|
||
| 批准 | 开发按工单直接创建,序号递增 | **用户单独批准** |
|
||
| 与 CHANGELOG 的关系 | 无要求;快照序号独立于构建显示版本,**不要求二者相等** | 必须同步写 `CHANGELOG.md` 顶部该版本段 |
|
||
| CI 门禁 | 不被当作正式版本 | 受版本一致性门禁约束 |
|
||
| 含义 | 代码快照,**不代表验收、不代表发布** | 发布事实,需 Release 等后续动作 |
|
||
|
||
**为什么不能用 `vX.Y.Z` 当快照(实测结论,勿凭直觉改回)**
|
||
|
||
- `make verify` → `scripts/check_changelog.py --tags`(`Makefile:27`、`scripts/ci_checks.py:254`)对每个
|
||
`vX.Y.Z` tag 断言:tag 指到的提交里 `CHANGELOG.md` 顶部正式版本 == tag 版本,且必须是注释 tag
|
||
(`scripts/check_changelog.py:44-45,257-278`)。
|
||
- CI 检出会把 `git ls-remote --tags origin` 落成 `.ci-remote-tags` 并 `fetch --tags`(`.gitea/scripts/ci_checkout.sh:122,127`);
|
||
`CI=true` 时拿不到清单直接判红 ⇒ **不带 CHANGELOG 段的正式 tag 会让 main 从此每次推送都红**。
|
||
- 正式 tag 的匹配是 `^v(\d+\.\d+\.\d+)$`(`scripts/check_changelog.py:45`),`snapshot/v0.1.1` **不匹配**,
|
||
因此不参与版本一致性判定;`scripts/version.py:119-151` 的发布证据也只认 `refs/tags/v<版本号>` 的注释 tag
|
||
与 CHANGELOG 顶部一致 ⇒ 快照 tag 不会把构建身份变成 release。
|
||
- 结论:快照一律用 `snapshot/vX.Y.Z`;要发正式版就单独走批准 + CHANGELOG 流程。
|
||
- 修复后的下一快照序号递增(`snapshot/v0.1.2`),**不得移动已交付的快照 tag**。
|
||
|
||
## 5. 每轮可交接的完整链路 + 不可变性
|
||
|
||
一轮可交付的修改必须走完整条链,任何一步失败都要如实报告**实际状态**,不能假装完整交付:
|
||
|
||
```
|
||
自测(真实命令 + 真实结果)
|
||
→ commit(信息含工单号;不用 Closes/Fixes/Resolves 等自动关单关键词)
|
||
→ 创建递增的不可变快照 tag(注释 tag)
|
||
→ 正常推送 main 与该 tag
|
||
→ 远端核实(main 含结束 SHA;tag 解引用后指向结束 SHA)
|
||
→ 工单评论完整交接证据 → status:review
|
||
```
|
||
|
||
- 开发的**正常 main 与快照 tag 推送无需逐次确认**;但**部署与正式发布不在授权内**。
|
||
- 推送前必须先核查:目标名未被占用、推送是否会触发生产部署(`.gitea/workflows/` 里是否有 deploy 作业)。
|
||
本仓唯一工作流 `build.yml` 头部明确"只做 CI,不做 CD"(`on: push: branches: "**"`)⇒ 普通 CI 允许放行。
|
||
- **保留旧提交与旧 tag**:不强推、不覆盖、不删除旧 tag、不改写历史。
|
||
- 回退只能由开发执行 `git revert` 并创建**新的**版本(`revert` + 递增快照),旧提交与旧 tag 原样留着。
|
||
- CI 绿 ≠ 已部署;`main` 不是自动可发布版本。
|
||
|
||
## 6. 交接与验收模板
|
||
|
||
### 6.1 开发交接(写进工单评论)
|
||
|
||
| 字段 | 内容 |
|
||
|---|---|
|
||
| 工单 | 编号 + 标题 |
|
||
| 起始 SHA | 动手前的 `origin/main` 完整 SHA |
|
||
| 结束 SHA | 本次提交的完整 SHA |
|
||
| tag | 快照 tag 名 + 类型(注释)+ 解引用后的 SHA |
|
||
| 实现摘要 | 改了什么、为什么这么改 |
|
||
| 文件清单 | `git diff --stat` 的范围,逐条列出 |
|
||
| 测试命令与结果 | **真实执行的命令 + 真实输出**(不可只写"已测试") |
|
||
| 已知问题 | 未验证项、环境限制、待批事项 |
|
||
| 剩余完成项 | 明确列表;没有就写"无" |
|
||
|
||
### 6.2 验收结论(写进工单评论)
|
||
|
||
| 字段 | 内容 |
|
||
|---|---|
|
||
| 版本锚点 | tag + 完整 SHA(结论必须绑在这上面) |
|
||
| 逐项判定 | 合同/矩阵每项 `PASS` / `FAIL` / `BLOCKED`,FAIL 必须列明确问题 |
|
||
| 复验命令与结果 | 独立跑过的只读检查(如 `git diff --check`、远端 tag 读回)与真实输出 |
|
||
| 问题与结论 | 通过 ⇒ 下一步;不通过 ⇒ 置 `rework` 并把问题列清;无法验证 ⇒ 置 `blocked` |
|
||
|
||
验收不得凭开发总结宣告通过;也不得自行 `checkout`/`reset` 去凑现场 —— 现场不对就要求开发准备。
|
||
|
||
## 7. 关单条件
|
||
|
||
同时满足才可关单:
|
||
|
||
1. 验收矩阵全部通过;
|
||
2. 目标版本可追溯(tag + 完整 SHA 可读回);
|
||
3. 远端交付已核实(远端 main 含结束 SHA,tag 解引用一致);
|
||
4. 交接与验收文档齐全(含真实执行证据);
|
||
5. 无未解除的阻塞项。
|
||
|
||
**不需要** PR、不需要合并、**不默认需要部署**。
|
||
|
||
## 8. 安全与边界
|
||
|
||
- 不提交任何密钥/隐私:决定只用 secret 文件(仓库外、0600),日志与评论不出现秘密与正文原文。
|
||
- 每个外部写操作(标签、评论、tag、推送)都**读回核实**;结果不明确时不得宣布成功。
|
||
- 不使用自动关单关键词,不绕过独立验收。
|
||
- 角色约束不是技术隔离;`main` 也不是自动可发布版本。
|
||
- 每次执行开始先确认:仓库、路径、工单、当前状态、最新评论、授权;缺一项且无法查询就先问,不猜。 |