Skip to content

feat(scripts): check-doc-links 扫描面第三扩 CONTRIBUTING/ROADMAP/docs (#3572) - #3589

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-3572-scan-roots-third-ext
Aug 7, 2026
Merged

feat(scripts): check-doc-links 扫描面第三扩 CONTRIBUTING/ROADMAP/docs (#3572)#3589
yinlianghui merged 1 commit into
mainfrom
claude/issue-3572-scan-roots-third-ext

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes#3572

SCAN_ROOTS 追加三行,全部沿用既有的 disk 规则,不新增规则类 / reason / hint:

{path: 'CONTRIBUTING.md',rule: 'disk'},{path: 'ROADMAP.md',rule: 'disk'},{path: 'docs',rule: 'disk'},

这三面正是 #3536 头注释里 "Still not bought" 点名的下一批,当时标价「one SCAN_ROOTS row each — plus fixing what that turns red」。红账已由 #3545 / PR #3571 单独付清(3 条死链),所以本次是纯三行

实测(与 #3571 的预告逐项吻合)

先预告再跑,四项全中:

文件可见链接可判定被围栏隐藏死链
CONTRIBUTING.md1151100
ROADMAP.md16400
docs/**15494700
合计177052100

node scripts/check-doc-links.mjsLinks are valid across 6 scan roots.,exit 0。零清理清单——对照 #3479(16 个死目标)、#3490(18 个)那种「门禁与欠账同时到货」。

docs/** 是三者中从未被量过的一面。Lychee 的扫描范围虽然列了它,但那个工作流只有 schedule + workflow_dispatch —— pull_request / push#3213 ruling B 被刻意注释掉,拦不住任何 PR。它的 49 条链接里 47 条此前从未被任何能让构建失败的东西解析过

已知边界:围栏内的链接看不见(如实写进头注释)

stripCode() 在扫描前抹掉围栏与行内代码(这正是相对链接检查得以安全开启的前提,#3536 已论证),所以围栏内的链接对本门禁不可见,死活都不可见

不是假想:CONTRIBUTING.md 共 25 条链接,10 条在围栏内,门禁真正判定的只有 1 条(其余 14 条是 #anchor 与外链)。那 10 条正是 #3570 的实例类——一段演示 docs 链接写法的围栏,其"正确示例"路由自己是死的。修那段文字是 #3570 的事;指出没有门禁够得着它是本注释的事。头注释同时写明为什么不该靠放宽 stripCode() 来补:围栏内合法地存在不是链接的 […](…),区分「示意路由」与「可执行路由」是另一个门禁的活。

#3570 的并行协调

本 PR 未触碰 CONTRIBUTING.md(#3570 正在改其内容)。真仓跑对该文件报出 0 条——与预期一致:它要修的三条死"示例"路由都在围栏内,stripCode 抹掉了。围栏边界测试用的是 fixture 而非真实文件内容,不与 #3570 的编辑抢同一段文本。

测试(+8,57 → 65)

pin 测试是否自动覆盖新行?一半是,一半不是 —— 这正是 #3542 自述里的 anti-vacuous-green 教训:

  • 两个既有 pin 测试用 toEqual 硬钉 SCAN_ROOTS / Object.keys,新行让它们响亮地红,已按新表扩写;
  • 逐根的 count 断言那一半不会自我扩展。原来只有前三根有下限,新行若打错字导致整棵树扫空,上面「无死链」的测试照绿。三行各自补了下限(CONTRIBUTING.md/ROADMAP.md 为 1,docs 为 ≥ 15)。

新 describe 覆盖三面的 reject/accept:#3545 真实死链形状、docs/递归遍历(15 个文件里 13 个在子目录,只开顶层会静默全绿)、离开 docs/ 的链接照收(无 collection 可逃)、无扩展名拼写与绝对 /... 照拒。

两处 control 链接:围栏边界测试与 docs/ vs content/docs/ 对照测试如果只断言「期望的那一条」,删掉扫描行它们会因什么都没扫而空绿。各加一条必被报出的 control 后,删行即红——已实测(见下)。

逆向验证(先定方向,再跑;四项全中)

#动作预告实际
1ROADMAP.md(单文件根)植入死链红,example-relative[example-relative] ROADMAP.md:1900 -> ./docs/NOWHERE-3572.md,exit 1
2同一条链接改放进围栏绿(这就是边界)✅ exit 0
3docs/adr/ 嵌套文件(目录根)植入死链[example-relative] docs/adr/9999-reverse-check.md:3,exit 1
4死链保留,撤掉三行绿——证明是这三行在干活Links are valid across 3 scan roots.,exit 0

测试层同做一次:撤掉三行后 7 个新增/扩写的测试变红,其中包含围栏边界测试——证明那条 control 链接确实让它无法空绿。全部植入项已还原,工作树只剩三个目标文件。

ci-cd-pipeline.md:三处被证伪,做最小事实订正(披露)

  1. 扫描面清单(第 254 行)——补三面;
  2. disk 规则适用文件的段落——补三面,并把「若改用 docs 规则会拒掉 61 条」按新扫描面重算为 111(旧 61 已复核确实准确,只是随扫描面变宽而过时);
  3. 双检查器对照表那一行——补三面,并标注 except 围栏内内容。

另加一段说明围栏边界,以免读者把该表读成全覆盖。该文件对 Lychee「deliberately not a PR gate」的描述本身正确,未动。

顺手发现(未在本 PR 修,已另立单)

#3587(observation-class,finding,未指派):scripts/check-doc-links.mjs:157 与测试文件 :853 两处称 Lychee 是 "weekly cron with continue-on-error",而 check-links.yml 实际是 fail: true根本没有 PR 触发器。结论「gates nothing」对,机制说反了——照该理由行事的人会去摘一行不存在的 continue-on-error,而真取消注释 pull_request: 会立刻变成 #3213 明令不要的硬门禁。属 #3536 既有注释,不在 #3572 改动面内,故只订正本 PR 新写的那句(按正确机制表述),旧两处留给 #3587

验证

pnpm exec vitest run scripts/ 16 files / 283 tests passed(check-doc-links 65,+8)
node scripts/check-doc-links.mjs Links are valid across 6 scan roots. (exit 0)
pnpm type-check:scripts exit 0
pnpm exec eslint (changed files) 0 errors
node scripts/check-control-bytes.mjs OK (3631 tracked text files)
grep -naP 控制字符自扫(超出门禁扫描面) clean

无 changeset:纯 CI 门禁改动,非用户可见特性。未触碰 content/docs/releases/


Generated by Claude Code

`SCAN_ROOTS` 追加三行,全部沿用既有的 `disk` 规则:
{ path: 'CONTRIBUTING.md', rule: 'disk' },
{ path: 'ROADMAP.md', rule: 'disk' },
{ path: 'docs', rule: 'disk' },
这三面正是 #3536 头注释里「Still not bought」点名的下一批,当时标价
「one SCAN_ROOTS row each — plus fixing what that turns red」。红账已由
#3545 / PR #3571 单独付清(3 条死链),所以本次是纯三行:实测 70 条链接、
52 条可判定、落地当日零死链——扩展该有的形状,对照 #3479(16 个死目标)
与 #3490(18 个)那种「门禁与欠账同时到货」。
`docs/**` 是三者中从未被量过的一面:Lychee 的扫描范围虽然列了它,但那个
工作流只有 schedule + workflow_dispatch,`pull_request`/`push` 按 #3213
ruling B 被刻意注释掉,拦不住任何 PR;它的 49 条链接里有 47 条此前从未被
任何能让构建失败的东西解析过。
不新增规则类、不新增 reason、不新增 hint。
头注释如实写下已知边界:`stripCode()` 在扫描前抹掉围栏与行内代码,所以
**围栏内的链接对本门禁不可见,死活都不可见**。这不是假想——CONTRIBUTING.md
的 25 条链接里 10 条在围栏内,门禁真正判定的只有 1 条。那 10 条正是 #3570
的实例类(演示 docs 链接写法的围栏,其"正确示例"路由自己是死的);修那段
文字是 #3570 的事,指出没有门禁够得着它是本注释的事。
测试(+8):
- 两个既有 pin 测试用 toEqual 硬钉 SCAN_ROOTS,新行会让它们**响亮地红**
——不是自动覆盖。逐根的 count 断言那一半才是不会自我扩展的:补齐三行
各自的下限,否则某行打错字导致整棵树扫空时上面的测试仍会绿。
- 新 describe 覆盖三面的 reject/accept,含 docs/ 递归遍历、离开 docs/ 的
链接照收(无 collection 可逃)、无扩展名拼写与绝对 `/...` 照拒。
- 围栏边界作为**决定**钉住,而非留成日后被误读为覆盖的静默缺口。该测试
与 docs/ vs content/docs 对照测试都带一条 control 链接:否则删掉扫描行
它们会因「什么都没扫」而空绿——本文件存在的意义就是防这个。
ci-cd-pipeline.md 三处被证伪,做最小事实订正:扫描面清单、disk 规则的
适用文件、双检查器对照表那一行;并把「若改用 docs 规则会拒掉 61 条」按新
扫描面重算为 111。另加一段说明围栏边界,以免读者把该表读成全覆盖。
Fixes#3572
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
@vercel

vercelBot commented Aug 7, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectuiIgnoredIgnoredAug 7, 2026 2:53pm

Request Review

@yinlianghui
yinlianghui marked this pull request as ready for review August 7, 2026 14:57
@yinlianghui
yinlianghui added this pull request to the merge queueAug 7, 2026
Merged via the queue into main with commit 6632114Aug 7, 2026
17 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-3572-scan-roots-third-ext branch August 7, 2026 15:55
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Aug 10, 2026
…) (objectstack-ai#3597)
`### Writing Documentation` 开头的「All docs are in `docs/`」停在搬迁前,而它
正是新贡献者「文档写在哪」的第一落点 —— 照它做的人会把新页面放进根 `docs/`,
站点上永远不出现。
改写为两句,按机制不按枚举:
- 站点页面在 `content/docs/**`,该根**只声明一处** ——
`apps/site/source.config.ts` 的 `dir: '../../content/docs'`,文件在该根下的
路径即其 `/docs` 路由;
- 仓库根 `docs/` **不属于站点**:放 ADR / 审计 / 架构笔记等内部材料,fumadocs
的 collection 根本不读它,因此不渲染、也没有 `/docs/...` 路由。
刻意**不写**「链接门禁不扫 `docs/`」一类的枚举式断言 —— objectstack-ai#3572 / PR objectstack-ai#3589 正要
把 `docs` 加进 `SCAN_ROOTS`,那句话落地当天就会变假。同节「Validating Links」
已经写了「read them there instead of trusting a list copied into prose」,本次
沿用同一种「指向声明处」的写法,与 objectstack-ai#3585 刚改写的门禁分工段一致。
顺带把紧随的围栏两行注释由「docs」改为「documentation site」,以免与新段落里
刚刚区分开的根 `docs/` 混读。两条命令 `pnpm site:dev` / `pnpm site:build` 经核
实在根 package.json 中存在,未改。
Fixesobjectstack-ai#3584
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Aug 10, 2026
… 条死链 (objectstack-ai#3622) (objectstack-ai#3649)
* feat(scripts): check-doc-links 扫描面第四扩 packages/*/README.md,并付清入场价的 11 条死链 (objectstack-ai#3622)
先量后付的第四次:红账先清零,再加扫描行,门禁首跑对真仓即绿。
11 条死链逐条查证后处置(全部改指实测存在的真实页,零删除):
- 三条 /api/PKG(components/core/react)——站点从来没有这个路由段
(apps/site/app/api 下只有 search/route.ts)。components 改指
/docs/components(Component Gallery,objectstack-ai#3629 给 vscode-extension 用过
的同一页),core 改指 /docs/api(站点自称的 API Reference 总页),
react 改指 /docs/core/schema-renderer(它主导出的参考页)。
- 四条指向 content/docs 下无 index 页的目录(core/fields/layout x2)——
fumadocs 不为裸目录生成路由,objectstack-ai#3603 正文的复核脚本把裸目录也算作候选
才误判为绿。core 改指 /docs/guide/architecture(Package Structure 一节
逐包说明 @object-ui/core),fields 改指 /docs/guide/fields(Field Registry,
正是该包的文档),layout 的 API Reference 改指 /docs/layout/app-shell、
Links 改指 /docs/guide/layout。
- /docs/types 完全不存在 → 改指 /docs/api/schema-reference,该页开头写着
「All types are available from @object-ui/types」。
- /examples 不是站点路由(objectstack-ai#3490 已确认)→ 改指
github.com/objectstack-ai/objectui/tree/main/examples,与
content/docs/utilities/vscode-extension.mdx 里同一条链接的写法一致。
- 两条磁盘路径:docs/SHADCN_SYNC.md 从未存在,真正的完整指南是同包的
README_SHADCN_SYNC.md(278 行);vscode-extension 没有 LICENSE 文件
(39 个包里 4 个没有),按该 README 已有的仓根文件写法改指
blob/main/LICENSE。
扫描行沿用 disk 规则:包 README 在 npm 与 GitHub 上被阅读,相对链接是
磁盘路径语义,与 examples/README/CONTRIBUTING/ROADMAP/docs 同类,无需新
规则类。同一条理由也决定了上面修好的站内链接必须保留 origin——GitHub 与
npm 都把开头的 / 解析到它们自己的域名。
该行是表里唯一带通配符的一条,故 collectFiles 增加 expandWildcard():只
认整段的 *,再复杂的写法直接抛错而不是静默匹配零个路径——扫描面被悄悄
丢掉是这个门禁唯一不能有的失效模式。
测试:SCAN_ROOTS 的 toEqual 与逐根 count 扩写;新根另加「可判定 href 数」
下限(200 条,其中 47 条站内绝对 URL),因为文件数只能证明通配符展开了,
证明不了这批文件里有东西可判;新增 7 条用例覆盖四种死链形状、通配符展开、
只收 README 的边界、packages/node_modules 排除、disk 与 docs 规则的对照对,
以及非整段通配符抛错。
逆向验证(方向先定后跑):植入两条死链(相对磁盘路径 + 站内绝对 URL 各一)
→ 门禁红,正是那 2 条;仅撤掉扫描行、死链留在原地 → 绿,证明是该行在干活;
还原后 7 根全绿。测试层同样验证:撤行后恰好 7 条用例红,唯二直接调
collectFiles 的两条保持绿——与预测一致。
不加 changeset:改的是包 README 的链接与 CI 脚本,不触发任何包的版本
发布,与 objectstack-ai#3589/objectstack-ai#3629 仓例一致。
Fixesobjectstack-ai#3622Fixesobjectstack-ai#3603
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
* docs(scripts): 头注释里 11 条的处置措辞改准 — 全部改指,一条没删
原句写成「Each was resolved to a real page, or dropped where none exists」,
但本次 11 条逐条都找到了实测存在的对位页面,零删除。措辞改准,并点明与
objectstack-ai#3603 那 9 条的差别:那 6 条删掉是因为它们假设了一整个从未写过的
/docs/packages/... 命名空间,本单这 11 条各自都有真实归属。
顺带把「七个包,其中五个 objectstack-ai#3603 从未打开」一句的中英夹缠语序理顺。纯注释,
零行为改动。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
---------
Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Aug 10, 2026
…ai#3587) (objectstack-ai#3648) (objectstack-ai#3656)
两处注释称 lychee 是「weekly cron with continue-on-error」,结论「gates
nothing」对,机制反了:check-links.yml 里没有任何 continue-on-error,第 77 行
是 fail: true,`on:` 只有 workflow_dispatch + schedule('17 4 * * 0'),push 与
pull_request 被注释掉并附 ⛔ Do NOT enable(objectstack-ai#3213 ruling B)。按错误理由行事的
人会去摘一行不存在的 continue-on-error,而真实风险相反 —— 取消注释
pull_request: 会让它立刻变成走网络的硬门禁。
改成同一文件 :194 起已有的正确表述(objectstack-ai#3589 头注释措辞):schedule +
workflow_dispatch、无 PR 触发器,所以它谁也拦不住。
同时删掉 judgeHref() 里被逐字复制两遍的那 4 行注释(objectstack-ai#3629 合并时的重复粘贴)。
纯注释改动,零行为变化;test 那处只改说明文字,断言未动。scripts/ 非发布包且
无用户可见变化,故无 changeset。
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

check-doc-links 扫描面第三扩:CONTRIBUTING.md + ROADMAP.md + docs/**(实测 70 链接、今日零死链、纯配置三行)

2 participants

@yinlianghui@claude