Skip to content

ci: 请审改成 PR 状态——开草稿、gh pr ready 即请审,必需检查红了由 Review gate 退回草稿 - #438

Merged
yesme merged 2 commits into
mainfrom
claude/review-gate
Oct 17, 2026
Merged

yesme merged 2 commits into
mainfrom
claude/review-gate

Conversation

@yesme

@yesme yesme commented Oct 17, 2026

Copy link
Copy Markdown
Owner

定位与重述

协作流程的机械关卡,不动产品代码。

起因。 #433 的 CI 红了 45 分钟没人发现,最后是所有者看到「大家都在等」:

  • 作者没等 CI 绿就发了「请审」评论;
  • 核验席看到红就默默等着;
  • 找问题席(我)写「可合」之前没看 CI。

所有者问以后谁侦测、谁推动,并定:「我不希望这种harness是在agents.md里边的散文 - 我希望这是一个能被执行的mechanical动作,就是固定流程」。

重述。 「请审」要变成一个机器读得到、也改得动的状态,而不是一句评论。CI 红了,由机器把状态拨回去、告诉作者,不靠谁记得去看。

做法:用 GitHub 原生的草稿 / 就绪。

  • 开 PR 一律 gh pr create --draft;作者 gh pr ready <号> 就是请审。
  • 新 workflow Review gate(.github/workflows/review-gate.yml)在两个时刻检查 PR 当前头上三项必需检查(CI gate、Release gate、PR contract,正是 main 保护要求的三项)的最新结论:一是 PR 被标成就绪时(pull_request: ready_for_review),二是 Code、Release、PR contract 任一 workflow 跑完时(workflow_run: completed)。有一项是 failure 或 timed_out,就 gh pr ready --undo 退回草稿,并留言列出红的检查和链接。
  • 只判三种条件都满足的 PR:开着、已就绪、头和这次运行一致。给旧头跑的结果不算数。不检出 PR 的代码,workflow_run 带着写权限也不执行 PR 里的任何东西。
  • 评审席只审就绪的 PR。审到一半被退回草稿就停下,等它重新就绪后对新头重新确认。草稿本来就合不进去,红头上的自动合入也会一直等着。

AGENTS.md「评审与合入」里「请审之前自己先过一遍」那一条,改写成上面的流程,另加一条说明 Review gate 做什么。

硬约束: 不加新的必需检查,不改 main 的保护规则;不检出 PR 代码。可协商: 草稿留言的措辞;要不要把 cancelled 也算红(现在不算:新推送会取消旧运行,算进去会误判)。

当前生效约束集

  • 所有者 2026-10-17:「落」;「我希望这是一个能被执行的mechanical动作,就是固定流程」。
  • AGENTS.md「评审与合入」:作者合入、两席对最终提交「可合」、CI 绿后自动合入;「可合」针对提交。本 PR 不改这些,只把请审变成状态。
  • 开工书 §二 第 23 条:必需检查是 CI gate、Release gate、PR contract。
  • CONSTRAINTS:先查业界与平台原生机制;结果如实报告。

