Skip to content

ci(docs): check-doc-links 提升为无路径过滤的独立 workflow,纯 docs PR 也拦得住断链 (#3448) - #3458

Merged
yinlianghui merged 2 commits into
mainfrom
claude/issue-3448-doclinks-own-workflow
Aug 6, 2026
Merged

ci(docs): check-doc-links 提升为无路径过滤的独立 workflow,纯 docs PR 也拦得住断链 (#3448)#3458
yinlianghui merged 2 commits into
mainfrom
claude/issue-3448-doclinks-own-workflow

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes #3448

按 PM 裁定采方案 A:把 node scripts/check-doc-links.mjs 提升为独立 workflow,无任何路径过滤,镜像 control-bytes.yml 的形状(触发集、最小 checkout、头注解释为什么不能加过滤)。裁定与「形式上偏离维护者 08-03 对 #3213 的『加进 ci.yml 的 docs 任务』原话」的理由已在单上论证:#3448 (comment) —— 那个裁决作出时结构洞尚未被发现,其意图(内链断裂 = 硬门禁)在字面落法下对纯 docs PR 恰好失效。

问题(已在 origin/main 上复核)

ci.ymlpaths-ignore 两处都列着 '**/*.md'content/**docs/**apps/site/**;站点文档全在 content/docs/**。GitHub 的语义是「改动文件全部命中即整个 workflow 不启动」,且没有 per-job path filter —— 所以只改文档的 PR 根本不启动 ci.yml#3450 加的那一步自然也不跑。它此前只覆盖「文档+代码」混合 PR 与 push 到 main。

改动

  • 新增 .github/workflows/docs-links.ymlpush / pull_request to main+developworkflow_dispatch既无 paths 也无 paths-ignore;checkout + setup-node + 一行 node scripts/check-doc-links.mjs。无 install、无网络、几秒钟。头注写清为什么路径过滤在这里是错的(paths: content/** 看着更紧,实则只是脚本扫描面的第二份副本,会各自漂移)。
  • ci.ymldocs job 删掉重复步骤 —— 这一处按最小重复原则由实现者定,我选:新 workflow 的触发集是该 job 的严格超集(同样的 main/develop,且无过滤),保留只会为同一条坏链多出一个红勾、多一处会忘记同步的副本。原地留注释说明它去哪了、为什么别加回来;那段已失效的 KNOWN GAP 注释一并删除(留着就是假话)。
  • 新增 scripts/__tests__/docs-links-workflow.test.ts:workflow 必须存在、必须门禁 PR、必须既无 paths 也无 paths-ignore、必须是唯一跑该脚本的 workflow。最后一条钉的是去重决策本身——把副本加回某个带路径过滤的 workflow,正是会重新制造「看着有覆盖、实则纯 docs PR 照样溜过去」的那个具体错误。扫描前先剥掉整行注释:ci.yml 的说明注释里仍提到脚本名,不剥会误报重复门禁。

⚠️ 越界说明:content/docs/guide/ci-cd-pipeline.md

派单文件面把 content/docs/** 列为禁止面。这一条我越了界,因为它不是顺手改文档,而是既有门禁的机械要求scripts/__tests__/ci-cd-pipeline-doc.test.ts.github/workflows/ 目录,任一 workflow 在该页没有点名标题就红。先加 workflow、不改文档,实测:

AssertionError: These workflows exist in .github/workflows/ but no heading in
content/docs/guide/ci-cd-pipeline.md names them:
  - docs-links.yml

该页自己的「Adding a New Workflow」也写着「Give it a section on this page in the same PR. Not a convention — a test.」。改动限于四处必要更正:清单表一行、新章节、ci.yml 任务表里 docs 行的更正(它不再跑链接检查)、Link Checking 章节里 #3448 那个「已知缺口」的收口(#3449 那个仍在)。如维护者认为该越界不可接受,我可以拆出去,但那样本 PR 必然是红的。

与在飞 PR #3456 的交叉#3456#3451)同样在改这个文件与 ci-cd-pipeline-doc.test.ts。两边不冲突的部分:它改 ci.yml 行与 dev-server 幽灵行,我加 docs-links.yml 行与新章节;可能冲突的一处是任务表里 docs 行——我改了它的内容,而它紧邻 #3456 删掉的 dev-server 行。两处修改都是有意的,谁后合谁 rebase 时按此说明取并集即可。#3456 不动 ci.yml,故 workflow 侧零交叉。

验证

  • python yaml.safe_load 两个 workflow 均解析通过;docs-links.yml 的触发集实测为 {'pull_request': {'branches': ['main','develop']}, 'push': {'branches': ['main','develop']}, 'workflow_dispatch': None} —— 没有任何 paths 键
  • node scripts/check-doc-links.mjsDocs links are valid. (exit 0)
  • pnpm exec vitest run scripts/(仓库根,规范调用)→ 9 files / 127 tests passed
  • node scripts/check-control-bytes.mjs → OK(3648 文件);另对本 PR 四个文件做了越出门禁的自扫 grep -naP,无命中。
  • 反向验证(方向先判后跑,两次均如期):把删掉的步骤加回 ci.yml → 新测试两处红(is the only workflow that runs the link checker 实得 ['ci.yml','docs-links.yml']every workflow that runs it is one a docs-only PR can start 点名 ci.yml 的 paths-ignore)。给 docs-links.ymlpaths: content/**carries NO path filter of any kind 红。

诚实的覆盖面说明:本 PR 改的是 .github/**,所以它自己既会启动 ci.yml、也会启动新 workflow —— 绿灯只证明「workflow 能在 PR 上跑通」,证明不了「纯 docs PR 会启动它」,后者只能由将来某个只改 markdown 的 PR 实证。能在此刻担保它的,是配置本身:on.pull_request 只有 branches,没有 paths/paths-ignore 两个键中的任何一个(YAML 解析结果如上),而 GitHub 只在存在过滤键时才做路径判断。这一条同时由上面那条测试机械看守。

未做的事


Generated by Claude Code

`check-doc-links.mjs` 由 PR #3450 接进 CI 时,落点是 `ci.yml` 的 `docs` job ——
而 `ci.yml` 的 `paths-ignore` 列着 `'**/*.md'`、`content/**`、`docs/**`、
`apps/site/**`。GitHub 的 `paths-ignore` 语义是「改动文件全部命中即整个 workflow
不启动」,且没有 per-job path filter;站点文档全在 `content/docs/**`。所以**只改
文档的 PR 根本不会启动 ci.yml**,这道门禁看不见的恰恰是最可能改坏内链的那一类
PR。它此前只覆盖「文档+代码」的混合 PR 和 push 到 main —— 坏链能经纯 docs PR 合
进 main,直到下一个无关作者推代码时才把 main 弄红,归因还错人。

`control-bytes.yml` 撞过同一堵墙,头注写着结论:看不见 markdown-only PR 的门禁
"rebuilds the hole it exists to close";`changeset-guard.yml` 是同一形状的第二例。
本次是第三例。

改动:
  • 新增 `.github/workflows/docs-links.yml`,镜像 control-bytes.yml 的形状:
    push/PR to main+develop + workflow_dispatch,**无 paths / 无 paths-ignore**,
    checkout + setup-node + 一行 `node scripts/check-doc-links.mjs`,无 install
    无网络。头注写清为什么不能加路径过滤。
  • **从 ci.yml 的 docs job 删掉重复步骤**(最小重复原则):新 workflow 的触发集
    是该 job 的严格超集,留着只会为同一条坏链多出一个红勾和一处会忘记同步的副本。
    原地留注释说明它去哪了、为什么别加回来。
  • 新增 `scripts/__tests__/docs-links-workflow.test.ts` 钉住形状:workflow 必须
    存在、必须门禁 PR、必须既无 `paths` 也无 `paths-ignore`、必须是**唯一**跑该
    脚本的 workflow;并以不变式表述「跑这个脚本的 workflow 必须是纯 docs PR 能
    启动的」,即使将来改名搬家也成立。扫描前先剥掉整行注释 —— ci.yml 的说明注释
    里仍然提到脚本名,不剥会误判成重复门禁。
  • `content/docs/guide/ci-cd-pipeline.md`:这一条不是顺手改文档,是
    `scripts/__tests__/ci-cd-pipeline-doc.test.ts` 的机械要求 —— 只加 workflow
    不加章节,该测试立刻红,报「docs-links.yml 无对应标题」。补:清单表一行、新章节
    (含为什么无路径过滤)、ci.yml 任务表里 docs 行的更正(它不再跑链接检查)、
    以及 Link Checking 章节里 #3448 那个「已知缺口」的收口。

反向验证(方向先判后跑):把删掉的步骤加回 ci.yml —— 新测试如期两处红:
"is the only workflow that runs the link checker"(ci.yml + docs-links.yml)与
"every workflow that runs it is one a docs-only PR can start"(ci.yml 有
paths-ignore)。给 docs-links.yml 加 `paths: content/**` —— "carries NO path
filter" 如期红。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Aug 6, 2026 6:52am

Request Review

@yinlianghui
yinlianghui marked this pull request as ready for review August 6, 2026 06:45
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 6, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Aug 6, 2026
#3456 (docs(ci): 删掉 ci.yml 任务表里的幽灵 dev-server 行) 与本分支 (#3448)
都改了 content/docs/guide/ci-cd-pipeline.md,冲突落在 ci.yml 任务表的最后两行。

按并集解:
  • 取 main 的 #3456 全部改动 —— 删掉 `dev-server` 行、「Seven jobs」改为不写死
    数字、清单表 ci.yml 行改为「every job but test-coverage (push only)」、
    「What is *not* in ci.yml」补记 dev-server 的完整来龙去脉。
  • 叠加本分支 #3448 的四处改动 —— 清单表新增 `docs-links.yml` 行、新增
    「Internal Docs Links (docs-links.yml)」章节、任务表 `docs` 行改写为不再跑
    链接检查、Link Checking 章节里 #3448 那个「已知缺口」收口(#3449 的保留)。

冲突区实际只有 `docs`/`dev-server` 两行:`docs` 行取本分支的新措辞,`dev-server`
行按 main 删除。ci.yml 与两份测试文件无冲突,自动合并。

验证:
  • pnpm exec vitest run scripts/ → 10 files / 144 tests 全绿。其中 #3456 新加的
    4 条任务表双向 pin 与本分支 docs-links-workflow 的 7 条断言同时对并集文档
    通过(任务表首列 = ci.yml 的 6 个 job key,`docs` 的「Appears as」= Build Docs)。
  • node scripts/check-doc-links.mjs → "Docs links are valid.",exit 0。
  • 两个 workflow YAML 经 yaml.safe_load 解析通过。
  • node scripts/check-control-bytes.mjs → OK(3663 个文件);并对本次涉及的
    5 个文件单独做了 grep -naP 控制字节自查,无命中。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 6, 2026
Merged via the queue into main with commit 84bd39e Aug 6, 2026
17 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-3448-doclinks-own-workflow branch August 6, 2026 07:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

check-doc-links 挂在 ci.yml 的 docs job 上,对「纯 docs PR」永远不会触发(paths-ignore 含 content/**)

2 participants