mcpp-docs-style · git:20260908.9a71c9a · 2026-09-08 · sha256 158fe166992260ad
mcpp-docs-style git:20260908.9a71c9aA
Immutable. This exact content is served forever at /api/v1/blob/158fe166992260ad.
---
name: mcpp-docs-style
description: Use when writing or editing anything under docs/ (English or 简体中文), docs/specs/, README files, or the design records under .agents/docs/ — states which tree a document belongs to, that docs/ is a usage manual for what mcpp has already implemented rather than a design account, the register it is written in (academic, declarative, precise, no emoji, no internet slang), the requirement that a document match the current implementation, the gradient a topic is documented along, the coverage a surface owes, and the bilingual parity rules.
---
# mcpp 文档规范
本规范回答六个问题:**这份文档的归属**(第一节)、**为什么要有这一章**(第二节)、
**怎么写**(第三至七节)、**它必须对得上什么**(第八节)、
**它欠多少覆盖**(第十节)、**怎么评审它**(第十四节)。
最核心的一条在第一节:**用户文档是已实现功能的使用手册**,不是设计说明。
代码注释与 commit message **不受本规范约束** —— 它们的读者、篇幅与目的都不同,
那里允许并鼓励叙述「为什么」以及实测过程。
## 一、文档的归属:三棵树与各自的准入判据
一份文档属于哪棵树,由**读者**决定,不由篇幅或主题决定。
| 树 | 读者 | 准入判据(问自己这一句) | 稳定性 |
|---|---|---|---|
| `docs/**` | 手上有任务的人 | 手上有这个任务的人,没有它做不完 | 增量;旧拼法留作别名 |
| `docs/specs/**` | 对着机制做实现的人:索引作者、下游工具、贡献者 | **没有它,两个独立实现会不一致** | 编号 + 版本 + 状态机 |
| `.agents/docs/**` | 做这次改动的人,以及以后问「为什么是这样」的人 | 做了一个决定,理由否则会丢 | **落地即不可变** |
| `.agents/skills/**` | 照着做的人或 agent | 这是**步骤**,不是解释 | 随流程变 |
### 用户文档是**已实现功能的使用手册**
这是本规范最核心的一条。
> `docs/**` 服务的是**要把事情做成的用户**。它写 mcpp **已经实现**的东西怎么用,
> 不写这些东西**为什么被设计成这样**,也不写**什么设计了、什么还没设计**。
不写进用户文档的四类内容,它们全部属于 `.agents/docs/`:
1. **设计理由与取舍** ——「为什么是一个机制而不是两个」「这个边界由模型的性质
决定而不是本文档的雄心」。
2. **被否掉的替代** ——「三种替代方案都不能去掉它」「某原语写出来又撤回了」。
3. **路线图与设计状态** ——「计划中」「将来会支持」「已设计未实现」「下一步是」。
用户文档里一个能力只有两种状态:**能用**(带版本下界)与**不支持**(一句话)。
4. **实现内幕** —— 除非用户不知道它就会用错。
**判据(逐段问一遍):把这一段删掉,读者还能不能正确地用?**
- 能 → 删掉,或移进设计记录。
- 不能 → 它不是设计论证,是**使用信息**;改写成事实陈述,去掉论证语气。
**边界写成事实,不写成论证。** 「当前边界」一节(第十节要求它必须存在)是一份
清单,不是一段说理:
| 不采用 | 采用 |
|---|---|
| OpenMP offload 与 stdpar 没有可分的岛,因此落在这套机制的论域之外 —— 这是模型的性质,而不是本文档雄心的缺口。 | 未支持:OpenMP offload、stdpar、Metal、HIP 的 AMD 平台。 |
| 之所以不发出 `accel` 字段,是因为该字段的含义是「实测所得」,而 mcpp 目前无从测量,把声明写进一个语义为实测的字段会让身份说谎。 | `mcpp pack` 不产出 `accel` 字段;需要它的发布方在描述符里手写。 |
理由**就是不给**。要理由的读者是另一类读者,他去读设计记录 —— 而用户文档
不链接设计记录(见上面的引用方向)。
**已测状态**(2026-09-08):九个用户章节含设计论证短语,`05` 21 处、`13` 8 处、
`20` 6 处,`20` 另有两个设计型标题。清理按
`.agents/docs/2026-09-08-documentation-architecture-three-trees.md` 的分阶段进行。
### 另外三条最容易被违反的推论
1. **用户章节不记历史。** 「过去是 X,2026.8.16 起改成 Y」是设计记录的句子。
章节陈述今天是什么;版本相关写**下界**(`2026.9.6.5+`)。
2. **设计记录落地后不再编辑**,除了追加状态行或一个具名带日期的更正块。
就地改写会让一份「某时刻的记录」悄悄变成「对现在的断言」。
3. **用户章节里出现「必须 / 禁止」,说明内容属于规范。** 把它移进
`docs/specs/`,章节引用它。只有规范有规范性语气。
### 引用方向是规则,不是习惯
```
docs/ ──▶ docs/specs/ 允许:引用精确语义
docs/ ─╳─ .agents/docs/ 禁止
docs/specs/ ──▶ .agents/docs/ 允许,仅限元数据表里的溯源行
docs/specs/ ──▶ docs/ 允许
.agents/docs/ ──▶ 任何 允许
代码注释 ──▶ docs/ 或 specs/ 允许,且被引用的文件必须存在
```
**为什么那条边被禁止**:设计记录描述一个时刻,不带稳定性承诺。用户章节想引用
它,只说明两件事之一 —— 章节不完整,或那份记录里的内容已经变成规范性的。两者
的修法都不是加链接,而是**把内容提升上来**(是操作就进章节,是保证就进规范)。
## 二、重构的定义,以及每章的设计规格
**重构不是在既有文档上修补,是重新设计。** 分组、重编号、把段落搬到别的章,这些
是**重组**;它们改的是索引,不是书。重构要回答的是:每一章**为什么存在**、给谁看、
放在哪里、按什么顺序、包含什么、传递什么信息 —— 并且把**为什么**写下来。
判据:拿掉某一章,读者少了哪个问题的答案?答不上来,这一章就没有被设计过。
### 四条产生每个决定的规则
| | 规则 | 排除的形态 |
|---|---|---|
| **R1** | **一个主题一个拥有者。** 恰好一章拥有一个主题;其余每一章只写一句话并链接过去 | 同一件事被解释两遍,然后各自过期 |
| **R2** | **一章为**有任务的读者**而存在,不为**有名字的机制**而存在** | 按机制建目录,于是「测试」「依赖解析」这类**任务**没有家 |
| **R3** | 每章在**前 15 行**内写明读者、它回答的那一个问题、以及它**排除**什么 | 排除是承重的:它是防止这一章重新吸收 R1 已经分配出去的主题的闸 |
| **R4** | 一个部分是**某类读者的一段弧**,其内部顺序是那类读者需要它的顺序 | 字母序、按特性发布时间排序 |
| **R5** | **背景一节的范围由问题决定,不由方案决定。** 先把读者实际面对的那个问题写完整,再写本工具触及其中的哪一部分 | 只写与本工具最近的那一条成因,读者据此以为问题就这么大 |
### 每章的设计规格
动一章之前,先把这张表填出来。填不出来的那一格,就是还没设计的地方。
| 项 | 填写要求 |
|---|---|
| 读者 | 谁在读它。一句话说不出来就是没定位 |
| 那一个问题 | 它存在的理由,一个问句 |
| 包含 | 哪些内容归它拥有(R1) |
| **排除** | 哪些内容**不**归它,以及归谁 |
| 位置与理由 | 在哪个部分、第几位,**为什么在这里而不是别处** |
| 前后 | 上一章与下一章,以及为什么是这两章 |
| 判据 | 读完这一章的人能做到什么 |
### 出版级的含义
这套规格施加于**每一章**,而不是只施加于新写的章。一份文档集合的质量由它最差的
那一章决定,因为读者不知道哪一章是被设计过的。
**先设计再动手。** 先重组、再设计,会得到两次重编号和一份没有被设计过的书 ——
第二次重编号的成本,就是没有先设计的代价。
## 三、总原则
文档是**参考资料**,不是博客,也不是聊天记录。判据只有一条:
> 一位不认识作者、只想解决自己问题的工程师,能不能在最短时间内拿到准确的事实,
> 并且不会误以为某个说法比实际更随意或更绝对。
由此得到四条可执行的规则:**学术、陈述、精确、克制**。
「学术」在这里是具体的三件事,不是气质:每个断言的强度与它的证据相符(第七节)、
每个可粘贴的东西都可复现(第八节)、每个枚举都有分母(第十节)。
## 四、标题
**标题一律是名词短语或陈述句,不使用疑问句、不使用口语片段。**
疑问句标题把「读者已经知道自己在找什么」这个前提丢掉了 —— 目录里一列问句,
读者要先把每个问句翻译成主题才能定位。
| 不采用 | 采用 |
|---|---|
| 一段话讲完 | 概述 |
| 打什么由谁决定 | 打包内容的决定依据 |
| 哪些 `.cppm` 会被发布 | 发布的接口单元 |
| 消费者的构建会检查什么 | 消费端的构建检查 |
| 怎么消费 | 消费方式 |
| 老版本 mcpp 拿到这种包会怎样 | 旧版本 mcpp 的行为 |
| 为什么两者都不许裁剪 | 两个集合不可裁剪的原因 |
| 这些说法验证到哪一步、在哪台机器上 | 验证范围 |
| The whole idea in one paragraph | Overview |
| What decides what gets packed | What determines the package contents |
| Consuming one | Consuming a package |
| What you may rely on, and what changes | Stability guarantees |
| 0x —— 人人都需要 | 0x —— 基础 |
| 0x — Everyone | 0x — Fundamentals |
| 背景:模块到了,工具链没跟上 | 背景:C++ 工程侧的工具现状 |
| 谁在为这个落差付账 | 这一现状的代价 |
| 大致相当于谁的活 | 可对照的工具 |
| 长什么样 | 形式 |
| 一个 flag 由哪根轴决定 | 决定一个 flag 的轴 |
| 一条运行时搜索路径可以住在哪里 | 运行时搜索路径的允许位置 |
「…的原因」「…的依据」「…的范围」是把 why 型标题转成名词短语的常用形。
**保留 why 本身,去掉疑问语气。**
**判据是疑问词,不是问号。**「谁在为这个落差付账」「打什么由谁决定」都不带问号,
都是疑问句。检查脚本第一版只匹配 `?` / 吗 / 呢,两句全部通过。判据是这一组词:
谁、哪、什么、多少、为何、如何、怎样、怎么。
**表头单元格与标题同规。** 一个列头按每一条要紧的性质都是标题:它命名一个主题、
被跳读、并且是读者扫描时看的那一行。`| 部分 | 大致相当于谁的活 |` 通过了当时
全部的检查,而它是全树最直白的一处违规。
这条同样管**部分名与段位名**,不只管章节标题。「人人都需要」描述的是受众、
是一个句子片段;「基础」是这一段**是什么**。受众写在每章开头的「读者」那一行,
不写在目录的骨架上。
## 五、词汇
### 不采用的类别
1. **emoji 与装饰性符号**:✅ ❌ ⚠️ ⭐ 🎉 🚀 💡 🔥 以及同类。
状态用词表达:**已实现 / 部分实现 / 未实现**、**是 / 否**、
**已验证 / 未验证**。一个符号要靠图例才能读,而词不用。
- `docs/**`、`docs/specs/**`、`README*` 今天是**零 emoji**,保持。
- `.agents/docs/**` 的既有记录里有四千余处(⚠ / ✅ / ⭐ / ❌)。
**新记录不使用;既有记录不回改** —— 设计记录落地即不可变,
为统一符号去改写历史记录,改的是它唯一的价值。
2. **网络用语与口语**:搞定、干活、坑、真香、翻车、打脸、一把梭、白给、
凉了、炸了、神器、黑科技、敲黑板、划重点。
3. **拟人与比喻性行话**:姊妹篇、腿(fat package 的一份产物)、travel(源码
「旅行」)、picky、happy path 的中文直译。技术术语本身可以是比喻
(rpath、sysroot),但**不要新造比喻**。
4. **填充语**:其实、说白了、简单来说、众所周知、显然、当然、值得一提的是。
如果一件事显然,就不必说;如果不显然,「显然」会让读者怀疑自己。
5. **含糊的程度词**:很快、非常、极其、基本上、差不多。用数字或范围替代 ——
「2.42×」「64.77s」「四个平台中的三个」。
### 人称
默认**不使用第二人称**。写动作的对象,不写「你」。
- 不采用:你可以在 `mcpp.toml` 里写 …
- 采用:在 `mcpp.toml` 中声明 …
例外:**教程体**文档可以使用第二人称,因为那里读者正在跟着做。教程体是
**列出来的,不是推断的**:`00-getting-started.md`、`01-examples.md`、
`04-build-from-source.md`。其余全部按参考文档处理。
引用 mcpp 自身输出的部分不受此限:`did you mean 'x86_64-linux-musl'?` 与
`your toolchain : …` 是程序打印的原文,**逐字复现是要求,不是文风问题**。
检查脚本因此会先剔除行内代码段再判定。
## 六、句式
- **陈述句优先。** 命令式仅用于操作步骤(「运行 `mcpp build`」)。
- **一句话一个事实。** 从句套从句的长句拆开。
- **不使用反问。**「难道不应该……吗?」没有信息量。
- **不使用感叹号。**
- **破折号克制使用**:插入语用逗号或括号;破折号留给「随后是对前半句的
重述或收束」这一种用法。
## 七、断言的强度必须与证据相符
这是本规范里最实质的一条,也是最容易违反的一条。
| 证据 | 允许的表述 |
|---|---|
| 跑过、有输出 | 「实测」「测量得到」,并给出数字或报错原文 |
| 读代码推断 | 「按 X 的实现」「由 Y 决定」 |
| 未验证 | 「未验证」「尚无测试覆盖」—— **必须写出来** |
**不要把推断写成实测。** 反例(本仓库真实发生过):把「守卫在原生构建上失效」
写成实测结论,而它是从「`targetTriple` 结构上可能为空」推断的;实际运行时
它非空,结论不成立。判据:**「结构上可能」不等于「运行时确实」——
要么读运行时产物,要么不要写成实测。**
同理,不要用「完全」「永远」「所有平台」这类全称词,除非确实逐个验证过;
写「已在 Linux / macOS / Windows 验证」比写「全平台可用」更有价值,
因为前者可被检验。
**「支持」有三档,分开写。** 同一个「是」可能意味着三件不同的事,合并写就是
把最弱的一档说成最强的:
| 档 | 含义 |
|---|---|
| 已端到端运行 | CI 或本机跑过,产物达成了断言 |
| 已安装并编译 | 组件装得上、代码编得过,没有跑过 |
| 已声明 | 描述符里有,没有装过 |
## 八、文档必须对应当前实现
一份与实现脱节的文档比没有文档更坏:读者按它写出来的东西编不过,而错的是
文档,他不知道。
1. **写作与核对一律读 `origin/main`,不读工作树。** 工作分支可能落后若干个
发布;「现在的实现是什么」只有 `origin/main` 能回答。
2. **每一个可粘贴的东西都必须可复现**:命令、输出、报错原文、路径、版本号。
判据是「在当前发布版上跑一遍能不能得到这一行」。做不到就删掉,或标注版本
下界。**诊断信息里那行可粘贴的版本号也是承诺** —— 它会被读者原样敲进去。
3. **改实现的 PR 同时改被它作废的文档。** 判据:这次改动触到的每一处
`docs/` 断言都重新读一遍,而不是等下一次文档 PR。
4. **用户章节不引源码行号。** 读者手上没有那一版源码树。引文件与符号
(`src/pack/prebuilt.cppm` 的 `tag_check`)。规范可以引文件与符号;
设计记录可以引行号,因为它记录的是一个时刻。
5. **一份文档「对齐到哪个版本」必须可判定。** 规范由元数据表的「对应实现」
回答;章节由它写出的版本下界回答。都没有,就说明没人能判断它是不是过期的。
6. **过期的判据不要用子串搜索。** 「grep 到这个词就算讲过了」会在有人改一次
措辞时静默变空转。要判断一份文档是否覆盖某个能力,读**结构化的东西** ——
示例的 `mcpp.toml`、源码里的键表、`print_usage()` 的正文。
7. **也不要数一个代理量。** 子串搜索的孪生形态:数**代码块个数**来判断「是不是把
几种做法并列了」、数**含某词的标题**来判断「哪一章拥有这个主题」。数字是真的,
而被量的对象不是那个性质 —— **正因为数字是真的,评审很难发现**。判据要直接指向
性质:并列的替代由「alternatively / 也可以 / 等价写法」这类**并列标记**识别,
主题归属由「这一节是不是在解释它」识别。
本轮三次同形:用含 test 的标题数「哪几章解释测试」、用字面拼写查反查索引、用
代码块数量查并列替代。三次的数字都对,三次量的都不是那个性质。
## 九、梯度:一个主题的五级台阶,以及只链接相邻级
文档目录要有梯度,读者才能按自己的深度进入。同一个主题从浅到深有五级:
| 级 | 形态 | 语气 |
|---|---|---|
| 0 入口 | 角色索引:「我想做 X」→ 读哪几章、跑哪个示例、用哪个模板 | 指路 |
| 1 教程 | 最小可跑的一份工程,从头跟到尾 | 可用第二人称 |
| 2 参考 | 按机制索引,字段完整 | 陈述,不用第二人称 |
| 3 规范 | 语义、约束、匹配规则,每条带实现状态 | RFC 2119 |
| 4 记录 | 为什么是这样,以及什么被推翻了 | 允许叙述 |
**规则:每份文档开头用一行「相关文档:」指出它的上一级与下一级,并且只链接
相邻级。** 参考文档向上链到教程与示例、向下链到规范;它**不直接把读者丢进设计
记录**,那是跨两级 —— 也正是第一节那条被禁止的边。
梯度本身由**入口**承载,不由每份文档自报级别:`docs/README.md` 的角色索引把
「我想做 X」映射到章节、示例与模板。一份自称「本章是第 2 级」的文档对读者没有
用处,而一条指出上下一级的链接有。
一个能力的文档化按这个顺序推进,不跳级:先有一个能跑的最小形态,再有字段参考,
再在「两个实现会不一致」时抽出规范。**倒过来做会得到一份没有人验证过的规范。**
## 十、覆盖度
「写了」不等于「覆盖了」。覆盖度要有分母,而**分母取自代码树,不取自文档**——
用文档自己的列表当分母,只能证明这份文档自洽。
- manifest 键:取自解析点(`modules/manifest/src/`)
- 构建程序 API:取自导出名(`modules/buildmcpp/src/`)
- 命令:取自 `print_usage()` 的正文
- 设备扩展名:取自 `modules/source-kind/src/` 的表
每个能力有且只有三种归宿,新增一个能力时**在同一个 PR 里回答它归哪一类**:
| 归宿 | 判据 |
|---|---|
| **一个示例** | 它改变**工程的形状** —— 文件、manifest、或作者敲的命令 |
| **一个代码块** | 它是既有工程里的一行 |
| **一条场景条目** | 它只经由命令到达(`docs/21`) |
两条配套要求:
- **每份参考章节必须有「当前边界 / Current limitations」一节。** 没写边界的
文档等于声称自己完整。这一节不是可选的,而且**是一份事实清单,不是说理**
(写法见第一节)。
**教程、模型、索引与场景章节不欠这一节** —— 它们的范围由开头的「不在这里」交代,
而它们本来就不声称覆盖一个完整的表面。
**写不出来就不要写。** 一节编造的边界会让检查通过而什么都没测到,那比缺这一节
更坏。写不出来时,把「这一章的边界尚未写出」记进设计记录,连同判据 —— 谁能说出
它、以及那句话要能被复现。
- **缺口要写出来,不要留白。** 「这一项尚无示例」是一条信息;什么都不说,
读者只能靠踩到才知道。缺口写在**它所属的那棵树**里:用户文档写「不支持
X」,设计记录写为什么以及打算怎么办。
## 十一、双语对照
`docs/X.md` 与 `docs/zh/X.md` 是**同一份文档的两个版本**,不是两篇文章。
- 章节结构、标题层级、表格行数必须一一对应;
- 代码块、命令、报错原文**逐字相同**,不翻译;
- 术语表统一:module interface unit / 模块接口单元、implementation partition /
实现分区、import library / 导入库、install name / install name(不译)。
- 改动一侧时**同时改另一侧**。只改一侧会让两份文档随时间分叉,
而读者无从知道哪一份是新的。
## 十二、结构
### 每份文档的开头三行
用户章节开头必须回答三件事,各一行,在前 15 行之内:
```
**读者:** … 谁在读它
**本章回答的那一个问题:** … 它存在的理由
**不在这里:** … 它刻意排除什么,以及那些内容归谁
```
第三行是承重的:**排除**是防止这一章重新吸收别处已经拥有的主题的那道闸(第二节
的 R1:一个主题一个拥有者)。再加一行「在此之前 / 在此之后」,指出相邻级(第九节)。
规范另有两项硬性要求:开头一张元数据表(编号、标题、状态、版本、最后修改、
对应实现、相关设计文档),结尾一份变更记录。
### 一条推荐路径写在正文,其余收进 `<details>`
mcpp 在很多场景支持不止一种做法,但它有自己的设计风格与语义,因此**总有一条
默认推荐**。正文只写那一条;其余的形态 —— 遗留拼法、逃生舱、只在某个平台成立的
写法、为兼容保留的别名 —— 收进折叠块:
```markdown
推荐写法。<正文,一条路径>
<details>
<summary>其它形态:子表形式、旧拼法</summary>
…
</details>
```
**判据:一个只读正文、不展开任何折叠块的读者,能不能不做选择就把事情做对?**
能 → 对。需要在 N 个并列的做法里自己挑一个 → 错,那是把设计决定推给了读者。
把一种做法降进折叠块**不表示它被弃用**。弃用要明说,并写清替代与从哪个版本起。
### 增量标在它自己旁边
一个后来才加进来的键、旗标或行为,版本下界写在**它那一行或那一段**旁边
(`2026.9.6.5+`),不写在章节顶部,也不写成「从前是 X,后来变成 Y」的叙述 ——
后者是设计记录的句子(第一节)。
### 书与工具书:两种属性,两种索引
一套文档同时要能被**从头读**和被**反查**。这两件事不能由同一张表兼任 —— 一张按
阅读顺序排的目录,回答不了「我手上有 `[feature-deps]`,该看哪一章」;一张按字母排
的索引,读者从头读会不知道先读哪个。
所以是两种索引,各司其职:
| 属性 | 承担它的东西 | 判据 |
|---|---|---|
| **书** | 章节的段位与部分内顺序(第九节的梯度) | 一个从头读的人不需要跳级 |
| **工具书** | **反查索引**:manifest 键 / 命令 / 概念 → 章节;以及每章开头的「不在这里」 | 一个拿着一个记号来的人,一步到位 |
反查索引的**分母取自代码树**(第十节):参考章节里出现的每一个键,反查表里都要有
一行。少一行,读者就会认为那个键没有文档。
### 优势由产物自己说明,不靠形容词
用户文档与示例要让读者**明显感到** mcpp 的长处,而做到这一点的方式不是形容词。
「简洁」「好用」「强大」本身不携带信息,读者读到的是一个主张。
写成可验证的三样东西之一:
| 不采用 | 采用 |
|---|---|
| 打包非常简单 | 六行 manifest,一条 `mcpp pack`,产出一个静态二进制 |
| 增量构建很快 | `Finished dev in 0.06s` |
| 不带加速器时开销很小 | 不点名加速器的构建**一个字节都不下载** |
| 依赖是可选的 | `counters` 不带 feature 出现 **0 次**,带 feature **2 次** |
**判据:把所有形容词删掉,读者还能不能看出优势?** 能 → 对。删掉之后只剩机制
描述 → 那份「感受」本来就只在形容词里。
**类比可以,对照不可以 —— 两者的区别是它服务谁。**
| | 目的 | 归属 |
|---|---|---|
| **类比** | 让读者把新概念挂到已有认知上 | 用户文档,**可以** |
| **对照** | 主张 mcpp 在某个维度上更好 | 设计记录,用户文档**不可以** |
「工具链管理大致相当于 rustup 在 Rust 里的角色」是类比 —— 它给一个部分定位,不作
评价。「比 CMake 简洁」是对照 —— 它是一个主张,而用户文档不是提出主张的地方。
类比要**带一句免责**:上面每个工具在它自己的领域里做的都比 mcpp 多。少了这一句,
定位会被读成等价。
### 渐进式叙事:最短可跑 → 常见形状 → 完整表面 → 边角
复杂或小众的特性不从机制讲起。四段,顺序固定:
| 段 | 内容 | 读者在这一段结束时 |
|---|---|---|
| 最短可跑 | 能跑的最小形态,连同它的真实输出 | 手上有一个跑起来的东西 |
| 常见形状 | 绝大多数工程实际会写的那一种 | 能照着改成自己的 |
| 完整表面 | 字段、旗标、取值 | 查得到 |
| 边角 | 平台差异、限制、失败形态 | 知道什么时候会撞墙 |
**判据:读者读到第几屏时手上有一个能跑的东西?** 第一屏之后还没有,就是把机制讲在
了可跑之前。
一次只加一条轴。`examples/09-heterogeneous/boundary` 是这条规则的形状:它先只讲
边界(不需要设备),`cuda` 再加设备编译器,`multi-backend` 再加第二个后端。
### 两个视角都要设计
- **全局**:入口的角色索引、部分的划分、编号所在的段位、章节之间的顺序。
- **局部**:每章的开头三行、每一节推荐哪一条路径、表格用于枚举而散文用于因果、
段落不超过约六行、代码块前有一句说明它演示什么。
一份全局清楚而局部混乱的文档,读者找得到却读不懂;反过来则读者读得懂却找不到。
两者都要过第十四节的评审。
## 十三、机器检查
规则里可判定的那一部分由 `.github/tools/check_docs_style.sh` 执行:
```
bash .github/tools/check_docs_style.sh
```
它今天检查三条:标题不是疑问句/口语片段;参考文档不使用第二人称;
`docs/X.md` 与 `docs/zh/X.md` 的标题结构一致(按层级序列比对,并剔除代码块内的
`#` 注释 —— 第一版脚本把 ```sh 块里的 `# GET, never HEAD` 数成了标题,报出一个
并不存在的结构分歧)。
**注意它的作用域是 `docs/*.md docs/zh/*.md`,不递归**,所以 `docs/specs/` 今天
不在检查范围内。这是通配符的后果,不是决定;扩作用域与新增下列检查已列入
`.agents/docs/2026-09-08-documentation-architecture-three-trees.md`:emoji、
禁止边、被引用的 `docs/…md` 路径必须解析得到、规范双索引完整、规范元数据表与
变更记录存在。
**它不检查第六、七、九节** —— 断言强度与证据是否相符、文档是否对得上当前实现、
覆盖是否有分母,都需要读者判断,而那三条是本规范里最重要的。
**脚本能做的事不等于规范的全部。**
## 十四、评审判据
文档改动**至少评审一次**,而且**不由写它的那一遍来评审** —— 刚写完就自审,读到的
是自己的意图而不是文本。判据:评审时只读渲染后的成文,不读 diff。
八个维度,每个都有一条可执行的判据,不是感觉:
| 维度 | 判据 |
|---|---|
| **面向人群** | 一句话说出这份文档的读者是谁。说不出,就是没定位。二次判据:从入口的角色索引能不能指到它 |
| **梯度** | 它是第九节五级里的哪一级?它链接的是不是相邻级?跨级链接一律是缺陷 |
| **渐进性** | 一个从零开始的读者,能不能不跳级地到达这里 —— 前置的最小可跑形态存在吗 |
| **直观** | 只读前 15 行,能不能答出「这章讲什么、我要不要读」 |
| **覆盖度** | 分母是什么(第十节)?「当前边界」一节在不在,且是事实清单不是说理 |
| **陈述方式** | 陈述句;无第二人称(教程除外);无 emoji;每条断言的强度与证据相符;「支持」分三档 |
| **信息密度** | 随机抽三段,逐段问「删掉它读者少知道什么」。答不上来就是低密度 —— 典型是复述上一段、为强调而重复、以及把一个事实拆成三句 |
| **易读** | 表格用于枚举、散文用于因果;一句一个事实;段落不超过约六行;代码块前有一句说明它演示什么 |
| **一条推荐路径** | 只读正文、不展开任何 `<details>`,读者能不能不做选择就把事情做对(第十二节) |
| **增量标注** | 每个后加的键/旗标/行为,版本下界写在它自己旁边,而不是章节顶部或历史叙述 |
| **章节规格** | 第二节那张表能不能填满 —— 读者、那一个问题、包含、排除、位置与理由、前后、判据 |
| **冲击力** | 把形容词删掉,优势还看得出来吗 —— 有没有最短可跑的产物、真实输出、可数的数字 |
| **渐进性(局部)** | 读者读到第几屏手上有一个能跑的东西;是不是一次只加一条轴 |
| **可查阅** | 拿着一个 manifest 键 / 命令 / 概念,能不能一步查到章节;反查索引有没有漏行 |
**用户文档额外一条,优先级高于以上八条**:逐段问「删掉它读者还能不能正确地用」
(第一节)。设计理由、被否掉的替代、路线图,一律不在用户文档里。
评审的产出是**一份逐条的结论**,不是「看起来不错」。每个维度给出:通过 /
不通过 + 具体位置。
## 十五、自检清单
提交文档改动前:
```
[ ] 这份文档属于哪棵树,判据答得上来
[ ] 用户文档:逐段问过「删掉它读者还能不能正确地用」,设计理由/被否替代/
路线图都不在里面
[ ] 用户文档:一个能力只写「能用(带版本下界)」或「不支持(一句话)」
[ ] 「当前边界」是事实清单,不是说理
[ ] 有多种做法时,正文只写推荐那一条,其余在 `<details>` 里
[ ] 后加的键/旗标带版本下界,且标在它自己旁边
[ ] 优势由最短可跑产物 / 真实输出 / 数字说明,不由形容词说明
[ ] 复杂特性按「最短可跑 → 常见形状 → 完整表面 → 边角」推进
[ ] 第二节的章节规格七格都能填出来
[ ] 没有 docs/** → .agents/** 的引用
[ ] 开头点明了它在梯度里的哪一级,且只链接相邻级
[ ] 标题没有疑问句、没有口语片段
[ ] 没有 emoji、没有网络用语、没有新造比喻
[ ] 没有第二人称(教程体除外)
[ ] 每条「实测」都有数字、路径或报错原文
[ ] 「支持」按三档分开写,没有把「已声明」写成「已运行」
[ ] 没有未经验证的全称断言
[ ] 每个可粘贴的命令与输出都在当前发布版上复现过,或标了版本下界
[ ] 本次实现改动作废的文档已在同一个 PR 里改掉
[ ] 新增的能力已归入示例 / 代码块 / 场景条目三者之一
[ ] 有「当前边界」一节
[ ] 中英两版结构对应,代码块逐字一致
[ ] `bash .github/tools/check_docs_style.sh` 通过
```