Skip to content

docs(getting-started): quick-reference 的 Kernel 计数按证据补回两行,并加一道计数校验门 (#6319) - #6357

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-6319-quick-reference-counts
Aug 7, 2026
Merged

docs(getting-started): quick-reference 的 Kernel 计数按证据补回两行,并加一道计数校验门 (#6319)#6357
hotlong merged 1 commit into
mainfrom
claude/issue-6319-quick-reference-counts

Conversation

@hotlong

Copy link
Copy Markdown
Contributor

Fixes#6319

先说结论:issue 报的三处计数只有一处是真的,而那一处的真相在标题那一侧 —— 不是数字过时,是两行漂到了别的小节。另外两处是测量假象,已逐一复现其成因。

⚠️ 基线是 #6304 合并后main(a585374,含 5b103d6)。立单人的读数取自 #6304 之前,我在自己的基线上重新数过。

一、逐小节三数对照

"实测行数" 由脚本给出,不是手数(手数正是本单要防的错误来源,见第二节)。

小节标题声明实测行数(修前)域内 .zod.ts判定修后
Data171730相符17
UI111117相符11
Kernel171532表格漏了两行17
System181837相符(#6304 已同步)18
AI111111相符11
API171728相符(#6304 已同步)17
Automation5514相符5
Security334相符3
Identity445相符4
Cloud5511两行本属 Kernel3
Integration111相符1
Shared5513相符5
QA111相符1

(N schemas) 的语义:是"本表行数",不是"该域 schema 数"

第 4 列存在的意义是证否它自己:13 个小节里,声明数与域内 .zod.ts一处都对不上(Data 声明 17 而 packages/spec/src/data/ 有 30 个 .zod.ts;System 18 对 37;API 17 对 28)。而声明数与表格行数在 13 个小节里对上了 12 个。所以这一页是一份精选索引,(N schemas) 说的是"这张表有几行",每行一个源文件。

这个判定是后面所有取舍的前提:"某个 schema 存在但不在表里" 本身不是缺陷,否则 Data 就该有 30 行。因此本 PR 不做索引扩编,只修计数确实对不上的那一处。

二、Cloud 5/6 与 Shared 5/12 是测量假象 —— 已复现成因

这两处在我的基线上不存在,在 #6304 之前的 main 上也不存在(两个版本上实测都是 5/5 与 5/5)。我用同样的错法把 issue 的三个数字逐一复现了:

立单人的扫描器把小节标题识别为复数(N schemas),于是:

  • ## Integration Protocol (1 schema)## QA Protocol (1 schema) 两个单数标题不被识别,其行数被记到上一小节;
  • 小节只在"下一个被识别的标题"处结束,所以 Shared 一路吃到文末,把 ### Declarative Endpoints 那张规则表的 6 行(| **Path shape** | ... 等)也算了进去。

于是:

小节复现出的数拆解
Kernel15真实行数,这处是真的
Cloud6自身 5 + Integration(单数标题)1
Shared12自身 5 + QA(单数标题)1 + Declarative Endpoints 规则表 6

#6304 之前的 main 上跑该错法,输出与 issue 表格逐字一致(Kernel 17/15、Cloud 5/6、Shared 5/12)。

⚠️ 这不是挑立单人的错 —— 恰恰相反,它把本单最有价值的部分点出来了:这一页靠人工清点是不可靠的,而且错得很像真的。两个陷阱现在都被新门的 self-test 钉住(第五节 case 4/5)。

三、真实的那一处:两行漂到了别的小节,标题一侧是真相

Kernel 声明 17、表里 15,差 2 行。这两行没有丢,它们坐在 Cloud Protocol 小节里:

Source File 列源文件实际位置参考页实际位置
Plugin Registryplugin-registry.zod.tspackages/spec/src/kernel/content/docs/references/kernel/plugin-registry.mdx
Plugin Securityplugin-security.zod.tspackages/spec/src/kernel/content/docs/references/kernel/plugin-security.mdx

三项机械证据全部指向 kernel:

  1. 源文件在 kernel —— packages/spec/src/cloud/没有同名文件(ls packages/spec/src/cloud/plugin-* 报 No such file);
  2. 参考页在 kernel —— 参考页由 build-docs.ts 按 spec 的目录结构生成,两页都生成在 references/kernel/,references/cloud/ 下没有 plugin-*;ci(check-links): 恢复 pull_request 断链门,仅检仓内链接、advisory-first (#6028) #6304 已经因为这个把 Plugin Security 的链接从 /docs/references/cloud/... 改成了 /docs/references/kernel/...,也就是说这两行的链接今天已经指向 kernel,只有它们所在的小节还留在 Cloud;
  3. 数字自洽 —— 15 + 2 = 17,不多不少正是 Kernel 标题声明的数。

所以判定 标题的 17 是真相,处置是"移",不是"改标题":

  • 两行移回 Kernel(按既有的 Plugin * 字母序插在 Plugin Loading 之后),Kernel 标题 17 保持不动;
  • Cloud 随之 5 → 3。

⛔ 我没有采用"把 17 改成 15"这个更省事的写法 —— 那会让声明去迁就现状,而现状恰恰是错的那一侧:两个 kernel schema 会继续挂在 "Cloud Protocol — Environments, marketplace, licensing, and multi-tenancy" 底下,而它们的 Source File 列和链接都写着 kernel。读者用 Source File 列去仓里找 schema,这一列必须和小节自洽。

一处连带改名:两行移回后,Kernel 里会出现两个都叫 "Plugin Security" 的条目(一个指 plugin-security.zod.ts,一个指 plugin-security-advanced.zod.ts)。把后者改名为 "Plugin Security Advanced" —— 与其源文件名、与其生成参考页的 title: 字段(实测就是 Plugin Security Advanced)、与邻座 "Plugin Lifecycle Advanced" 的约定三者一致。同名两行指向不同页面,是移动本身引入的缺陷,必须在同一次改动里消掉。

四、该页是手写的(范围 2 的判定)

判据实测
文件头 AUTO-GENERATED 标记无(content/docs/references/** 的生成物都有)
有没有生成器写它没有。packages/spec/scripts/build-docs.ts 的输出根是 content/docs/references(第 62 行 DOCS_ROOT),只写这一棵树
全仓提到 quick-reference 的地方4 处,没有一处是生成:build-docs.ts 的一句历史注释、其测试里同一句、content/docs/getting-started/meta.json 的导航项、apps/docs/redirects.mjs 的两条重定向
AGENTS.md 文档护栏表content/docs/getting-started/ 一行明写 hand-written

手写。所以走范围 2 的第一条:加计数校验门。

五、新门:check:quick-reference-counts

落点与既有 check:* 家族同址:

  • scripts/check-quick-reference-counts.mjs(新)
  • package.json 一行:"check:quick-reference-counts": "... --self-test && ..."(与家族同写法)
  • .github/workflows/lint.ymlESLint job 一步,紧跟 check:role-word,与其余 docs 类守卫同址

门只做一件事:读该页每个 (N schemas) 标题,与其表格行数比对,不符即红,点名小节、声明数、实际行数、行号

两个抗错设计,都是从第二节的假象里学来的:

  1. 标题计数认 (N schema)(N schemas)(单复数都认);
  2. 小节在下一个 ## 标题处结束 —— 不论那个标题有没有计数。这条正是防止小节一路吃到文末、把无关表格算进来。

结构变化响亮报错,不静默放行。 一个悄悄不再认识自己页面的计数器会永远报绿,那正是这道门要防的失败模式,只是高了一层。所以以下都是 error 而不是 skip:一个小节都没找到;某个 ... Protocol 标题没有计数;某个小节没有表 / 有多张表 / 表里零行。

self-test 覆盖(9 组,--self-test)

#断言极性
1好页面逐小节量出的三元组等于期望值肯定式
1b好页面零 finding否定式(见下)
2标题数字改错 ⇒ 恰好 1 条 count finding,且消息含小节名 + 声明数 + 实际数肯定式
3删掉一行表格 ⇒ 红,且消息含两个数字肯定式
4单数(1 schema) 标题被当作真小节(把它的数字改错必须变红)肯定式
5末尾小节量出的行数 = 1(不吃下面那张规则表)肯定式(断言实测值,不是断言"无 finding")
6标题格式改掉 ⇒ structure finding 点名它肯定式
7小节的表没了 ⇒ structure finding肯定式
8整页认不出来 ⇒ structure finding(而不是零比较报绿)肯定式
9一个小节两张表 ⇒ structure finding(不静默相加)肯定式

case 4 与 case 5 就是第二节两个陷阱的定桩:用复数-only 的正则,case 4 得到 0 条 finding;用"吃到文末"的作用域,case 5 量出 3 而不是 1。

六、反向验证(先申报,后执行)

声明 A(修正面)—— 成立

预期:改后每个小节的 (N schemas)、其表格行数、以及第一节判定的真相三者一致。实测 13/13 相符:

✓ content/docs/getting-started/quick-reference.mdx: 13 section(s), every "(N schemas)" heading matches its table.

逐小节三数见第一节表格(修后一列)。

声明 B(门会咬)—— 三段全部成立,另加一段更强的

预期在执行前写下:B1 改错标题数字 ⇒ 红且点名小节与两个数字;B2 删掉一行表格 ⇒ 红;B3 恢复 ⇒ 绿。另加 B4:把门跑在修复前的基线上 ⇒ 必须红,且点名 Kernel 17/15(如果 Cloud/Shared 真的也不符,这里会一起报出来 —— 这是对第二节结论的独立检验)。

操作预期实测
B1Shared 标题 5 → 7红,点名EXIT=1[count] section "Shared Protocol" declares 7 schema(s) but its table has 5 row(s)
B2删掉 Cloud 的 Tenant 行EXIT=1[count] section "Cloud Protocol" declares 3 schema(s) but its table has 2 row(s)
B3恢复绿EXIT=0,13 小节全绿
B4跑在 origin/main#6304 之前的 main 上红,只点 Kernel两个版本都是 1 条 finding:[count] line 57: section "Kernel Protocol" declares 17 schema(s) but its table has 15 row(s)

B4 是本单结论的独立佐证:同一把尺子在两个历史版本上都只报 Kernel 一处,Cloud 与 Shared 一次都没报过。

探针未留残留:git diff --stat origin/main -- content/docs/getting-started/quick-reference.mdx4 insertions(+), 4 deletions(-),即本 PR 的意图改动本身。

断言极性(申报)

上表 B1/B2/B4 与 self-test 的 case 2–9 都是肯定式:门被删空或退化,它们会变红。

唯一的否定式断言是 self-test case 1b("好页面零 finding") —— 门若被掏空成"永远返回空",这一条会平凡成立、无法转红。所以我没有让它独自承担 case 1:同一组固件里用肯定式的 case 1 断言逐小节量出的 [标题, 声明, 实际] 三元组等于具体值,掏空的门在这里立刻失败。case 5 也是同样的处理 —— 本可以写成"不误报",改写成断言实测行数 = 1,于是它同样是肯定式。

声明 C(不造死链)—— 成立

预期:改后该页所有仓内链接目标在仓内存在。

本地无 lychee 二进制,故按 --offline --root-dir (workspace)/content --fallback-extensions mdx,md 的同一解析规则逐条判定(root-relative → content/... + {,.mdx,.md,/index.mdx,/index.md}):118 条仓内链接,0 条死链,1 条外链在 --offline 下被排除。

结构上也不可能造出死链:本 PR 没有新增任何链接目标 —— 两行是整行搬家(其 /docs/references/kernel/plugin-registry/docs/references/kernel/plugin-security 两个目标在 #6304 的绿跑里已被检过),改名那行只改可见文字、目标未动。

七、门禁 EXIT 表(均在 git add 之后跑)

命令EXIT输出
pnpm check:doc-authoring0365 files clean
pnpm check:role-word0OK (44 baselined file(s), no new occurrences)
pnpm check:nul-bytes0scanned 6003 tracked text file(s) ... no raw ASCII control bytes
pnpm check:docs-audit-scope0scope is in sync with content/docs/: 178 hand-written doc(s)
pnpm check:quick-reference-counts(新)0self-test 9 组 + 13 小节全绿
pnpm check:workflow-status-functions(动了 lint.yml)0scanned 22 workflow file(s), 41 job(s)
lint.yml YAML 解析 + 落位核对0解析通过;新步骤在 jobs.lint(name: ESLint)内,共 35 步
npx eslint scripts/check-quick-reference-counts.mjs0无输出
pnpm --filter @objectstack/spec check:generated --reconcile-only0见下

最后一条是特意跑的:check:generated 的元门会把 check:/gen: 脚本名与 package.json 双向对账,未分类者直接红。实测它读的是 packages/spec/package.json(pkgRoot = packages/spec,脚本第 39/407 行),而新门接在package.json,故不在其对账面内 —— 已实跑确认绿(18 check: + 13 gen: scripts, all classified)。

另:控制字节自查(grep -naP 覆盖 NUL 之外的整个扫描面)对四个改动文件均无命中。

八、不在本 PR 里

  • connector-auth 参考页(issue 观察二):packages/spec/src/shared/connector-auth.zod.ts 存在,content/docs/references/shared/connector-auth.mdx不存在;ci(check-links): 恢复 pull_request 断链门,仅检仓内链接、advisory-first (#6028) #6304 的处置是保留该行、去掉链接,所以今天读起来是"有这个 schema,但没有参考页可看"。补一整页是独立的写作工作量,按派单不在本单;本 PR 未新建该页,也未动那一行。需要补页请另立单。
  • 索引扩编:不给任何小节补"schema 存在但不在表里"的行(理由见第一节:这一页是精选索引,不是穷举;补了 Cloud 就得补 Data 的另外 13 个)。
  • required 集:未改动。新门与 ci(check-links): 恢复 pull_request 断链门,仅检仓内链接、advisory-first (#6028) #6304 同理走 advisory —— 它跑在 ESLint job 里,该 job 本身已是 required,故无需单独动 required 名单。
  • 未建 changeset:纯文档 + 一道仓内门禁,不发布任何包 ⇒ 走 skip-changeset 标签。
  • ⛔ 未动 packages/spec/**(只读清点)、content/docs/references/**.github/workflows/check-links.ymlcontent/docs/releases/**

Generated by Claude Code

…6319)
三处计数只有一处是真的。#6319 报的 Kernel 17/15 属实;Cloud 5/6 与
Shared 5/12 是测量假象 —— 立单人的扫描器只认复数 `(N schemas)`,于是
`## Integration Protocol (1 schema)` 与 `## QA Protocol (1 schema)` 两个
单数标题不被识别、其行数被记到上一小节;而且小节只在下一个"被识别的"
标题处结束,Shared 因此一路吃到文末,把 `### Declarative Endpoints`
规则表的 6 行也算了进去(5+1+6=12)。三个数字已用同样的错法逐一复现。
真实的那一处不是标题过时,而是两行漂到了别的小节:
plugin-registry.zod.ts 与 plugin-security.zod.ts 都在 packages/spec/src/kernel/
(cloud/ 下没有同名文件),参考页也生成在 content/docs/references/kernel/,
它们却列在 Cloud Protocol 小节里。15 + 2 = 17,正是 Kernel 标题声明的数。
故判定标题一侧为真:两行移回 Kernel(标题 17 不动),Cloud 随之 5 → 3。
移回后 Kernel 会出现两个同名 "Plugin Security",按源文件名与参考页标题
把指向 plugin-security-advanced 的那行改名为 "Plugin Security Advanced"
(与邻近的 "Plugin Lifecycle Advanced" 同一约定)。
该页是手写的 —— build-docs.ts 只写 content/docs/references/,AGENTS.md
的文档护栏表也把 content/docs/getting-started/ 列为手写 —— 所以按
declared = enforced 加一道计数门:每个 `(N schemas)` 标题与其表格行数
比对,不符即红并点名小节与两个数字。门对结构变化刻意响亮报错而不是静默
放行(零小节、无计数的 Protocol 标题、小节无表/多表/空表都是 error),
因为一个悄悄不再认识自己页面的计数器会永远报绿 —— 那正是这道门要防的
失败模式,只是高了一层。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3
@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)
objectstackIgnoredIgnoredAug 7, 2026 3:04pm

Request Review

@hotlonghotlong added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed size/m labels Aug 7, 2026 — with Claude
@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation ci/cd dependencies Pull requests that update a dependency file labels Aug 7, 2026
@hotlong
hotlong marked this pull request as ready for review August 7, 2026 15:35
@hotlong
hotlong added this pull request to the merge queueAug 7, 2026
Merged via the queue into main with commit bbd2d8dAug 7, 2026
34 of 35 checks passed
@hotlong
hotlong deleted the claude/issue-6319-quick-reference-counts branch August 7, 2026 15:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cddependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] quick-reference.mdx 的协议索引与 packages/spec 现状漂移:三处小节计数不符 + connector-auth 有 schema 无参考页

2 participants

@hotlong@claude