架构、接口、上线与复盘评审工具化手册
一次“已经评过”的上线为什么仍然无法放行
支付接口准备上线时,发布负责人问数据库回滚是否演练过。架构师说方案会已经同意,接口负责人说评审群里没有反对,开发者贴出一张打勾的清单。真正打开证据后,清单来自旧版本,接口 diff 没有消费者确认,容量测试使用的是迁移前模型,唯一的“同意”是一条聊天表情。团队拥有评审活动,却没有可判定的评审结果。
工具化评审不是把问题越列越多,而是让每次检查都能落到对象、状态和证据:评什么版本,谁有决定权,哪些检查通过,哪些发现阻塞,允许了什么例外,后续工作去了哪里,哪个系统真正执行合并或发布门禁。
评审记录是一张带状态的证据图
一个可追踪评审至少包含这些节点:
| 对象 | 关键字段 | 失效时的典型假象 |
|---|---|---|
| Review | 类型、对象 ID、基线版本、owner、decision-makers | 标题相同就被当成同一次评审 |
| Check | check ID、适用条件、结果、证据要求 | 勾选等于验证 |
| Finding | 严重度、影响、证据、提出者 | 评论很多但没有阻塞关系 |
| Conclusion | approved、blocked、approved-with-exception | “没有反对”被解释为批准 |
| Exception | 偏离项、风险 owner、补偿控制、退出条件 | 临时放行永久存在 |
| Action | 独立工单、owner、检查点、验收标准 | 结论里写“后续优化” |
| Evidence | 提交、契约 diff、测试运行、仪表盘快照、批准记录 | 链接指向持续变化的首页 |
Review 的 subject 必须是可复现版本,例如提交 SHA、制品 digest、OpenAPI 基线与候选提交、发布候选 ID 或事故记录 ID。接口 diff 需要同时保存 baseline 与 candidate,发布评审还要保存制品、配置和迁移版本;这些共同组成输入指纹。只写“订单服务方案”会让后续修改继续借用旧批准。Check 是规则实例,不是模板文字;同一条“已做容量评估”在某次 Review 中必须得到 pass、fail、not-applicable 或 waived,并带证据或理由。
输入指纹中任一受评部分变化,旧结论就不再覆盖新候选。门禁应把 PR HEAD、制品 digest 或契约 candidate 与 Review 逐项比较,而不是只检查评审编号存在。GitHub 规则集还可以在新提交后撤销旧批准,或要求最近一次可评审推送得到批准;这类平台规则负责防止“批准后加代码”,Review subject 比较负责防止“代码没变但制品、配置或契约换了”。
四类评审共享骨架,但不共享证据
| 评审类型 | 必须绑定的对象 | 能证明通过的证据 | 常见阻塞信号 |
|---|---|---|---|
| 架构评审 | 方案版本、受影响系统、数据与故障边界 | 可替代方案、容量模型、故障实验、安全分析、ADR 提案 | 关键约束未知、失败传播未验证 |
| 接口评审 | OpenAPI/AsyncAPI/Proto 基线与候选版本、消费者 | breaking check、Mock/契约测试、错误模型与鉴权结果 | 破坏兼容、消费者无人确认 |
| 上线评审 | 不可变制品、配置版本、迁移与回滚入口 | 流水线运行、演练记录、变更 diff、监控与值守确认 | 回滚不可执行、凭证或容量未就绪 |
| 复盘评审 | 事故 ID、时间线版本、修复工单 | 原始观测、因果链、验证过的修复与演练 | 只有责任归因、行动项无 owner |
共享模板可以规定 ID、结论、例外和行动项字段,但不能用同一组问题替代领域证据。架构评审关注边界与取舍;接口评审关注消费者可观察契约;上线评审关注候选制品能否安全变更和恢复;复盘关注机制如何产生故障以及防复发动作是否可验证。
在仓库里启用一个最小评审入口
代码与评审对象在同一仓库时,可以先用 GitHub Issue Form 保存评审记录,用 PR、CODEOWNERS、规则集或受保护分支执行真正的合并门禁。Issue Form 的结构和限制以 GitHub 官方语法 为准;它仍处于可能变化的预览阶段,推广前应在目标 GitHub 产品与版本上确认。
先创建结论标签:
gh label create review:pending --color D4C5F9 --force
gh label create review:approved --color 0E8A16 --force
gh label create review:blocked --color B60205 --force
gh label create review:exception --color FBCA04 --force
gh label create review-action --color 5319E7 --force在 .github/ISSUE_TEMPLATE/review-record.yml 放置入口:
name: Engineering review record
description: Record a versioned review, evidence, conclusion, and follow-ups
title: "[Review] "
labels: ["review:pending"]
body:
- type: dropdown
id: kind
attributes:
label: Review type
options:
- Architecture
- API or event contract
- Release readiness
- Incident follow-up
validations:
required: true
- type: input
id: subject
attributes:
label: Versioned subject
description: Commit, immutable artifact, schema baseline/candidate, or incident ID.
validations:
required: true
- type: input
id: checklist_version
attributes:
label: Checklist version
description: Immutable version or commit of the check definitions used by this review.
validations:
required: true
- type: textarea
id: checks
attributes:
label: Check results and evidence
description: Give each check an ID, result, and stable evidence URL.
value: "- CHECK-ID | pass/fail/n-a/waived | evidence URL or reason"
validations:
required: true
- type: dropdown
id: conclusion
attributes:
label: Proposed conclusion
options:
- Blocked
- Approved
- Approved with exception
validations:
required: true
- type: textarea
id: exception
attributes:
label: Exception and compensating controls
description: For an exception, name risk owner, control evidence, expiry checkpoint, exit condition, and revocation action; otherwise write N/A.
validations:
required: true
- type: textarea
id: actions
attributes:
label: Linked action issues
description: Link owned work items; do not leave prose promises.
value: "- "
validations:
required: true
- type: textarea
id: decision
attributes:
label: Decision makers and rationale
description: Record authorized roles, selected conclusion, rationale, and dissent.
validations:
required: true模板中的 Proposed conclusion 只是提交者请求的状态。最终结论应由有权限的评审角色在完成检查后设置唯一结论标签,并在评论中记录完整输入指纹与理由。标签本身仍可被拥有写权限的人修改,因此高风险变更不能仅依赖标签授权;合并权限要交给规则集、必需检查和受保护分支。
清单项必须包含判定器
“检查监控”“确认安全”“评估容量”都无法复核。每个 check 至少写成五元组:
check = {
id,
applies_when,
assertion,
evidence_type,
failure_effect
}例如上线检查 REL-ROLLBACK-01:当变更包含数据库迁移时适用;断言是“候选版本可在保留已提交业务数据的前提下停止或前滚恢复”;证据类型是演练运行 ID、迁移版本和恢复后查询;失败效果是阻塞发布。这样,n-a 必须解释为什么没有数据库迁移,waived 必须创建例外,pass 必须链接演练,而不是由填写人自行理解“已确认”。
接口检查可以写成:候选契约相对生产基线不得包含未批准的 breaking change;证据是兼容检查运行及消费者确认。架构检查可以写成:单点故障实验满足恢复目标;证据是故障注入运行、指标和恢复动作。复盘检查可以写成:每个高影响原因至少有一个能改变系统行为或检测能力的行动项;证据是独立工单和验收实验。
模板版本也要进入记录。给每个 check 保持稳定 ID,并在 Review 中记录 checklist_version。规则升级只影响新 Review;历史记录不能因为模板文字改变而被重新解释。确需复评时创建新 Review 并链接旧记录。
正向实验:从评审工单走到合并门禁
创建一条接口评审,subject 同时记录基线和候选提交,至少放入一个兼容检查运行 URL。通过后由授权评审者移除 review:pending,添加 review:approved,再把编号和候选身份写入 PR:
## Review record
Review: #123
Subject: candidate commit SHA
Checklist: checklist commit SHA查询评审记录:
gh issue view 123 --json number,state,labels,assignees,body,url \
--jq '{number,state,labels:[.labels[].name],owners:[.assignees[].login],url}'预期只有一个结论标签,正文含版本化 subject、清单版本、检查证据、结论理由和行动项引用。PR 还应显示必需状态检查通过、所需评审者批准。把 Review 完整性检查设为 required status check,并在规则集中限定预期 GitHub App 来源,可以防止另一个有写权限的身份用同名绿色状态冒充门禁;规则行为见 GitHub rulesets 可用规则。GitHub 的 review 可以产生 comment、approve 或 request changes;受保护分支可以要求批准后才合并,行为见 Pull request reviews 与 protected branches。
再向 PR 推送一个提交。若启用了撤销过期批准,预期原批准失效;即使没有启用该选项,Review 完整性检查也应因 Subject 不等于最新 PR HEAD 而失败。重新评审新输入并获得新的成功检查后才可合并。这个第二步才真正证明批准绑定版本,而不是绑定标题。
完成测试后关闭实验 Review 和行动项,删除仅供实验的标签或 Project 条目;不要把测试批准复用于真实候选版本。
反向实验:证明模板不能阻止绕过
Issue Form 只约束从网页表单进入的数据。使用 CLI 创建一条空壳评审,再同时添加两个冲突结论标签:
url=$(gh issue create \
--title "[Review] Incomplete record" \
--label review:approved \
--label review:blocked \
--body "No versioned subject or evidence")
gh issue view "$url" --json number,labels,body \
--jq '{number,labels:[.labels[].name],body}'预期命令成功,输出同时含 review:approved 与 review:blocked。这不是 CLI 的缺陷,而是模板校验与数据写入权限处于不同层。导入工具、API、机器人和有写权限的成员都可能绕过表单,因此关键不变量还要由自动检查验证:
PR 必须引用存在且可读取的 Review。Review 的 subject 必须等于 PR 候选提交或制品。Review 记录的 checklist version 必须存在且不可变。
approved、blocked、exception 最多且必须有一个有效结论。通过项有证据,n-a 有适用性理由,waived 有例外记录。开放阻塞 finding 时不得放行;后续工作必须是独立工单。
例外已到期、补偿控制失效或退出工单无 owner 时不得放行。
清理坏数据:
gh issue close "$url" --comment "Negative test complete; record is intentionally invalid."反向实验的故障证据应包括创建命令退出码、冲突标签查询结果和门禁拒绝信息。只有“模板页面显示必填”不能证明 API 路径安全。
用仓库规则执行权限,而不是用清单假装权限
把评审角色写入 .github/CODEOWNERS,再在规则集或分支保护中要求 code owner review:
/api/ @your-org/api-reviewers
/migrations/ @your-org/data-reviewers
/.github/ @your-org/repository-governors
/docs/architecture/ @your-org/architecture-reviewersCODEOWNERS 会请求对应 owner 评审,但只有同时启用 required review 才能阻止未批准合并;而且列出多个 owner 时,通常任一符合条件的 owner 批准即可,不等于所有人会签。文件位置、权限要求和保护行为应按 GitHub CODEOWNERS 官方说明 配置。保护 .github/ 自身,避免提交者在同一个 PR 中弱化清单、工作流和 owner 规则。
流水线检查负责可计算事实:契约兼容、迁移 lint、测试、制品签名、漏洞阈值和 Review 引用完整性。人类评审负责无法由机器直接判断的取舍、风险接受与例外。不要让机器人自动添加“批准”来模拟决策者,也不要让人工勾选替代已经能自动执行的测试。
结论、例外和行动项必须是三种对象
结论回答“这个特定版本现在能否进入下一状态”。推荐只保留:
approved:所有阻塞检查通过,指定版本可进入下一状态。blocked:至少一个阻塞 finding 未关闭,不能推进。approved-with-exception:指定偏离已被有权角色接受,补偿控制已生效,并有退出条件。
所谓“条件通过”只能落成 approved-with-exception,不能另造一个含糊的黄色状态。它不是低优先级 finding,必须记录被偏离的 check、风险、风险 owner、适用对象、补偿控制及其证据、到期检查点、退出条件和撤销动作。比如发布暂时跳过全量消费者兼容确认,补偿控制可以是流量开关、兼容适配层、消费者白名单和可观测指标;退出条件是所有消费者完成迁移。补偿控制没有证据时,结论仍是 blocked。
例外到期不是提醒事件,而是授权失效事件。检查点到达时,自动化先验证退出工单和补偿控制:退出条件满足则关闭例外;仍需延长则由风险接受者创建新例外并重新批准;无人处理、控制指标越界或 owner 已失效时,门禁把后续发布转为 blocked,必要时执行记录中的撤销动作。禁止原地改掉旧到期时间,因为那会抹去风险曾经被接受到何时。
行动项回答“谁去改变系统”。每个行动项进入工单系统,拥有 owner、检查点、验收和源 Review 回链。评审记录只引用它,不复制实时状态。行动项关闭后,Review 可以从链接读取结果,但不回写历史结论;若新证据推翻批准,应创建复评记录或撤销发布,而不是静默改旧评论。
ADR、评审记录、工单和 PR 各自保存什么
这四类对象经常被混写:
| 对象 | 回答的问题 | 生命周期 | 变更方式 |
|---|---|---|---|
| Review record | 某个版本经过哪些检查,谁基于什么证据得出什么结论 | 随被评对象形成历史快照 | 新版本创建新评审或明确复评 |
| ADR | 为什么长期选择某种架构方向,比较过什么,什么条件会触发替代 | 跨多个实现与发布长期存在 | 新 ADR 通过替代链演进 |
| Work item | 为实现、修复或退出例外要做什么 | 从开放到验收或取消 | 状态持续更新 |
| PR/MR | 哪些代码和配置将进入目标分支 | 合并或关闭后固定 | 新提交触发重新检查与评审 |
一次架构评审可以批准 ADR 提案,但 Review 不能替代 ADR 的长期理由和替代链;ADR 也不能证明某个候选制品已经通过上线检查。普通缺陷修复只需要工单与 PR,不要为每个局部选择创建 ADR。会改变系统边界、数据所有权、兼容承诺、故障传播、安全模型或长期成本的选择,才值得进入 ADR。行动项的详细状态仍留在工单,不要把 ADR 变成任务看板。
闭环顺序应能沿链接复算:ADR 保存长期选择,Review 引用 ADR 与受评输入,finding 或例外生成独立工单,PR/MR 实现工单,流水线为候选版本产生证据,required check 读取 Review 并决定能否合并或发布。工单关闭不能自动批准 Review,ADR 被接受也不能让门禁变绿;只有相应证据满足判定器且输入指纹仍一致,门禁才放行。反过来,门禁拒绝信息要回链具体 check、过期例外或开放 finding,让修复者知道应更新哪个对象。
失效证据要能定位到哪一层坏了
| 现象 | 第一证据 | 原因分支 | 修复与复验 |
|---|---|---|---|
| PR 有评审编号仍无法合并 | 规则集结果、required checks、PR review 状态 | 记录批准但 code owner 未批准,或新提交使批准失效 | 重新请求评审并确认最新提交受保护 |
| Review 显示 approved 但 subject 过期 | PR HEAD、制品 digest、Review subject | 批准后又推送提交 | 使门禁比较不可变身份并重新评审 |
| 清单全部 pass 仍发生事故 | 证据 URL、check 适用条件、模板版本 | 证据指向错误环境,或检查不适用于真实故障模型 | 新增可判定 check 和反向实验,不篡改旧记录 |
| 例外长期不退出 | 例外工单、补偿控制指标、owner 状态 | 没有退出条件、owner 离开、提醒失败 | 重分派,验证控制,未满足则撤销放行 |
| 条件通过已到期但新发布仍放行 | 例外到期检查点、门禁输入、规则执行日志 | 到期只发通知,required check 没有读取例外状态 | 让到期成为失败条件,并用过期样本验证门禁拒绝 |
| 复盘行动项很多但风险不降 | 行动项类型、验收实验、复发指标 | 任务只改文档或培训,没有改变机制 | 重新建立因果链与系统性动作 |
排障时先确认身份与权限,再看结论和证据,最后看通知。通知没到不必然表示评审没执行;一条绿色评论也不必然表示规则集真正阻止了合并。
权限、凭证和敏感证据
评审平台通常能看到设计、未发布接口、事故日志、漏洞、客户数据和生产拓扑。记录中使用脱敏样例、稳定证据 ID 和受控链接;原始流量、密钥、客户标识、攻击路径和高敏附件留在权限更窄的系统。导出、邮件通知、聊天机器人和搜索索引都可能扩大可见性,权限评估要沿数据流做,而不是只看 Review 页面是否私有。
自动检查使用短期 token,并只授予读取 PR/Issue、写检查结果所需权限。跨组织集成优先使用可审计、可轮换的应用身份。规则管理员、决策者和实施者分离:实施者不能单独修改门禁并批准自己的变更;紧急绕过必须留下操作者、理由、被绕过规则、补偿控制和后续 Review。
评审者离组时,撤销仓库与工单权限,转移开放 finding、例外和自动化 owner,并验证 CODEOWNERS 团队仍有可响应成员。只有账号已禁用而对象仍指向旧 owner,会把权限回收变成新的阻塞点。
容量、成本和架构选型
评审系统的容量瓶颈通常先出现在人类队列,其次才是存储。观察待评审年龄、每类 Review 数量、被退回比例、例外存量与年龄、失效证据链接、自动化执行失败、API 限流和通知扇出。过细的清单会制造机械勾选,过粗的清单会把判断藏回聊天;按失败风险维护稳定 check ID,只保留能改变结论或排障路径的项目。
仓库原生方案适合代码边界清晰、变更量可控的团队,优势是提交、PR、检查和 Review 身份相邻;复杂跨项目查询、审批分层和监管报表可能需要中心工单或专用变更平台。中心化方案提供更强字段、自动化和权限模型,但增加席位、集成、管理员、数据驻留、导出和退出成本。自建方案能控制数据与扩展,却把升级、备份、审计、可用性和插件供应链交给团队承担。
GitHub 的规则、Projects 自动化和组织级字段会随产品与套餐变化;Jira 自动化也有执行量、并发和查询限制。选型时从目标组织的设置页、GitHub plans 和 Atlassian automation limits 确认能力,不在制度里写死价格。更重要的成本是退出时能否导出 Review、结论、证据 URL、评论、行动项和审计记录,并保持旧 ID 可解析。
清理、回滚与长期治理
新门禁误伤正常交付时,先保留失败运行和规则版本,使用有审计的临时例外恢复流转,再修正规则;不要直接删除失败证据。模板或 workflow 回滚用普通代码回退完成,规则集与平台配置要导出或记录变更 ID,确保仓库文件和平台状态能一起恢复。外部机器人停用时先禁用 webhook/规则,再撤销凭证,最后删除应用;顺序相反会产生大量无法解释的失败重试。
迁移平台时先导出对象和关系,建立旧 Review ID 到新 ID 的映射,抽样验证结论、例外、行动项、评论与证据链接,再把旧系统设为只读。不能只迁移“approved”状态,因为没有基线版本与证据的批准不可审计。
长期 owner 应维护 check ID、适用条件、模板版本、规则权限和退出说明,并定期执行一正多反验证:合法记录能推进指定版本;缺少 subject、候选输入变化、冲突结论、开放阻塞项、例外到期或失效证据都会被拒绝。抽样时还要从 ADR 追到 Review、工单、PR 和 required check,再从门禁失败回到具体 finding。团队能双向走通这条链,才能说明评审工具真正约束了研发系统。
