Skip to content

Commit 33409bc

Browse files
committed
chore(changeset): 参考页模块描述选块规则 (#5059)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014wsZeReNTqiceBfLb5Pyf5
1 parent efc9831 commit 33409bc

1 file changed

Lines changed: 57 additions & 0 deletions

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
"@objectstack/spec": patch
3+
---
4+
5+
fix(spec): a reference page's opening paragraph is the module's own doc block, never a symbol's (#5059)
6+
7+
`getFileDescription()` took the **first** doc block anywhere in a `*.zod.ts`
8+
file, verbatim, and published it as the page's opening paragraph. That is not a
9+
rule about descriptions — it is a rule about *ordering*: whichever declaration
10+
happened to sit at the top of the file donated its comment to a public
11+
document. Adding a helper above the first schema silently rewrote a published
12+
page, and no gate could see it. `check:docs` compares the generated page against
13+
the source and the page reproduced the wrong block faithfully, so there was no
14+
drift to report; the trap was written down when the generator was built and
15+
still landed on `main` twice.
16+
17+
The measured victim surface was **six pages**. The Translation protocol
18+
reference opened with `Shared history sentence for every shape in this file
19+
(#4001).` — this repo's internal tightening-campaign narrative — and the Mapping
20+
page with its sibling. Four more had no history constant anywhere near them:
21+
`api/contract` published the doc of `ApiErrorSchema.code` (a comment *nested
22+
inside* an object literal), `api/realtime` published `Transport Protocol Enum`
23+
on a page documenting fourteen schemas, and `api/protocol` / `kernel/plugin` the
24+
same shape. Any future "move a helper to the top of the file" makes another.
25+
26+
The selection now follows **TSDoc's own rule, read back**: a doc block belongs
27+
to the declaration it immediately precedes — which is exactly the text an editor
28+
shows when you hover that symbol. So a module description must be a block that
29+
30+
- starts at column 0 (a block indented inside a declaration body documents a
31+
property, never a module),
32+
- appears before the first declaration (imports and re-exports introduce no
33+
symbol of their own and do not close the header zone), and
34+
- is not immediately followed by a declaration.
35+
36+
When no block qualifies the page prints no description at all — 宁可缺,不要错.
37+
A confidently rendered internal note is a page that lies about its subject,
38+
which is worse for a reader (and for an AI author working from these pages) than
39+
a page that opens with its `Source:` pointer.
40+
41+
**Twenty reference pages lost an opening paragraph**, each of which was a
42+
symbol's JSDoc rather than the module's: the six above plus `ai/solution-blueprint`,
43+
`ai/tool`, `api/error-code-ledger`, `api/router`, `automation/approval`,
44+
`cloud/template-manifest`, `data/driver-mysql`, `data/driver-postgres`,
45+
`data/driver-sqlite`, `kernel/manifest`, `shared/enums`, `system/doc`,
46+
`system/notification`, `ui/responsive`. **No page lost a real module header**
47+
the other 178 pages with a `Source:` line keep their description byte for byte.
48+
A module that wants its opening paragraph back writes one block that documents
49+
no symbol; 178 sources already do.
50+
51+
The rule is also the gate. The issue proposed failing on first sentences
52+
matching `#\d{3,}` / `Shared history`, but that recognises only the
53+
history-constant subclass, and only after publication — it would have caught two
54+
of the six. A selection rule that cannot pick a symbol's comment makes the whole
55+
class impossible instead. `scripts/lib/file-description.ts` (extracted from
56+
`build-docs.ts`, following `format-type.ts` #4912 and `escape-mdx.ts` #5452) and
57+
its pin suite `scripts/file-description.test.ts` carry it, corpus check included.

0 commit comments

Comments
 (0)