业界方案调研

  • GitHub 原生的草稿 PR(「Draft pull requests」):草稿不能合并,不会请求 code owner 评审;gh pr create --draft、gh pr ready、gh pr ready --undo 都是官方 CLI 的现成命令。ready_for_review 是 pull_request 的原生事件类型,workflow_run 是原生的「另一个 workflow 跑完」触发器。「CI 红了退回草稿」这一步,GitHub 设置里没有现成开关(分支保护只挡合并,不改 PR 状态),所以要一个 workflow 把这几样原生能力串起来,里面是约 30 行 shell。
  • 合并队列(GitHub merge queue) 解决的是「只有绿的才合进去」,本库已经靠必需检查加自动合入做到了。它不解决「评审席知不知道这个头是红的」,所以不选。
  • 标签加机器人(Kubernetes Prow / Tide 用 do-not-merge/* 标签,或 Mergify 一类服务):要另装服务或维护标签约定。草稿状态是 GitHub 自带的,网页、gh pr list、各家 harness 调的 gh pr view --json isDraft 都直接读得到,比标签少一层约定。
  • 只在 AGENTS.md 里写规矩:就是这次失效的做法,所有者明确否了。

实测

  • 查询逻辑在本机对真实的头试跑过(和 workflow 里用的是同一条 gh api … check-runs 加 jq):

    三项检查在 check-run 里的名字就是 CI gate、Release gate、PR contract。

  • ruby -ryaml 解析 workflow 通过;run 段单独抽出来 bash -n 通过;文档检查 root//build/docs:profile-all Pass 14。

  • 还没在真 PR 上跑过的两条路径,留给核验:

    • ready_for_review 路径:PR 自己的 workflow 版本就会跑,合入前就能测。核验席另开一个故意让 PR contract 红的试验 PR,标成就绪,看它被退回草稿、有没有留言。
    • workflow_run 路径:只认默认分支上的 workflow,合入前测不了。合入后,下一个红的 PR 就是第一次实跑,我会在这里补记结果。
  • 本 PR 自己就是开成草稿的,CI 绿了才 gh pr ready。

#433 的 CI 红了 45 分钟没人发现:作者没等 CI 绿就发「请审」评论,核验席默等,找问题席写「可合」
前没看 CI。所有者要的是能被执行的固定流程,不是 AGENTS.md 里多一句话。

用 GitHub 原生的草稿 / 就绪状态:开 PR 一律 --draft,作者 gh pr ready 就是请审。新 workflow
Review gate 在 ready_for_review 时、以及 Code / Release / PR contract 每次跑完时,看 PR 当前头上三项
必需检查(CI gate、Release gate、PR contract)的最新结论;有一项 failure 或 timed_out,就 gh pr ready
--undo 退回草稿,并留言列出红的检查与链接。只判开着的、就绪的、头与这次运行一致的 PR;不检出 PR 代码。
AGENTS.md「评审与合入」那句「请审之前自己先过一遍」随之改写成这个流程。

Co-authored-by: Claude Code claude-opus-5-5 effort=xhigh <281844019+a-claude-code-bot[bot]@users.noreply.github.com>
@yesme
yesme marked this pull request as ready for review October 17, 2026 07:15
@yesme

yesme commented Oct 17, 2026

Copy link
Copy Markdown
Owner Author

Codex · #438 · 找问题(8780833)

修正后可合。实际审查 head:87808339e6b5f9c272f4b138f53cee40392058e2,base:ec3995a91f40a073c95590b69827a7794b187043;等 isDraft=false 后才开始读 diff。没有读其他评审席的意见。

这个头的 CI 状态

查询时三项必需检查 CI gate、Release gate、PR contract 全绿;Docs checks 与新 Review gate 也绿。Review gate 的 ready_for_review 实跑拿到的权限是 Checks: read、Contents: read、PullRequests: write。但这一轮没有失败检查,没有执行退草稿和留言两条写操作,不能据它证明权限足够。Buck2 / Cargo / 完整包矩阵按路径跳过;这批不改产品代码,不把跳过说成实跑通过。另实查 main 保护 API,必需项确实就是上述三项。

修正

级别 位置 具体问题与依据 最小改法 / 怎样算达到
P1 .github/workflows/review-gate.yml:16–19、66 退草稿的 GraphQL 操作缺少已知需要的 Contents 写权限,红分支还没有实证。 gh pr ready --undo 调的是 convertPullRequestToDraft,不是普通的 PR 评论接口。上游 Apache Arrow 对同一个操作已有直接复现:已有 pull-requests: write 时返回 Resource not accessible by integration,加 contents: write 后真实 PR 自动变草稿;原作者复现与修复确认,对应已合入补丁。这里沿用原权限,遇到红检查会在第 66 行退出,PR 仍然就绪,留言也不会执行。我没有拿本机个人令牌冒充 Actions token 做此项实测。 按已验证的最小权限补 contents: write,保留 Checks read / PullRequests write;用受控红 PR 在真正的 Actions token 下验一次“就绪 → 草稿 → 留言”,再验修好后重新就绪不被退。若当前权限在本库已经能成功,贴同一权限下的真实红分支日志即可反证此项,不必无证扩权。不需要 write-all,也不需要另加 Issues write。

跟进(P2,不为这些单独开一轮)

位置 诚实输入下的后果 建议
.github/workflows/review-gate.yml:21–23、50–66 三个条件只在第一次读取 PR 时成立,不是写操作的前置比较条件。顺序可以是:读到头 A 就绪 → 读到 A 红 → 作者推 B → 对 PR 号执行退草稿,误退 B;同头的失败重跑恰在读完后转绿也一样。本机对原样 shell 段注入这两种 API 返回时序,两个都仍发出了 ready --undo。另外 ready 事件用 review-gate-438,workflow_run 用 review-gate-<SHA>,两路并不互斥,会重复退和重复留言。 写前再核当前 PR 与最新失败集合;两路尽量使用同一串行组,转换已是草稿时不要重复留言。这只是减小窗口:GitHub 的该 mutation 没有 expected-head 条件,不要求为绝对原子性另造锁或服务,描述也别声称三条件消除了全部竞争。两路之间的真实并发尚未在 GitHub 注入实测。
.github/workflows/review-gate.yml:10–11、45–46 外部 fork 的覆盖未成立。 ready_for_review 的 pull_request token 通常会被平台降成只读;workflow_run 的关联 PR 数组也不能保证非空。数组为空时这里退出 0、什么都不做,本机空数组用例已确认这条漏退路径。GitHub 官方 fork 权限说明与runner 项目的 fork 空数组复现分别支持这两个限制。 当前若只承诺本库 harness 的同仓分支,明确这个覆盖范围;未来支持 fork 时,从可信 API 定位 PR 并复核头,选用默认分支的受信任事件代码。不要靠 PR 上传的可执行制品传入 PR 号。本次没有创建外部 fork PR 实测。

维持

  • workflow_run 的写权限没有流向 PR 代码。 此事件执行默认分支上的 workflow;当前实现不 checkout、不拉 artifact、不恢复缓存、不 source 仓库脚本,也不执行 check 输出。事件里的编号 / SHA 放 env,后续作为带引号的参数;检查名和 URL 只进入评论正文,没有 eval 或拼进待执行 shell。这个判断限于当前写法,不能泛化成“workflow_run 天然安全”。GitHub 官方事件与安全说明。
  • 评论权限足够,不必为评论加 Issues write。 PR 的普通留言 API 接受 Pull requests write 或 Issues write 其中之一;这里已有前者。官方评论接口权限。问题在退草稿 mutation,不是留言接口。
  • 重跑不是简单地沿用事件的红结论。 代码查的是头上最新 check runs,而不是直接信 workflow_run.conclusion。我对本库真实重跑的 SHA 04b71feed90cdf6a60e17abf88210528c10c5825 查询:默认 latest 只返回成功的 Release gate 114401827544;filter=all 同时能看到旧失败 114400422989。因此旧失败事件延迟到达、但最新重跑已绿时,正常查询不会仅因旧事件而误退。
  • 已过时的头在读取时能挡住。 关闭的 PR、已经是草稿、当前头不同,都不会退;取消本身也不被当 failure。新推送已在查询前发生时,旧运行会被跳过。三个 workflow 同头的完成事件使用同一个 SHA 组,串行后每次都重查全部三项,不会因默认只保留一个 pending 事件而必然漏掉某一项红。这不替代前面所列的“读完之后变了”的窗口。
  • AGENTS 两条把请审改成原生状态,未增加新的必需检查、未修改保护规则,也没把“就绪”写成评审通过。

核验范围

  • 完整读两文件 diff、Code / Release / PR contract 的触发与并发配置;只读查询 main 保护配置、PR 状态、check runs 和新 Review gate 的真实日志。
  • 仓库既有 src/build/tools/actionlint-bin 对新 workflow 通过;抽取原样 run 段 bash -n 通过;git diff --check 通过。
  • 原样 shell + 本机模拟 gh 返回共 10 条:当前红、当前绿、草稿、关闭、旧头、最新重跑进行中、取消、空关联 PR,以及上表两条交错时序。前七条符合当前规则;空数组展示漏退,两条交错展示误退。这是控制流实验,不是假称 GitHub 实际发生过那些竞争。
  • 未在仓库创建试验 PR、未用 Actions token 实打退草稿 / 留言;workflow_run 真事件路径按平台规则要等本 workflow 合入默认分支后验证。未改文件、未 push、未合并。

@yesme

yesme commented Oct 17, 2026

Copy link
Copy Markdown
Owner Author

Antigravity(ubuntu)· #438 · 核验(8780833)

结论:修正后可合。 实际核验完整 SHA:87808339e6b5f9c272f4b138f53cee40392058e2(等待 gh pr view 438 --json isDraft 变为 false 后开始);机器:Linux 7.0.0-34-generic x86_64(ubuntu);模型:gemini-4-argon(effort=high)。


1. #438 头(8780833)的 CI 状态

命令:

gh pr checks 438 -R yesme/hctl2

原样输出:

All checks were successful
0 cancelled, 0 failing, 7 successful, 4 skipped, and 0 pending checks

   NAME                         DESCRIPTION  ELAPSED  URL                       
✓  Code/CI gate (pull_request)               3s       https://github.com/yesme/hctl2/actions/runs/39012894013/job/117339006684
✓  Code/Docs checks (pull_r...               9s       https://github.com/yesme/hctl2/actions/runs/39012894013/job/117338990297
✓  Review gate/Review gate ...               3s       https://github.com/yesme/hctl2/actions/runs/39012983051/job/117339251792
-  Code/Buck2 / ${{ matrix....                        https://github.com/yesme/hctl2/actions/runs/39012894013/job/117339006378
-  Code/Cargo hygiene / Lin...                        https://github.com/yesme/hctl2/actions/runs/39012894013/job/117339006055
✓  Release/Release gate (pu...               4s       https://github.com/yesme/hctl2/actions/runs/39012894002/job/117338953319
-  Release/Complete package...                        https://github.com/yesme/hctl2/actions/runs/39012894002/job/117338952979
-  Release/Publish GitHub r...                        https://github.com/yesme/hctl2/actions/runs/39012894002/job/117338953674
✓  PR contract/PR contract ...               7s       https://github.com/yesme/hctl2/actions/runs/39012894011/job/117338931067
✓  Code/Path filter (pull_r...               16s      https://github.com/yesme/hctl2/actions/runs/39012894013/job/117338931088
✓  Release/Release path fil...               7s       https://github.com/yesme/hctl2/actions/runs/39012894002/job/117338931080

三项必需检查(CI gate、Release gate、PR contract)以及 Docs checks、Review gate 均绿。


2. 试验 PR #439(分支 agy/review-gate-probe)实测「标成就绪时」路径

从 origin/claude/review-gate(8780833)拉出试验分支 agy/review-gate-probe,开草稿 PR #439(https://github.com/yesme/hctl2/pull/439),故意留空 ## 业界方案调研 让 PR contract 转红,分三步实测:

2a. 原版权限(contents: read,提交 c3b45a4):gh pr ready 439 触发 P1-1(403 失败)

PR contract 红后执行 gh pr ready 439 -R yesme/hctl2:

Review gate	Send a ready PR with a red required check back to draft	2026-10-17T07:19:00.4094628Z   GH_TOKEN: ***
Review gate	Send a ready PR with a red required check back to draft	2026-10-17T07:19:00.4094996Z   REPO: yesme/hctl2
Review gate	Send a ready PR with a red required check back to draft	2026-10-17T07:19:00.4095588Z   EVENT: pull_request
Review gate	Send a ready PR with a red required check back to draft	2026-10-17T07:19:00.4095953Z   EVENT_PR: 439
Review gate	Send a ready PR with a red required check back to draft	2026-10-17T07:19:00.4096366Z   EVENT_HEAD: c3b45a4c9f43d86f6593a0cc62ddcad0ec9365d2
Review gate	Send a ready PR with a red required check back to draft	2026-10-17T07:19:02.2898039Z API call failed: GraphQL: Resource not accessible by integration (convertPullRequestToDraft)
Review gate	Send a ready PR with a red required check back to draft	2026-10-17T07:19:02.2917614Z ##[error]Process completed with exit code 1.

2b. 在试验分支验证 contents: write(提交 7219587):退草稿与留言成功

在试验分支把 .github/workflows/review-gate.yml 的 contents: read 改为 contents: write(7219587),待 PR contract 红后执行 gh pr ready 439 -R yesme/hctl2:

## Review gate · 当前头 `7219587` 的必需检查红了,已退回草稿

- PR contract:https://github.com/yesme/hctl2/actions/runs/39013405290/job/117340472369

作者修好、检查转绿后 `gh pr ready 439` 再请审。评审席在它重新就绪之前不审;就绪之后对新头重新确认。

2c. 补好描述等 PR contract 绿后再次 gh pr ready 439:触发 P1-2(仍被旧 check suite 退回草稿)

用 gh pr edit 439 补齐 ## 业界方案调研,等待 PR contract 新运行(job 117340845728)转绿:

All checks were successful
0 cancelled, 0 failing, 6 successful, 5 skipped, and 0 pending checks
✓  Code/CI gate (pull_request)               4s
✓  PR contract/PR contract ...               6s
✓  Release/Release gate (pu...               4s

随后再次执行 gh pr ready 439 -R yesme/hctl2:

gh api "repos/yesme/hctl2/commits/72195878660dacdb74d7c59c51fdfae6e3a2cfcc/check-runs?per_page=100" \
  --jq '.check_runs[] | select(.name == "PR contract") | {id, status, conclusion, started_at, html_url}'

原样输出:

{
  "conclusion": "success",
  "html_url": "https://github.com/yesme/hctl2/actions/runs/39013531733/job/117340845728",
  "id": 117340845728,
  "started_at": "2026-10-17T07:24:50Z",
  "status": "completed"
}
{
  "conclusion": "failure",
  "html_url": "https://github.com/yesme/hctl2/actions/runs/39013405290/job/117340472369",
  "id": 117340472369,
  "started_at": "2026-10-17T07:22:45Z",
  "status": "completed"
}

GitHub commits/<sha>/check-runs 的默认 filter=latest 是**按每个 check suite(每次 workflow run 是一个独立 check suite)**各返回最新一条,而不是按 check name 全局去重。当同一头因编辑 PR 描述(触发新的 PR contract workflow run)而不改 commit SHA 转绿时,新旧两个 check suite 的 PR contract 会同时返回,现有 jq 直接遍历 .check_runs[] 会命中旧 suite 的 failure。

2d. 清理

已关闭试验 PR #439 并删除远端与本地分支 agy/review-gate-probe:

✓ Closed pull request yesme/hctl2#439 (chore(ci): [DO NOT MERGE] #438 Review gate 核验试验 PR)
✓ Deleted branch agy/review-gate-probe

3. 发现的问题

编号/级别 文件与位置 触发与后果 证据 最小改法
P1-1 .github/workflows/review-gate.yml:16-19 permissions 仅声明 contents: read,而 gh pr ready --undo 底层 GraphQL convertPullRequestToDraft 对 GITHUB_TOKEN 要求 contents: write + pull-requests: write。遇到红检查时直接报 403 退出,PR 不会被退回草稿,也不会留言。 试验 PR #439 头 c3b45a4 上运行 39013169576 报错 GraphQL: Resource not accessible by integration (convertPullRequestToDraft);改为 contents: write 后运行 39013474008 成功退草稿并留言。 将 permissions.contents 从 read 改为 write。
P1-2 .github/workflows/review-gate.yml:57-62 同一 commit SHA 上因编辑 PR 描述等原因触发新一次 workflow run 转绿后,commits/<sha>/check-runs 仍会返回旧 check suite 里的 failure 记录;作者修好描述、检查全绿后再执行 gh pr ready 仍会被 Review gate 误判为红并无限退回草稿。 试验 PR #439 头 7219587 补齐描述后 PR contract 新运行 117340845728 已 success,但 gh pr ready 439 触发的运行 39013580887 仍命中旧运行 117340472369(failure)并把 #439 退回草稿。 在 jq 中先按 .name 分组并取 max_by(.id)(代表该检查名最新一次创建的 check-run),再判断 .conclusion == "failure" or .conclusion == "timed_out"(若保留 --paginate 需配 --slurp 后合入 .[].check_runs[])。

Antigravity 在试验 PR #439 上实测出两处、Codex 读出同一处权限问题:
- convertPullRequestToDraft 只给 pull-requests: write 时报 Resource not accessible by integration
  (run 39013169576),加 contents: write 后退草稿与留言成功(run 39013474008)。
- check-runs 的 latest 是每个 check suite 各一条;改描述让 PR contract 重跑转绿后,旧那次的
  failure 还在,#439 被无限退回草稿(run 39013580887)。现在按检查名分组、取 id 最大的那条再判。
  本机对四个真头试过:7219587(先红后绿)不判红,e2e3bb8 照样挑出 Release gate,c19b067 与
  04b71fe(重跑转绿)不判红。

Codex 的 P2 一并收:ready 事件与 workflow_run 用同一个以 PR 号命名的并发组,不再一个 PR 退两次、
留两条言;写之前再看一次 PR 状态与红项,缩小「读完之后变了」的窗口(GitHub 的这个 mutation
不带预期头,关不死,注释里照实写);注释写明只覆盖同仓分支。actionlint 1.7.12 通过。

Co-authored-by: Claude Code claude-opus-5-5 effort=xhigh <281844019+a-claude-code-bot[bot]@users.noreply.github.com>
@yesme

yesme commented Oct 17, 2026

Copy link
Copy Markdown
Owner Author

处理说明(对 Codex 找问题、Antigravity 核验,新头 15c67383)

两个 P1 都收了,Codex 的两条 P2 也一起收了。

  1. 退草稿要 contents: write(Antigravity P1-1,Codex P1):权限里的 contents 从 read 改成 write,注释里写明出处:chore(ci): [DO NOT MERGE] #438 Review gate 核验试验 PR #439 的 run 39013169576 原样报错,改了之后 run 39013474008 成功。没加别的权限,评论用 pull-requests: write 就够。

  2. 按检查名取最新一次(Antigravity P1-2):查询改成先按检查名分组,每组取 id 最大的那一条,再判 failure / timed_out。本机对四个真头试过:

    最新一次还在跑的话,结论是空的,不算红;等它跑完,workflow_run 会再判一次。

  3. 两路同一并发组(Codex P2):组名改成 review-gate-<PR 号>,workflow_run 那一路取 pull_requests[0].number,取不到才退回用 SHA。一个 PR 不会被退两次、留两条言。

  4. 写前再看一次(Codex P2):退回之前再核一次「开着、就绪、头没变」,并重算红项。GitHub 的这个 mutation 不带预期头,窗口关不死,注释里照实写了,不声称原子。

  5. 覆盖范围(Codex P2):注释写明只覆盖同仓分支,所有席位都是这么干活的;fork 的 token 只读,workflow_run 也可能取不到 PR 号。

actionlint 1.7.12 通过(仓库自带的 src/build/tools/actionlint-bin)。

请两席对新头复核。 Antigravity:请照上次的办法,从新头起一个试验 PR,把 2b、2c 两步再走一遍:红了退回草稿并留言;补好描述转绿后再就绪,不再被退回。测完照旧清理。workflow_run 那条路径要等合入后,第一个红的 PR 才算实跑,到时我补记。

@yesme

yesme commented Oct 17, 2026

Copy link
Copy Markdown
Owner Author

Antigravity(ubuntu)· #438 · 核验(15c6738)

结论:可合。 实际核验完整 SHA:15c67383767f1ff23d95de3c4e60044ddb3712b4;机器:Linux 7.0.0-34-generic x86_64(ubuntu);模型:gemini-4-argon(effort=high)。


1. #438 新头(15c6738)的 CI 状态

命令:

gh pr checks 438 -R yesme/hctl2

原样输出:

All checks were successful
0 cancelled, 0 failing, 5 successful, 5 skipped, and 0 pending checks

   NAME                         DESCRIPTION  ELAPSED  URL                       
✓  Code/CI gate (pull_request)               3s       https://github.com/yesme/hctl2/actions/runs/39014424735/job/117343536108
-  Code/Buck2 / ${{ matrix....                        https://github.com/yesme/hctl2/actions/runs/39014424735/job/117343536106
-  Code/Cargo hygiene / Lin...                        https://github.com/yesme/hctl2/actions/runs/39014424735/job/117343535790
-  Code/Docs checks (pull_r...                        https://github.com/yesme/hctl2/actions/runs/39014424735/job/117343535439
✓  Release/Release gate (pu...               4s       https://github.com/yesme/hctl2/actions/runs/39014424765/job/117343483223
-  Release/Complete package...                        https://github.com/yesme/hctl2/actions/runs/39014424765/job/117343482839
-  Release/Publish GitHub r...                        https://github.com/yesme/hctl2/actions/runs/39014424765/job/117343483576
✓  PR contract/PR contract ...               6s       https://github.com/yesme/hctl2/actions/runs/39014424748/job/117343462519
✓  Code/Path filter (pull_r...               15s      https://github.com/yesme/hctl2/actions/runs/39014424735/job/117343462506
✓  Release/Release path fil...               6s       https://github.com/yesme/hctl2/actions/runs/39014424765/job/117343462511

三项必需检查(CI gate、Release gate、PR contract)全绿。


2. 试验 PR #440(从 15c6738 起分支 agy/review-gate-probe)完整实测

从 15c6738 拉出试验分支 agy/review-gate-probe(只改 .memo/README.md 空行,提交 b5113cb,不改动 .github/workflows/review-gate.yml),开草稿 PR #440(https://github.com/yesme/hctl2/pull/440):

2a. PR contract 红时执行 gh pr ready 440:退回草稿 + 留言

故意留空 ## 业界方案调研,等待 PR contract 转红后执行 gh pr ready 440 -R yesme/hctl2:

## Review gate · 当前头 `b5113cb` 的必需检查红了,已退回草稿

- PR contract:https://github.com/yesme/hctl2/actions/runs/39014517853/job/117343724459

作者修好、检查转绿后 `gh pr ready 440` 再请审。评审席在它重新就绪之前不审;就绪之后对新头重新确认。

2b. 补齐描述等 PR contract 转绿后再次执行 gh pr ready 440:保持就绪,不再被退回

用 gh pr edit 440 补齐 ## 业界方案调研,等待 PR contract 转绿后再次执行 gh pr ready 440 -R yesme/hctl2:

  • Review gate 运行链接:https://github.com/yesme/hctl2/actions/runs/39014654904 (conclusion: "success")
  • 状态核对:gh pr view 440 -R yesme/hctl2 --json isDraft,comments 原样返回:
    • "isDraft": false(保持就绪,未再被退回草稿,P1-2 已修复)
    • comments 仍只有首轮那 1 条留言,无新增留言。

2c. 清理

已关闭试验 PR #440 并删除远端与本地分支 agy/review-gate-probe:

✓ Closed pull request yesme/hctl2#440 (chore(ci): [DO NOT MERGE] #438 (15c6738) Review gate 核验试验 PR)
✓ Deleted branch agy/review-gate-probe

3. 发现的问题

无(首轮 P1-1、P1-2 在 15c6738 均已验证修复)。

@yesme

yesme commented Oct 17, 2026

Copy link
Copy Markdown
Owner Author

Codex · #438 · 找问题(15c6738 复核)

可合。实际复核 head:15c67383767f1ff23d95de3c4e60044ddb3712b4;复核时 PR 为 OPEN、非草稿。

新头的 CI 状态

重新查询了这个头,不沿用旧头结果:

必需检查 状态 证据
CI gate SUCCESS 39014429124 / 117343521403
Release gate SUCCESS 39014429126 / 117343497966
PR contract SUCCESS 39014429127 / 117343470911

全部检查共 5 成功、5 跳过,0 失败、0 待跑。Docs checks、Buck2 / Cargo、完整包等按路径跳过,不说成实跑通过。新头这次 synchronize 没有触发 Review gate;其写入路径的证据是下述 #440 实跑,不混为本头的 CI 检查。

逐项复核

上轮意见 结论与依据
P1:退草稿缺 Contents 写权限 已改对。 只将 Contents 改为 write,保留 Checks read / PullRequests write。我实际读取了 #440 的退草稿运行日志 39014562755:Actions token 确有这三项权限,gh pr ready --undo 成功,随后产生唯一一条留言。不是用个人令牌替代验证。
Antigravity P1:旧 suite 的红记录使同头转绿后仍被退 已改对。 --paginate --slurp 合并全部页,再按名称分组取最大 check-run ID,最后才判红;不会先筛红再取最新。我核了 #440 的第二次运行日志 39014654904:同一个头修好描述后保持就绪,没有第二条留言。
P2:两路并发与写前状态过时 按上轮要求收好。 同仓单 PR 的 ready 与 workflow_run 都归 PR 号并发组;写前重新核状态、头和红项。我用原样 shell 模拟“第一次查询后推新头”“同头重跑转绿”“另一路已退草稿”,均不再发写操作。最后一次查询与 mutation 之间仍非原子,代码已明确限制;不要求为这个极窄窗口另造机制。
P2:fork 漏退的覆盖范围 已明确范围。 文件注释只承诺同仓分支,明确 fork token 与关联 PR 数组的限制。本次不声称已经支持 fork,也不再把它作为本批待修项。

更正我上轮的一句判断: “默认 latest 会排除旧失败检查”不能泛化到不同 check suite。上轮查的单次重跑样本只证明那一种形状,不能覆盖编辑描述后产生的新 suite;Antigravity 的 #439 反例成立。此次按名称跨 suite 去重才补齐了这一点。

我实际核了什么

未发现遗留 P1。未改文件、未 push、未合并。

@yesme
yesme enabled auto-merge October 17, 2026 20:04
@yesme
yesme merged commit 009c1d9 into main Oct 17, 2026
10 checks passed
@yesme
yesme deleted the claude/review-gate branch October 17, 2026 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant