本文件是 vanblog 文档包的权威质量契约。
doc-reviewer子 agent 依此审查;所有文档作者(人 / agent)在写作前必须读本文件。 版本: 1.0 · 生效日期: 2026-08-14 · 维护者: 仓库维护者 机器检测:node scripts/check/doc-dup-check.mjs(见 §6)
面向 CMS(博客系统) 这类产品,文档包不是「一篇文章」,而是一组面向不同读者角色的文档。核心矛盾是:
-
事实只有一份,但读者有很多种。
-
事实(端口、路径、默认值、命令、字段)必须只存在一份权威出处(Single Source of Truth, SSOT)。
-
面向不同 level 用户的使用文档,不重复事实,而是引用(
ref) 权威出处。 -
用「分层 + 引用」替代「复制粘贴」,从源头杜绝内容漂移(同一事实两处改了其中一处 → 文档互相矛盾)。
-
语言去 AI 味:直说、信息密度高、口语但准确。写作/审查前读
.agents/skills/de-ai-write/SKILL.md(空洞连接词、排比、注水、假精确都属于 AI 味,检测即修)。
所有文档按以下四类组织。新文档必须先归位,不允许新造扁平文件。
| 层 | 目录/文件 | 读者 | 职责 | 写作铁律 |
|---|---|---|---|---|
| R · 参考层(事实 SSOT) | docs/reference/*.md,按系统细分 |
查表型用户 / 高级用户 | 存放事实:环境变量表、端口、路径、命令、字段、API。每个事实在此且仅在此定义一次。 | 每个事实唯一;只陈述事实,不写教程叙事 |
| G · 使用层(面向不同 level) | docs/guide/*.md |
按 level 细分:L0 新手 / L1 普通 / L2 折腾 | 教用户完成任务(写文章、换主题、反代、升级)。 | 出现事实 → 用链接 ref 到 R 层,不抄录;允许一句带链接的总结 |
| F · 门面层 | README.md、docs/README.md(文档索引) |
路人 / 潜在用户 | 门面 + 索引。给出定位、截图、最快的上手路径、到文档的入口。 | 只做入口与最短路径;不放任何可被 R/G 层覆盖的长事实 |
| Q · 问答层 | docs/faq.md |
出问题的用户 | 症状 → 原因 → 解决方案(ref 到 R/G)。 | 每条 FAQ 结论必须 ref,不得把解决步骤整段复制进来 |
开发者文档(主题开发、SDK、贡献)按读者归入
docs/developer/,同样遵守「事实进 R 层、教程进 G 层」的分层。
一句话里如果包含以下任一,它就是「事实」,必须进 R 层:
- 参数值:端口号、路径、卷挂载点、默认值、镜像名/标签、域名
- 命令:
docker compose ...、./vanblog.sh ...、go build ... - 配置键:环境变量名(
VANBLOG_*)、site 集合字段名、JSON 结构 - 契约:API 端点、权限规则、L0/L1/L2 契约
使用文档引用 R 层事实时,用相对链接,并给出「一句话总结 + 链接」,示例:
完整环境变量表见 [参考: 配置](../reference/configuration.md)。禁止形态:
- ✗ 把整张环境变量表 / 整段端口说明复制进使用文档。
- ✗ 使用文档里出现与 R 层不同的端口 / 默认值(这是 S0 冲突,见 §4)。
- ✗ FAQ 里把解决步骤写成「完整教程」,而不是指向教程。
对任何一段跨文件重复内容,按以下分级处置。优先级从高到低。
同一事实在两处及以上定义,且取值冲突(例如 A 文档写 8080、B 文档写 8081)。
- 危害:直接误导用户,可能造成配置事故。
- 处置:合并到唯一的 R 层出处,其余全部改为 ref。全文档要求 S0 = 0。
- 检测:脚本的「参数冲突检测」+ doc-reviewer 人工抽查。
同一事实多处定义且内容一致,但连续重复文本达到阈值。
- 阈值:连续 ≥ 2 句(或 ≥ 100 中文字符 / ≥ 200 字节) 与另一文件重叠。
- 危害:改一处漏一处 → 逐步演化为 S0。
- 处置:保留 R 层唯一出处,其余改为 ref;FAQ 保留「症状+一句结论」但结论 ref。
- 检测:脚本的「句子级跨文件匹配」(shingle 8-gram)。
不可避免的短片段重复:命令本身、术语、固定链接、许可声明。
- 判定:单条 ≤ 1 句,且属于以下白名单类。
- 白名单:
./vanblog.sh命令名、docker compose up -d、ghcr.io/cornworld/vanblog:prod-edge、GPL 声明、指向同一 URL 的链接。 - 处置:不改。若脚本误报白名单项,在脚本的
WHITELIST数组登记。
引用式提及:一句话带链接指向权威出处(见 reference/configuration.md)。
- 这是目标形态,不视为重复。
| 指标 | 定义 | 目标 / 阈值 |
|---|---|---|
| 全局段落级重复率 | 所有「≥2 句的跨文件重复块」的字数 ÷ 全文总字数 | < 5%(超出告警 |
| 单文件段落级重复率 | 该文件「与所有其他文件的 ≥2 句重叠」字数 ÷ 该文件字数 | < 15%(超出告警 |
| S0 冲突数 | 参数值 / 默认值冲突的处数 | = 0(硬性要求,不满足即不通过) |
| S1 重复块数 | 达到 S1 阈值的跨文件重复块 | = 0(新文档要求;存量文档限期清零) |
| 事实漂移数 | 文档事实与代码/配置不一致的处数(doc-reviewer 抽查) | 趋近 0;任何新发现立即修 |
| 链接可解析率 | 文档内相对链接目标存在 | 100% |
node scripts/check/doc-dup-check.mjs [glob] 扫描 docs 包:
- 切句 + 规范化:按中英文句号/换行切句;去除 markdown 语法、行内代码标记、链接、空白、大小写。
- shingle 匹配:以 8 词 shingle 索引所有句子;跨文件 ≥ 2 个连续 shingle 命中的句子合并为「重复块」。
- 参数冲突检测:正则抽取
\b\d{2,5}\b(端口)、VANBLOG_[A-Z_]+、/[\w/-]+路径、默认值;同参不同值出现在多文件 → 报 S0。 - 输出:每文件重复率、全局重复率、重复块清单(文件 A↔ 文件 B、行号、文本)、S0 冲突清单、白名单命中数。
- 退出码:
0= 通过;1= 存在 S0 或单文件重复率 ≥ 30%;2= 存在 S1 或告警。
脚本是证据机器,不是裁判。
doc-reviewer在脚本输出之上做人工级审查(事实漂移、结构、ref 质量)。
| 时机 | 动作 |
|---|---|
| 每次文档变更 PR | 跑 node scripts/check/doc-dup-check.mjs,要求 S0=0、无新 S1、链接 100% |
| 每周(或每次大改) | doc-reviewer 子 agent 全量审查:#agent_doc-reviewer,输出结构化报告(§ 报告模板) |
| 发布前 | 事实漂移抽查:环境变量、端口、镜像 tag 与 docker/entrypoint.*.sh、docker-compose.yml、vanblog.sh 对齐 |
| 发现过时笔记 | 立即修(不归档旧结论,直接改),见 AGENTS.md「知识源」原则 |
- S0:阻断合并;修复后重跑脚本。
- S1:要求改为 ref;修复者必须删除重复块并补链接。
- 事实漂移:修文档或修代码(以代码/行为为准);若代码是 bug,则修代码并在文档标注版本。
- 白名单误报:向脚本
WHITELIST登记(附理由),不视为违规。
README.md F 门面
docs/README.md F 文档索引(地图)
docs/quality/doc-standard.md (本文件,元文档)
docs/reference/deployment.md R 部署事实:镜像/端口/卷/入口
docs/reference/configuration.md R 配置事实:环境变量表 + site 字段
docs/reference/backup.md R 备份/恢复/升级事实
docs/reference/api.md R API 事实
docs/reference/packs.md R Pack 事实
docs/reference/themes.md R 主题事实
docs/reference/architecture.md R 架构事实
docs/guide/quickstart.md G L0 新手:5 分钟跑起来
docs/guide/backup-upgrade.md G L2:备份/升级/回滚(ref reference/backup.md)
docs/guide/reverse-proxy.md G L2:反代/安全(ref reference/deployment.md)
docs/guide/packs.md G L2:安装/启用 Pack(ref reference/packs.md)
docs/faq.md Q 症状 → 原因 → ref
docs/developer/theme-implementer-guide.md G 开发者(主题作者)
docs/developer/sdk-design.md G 开发者(SDK)
docs/developer/contribution.md G 开发者(贡献)
存量文档(
docs/*.md平铺的 13 篇内部文档)按 §2 归位:面向用户/作者的进guide/或developer/,纯内部设计笔记归docs/internal/(明确标注,不进用户导航)。
- 我写的是「事实」还是「任务」?事实 → 找 R 层唯一出处;任务 → 进 G 层并 ref 事实。
- 这段内容是否已经在别的文档存在?存在 → ref,不复制。
- 我写到的端口/路径/变量/命令,是否与代码一致?不一致 → 改。
- 我给的链接能点通吗?相对路径是否正确?
- 我在 FAQ 里是否把「完整步骤」复制了进来?应该只给症状 + ref。
- AI 味检查(用
.agents/skills/de-ai-write/SKILL.md):有没有「总之 / 值得注意的是 / 我们需要 / 接下来」这类空洞词、排比堆砌、注水填充、假精确副词(非常/极大/无缝)?有 → 清掉。