Files
deepseek-harness/docs/rfc/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.zh.md
Tianyi Cui e6fad266a6 docs(rfc): define and enforce a uniform RFC format; adopt it across the corpus
Define the in-file RFC contract in docs/rfc/README.md § The file format:
the header block (`# RFC: <title>` plus a dateless Status enum
cross-checked against the lifecycle folder), the per-lifecycle body
skeleton (a Problem opener everywhere; Proposal/Alternatives considered/
Acceptance criteria/Risks in proposed/; present-tense Decision/
Consequences with proposal-era headings banned in implemented/; the
frozen proposal shape in rejected/), and a mandatory Alternatives
considered section with a date-fenced grandfather comment for pre-format
RFCs whose alternatives are not reconstructible from the record.

Enforce it with a new doc-sync gate, scripts/verify-rfc-format.ts, and
normalize all 112 RFCs to it: ~15 Status-line spellings collapse to the
enum, 29 Context openers become Problem, the 39 legacy-format XXX debt
markers are resolved and banned from reappearing, proposal-era sections
in implemented RFCs are rewritten to shipped reality (including the
web/fs/subagent seam RFCs' migration plans and test checklists, closing
the doc-tiers deferred-work item on the web seam), every RFC gains an
Alternatives considered section or the grandfather comment, and the
bilingual pair is re-mirrored and re-recorded.

Move the generated index tables out of README.md into a fully generated
docs/rfc/INDEX.md — gen-rfc-index now writes the whole file, and
verify-rfc-classification checks its freshness and rejects index-shaped
rows in the curated README — which makes room for the format contract to
live in the README front door instead of a separate FORMAT.md.

The decision record, and the first RFC written in the new format, is
docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md.
2026-07-05 22:58:25 +08:00

