Skip to content

docs(getting-started): quick-reference 计数改 (N of M schemas),并把真实参考目录纳入门 (#6530) - #7302

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-6530-quick-reference-counts
Aug 10, 2026
Merged

docs(getting-started): quick-reference 计数改 (N of M schemas),并把真实参考目录纳入门 (#6530)#7302
os-project-manager merged 1 commit into
mainfrom
claude/issue-6530-quick-reference-counts

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes #6530

按 maintainer 2026-08-08 的 Option C 裁决实施(「接受你的建议」):表继续保持策展子集,但措辞携带真相,且漂移进门。


一、今日 main 上重新实测的 13 个 M(未复用 08-08 的表)

content/docs/references/ 是自动生成的,两天里有过合并,所以按调度要求在今日 main397e731a5)上重新按集合实测:一行只有当它链接进该分类目录时才算覆盖了那个页。

小节 分类目录 N(表行数) M(目录页数,去 index.mdx 其中指向本目录的行 未被覆盖的页 08-08 的 M 变化
Data data 17 30 17 13 29 +1
UI ui 11 16 10 6 16
Kernel kernel 17 31 16 15 31
System system 18 37 18 19 37
AI ai 11 11 11 0 11
API api 17 28 17 11 28
Automation automation 4 13 4 9 13
Security security 3 5 3 2 5
Identity identity 4 5 4 1 5
Cloud cloud 3 11 3 8 11
Integration integration 1 1 1 0 1
Shared shared 5 8 4 4 8
QA qa 1 1 1 0 1

无小节的分类:studio 3 页、contracts 0 页(目录里只剩一个 meta.json)。所有指向目录内的行都指向真实存在的页 —— 今日无死链。

⚠️ M 确实动过一格:data 29 → 30

$ git log -1 --format='%h %ad %s' --date=short -- content/docs/references/data/driver-turso.mdx
e2798fab7 2026-08-09 fix(spec,cli,runtime,service-datasource)!: one driver vocabulary — `os start` 和 `os migrate` 停止互相矛盾 (#6345) (#6910)

08-09 新增了 driver-turso.mdxdata 的未覆盖页也从 12 变成 13。两天,一格漂移,而原来的自指门全程报绿 —— 这就是这道门值得有的直接证据。其余 12 个 M 与 08-08 一致。


二、页面改了什么

  1. 13 个标题一律改为 (N of M schemas),例如 ## Data Protocol (17 of 30 schemas)

    • N = 本表行数(原来的自指校验原封不动保留,读者数一遍表格就能验证);
    • M = content/docs/references/{category}/ 实际发布的参考页数(.mdx 去掉 index.mdx)。
    • 顶部新增一段「Reading the counts」把这两个数的定义写死,并说明 N 小于 M 是正常且被门检查的状态。AI 的 11/11、Integration 与 QA 的 1/1 这三个完整索引照实写成 11 of 11 / 1 of 1,ca602727d 那次刻意补全因此被保留成事实而不是巧合。
  2. 三行指向 references/ 之外的行统一带 标记,并把「Connector Auth 裸名无链接」这一条修掉:

    处理
    UI · Widget Contract 保留 /docs/protocol/objectui/widget-contract,加
    Kernel · Events 保留 /docs/kernel/events,加 ,并在 Purpose 里说明 references/kernel/ 把同一面拆成六个 events-*
    Shared · Connector Auth 原来完全没有链接,现指向 /docs/references/integration/connector,加 ;Key Schemas 从未发布的 ConnectorAuthConfig 改为已发布的 ConnectorInstanceAuth
  3. 新增 ## Categories Without a Section,把分类级策展写在页面上:studio(3 页,Studio 自己的编辑器面,不是 app 声明的协议)与 contracts(0 页)。

我选定的规则(N、M 与 的对账口)

调度要求我自己判定「指向 references/ 之外的行如何与 M 相互作用」,并把规则写进 PR 与脚本注释。选定的是:

N 数的是表格里的全部行;M 数的是目录里的页。带 的行算进 N,但不是 M 里的那些页 —— 标记就是告诉读者这件事的东西。

理由:另一种写法(N 只数指向本目录的行,UI 写成 10 of 16)能让「N of M」成为字面精确的覆盖率陈述,但代价是读者数一遍表格得到 11、标题却写 10 —— 那恰恰是本单要消灭的那种「标题里的数字对不上眼前的东西」,只是方向反过来。而且裁决给的样例 17 of 29 中的 17 就是行数。所以保留「N = 行数」,把精度交给 标记 + 顶部图例,并让门双向强制这个标记(见下)。

Connector Auth 的落点不是随手挑的,仓内有两处白纸黑字:

即:该文件在 src/shared/,但 shared 桶不发布它(shared/index.ts 没有它的 barrel 行),它经 connector.zod.ts 再导出到 @objectstack/spec/integration,参考文档就落在 Connector 页上(connector.mdxConnectorInstanceAuth 等五节实测存在)。所以这一行既不是「等一个待写的新页」,也不该留在 Shared 里当裸名。


三、门改了什么

scripts/check-quick-reference-counts.mjs 保留原有全部检查,新增:

  • M 断言:标题的第二个数与 content/docs/references/{category}/ 的真实页数比对。
  • 分类是从行里推导出来的,不是从标题猜的:一个小节的分类 = 它所有未标记行链接进的那个唯一 /docs/references/{category}/。这让 [finding] quick-reference.mdx 的协议索引与 packages/spec 现状漂移:三处小节计数不符 + connector-auth 有 schema 无参考页 #6319 的原始缺陷(行迁移到了错误的小节)从「靠计数发现」升级为「靠链接发现」—— 迁移后的行会让小节指向两个分类,门点名两个。
  • 行规则(四条,双向):每行必须有链接;未标记的行必须指向本小节自己分类目录下真实存在、且不与别行重复的页;指向别处的行必须带 ;带 却指回自己目录的行也红(否则标记会悄悄从覆盖率里减掉一页)。
    • 刻意没有加「未标记行数 小于等于 M」这条:未标记行已经是该目录里互不相同的真实页,这个不等式是上面三条的定理。一条永远不会红的检查读起来像覆盖率,其实不是。
  • 分类级覆盖扫描references/ 下每个分类目录必须要么有小节、要么## Categories Without a Section 里被声明(且声明的页数与真实页数一致)—— 不能两者都是,也不能两者都不是;声明了一个不存在的目录同样红。
  • 旧的 (N schemas) 拼法不再被当作计数标题(会落进「protocol 标题却没有计数」的结构错误),所以本次迁移无法被一个标题一个标题地悄悄回退。

自测从 9 例扩到 22 例


四、反向验证(反空转,方向事先预测:

裁决要求「至少一条新用例在 M 断言被删掉时变红」。删掉 checkPagedeclaredTotal !== pages.length 那一段后:

$ node no-m-assert.mjs --self-test
✗ check-quick-reference-counts self-test failed:

  ✗ wrong M produces exactly one finding: expected 1, got 0
  ✗ wrong M is a total finding: expected "total", got undefined
  ✗ names the declared total: expected true, got false
  ✗ names the real page count: expected true, got false

第 3 例的构造正是「页面内部完全自洽、只有目录不符」((3 of 9 schemas),catalog 里 4 页),所以断言被删后它实测归零 —— 就是 #6530 记录的那个「永远绿」状态。方向与预测一致。

同样对分类级覆盖扫描做了一次(把那段 for 循环短路):

$ node no-coverage.mjs --self-test
  ✗ and its category falls out of coverage: expected true, got false
  ✗ undeclared category is reported: expected true, got false
  ✗ undeclared category is a coverage finding: expected "coverage", got undefined
  ✗ and contracts then falls out of coverage: expected true, got false

另外把新门跑在改动前的页面上(git show origin/main:...),得到 15 条 finding(13 个旧标题 + 「没有任何计数小节」+「缺 Categories Without a Section 块」),确认迁移是被强制的而不是只被建议的。


五、跑过的命令(逐字)

$ node scripts/check-quick-reference-counts.mjs --self-test
✓ check-quick-reference-counts self-test: 22 cases pass.

$ node scripts/check-quick-reference-counts.mjs
✓ content/docs/getting-started/quick-reference.mdx: 13 section(s), every "(N of M schemas)" heading matches its table AND content/docs/references/ (15 categories, all sectioned or declared).

$ node scripts/check-nul-bytes.mjs --self-test
✓ check-nul-bytes --self-test: 75 assertions over a temp git repo (real scan() path)

$ node scripts/check-nul-bytes.mjs
check-nul-bytes: OK (scanned 6648 text file(s) -- 6648 tracked, 0 untracked-not-ignored; skipped 5 binary; no raw ASCII control bytes).

$ pnpm exec eslint --no-inline-config scripts/check-quick-reference-counts.mjs content/docs/getting-started/quick-reference.mdx
(.mjs 0 error;.mdx 报 "File ignored because no matching configuration was supplied" —— eslint 本来就不覆盖 mdx)

$ pnpm check:doc-authoring
✓ doc authoring guard: 374 files clean — no bare metadata literals.

$ pnpm check:docs-audit-scope
✓ docs-accuracy-audit scope is in sync with content/docs/: 179 hand-written doc(s).

$ pnpm check:role-word
check-role-word: OK (44 baselined file(s), no new occurrences).

仓内断链门是 check-links.yml(lychee --offline,advisory lane)。新增的 /docs/references/studio/docs/references/integration/connector 与本页既有链接同形(本页 Search Tips 已有 /docs/references/data 这类目录式链接),lychee.tomlinclude_fragments = "none",所以新增的 #categories-without-a-section 锚点不参与解析。


六、Changeset

不加 changeset,改用 skip-changeset 标签。 本 PR 只动 content/docs/ 与根 scripts/,两者都不随任何已发布包出货。仓内先例一致:本门的创建 PR #6357bbd2d8d3d,改动 .github/workflows/lint.yml + content/docs/ + package.json + scripts/)与同族的 #6519ebc2baf16,只改本页)都没有 changeset。


⚠️ 未 arm auto-merge、未入合并队列,等 PM review。


Generated by Claude Code

…录纳入门 (#6530)

按 maintainer 2026-08-08 的 Option C 裁决实施。

原来的 `(N schemas)` 是**自指**的:N 只与它自己下面那张表比对,与
content/docs/references/{category}/ 的真实面之间没有任何门在看。#6530 实测出
`## Data Protocol (17 schemas)` 之上是一个发布 29(今日 30)个 schema 页的目录,
其中 13 个页在整张页面上没有任何一行 —— 而门一直是绿的,并且永远会是绿的。

13 个标题一律改为 `(N of M schemas)`:N 仍是本表行数,M 是该分类目录实际发布的
参考页数(`.mdx` 去掉 index.mdx)。表继续保持策展子集 —— 一个把 30 个 data 页
全镜像过来的 quick reference 就不 quick 了 —— 但措辞不再读作总数,且 N < M 这个
正常状态从此有门在看。

今日 main 上全部 13 个 M 重新实测(未复用 08-08 的表):只有 data 动了,29 → 30,
因为 e2798fa(#6345 / PR #6910)在 08-09 新增了 driver-turso.mdx。这正是这道门
值得有的证据 —— 两天,一格漂移,原来的自指门看不见。

跨切规则(裁决要求随行):

- 每一行都必须有链接。Shared 的 `Connector Auth` 原来是**裸名无链接**,现在指向
  /docs/references/integration/connector —— 那个文件在 src/shared/,但
  `@objectstack/spec/shared` 并不发布它,它经 `@objectstack/spec/integration`
  到达消费者,build-docs.ts 的 `integration:` 注释与 scripts/lib/root-index.ts
  都写明了这一点(后者还把 `shared/connector-auth.zod.ts` 这类行点名为缺陷类)。
  Key Schemas 一并从未发布的 ConnectorAuthConfig 改为已发布的 ConnectorInstanceAuth。
- 三行指向 references/ 之外的行统一带 `↗` 标记(UI 的 Widget Contract、Kernel 的
  Events、Shared 的 Connector Auth)。标记就是 N 与 M 的对账口:带标记的行算进 N,
  但不是 M 里的那些页。门双向校验 —— 未标记的行必须指向本小节自己的分类目录下
  一个真实存在、且不与别行重复的页;指向别处的行必须带标记;带标记却指回自己
  目录的行也红,否则标记会悄悄从覆盖率里减掉一页。
- 分类级策展写在页面上而不是留作默认:新增 `## Categories Without a Section`
  一节,写明 references/studio/(3 页)与 references/contracts/(0 页,只剩一个
  meta.json)为何没有小节;门同样读这张表,任何分类目录必须要么有小节、要么在
  这里被声明,不能两者都是、也不能两者都不是。

门的自测从 9 例扩到 22 例。第 3 例是反空转的那一例:页面内部自洽、只有目录不符,
删掉 M 断言后它实测归零(4 条断言全红),即 #6530 记录的"永远绿"状态。第 18/20 例
对分类级覆盖扫描做同样的反向验证。

Claude-Session: https://claude.ai/code/session_01F8q5J1MQyocgtNspb15fSn

Co-authored-by: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 10, 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)
objectstack Ignored Ignored Aug 10, 2026 5:31am

Request Review

@os-project-manager os-project-manager added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed size/l labels Aug 10, 2026 — with Claude
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

PM 验收:实质 ACCEPT,门禁 HOLD。 05:3xZ 时 27 项检查零 failure,但 Build Docs / TypeScript Type Check / ESLintin_progress —— 按本席假绿判据 2,in_progress 不是绿,武装 auto-merge 前必须等它们报到。

下列每一条都是我在 head 7085c1ce0独立复算的,不是采信报告:

重测纪律 —— 派单的硬约束兑现了,而且抓到了真东西

派单里禁止复用 08-08 那张测量表。13 个 M 值我逐个重算,全部吻合,其中一个变了:references/data/ 从 08-08 的 29 变成今天的 30(ls-tree 实测 31 个 .mdxindex.mdx)。两天里那个目录确实多出一页 —— 如果照抄旧表,这张 PR 会带着一个当天就已过期的数字落地,而且正是这条门禁本来要防的那种漂移。这是"为什么值得建这道门"的现场证据。

其余 12 个:ui 16 / kernel 31 / system 37 / ai 11 / api 28 / automation 13 / security 5 / identity 5 / cloud 11 / integration 1 / shared 8 / qa 1,与实测一致。

三处最容易出事的地方,都没出事

  • 单数形态:IntegrationQA 写作 (1 of 1 schema),正则是 schemas? —— 如果只匹配复数,这两节会静默脱离覆盖,恰是裁决点名要防的失败形态。自测里有一条正例专门钉住它。
  • 丢 token 不能脱管:PROTOCOL_HEADING 会抓"名字像协议小节却没有 (N of M schemas) 计数"的标题并报错 —— 想靠删掉计数来绕过门禁是不行的。
  • 类目级策展:没有停在"写在页面上",而是做成了受门禁强制的 ## Categories Without a Section 小节 —— references/ 下每个目录必须要么是某小节的派生类目、要么在这里申明。studio(3 页)与 contracts(0 页)据此登记。这比裁决要求的更硬。

表外三行

Widget Contract/docs/protocol/objectui/widget-contractEvents/docs/kernel/eventsConnector Auth/docs/references/integration/connector,三行统一用 标记并在单元格里写明为什么在外面。原先那个裸名无链接的 Connector Auth 现在有真链接了,"不得留裸名"达成。

我自己跑的四次验证

门禁本体          ✓ 13 section(s) … AND content/docs/references/ (15 categories, all sectioned or declared)   EXIT=0
自测              ✓ 22 cases pass(原 9 例)                                                                    EXIT=0
反向A 真实面漂移   从 references/data/ 移走一页 → 报 "declares of 30 … but publishes 29 page(s)" 且连带
                  抓出该页的死链                                                                    **EXIT=1**
反向B 拆 M 断言   中和 declaredTotal 比较 → 4 条自测转红                                            **EXIT=1**

反向 A 是关键:它证明这道门看的是真实目录而不是自己,而且真的会拦 CI(退出码 1)。⚠️ 我第一次测反向 A 时把 EXIT=$? 取成了管道末端 head 的状态,读出 EXIT=0 —— 那是我的测量缺陷,不是脚本缺陷,重测后为 1。记在这里,因为"报红却 exit 0"正是本席假绿清单上的形态,任何人复核时都该用 PIPESTATUS 或不带管道。

待办

三项 in_progress 报到且为绿 ⇒ draft:false → auto-merge → 合入后 #6530 收卡清 pm:dispatched。⛔ 在那之前不武装。


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

门禁已全部报到:27 项全 success/skipped,零 failure(Build Docs 05:33:43Z、ESLint 05:35:03Z、TypeScript Type Check 05:46:36Z)。此前 HOLD 的三项 in_progress 现已转绿 ⇒ 已 draft:false + auto-merge 入队。

dev 报告随后到达,与我上一贴的独立复核逐条吻合,并补上了两件我没做的:

那条被裁决下放给 dev 的规则,我认可

裁决说「⚠️ 无论选哪个方案,都需要一句话规则处理两件横切的事」,其中表外行怎么计入 N 是留给实现者的。dev 定的是:N 数表里每一行(含 标记行),M 数目录页数; 行是 N 的一员但不是 M 的一员。于是 UI 读作 11 of 16,而真正指进 references/ui/ 的只有 10 行。

另一种写法(N 只数目录内的行 ⇒ 10 of 16)能让「N of M」成为字面精确的覆盖率声明,但它会把这张卡的缺陷镜像复制一遍 —— 读者数表得 11、标题写 10,又一个"数字和它旁边的东西对不上"。dev 选了与可见表格一致,精度由 标记 + 新增图例承担,而且标记本身双向受门禁强制(缺标记会红,滥用标记也会红)。维护者裁决里给的示例 17 of 29 中的 17 本身就是行数,与这个选择同向。

记在这里是因为它是一次有代价的取舍而非顺手决定:两种读法都能自圆其说,dev 把理由同时写进了 PR 正文和脚本头注,后人要推翻它有据可依。

顺带发现按纪律处置

references/contracts/ 空目录(只剩 meta.json)已立 #7303,finding 档、⛔ 未定级、未认领、未自我指派,git 考古追到 c483c1326(删页)与 36425099a(只把 meta.json 加回来)两笔,影响面据实写作"今天没有用户会撞到",处置留给分诊。合规。

合入后 #6530 收卡清 pm:dispatched


Generated by Claude Code

Merged via the queue into main with commit 1edc3aa Aug 10, 2026
28 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-6530-quick-reference-counts branch August 10, 2026 06:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants