Files
knowledge-governance/docs/architecture/three-agent-handoff-workflow.md
T
姚章浩 c1d49adb62
build / build (push) Successful in 53s
docs(agents): 补三Agent交接闭环工作流(状态机、快照tag与验收模板)
工单 #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)。
2026-10-14 17:33:22 +08:00

9.8 KiB
Raw Blame History

三 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 也不是自动可发布版本。
  • 每次执行开始先确认:仓库、路径、工单、当前状态、最新评论、授权;缺一项且无法查询就先问,不猜。