Bundle
dsh-doc-guard
文档-代码一致性守护(Document-Code Consistency Guard):审计仓库的版本号/更新记录表/结构树/模块清单/测试计数/文档间交叉引用,检测漂移并按严重度输出修复建议。全程只读。
- Source
- lucky8197
- stars
- 2 stars
- License
- BSD-3-Clause
- Updated
- Updated 19 hours ago
Readme
# dsh-doc-guard(文档-代码一致性守护)
> **Document-Code Consistency Guard for DeepSeek Harness.**
> A read-only DSH plugin that audits your versioned Markdown design docs against the
> actual repository: header version numbers, changelog tables, directory-structure trees,
> module/test counts, and cross-document references. It detects drift (docs saying one
> thing, code being another) and outputs actionable, severity-sorted fix suggestions.
> Install with: `dsh plugin --profile web add "github:<your-github-user>/dsh-doc-guard#main"`.
很多仓库用「版本化 Markdown 文档」记录设计:`doc/` 下多份文档,头部有 `文档版本:vX.Y`,
更新记录是 Markdown 表格,正文含目录结构树、模块/系统清单、测试计数、验收数字与文档间互相引用。
代码改完后文档极易漂移:改了代码没加更新记录行、版本号没递增、结构树与真实文件树不符、
测试数与验收记录对不上、文档间引用版本不一致。
`dsh-doc-guard` 用**纯启发式、全程只读**地审计这些维度,检测漂移并按严重度输出可直接执行的修复建议。
是 DSH 生态中第一个做「文档漂移审计」的插件(context-doctor 只审上下文注入成本,不审文档漂移)。
## 特性
| 审计维度 | 说明 | 漂移类型 | 严重度 |
| --- | --- | --- | --- |
| 版本号一致性 | 头部 `**文档版本:vX.Y**`(或 `> - 文档版本:vX.Y`)与更新记录表最新行版本比对;文档间 `对应技术设计 vX` 引用值与目标文档当前版本比对 | `version_mismatch` | high |
| 更新记录表 | 解析 `\| 版本 \| 日期 \| 更新内容 \|` 表格:最新版本≠头部版本、更新内容为空(禁止只改版本号不记内容) | `version_mismatch` / `missing_record` | high / medium |
| 代码变更未记录 | 最近代码文件 mtime 晚于记录表最新日期超过窗口 → 「可能有未记录的代码变更」(mtime 启发式,安全边界内不执行 git) | `stale_record` | low |
| 结构树漂移 | 代码块中 `├──`/`└──` 目录树 vs 真实文件系统(自动排除构建/VCS 目录;目录级摘要树只比目录层级) | `tree_missing` / `tree_extra` | medium / low |
| 模块/系统清单 | `N 个 System` / `N 份文档` / `N 个测试文件` 等计数声明 vs 真实计数(目录条目/文档数/测试数) | `count_mismatch` | low |
| 测试计数 | `Core 199/199`、`Net 91 通过/4 跳过` 等验收数字 vs 测试源文件静态统计(按扩展名识别 `[Fact]`/`it(`/`#[test]`/`def test_`/`@Test`/`func Test`,不执行测试) | `count_mismatch` | low |
| 文档间交叉引用 | `详见 §X` / `见实现文档 §X` → 被引文档是否存在;`对应技术设计 vX` → 版本值是否等于被引文档当前版本 | `cross_ref` / `version_mismatch` | high |
全部启发式可配置、可忽略;**误报宁可少**——无法确定性解析的目标一律跳过,不猜测。
## 快速安装
```bash
# GitHub 源(构建产物 lib/ 已入库,无需构建)
dsh plugin --profile web add "github:<your-github-user>/dsh-doc-guard#main"
```
安装后重启 dsh web,`doc_guard` 工具即出现在模型工具列表;`dsh --profile web --dump-config | grep doc-guard`
应输出含 `id: doc-guard` 的挂载记录。
## 工具用法
```
doc_guard
参数:
cwd?: string 审计起点目录(默认当前会话工作目录)
docs?: string[] 要审计的文档路径(默认自动发现 cwd 下 doc*/ 目录 + 根目录含版本头的 *.md)
includeCounts?: boolean 是否做测试计数/模块计数启发式(默认 true)
detail?: 'summary' | 'developer' 默认 summary;developer 附可定位 receipt(路径+行号)
输出:canonical JSON 报告(见下),渲染为分节文本
```
### canonical JSON
```jsonc
{
"tool": "doc_guard",
"version": 1,
"cwd": "/path/to/repo",
"docs": [
{ "path": "doc/实现文档.md", "headerVersion": "v1.43",
"records": [{ "version": "v1.43", "date": "2026-08-15", "hasSummary": true }] }
],
"drifts": [
{ "severity": "high",
"kind": "version_mismatch",
"doc": "doc/实现文档.md",
"detail": "头部文档版本 v1.43 与更新记录表最新行版本 v1.42(第 8 行)不一致",
"evidence": "文档版本:v1.43;更新记录 v1.42 / 2026-08-14",
"fix": "在 doc/实现文档.md 更新记录表追加 v1.43 行(含日期与更新内容),或把头部版本改回 v1.42" }
],
"stats": { "docsScanned": 3, "driftCount": 1 },
"suggestions": [ { "severity": "high", "text": "…" } ]
}
```
`detail=developer` 时附加 `receipt`:每份文档的版本头/记录表行号、每条漂移所在行号、
测试文件静态统计明细(路径+标记数)——供 Agent 定点修复。
## 配置(cordis 配置节)
```yaml
# ~/.dsh/profiles/web/cordis.patch.yml 或 cordis.yml 中
- insert:
- id: doc-guard
name: 'dsh-doc-guard'
config:
docsPatterns: ["doc/**/*.md", "*.md"] # 自动发现的文档 glob
ignoreTreePaths: [".git", "bin", "obj", "node_modules", "dist", "lib", ".dsh"] # 结构树忽略
countTolerance: 1 # 计数对比容差(±N 内算一致)
staleCommitWindow: 5 # "代码改了文档没动"窗口(天,mtime 启发式)
maxEvidenceLen: 200 # 报告 evidence 片段最大长度(字符)
maxFileBytes: 524288 # 单文件大小硬上限(字节),超限跳过
```
> `staleCommitWindow` 语义为「最近 N 天内有代码变更但文档记录未跟进」。
> 因安全边界禁止执行 git(见下),实现为只读 mtime 启发式而非提交数。
## 安全边界(硬性要求)
- **全程只读**:只用 `ctx.fs` 的 `resolve`/`stat`/`readText`/`listDir` 子集;
唯一的 `node:fs` 使用是**只读 `stat`** 取文件 mtime(陈旧度启发式),不写、不删、不执行;
- **单文件 > 512 KB 跳过**(`maxFileBytes` 可配,硬上限);
- **报告不含完整文件内容**:只含路径、统计与 ≤200 字符的证据片段;
- **不执行测试、不跑构建**:测试计数用静态扫描(按扩展名匹配测试标记);
- 不修改任何文件:审计前后仓库内容逐字节不变(有测试断言)。
## 防误报设计(误报宁可少)
- 更新记录表区域(历史快照)不参与当前状态判定:`v1.42:对应实现文档 v1.41` 是历史事实,不是当前引用;
- 里程碑/作用域验收数字(`M3 83/83 全绿`、`Core 153/153 + Net 24/24`)不与全局总数对比——
仅当全文是单一通用标签(`tests 290/290` 等)且声明数 ≤3 时才与静态统计对比;
- 目录级摘要树(无文件名明细)只比对目录层级,不报 `tree_extra`;
- 树中未展开的目录(列出但无子行)不报其内容为 extra;隐藏/临时文件(`.env`、`*.tmpdir`)忽略;
- 流程图/时序图/ASCII 框图(`└──▶ M5 ──▶ M6`、`───┬───┘`)不会被误判为结构树;
- 多树块文档只取行数最多的主结构树;`game01.slnx` 这类文件标签不会当目录根。
## 工程结构
```
dsh-doc-guard/
├── package.json # name=dsh-doc-guard, type=module, main=./lib/index.js,
│ # dsh.bundle.patch=./cordis.patch.yml; peerDeps: @deepseek-ai/cordis
├── cordis.patch.yml # - insert: [{ id: doc-guard, name: 'dsh-doc-guard' }]
├── tsconfig.json # 编译到 lib/types/(纯 tsc,无打包器)
├── scripts/
│ ├── setup-dsh-deps.mjs # 定位本机 DSH 安装并链接 @deepseek-ai/* 依赖(junction/symlink)
│ ├── build.sh # setup + tsc(POSIX)
│ ├── build-win.mjs # 等效 Windows 构建(无 bash 依赖)
│ ├── self-test.mjs # 对任意仓库跑审计引擎
│ └── verify-drift.mjs # 注入漂移验证(真实仓库拷贝 + 篡改版本号)
├── src/
│ ├── index.ts # apply(ctx):注册 doc_guard 工具 + 配置读取
│ ├── audit.ts # 编排:runAudit 全链路 + developer receipt
│ ├── scan.ts # 文档发现、版本头/更新记录表/结构树/计数/交叉引用解析、测试静态统计
│ ├── diff.ts # 结构树 vs 磁盘对比(虚拟根/摘要树/穷尽目录处理)
│ ├── analyze.ts # 六类漂移判定 + 严重度分级 + 修复建议 + 分节渲染
│ └── types.ts # canonical 类型 + 配置 + fs 服务面子集
└── tests/ # node --test(54 用例,零测试依赖,真实临时目录端到端)
```
## 开发 / 测试 / 构建
```bash
npm install # 安装 typescript/@types/node(devDeps)
npm run setup # 定位本机 DSH 安装,链接 @deepseek-ai/* 依赖
npm test # node --test 'tests/*.test.ts'(54 用例)
npm run build:win # Windows 构建;POSIX 用 npm run build(scripts/build.sh)
node scripts/self-test.mjs /path/to/repo # 对真实仓库跑审计引擎
```
构建产物 `lib/`(`lib/index.js` + `lib/types/*`)**入库提交**——GitHub 源安装依赖它,用户无需构建即可 `dsh plugin add`。
## FAQ
**Q: 为什么不执行 `git log` 判断「代码改了文档没动」?**
安全边界禁止执行任何命令(含 git)。实现为只读 mtime 启发式:最近代码文件修改时间 vs 更新记录最新日期。
**Q: 测试计数为什么有时不报?**
只有「全文单一通用标签(tests/测试/全部)且声明 ≤3」的验收数字才与全局静态统计对比;
`Core 199/199`、`M3 83/83` 这类带作用域的里程碑数字无法静态映射,宁可少报。
**Q: 报告会泄露文档内容吗?**
不会。报告只含路径、统计与 ≤200 字符证据片段(`maxEvidenceLen` 可调)。
**Q: 支持哪些测试框架标记?**
按扩展名静态匹配:C# `[Fact]`/`[Theory]`、JS/TS `it(`/`test(`、Rust `#[test]`、
Python `def test_`、Java/Kotlin `@Test`、Go `func Test`。
## License
BSD-3-Clause。见 [LICENSE](./LICENSE)。
Install
dsh plugin --profile web add github:lucky8197/dsh-doc-guard
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-doc-guard from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.