fix(ci): docs 自动合并通道的两处盲区 —— 合并后下游看不见、拒绝后作者看不见 - #1987
Conversation
…without a word Two gaps in the same file (issue #1983), failing in opposite directions. **The merge was invisible to the rest of the repository.** `gh pr merge` used `secrets.GITHUB_TOKEN`, and a merge made with `GITHUB_TOKEN` produces a push that starts **no workflows**. Measured 2026-09-21 by counting push-triggered runs per commit: 8044678 #1969, merged here (GITHUB_TOKEN) → 0 runs 8417494 #1965, merged with the PAT → 5 runs dc50c25 #1962, merged with the PAT → 5 runs `Release Please` and `Leaderboard Watch`'s last eight runs all correspond to PAT or manual pushes; none of the three `GITHUB_TOKEN` commits has one. At least ten workflows key on `push` — Release Please, Leaderboard Watch, Build Live Feed, Update Badge Counts, Deploy Documentation, Lesson Security Scan, Setup Package CI, MCP Endpoint Stress Tests, PyPI Wheel Smoke, fatal-guard CI — so every PR merged through this channel landed without any of them noticing. The repository has paid for this lesson twice (`auto-sync-prs.yml`, and `lessons/contrib/ci-github-token-push-does-not-trigger-workflows.md`); this was the third place. The token must **not** be widened to `workflow`: that scope is only needed for PRs that modify `.github/workflows/`, and this channel merges docs only — granting it would let an auto-merged PR change CI itself. **The refusal was invisible to the person who opted in.** This workflow had no comment step at all (the lesson channel has three), so a refusal existed as one `core.info` line inside a green run. #1801 is the measured case: the maintainer applied `auto-merge-eligible` four times on 2026-09-19, the 13:23 run executed and refused it (`Docs-only: false (3 files)`), and nothing was posted and no run happened again — from the author's side, the label did nothing for three days. There is now a step on the refusal path that upserts a comment (capped at 20 offenders) naming the files that broke the rule and the way back in: re-apply `auto-merge-eligible`, which is not busywork, because the gate only re-evaluates on `labeled`/`unlabeled`/`edited`/`synchronize`/`ready_for_review`. Both checks are functions over the workflow text and the mutation cases feed a mutated copy through those same functions — asserting "the mutation took" and then asserting something trivially true is decoration, not a guard. Signed-off-by: Ikalus1988 <136884451+Ikalus1988@users.noreply.github.com>
PR Genius Analysis
Checklist
Anti-Patterns Detected
Suggestions
|
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
misakanet-web | a776f9e | Commit Preview URL Branch Preview URL |
Sep 21 2026, 03:50 AM |
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
🧾 Audit Report — PR #1987 (a776f9e)📊 Quality Score🔏 DCO Audit✅ All commits signed-off. 📏 PR Size
🔐 Secret Scan✅ No hardcoded secrets detected. 📦 Dependency Audit⏭️ Skipped; no Python/JS dependency files changed. 🧪 Test Suite✅ PASS — 54% coverage 📋 Lesson Schema✅ All lessons valid. ⚖️ Verdict✅ All gates passed. Ready for merge. Scope: |
🎉 Merged — Thank you!Your contribution has been merged into main. PR: #1987 — fix(ci): docs 自动合并通道的两处盲区 —— 合并后下游看不见、拒绝后作者看不见 What's next:
Welcome to the MisakaNet contributor community! 🧠 |
PR Code Suggestions ✨Explore these optional code suggestions:
|
|
✅ Merged! Thanks again, @Ikalus1988. fix(ci): docs 自动合并通道的两处盲区 —— 合并后下游看不见、拒绝后作者看不见 (+202 lines, 2 files) Quick question — did any MisakaNet lesson help you this time? No need to reply if nothing comes to mind. ⚡ |
User description
Fixes #1983.
缺口 1:合并之后,整个仓库看不见
gh pr merge用的是secrets.GITHUB_TOKEN。用GITHUB_TOKEN产生的推送不触发任何 workflow,所以这条通道合入的 PR,下游那串后处理全部静默跳过。按 commit 数 push 事件创建的 run(2026-09-21 实测):
804467880(#1969,本通道)github-actions[bot]/ GITHUB_TOKEN8417494c4(#1965)dc50c25ce(#1962)Release Please/Leaderboard Watch最近 8 次运行全部对应 PAT 或人工 push,三个 GITHUB_TOKEN 提交一个都没有。受影响:Release Please(release PR 不更新)、Leaderboard Watch、Build Live Feed、Update Badge Counts、Deploy Documentation、Lesson Security Scan、Setup Package CI、MCP Endpoint Stress Tests、PyPI Wheel Smoke、fatal-guard CI —— ≥10 个。站点部署不受影响(Cloudflare Workers Builds 是 Git 集成)。
改法:合并改用
secrets.SHELDON_PAT,并把"为什么不能是 GITHUB_TOKEN"与"为什么不需要workflowscope"写进注释 —— 后者是刻意的:那个 scope 只对"修改.github/workflows/的 PR"生效,而这条通道按自己的规则只合纯文档 PR;放宽它等于让自动合并的 PR 能改 CI 本身。缺口 2:拒绝之后,作者什么都看不到
这个 workflow 一个评论步骤都没有(lessons 通道有 3 处),拒绝只存在于绿 run 里的一行
core.info。实测受害者 #1801:09-19 13:09–13:23 被打了 4 次auto-merge-eligible,13:23 那次确实跑了并拒绝(Docs-only: false (3 files)),此后无运行、无留言 —— 作者那边"打了标签,然后什么都没发生",静坐 3 天。改法:拒绝路径新增一步,upsert(发现已有 marker 就更新,不堆叠)一条评论,写明:判据(哪些文件破坏了 docs-only)、以及怎么让 gate 重看(移除再重打
auto-merge-eligible—— 这不是废话:gate 只在labeled/unlabeled/edited/synchronize/ready_for_review醒来,已经推过的 PR 不会自己重跑)。文件列表最多列 20 个。验收对照(#1983)
workflowscope / 删掉拒绝步骤 / 只 create 不 update)测试
判定逻辑写成两个对工作流文本求值的函数(
merge_token_problems/refusal_report_problems),变异用例外加一份被改过的副本喂进同一个函数 —— "断言变异生效了"然后再断言一件恒真的事,那是装饰不是门禁。python3 -m pytest tests/test_auto_merge_docs.py -q→ 9 passed(原有 3 条 + 新增 6 条)。PR Type
Bug fix, Tests
Description
Switch merge token from
GITHUB_TOKENtoSHELDON_PATso downstream workflows actually runAdd upserted refusal comment step when the docs-only rule fails
Surface the offending file list so authors see what to fix
Add mutation tests guarding both gaps against future regressions
Diagram Walkthrough
File Walkthrough
auto-merge-docs.yml
Switch merge to PAT and post upsert refusal comment.github/workflows/auto-merge-docs.yml
secrets.GITHUB_TOKENwithsecrets.SHELDON_PATon theEnableauto-mergestep and documents whyGITHUB_TOKEN(and widening toworkflowscope) is forbiddenoffendersoutput to the check step so the refusal can list thefiles that broke the rule (capped at 20)
Report the refusal on the pull requeststep that upserts(creates or updates) a single marker-tagged comment explaining the
rule, the offending files, and how to re-trigger the gate
test_auto_merge_docs.py
Add gap-closing and mutation tests for docs gatetests/test_auto_merge_docs.py
merge_token_problemsandrefusal_report_problemsanalyzers overthe workflow YAML, plus a parametrized test that asserts both stay
empty
GITHUB_TOKEN, widen thescope to
workflow, drop the reporting step, or replaceupdateCommentwith
createComment, asserting each is caughtfile, so a no-op mutation cannot falsely pass