Skip to content

ci(skills): skills 指南正文反引号里的仓内路径上门禁,豁免走双向陈旧检测的 baseline (#3735) - #3864

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-3735-skills-path-gate
Aug 8, 2026
Merged

ci(skills): skills 指南正文反引号里的仓内路径上门禁,豁免走双向陈旧检测的 baseline (#3735)#3864
yinlianghui merged 1 commit into
mainfrom
claude/issue-3735-skills-path-gate

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes#3735

缺口

skills/objectui/** 的指南是本仓 agent 写代码的直接输入,正文大量用反引号给出仓内路径当坐标,而此前没有任何门禁校验它们存在scripts/check-doc-links.mjs 两头都不沾:它的 SCAN_ROOTS 没有 skills 一行,而且它判的是 markdown 链接,反引号里的裸路径本来也不在它眼里 —— 所以单纯给它扩面也看不见这一类。

代价付过两轮,两轮都靠人肉阅读发现:#3713 / PR #3729,以及 #3730 / PR #3734(同一文件 13 个真实符号指向不存在的目录)。

这类缺陷贵得不成比例:符号通常是真的,只有坐标错了,所以没人拿到编译错误 —— agent 从 Read 拿到「文件不存在」,以为是自己搜得笨,再花一整圈重新定位指南声称已经替它定位好的东西。它还天然复发:app-shell 抽取那批 commit 搬走代码时,没有任何东西提醒指南跟着改。

门禁

scripts/check-skills-paths.mjs:读 skills/ 下每个 markdown,把正文反引号 span 里以五个顶层目录(apps/packages/examples/scripts/content/)开头、不含空格的 token 逐个 existsSync。三条排除都是规则而不是豁免,因为它们都不是「某文件存在」这个断言:

排除今天指南里的实例理由
span 里含空白PR #3856 新加的 grep -rn … packages/app-shell/src 自查命令行散文、命令行或类型,不是路径 —— 凭此一条就出局,不需要任何名单条目
含 glob 元字符或占位段packages/components/src/ui 下的受保护 glob;framework 那条带角括号 domain 占位段的 schema 路径是形状不是位置,对它 existsSync 无意义
围栏代码块创建文件的 bash示例可以合法地写出读者「即将创建」的文件

main@6422aa891 实测:18 个指南文件、91 个候选 span、其中 5 个是 pattern,86 条路径断言里 85 条落地。 与 issue 正文的 34/33 有出入 —— 那是 PR #3734 当时用 8 行脚本在单文件上量的读数,本 PR 以全面实测为准(单看 console-development.md:54 候选 / 52 断言 / 1 缺)。

豁免与它为什么不会烂掉

scripts/skills-path-baseline.json 只收「指南刻意声明其不存在」的路径,今天恰好一条:console-development.md 的 Key contexts 一节存在的意义就是纠正那个反复出现的错猜,原话是根本没有 apps/console/src/context/ 这个目录。

该条目是双向红的棘轮:

  • 路径哪天真出现在磁盘上 → 门禁红并点名(那句话已经变成假的,先改散文再删条目);
  • 扫描不再命中该条目 → 门禁也红(散文被改写或文件搬家,条目成了死重)。

条目按「文件 + token」定位,刻意不含行号:指南散文一直在动(PR #3856 刚搬过这一段),行号定位会在每次无关编辑后陈旧。先例是 check-control-bytes.mjsKNOWN_OFFENDERSscripts/i18n-call-site-key-baseline.json

另有空判定护栏:扫到 0 个文件或 0 条断言即红 —— 「什么都没查到」不能算干净。

反向验证(方向先判后跑,五个方向全部与预判一致)

方向预判实跑
真实 skills/绿,85/86 + 1 豁免check-skills-paths: OK (85/86 stated path(s) resolve across 18 guide file(s); 1 baselined)
fixture 种一个死路径红并点名1 stated path does not exist + demo.md:3 — packages/app-shell/src/layout/Gone.tsx,exit 1
豁免条目满足绿OK (1/2 … 1 baselined),exit 0
豁免路径出现在磁盘上红并点名1 baselined path now EXISTS on disk + 条目的 reason/issue,exit 1
豁免不再被命中红并点名1 baseline entry the scan never met,exit 1
扫描面为空scanned 0 markdown file(s) … found 0 path assertion(s),exit 1

前三条与后三条都在 scripts/__tests__/check-skills-paths.test.ts 里有对应的 fixture 用例(临时目录树,不碰真 skills/:committed fixture 必须自带一条故意的死路径,迟早会被别的门禁扫到)。

接线

按同族三个门禁(control-bytes.ymldocs-links.ymlchangeset-guard.yml)的挂法:独立 workflow、无任何 paths / paths-ignore 过滤、订阅 merge_group、根脚本 pnpm check:skills-paths

为什么不塞进 ci.yml:本门禁扫描面全是 markdown,而 ci.ymlpush 触发器把 '**/*.md' 列进 paths-ignore、GitHub 又没有 per-job 路径过滤 —— 放进去就等于重建它要堵的洞(docs-links.yml 自家 header 的原话,#3448)。

content/docs/guide/ci-cd-pipeline.md 的 workflow 清单在两个方向上都被 ci-cd-pipeline-doc.test.ts 钉住,所以新 workflow 连带一节文档与一行清单;merge-queue-reporting.test.tsMUST_SUBSCRIBE_MERGE_GROUP 也加了一条,让这份订阅将来被删掉时会红。

刻意不做

验证

pnpm exec vitest run scripts/__tests__ --maxWorkers=2 # 22 files / 442 tests passed(新增 31)
pnpm type-check:scripts # tsc -p tsconfig.scripts.json,干净
pnpm exec turbo run type-check --concurrency=2 # 78 successful, 78 total
node scripts/check-control-bytes.mjs # OK,3766 tracked text files
node scripts/check-skills-paths.mjs # OK,85/86 + 1 baselined
pnpm docs:check-links # Links are valid across 7 scan roots

Generated by Claude Code

`skills/objectui/**` 的指南是本仓 agent 写代码的直接输入,正文大量用反引号给出
仓内路径当坐标,而此前无任何门禁校验它们存在。`check-doc-links.mjs` 两头都不沾:
它的 SCAN_ROOTS 没有 skills 一行,而且它判的是 markdown 链接,反引号里的裸路径
本来也不在它眼里。代价付过两轮,两轮都靠人肉阅读发现 —— #3713/PR #3729#3730/PR #3734(同一文件 13 个真实符号指向不存在的目录)。
这类缺陷贵得不成比例:符号通常是真的,只有坐标错了,所以没人拿到编译错误 ——
agent 从 Read 拿到「文件不存在」,以为是自己搜得笨,再花一整圈重新定位指南声称已
经替它定位好的东西。它还天然复发:app-shell 抽取那批 commit 搬走代码时,没有任何
东西提醒指南跟着改。
## 门禁
`scripts/check-skills-paths.mjs` —— 读 `skills/` 下每个 markdown,把正文反引号
span 里以五个顶层目录(apps/ packages/ examples/ scripts/ content/)开头、不含空格
的 token 逐个 existsSync。三条排除都是**规则**而不是豁免,因为它们都不是「某文件
存在」这个断言:
- span 里含空白 —— 散文、命令行或类型,不是路径(PR #3856 新加的自查命令行正好
是这个形状,凭此一条就出局,不需要任何名单条目);
- 含 glob 元字符或占位段 —— 是形状不是位置,对它 existsSync 无意义;
- 围栏代码块 —— 示例可以合法地写出读者「即将创建」的文件。
main@6422aa891 实测:18 个指南文件、91 个候选 span、其中 5 个是 pattern,86 条
路径断言里 85 条落地。
## 豁免与它为什么不会烂掉
`scripts/skills-path-baseline.json` 只收「指南刻意声明其不存在」的路径,今天恰好
一条:console-development.md 的 Key contexts 一节存在的意义就是纠正那个反复出现的
错猜,原话是根本没有 `apps/console/src/context/` 这个目录。该条目是**双向**红的
棘轮 —— 路径哪天真出现在磁盘上,门禁红并点名(那句话已经变成假的);扫描不再命中
该条目,门禁也红(散文被改写了,条目成了死重)。条目按「文件 + token」定位,刻意
不含行号:指南散文一直在动(PR #3856 刚搬过这一段),行号定位会在每次无关编辑后
陈旧。
反向验证(方向先判后跑,五个方向全部与预判一致):真实 skills 面绿(85/86 + 1
豁免);fixture 种死路径红并点名 file:line — token;豁免条目满足则绿;豁免路径出现
在磁盘上则红;豁免不再被命中则红。另有空判定护栏:扫到 0 个文件或 0 条断言即红 ——
「什么都没查到」不能算干净。
## 接线
按同族三个门禁(control-bytes.yml、docs-links.yml、changeset-guard.yml)的挂法:
独立 workflow、无任何 paths 过滤、订阅 merge_group、`pnpm check:skills-paths`。
本门禁扫描面全是 markdown,而 ci.yml 的 push 触发器把 `'**/*.md'` 列进
paths-ignore、GitHub 又没有 per-job 路径过滤,放进 ci.yml 等于重建它要堵的洞
(#3448 的原话)。ci-cd-pipeline.md 的 workflow 清单在两个方向上都被钉住,所以
新 workflow 连带一节文档与一行清单。
扫描面刻意不含 `content/docs/**`:扩面自带一批要清的红,check-doc-links 学过三遍
(#3479/#3490/#3545),先量红再单独落地。五前缀名单同理 —— 补上本仓另外五个顶层
目录实测为 +2 候选、0 新红,便宜,但仍然是一个刻意的决定。
无 changeset:同族三个门禁脚本(check-control-bytes、check-i18n-call-site-keys、
check-changeset-presence)落地时都没带,且本改动不碰任何发版包 src/。
Co-authored-by: Claude <noreply@anthropic.com>
@vercel

vercelBot commented Aug 8, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectuiIgnoredIgnoredAug 8, 2026 10:24pm

Request Review

@yinlianghuiClaude

Copy link
Copy Markdown
CollaboratorAuthor

✅ 验收(PM,session session_01GTRjn8xBqp75dk7kFupVRt)

实物核验:origin/claude/issue-3735-skills-path-gate4343ebf66,7 文件全部新增/追加(+965/−0),trailer 0 命中;未改任何 skills/*.md 正文,与在飞 #3546s6/#3746/#3741/#3848 零相交(scripts/tests 下用独立文件名)。
CI 终态(独立复核):18 检查全部 completed,零失败 —— 新 context Skill Guide Path Check 首跑即绿,四 shard/Type Check/Lint 全绿。

裁定要点:

  • 分诊缺省形状全部落实:独立脚本 + baseline JSON(仿 i18n 先例)、只扫 skills/**;三类不可解析 token(含空白/glob 元字符/围栏代码块)做成规则而非豁免,豁免面因此收到恰好 1 条。
  • 豁免设计超出要求地好:按「文件 + token」定位刻意去行号(PR3856 刚移动过该文件段落,行号键会在无关编辑上腐烂)、双向陈旧自动红(路径出现在磁盘 → 红;扫描不再命中 → 红)+ 空判定护栏(0 文件/0 断言即红)。
  • 读数纪律:实测 18 文件/86 断言/85 落地与 issue 的 34/33 不一致 → 以实测为准并解释了差异来源(issue 是单文件量的),正确执行。
  • 五方向反向验证预判全中(真实面绿/种死路径红/豁免绿/豁免复活红/死豁免红);CI 接线的两处联动(workflow 清单钉、merge_group 订阅钉)是既有门禁强制的,非扩面。
  • 无 changeset 有同族三门禁先例 + 不碰发版包 src 双重依据。

转 ready 并挂 auto-merge。#3867(content/docs 扩面量红读数:113 条中 10 缺,含 4 疑似真死路径与三个新排除类别)正是本单要求的「扩面先量红」作业,归分诊席定级。


Generated by Claude Code

@yinlianghui
yinlianghui marked this pull request as ready for review August 8, 2026 22:39
@yinlianghui
yinlianghui added this pull request to the merge queueAug 8, 2026
Merged via the queue into main with commit 7437064Aug 8, 2026
19 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-3735-skills-path-gate branch August 8, 2026 22:40
Sign up for freeto 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.

docs(skills): guide 里反引号包裹的仓内路径无任何门禁校验 —— #3713/#3730 两轮 13+ 处死路径都是靠人肉发现的

2 participants

@yinlianghui@claude