39 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# RFC: 通过配对兄弟文件与配对门禁实现双语文档
Status: implemented
[English](2026-07-02-bilingual-docs-and-pairing-gate.md) | 中文
## 问题
本仓库的 README 与 docs 目录树会被公司内外的人和 agent(智能体)以中英两种语言阅读。没有机制、纯靠手工维护第二语言,正是译文腐烂的方式:一侧继续演进,另一侧默默地说谎,而没有门禁会注意到。对这类不变式,本仓库一贯的答案是把它编码成机械检查(见[质量门禁](2026-06-11-quality-gates.md)与 [doc-sync 强制](2026-06-11-doc-sync-enforcement.md)),因此双语政策随附一道门禁一起交付。
## 决策
- **配对兄弟文件,两种语言同权。**一对文档是三个兄弟文件:英文 `foo.md`、中文 `foo.zh.md`,加一份一致性记录 `foo.i18n.yaml`。没有哪种语言是正典——一篇文档可以先用中文撰写和评审、之后再译成英文,反之亦可;约束这对文件的是两侧必须说同样的话,且配对整体合入(两种语言加记录,绝不单独落一侧)。政策见 [docs/i18n/README.md](../../../i18n/README.md);翻译规则见 [docs/i18n/translation-rules.md](../../../i18n/translation-rules.md);术语真源见 [docs/i18n/terminology.md](../../../i18n/terminology.md)。
- **旁挂记录两侧 blob hash,使一致性可检查。**`foo.i18n.yaml` 保存两侧文件在上一次确认一致状态下各自的完整 git blob hash。此后改了任一侧而没重新确认配对,都能被机械检测出来——纯内容比较、无需查询历史——而且同一个 PR 里改动的文件也能算出 hash,commit hash 式的记录做不到这一点。重新记录(`verify-translation-pairing --write`)产生一份可评审的 yaml diff:确认一致在 PR 里是一个显式、可见的动作。
- **`verify-translation-pairing` 加入 `doc-sync`。**门禁([scripts/verify-translation-pairing.ts](../../../../scripts/verify-translation-pairing.ts))强制执行:required 的配对存在;任何已存在的配对完整(三个文件齐全)且一致(两个 hash 都匹配、切换行双向互链、结构签名一致);被排除的文件(生成物或本身即双语的)保持不配对。[scripts/translation-pairing.manifest.json](../../../../scripts/translation-pairing.manifest.json) 中的 `required` 清单是一个棘轮:每个合入的翻译批次把自己的文件加进去,覆盖面只增不减。
- **翻译是 agent 的工作,由人评审。**进仓的工作流是 [.agents/skills/dsh-translate-docs](../../../../.agents/skills/dsh-translate-docs/SKILL.md),与 [dsh-code-review](../../../../.agents/skills/dsh-code-review/SKILL.md) 同一模式:skill 承载工作流,并把真源让给文档。
## 曾考虑的替代方案
- **英文为正典源、指纹放在译文内**——本 RFC 最初提出的设计:`.zh.md` 文件携带一条 HTML 注释记录英文源的 blob hash,翻译只沿 EN → ZH 单向流动。评审中修订:团队需要中文先行的撰写方式(先写、先审中文 RFC,再译英文),两种语言同权,而单向正典模型无法表达这一点。覆盖**两侧**的旁挂记录取代了文件内的单向指纹;blob hash 的机制原样保留。
- **语言目录(`docs/en/` + `docs/zh/`,Kubernetes/ECharts 模式)**——否决:本仓库没有把 locale 映射到路由的文档站框架,挪动每个英文文件会搅动所有既有交叉引用,且 `verify-md-links`/`verify-doc-refs` 将需要路径映射逻辑而不是原样工作。
- **独立翻译仓库(PingCAP `docs`/`docs-cn` 模式)**——否决:适合有独立发布节奏的文档产品,对 monorepo 自己的文档而言过重;还会把译文置于本仓库门禁够不到的地方。
- **中英混排单文件(一个文件、两种语言)**——否决:每个 diff 都翻倍,破坏一段一行约定的 diff 工效,且局部不一致不可见。
- **Commit hash 式记录(MDN `l10n.sourceCommit` 模式)**——否决,改用 blob hash:同一个 PR 内的改动还没有 commit hash,MDN 模式无法表达「与本 PR 引入的状态一致」,且校验它需要 git 历史而非文件内容。
- **比较配对两侧的 git 时间戳(无记录)**——否决:纯格式化的改动会误报,一次无关改动之后提交的另一侧会漏报;只有内容同一性这个信号与门禁的承诺名实相符。
## 业界先例
带语言后缀的配对兄弟文件是中国大厂的主流约定(ant-design 的 `index.zh-CN.md`/`index.en-US.md`;arco-design 的 `README.zh-CN.md` 加顶部切换行;Apache ShardingSphere 的 387 对 `.cn.md`/`.en.md`)——但这些仓库都没有在 CI 里**强制**配对或一致性;约定纯靠评审维系。一致性自动化存在于中国之外:MDN 的 `l10n.sourceCommit` front-matter 指纹、Vue 的 Ryu-Cho action(监视上游 commit、为陈旧译文自动开 issue/PR)、Kubernetes 的本地化漂移脚本、微软 Azure co-op-translator(CI 中由源 hash 驱动的 LLM 重译)。本设计把两者结合:中文生态的文件布局,加 hash 对门禁,再加一个进仓 agent skill(技能)替代 bot 服务。
## 后果
- 修改已配对文档的任一侧,同一个 PR 就有义务更新另一侧并重新记录配对——门禁把 doc-sync 规则双语化,不变式由 CI(而非评审者的记忆)承载。
- 每个配对给目录树多添一个文件。记录由机器写入(`--write`),代价是目录噪音而非维护负担;换来的是「谁在何时确认过这对一致」可以从 yaml 的 git blame 直接回答。
- 两侧说法冲突时,没有机械规则裁决谁赢——由 PR 评审裁决。这是同权的代价,是有意接受的:另一个选项(正典语言)禁止中文先行撰写。
- 生成文档(`cordis-catalog/`、`tool-catalog/`、`module-graph.md`)暂被排除;计划中的后续工作是让它们的生成器在输出英文的同时输出中文,届时移出排除清单。
- 推进天然是渐进的:`required` 之外的文档是可见的 backlog(`--list`),不是红的 CI,因此配对按可评审的批次落地,无需一个巨型 PR。
- 记录的 hash 兼作更新工具(`git cat-file -p <hash>` 能还原任一侧上次确认的文本,用于基于 diff 的最小更新),所以这套机制从不强迫整篇重译。