Uh oh!
There was an error while loading. Please reload this page.
feat(scripts): check-doc-links 扫描面第三扩 CONTRIBUTING/ROADMAP/docs (#3572) - #3589
Merged
Conversation
`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_01GTRjn8xBqp75dk7kFupVRtThe latest updates on your projects. Learn more about Vercel for GitHub. |
yinlianghui
marked this pull request as ready for review
August 7, 2026 14:57
This was referenced Aug 7, 2026
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 7, 2026
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#3572
SCAN_ROOTS追加三行,全部沿用既有的disk规则,不新增规则类 / reason / hint:这三面正是 #3536 头注释里 "Still not bought" 点名的下一批,当时标价「one SCAN_ROOTS row each — plus fixing what that turns red」。红账已由 #3545 / PR #3571 单独付清(3 条死链),所以本次是纯三行。
实测(与 #3571 的预告逐项吻合)
先预告再跑,四项全中:
CONTRIBUTING.mdROADMAP.mddocs/**node scripts/check-doc-links.mjs→Links 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 教训:
toEqual硬钉SCAN_ROOTS/Object.keys,新行让它们响亮地红,已按新表扩写;CONTRIBUTING.md/ROADMAP.md为 1,docs为 ≥ 15)。新 describe 覆盖三面的 reject/accept:#3545 真实死链形状、
docs/递归遍历(15 个文件里 13 个在子目录,只开顶层会静默全绿)、离开docs/的链接照收(无 collection 可逃)、无扩展名拼写与绝对/...照拒。两处 control 链接:围栏边界测试与
docs/vscontent/docs/对照测试如果只断言「期望的那一条」,删掉扫描行它们会因什么都没扫而空绿。各加一条必被报出的 control 后,删行即红——已实测(见下)。逆向验证(先定方向,再跑;四项全中)
ROADMAP.md(单文件根)植入死链example-relative[example-relative] ROADMAP.md:1900 -> ./docs/NOWHERE-3572.md,exit 1docs/adr/嵌套文件(目录根)植入死链[example-relative] docs/adr/9999-reverse-check.md:3,exit 1Links are valid across 3 scan roots.,exit 0测试层同做一次:撤掉三行后 7 个新增/扩写的测试变红,其中包含围栏边界测试——证明那条 control 链接确实让它无法空绿。全部植入项已还原,工作树只剩三个目标文件。
ci-cd-pipeline.md:三处被证伪,做最小事实订正(披露)except围栏内内容。另加一段说明围栏边界,以免读者把该表读成全覆盖。该文件对 Lychee「deliberately not a PR gate」的描述本身正确,未动。
顺手发现(未在本 PR 修,已另立单)
#3587(observation-class,
finding,未指派):scripts/check-doc-links.mjs:157与测试文件:853两处称 Lychee 是 "weekly cron withcontinue-on-error",而check-links.yml实际是fail: true且根本没有 PR 触发器。结论「gates nothing」对,机制说反了——照该理由行事的人会去摘一行不存在的continue-on-error,而真取消注释pull_request:会立刻变成 #3213 明令不要的硬门禁。属 #3536 既有注释,不在 #3572 改动面内,故只订正本 PR 新写的那句(按正确机制表述),旧两处留给 #3587。验证
无 changeset:纯 CI 门禁改动,非用户可见特性。未触碰
content/docs/releases/。Generated by Claude Code