--- name: dsh-knowledge-upkeep description: dsh 平台文档库 / 项目知识的**维护与纠偏方法**。当发现「文档与现状不符」「同一事实多处打架」「知识越积越碎」「AI 忘了某条规则」「要收敛或重构知识库结构」时使用;也用于定期体检。核心 = 六层知识结构(L0-L5)+ **分层判据(实体 vs 指针)** + Lint 四件套 + **漂移处理 SOP** + **自动化的边界(检测可自动,改写不可自动)** + 今天踩过的 5 个反例 + **§8.6「注入预算」维度**(每轮注入有上限 ⇒ 长文件后半段等于不存在;**先重排、后删减**)。**配套:`dsh-feature-first`(谁定什么)· `dsh-decision-method`(怎么定得对)· `dsh-change-workflow`(怎么落地)。** version: 1.2.0 updated_at: 2026-09-16 agent_created: true --- # dsh-knowledge-upkeep — 知识库维护方法 > **一句话**:知识库不会自己变好,**只会慢慢变错**。本技能把"纠错"从临时动作变成**可复跑的方法**。 > 素材来源:2026-09-12 全库校验实证(20 项违背 → 0)。 --- ## 0. 为什么需要它(实证,不是理论) | 现象 | 实测 | |---|---| | **同一事实被抄很多份** | 现行域名出现在 **21 个文件 / 123 处**;档案"下一号"写在 4 处且**互相打架**(72 / 69 / 53 / 20) | | **过时值长期存活** | 旧配额活在 15 个文件;实例 MemoryMax 曾同时存在两个"现役值" | | **权威源头本身是错的** | `BRIEF.md`(首读现状卡)自己带着旧值 → AI 老老实实读了它,读到就是错的 | | **校验工具查不到** | 原 `docs-audit.py` 只查**结构**(编号/悬空/重复),**不查事实** → 漂移不可见 | | **规模已超"全量塞入"上限** | 库 = 93 md / 555,533 字符 ≈ **388,873 tokens**;Karpathy 模式实证 **~100 篇就崩**(模型开始略读并给出自信的错误答案)| --- ## 1. 知识结构:六层 + 单一来源 | 层 | 内容 | 唯一权威 | 变更频率 | 送达方式 | |---|---|---|---|---| | **L0 不变量** | 架构与机制(为什么这样设计) | `01-规划与架构` + 早期档案 | 年 | 按需 | | **L1 现行值** | 现在到底是什么(域名/配额/端口/路径/阈值) | **`BRIEF.md`** | 周 | 首读 | | **L2 规则** | 必须遵守(提问判据/红线/提交边界) | **`CODEBUDDY.md`** | 很少 | **自动注入** | | **L3 方法** | 怎么想、怎么做 | 3 个 dsh 技能 | 月 | 按需触发 | | **L4 状态** | 现在在哪(待办、落差) | `交接单/` + `.workbuddy/memory/MEMORY.md` | 天 | **自动注入** | | **L5 历史** | 怎么变成现在这样 | `04-调整方案/` + `archive/` | **只增不改** | 按需 | **三条铁律** 1. **每个事实只有一个权威** —— 其余文件**只许写指针,不许复制数字**。 2. **L5 冻结** —— 历史档案里的旧值**不回改**(写的时候是对的,回改破坏历史);需要修正时**在文末追加「修正(YYYY-MM-DD)」小节**,并改 L1 的现值。 3. **校验必须能查"事实一致性"** —— 否则前两条必然失守。 --- ## 2. 分层判据:**什么必须实体,什么可以只给指针** > **"不做会违规、会出事"的 → 实体保留;"看了更准但不看也不违规"的 → 才给指针。** | 处理 | 内容 | |---|---| | **实体保留**(压缩不许删语义) | 提问判据 · 红线 R1–R8 · 提交边界 · 规划/执行分离 · 并发纪律 · **会导致事故的实测事实** · 环境要点 | | **只给指针** | 平台现状与历史细节 · UI 规范全文 · 档案模板细则 · 某功能的实现内幕 | ⚠️ **指针必须绑定可识别的动作**,否则"去查"不会发生: `当你要写前端页面 → 先读 06-UI规范`,而不是 `详见 06-UI规范`。 --- ## 3. Lint 四件套(可复跑,退出码可接 CI) ```bash python3 scripts/docs-audit.py # 结构:编号冲突 / 标题号不符 / 悬空引用 python3 scripts/docs-manifest.py # 刷新机读清单 docs-manifest.json(含被引次数/tier) bash scripts/docs-sync-check.sh # 双端对账(本机 ↔ /opt/dsh/docs) python3 scripts/docs-consistency.py # 事实:写死取值 + 跨页取值冲突 ``` **`docs-consistency.py` 的设计要点**(写它时踩过的坑,别重踩): - 只查**高置信**模式。首版把「旧域名」「旧配额」当违规 → **几乎全是误报**(库里都是"旧域已 301" / "512M→384M" 的合法表述)。 - **引号感知**:引号内的匹配 = **引用历史**,不是断言,不算违规。 - 判据 = 「**承诺现行**的文件不许含已废止/写死/矛盾的取值」; **历史豁免**:`04-调整方案/**`、`archive/**`、`01-规划与架构`、`02-运维手册`。 **建议补跑(不在四件套内,但会毁可读性)—— 编码合法性** ```python for p in all_md: # 用 open(p,'rb').read().decode('utf-8') 整块判,别逐字节 try: open(p,'rb').read().decode('utf-8') except UnicodeDecodeError as e: print(p, e.start) ``` 🔴 **只有几个非法字节也会毁掉整份文件**:自动编码检测判"不是 UTF-8"⇒ 走偏为 GBK ⇒ **整份读出来全乱码**。 (2026-09-16 实测:212 KB 的日志因**开头 2 字节**坏 ⇒ `Read` 全文乱码。处置见 `PLAYBOOK §10.1`。) --- ### 3.1 交接单的「口径指纹」—— 改正文必连带(2026-09-16 实测) | 项 | 内容 | |---|---| | 算法 | `tail -n +4 <单子>.md \| md5sum`(**跳过前 3 行**:标题 / 空行 / 指纹行) | | 含义 | 前 3 行**不参与** ⇒ 改指纹行本身不破指纹;改**正文任何一字** ⇒ 指纹必变 | | 引用点 | ① 单子第 3 行 ② 接续包/入口里对它的引用 ③ 记忆(`MEMORY.md` / 日志)里记的值 | 🔴 **改完单子正文的正确收尾顺序**:改正文 → **复算指纹** → 写回第 3 行 → 用脚本**全文 `replace`** 所有引用点(⛔ 别手改)→ 复算自证「实算值 == 三处登记值」。 ⚠️ **一次要改多处正文时,先全改完再算一次**(实测改两轮 ⇒ 指纹算三轮 ⇒ 白绕 2 轮工具调用)。 **⛔ 最容易漏的不是单子,而是"单子之外"的过期口径**(本轮真漏过一次): ```bash grep -rn '<旧口径关键词>' --include='*.md' . # 例:未修 / 待专门一轮 / 已定位、未修 ``` - **文件顶部 `>` 摘要块最容易残留** —— 下一棒第一眼读的就是它。 - 单子的**历史章节**(如"§11.6 当时未修")**保留原文 + 加勘误段/标题后缀**,别删 —— 历史可追溯,且不会误导跳读者。 --- ## 4. 漂移处理 SOP(发现 → 收敛,五步) ``` ① 发现 → 四件套任一项退出码非 0 ② 定性 → 真漂移 / 合法历史表述 / 校验器误报 ← **这一步不能跳** ③ 定权威 → 这个事实的**唯一权威**是哪一层哪个文件(见 §1) ④ 收敛 → 改权威文件;其余副本改为指针或删除;写死值改为"复跑取号" ⑤ 复跑+同步 → 四件套全绿 → scp → 复跑 docs-sync-check.sh ``` **② 定性是分水岭**——2026-09-12 首跑报 20 项,逐条看上下文后: - 真漂移 **≈6 项**(下一号三处矛盾、MemoryMax 两处取值不一致、`maidou`、旧路径、SSH 端口) - **合法历史 14 项**("旧域已 301" / "512M→384M" 的迁移表述) ⇒ 若不做定性就批量改,会**破坏历史档案**并制造新错误。 --- ## 5. 自动化的边界(**重要**) | 动作 | 可否自动 | 理由 | |---|---|---| | **检测**(跑四件套、出报告) | ✅ **可以,且应该** | 只读、零风险、退出码可判定 | | **刷新派生件**(`docs-manifest.json`) | ✅ 可以 | 纯派生,无人工语义 | | **改写正文 / 批量替换** | ❌ **不可以** | ① 触 **R7**(批量写入须确认)② **认识论漂移**:LLM 改知识库后,错误会成为后续输入并**复利放大**(LLM Wiki 社区已实证)③ 研究员明确指出:**git diff + 人工审阅才是真正的安全网** | | **删历史档案里的旧值** | ❌ 不可以 | 违反铁律 2(L5 冻结) | ⇒ **推荐形态**:自动任务**只做"体检 + 出报告"**,**发现违背时通知人**,由人或新会话按 §4 SOP 收敛。 --- ## 6. 反例(今天真实踩过,别重犯) | # | 反例 | 后果 | 规避 | |---|---|---|---| | 1 | 校验规则太宽(拿"旧域名"当违规) | 20 项里 14 项误报 → 校验器被忽视 | 只留高置信模式;拿不准就不查,改人工 | | 2 | 改了**技能工作副本**却忘了**归档副本** | 校验器扫的是归档副本 → 改了等于没改 | 技能两处位置必须同步(md5 一致) | | 3 | 备份文件 `*.bak-*` 留在**文档库内** | 污染 `docs-sync-check`(算成"仅本地") | 备份放库外,或收尾删掉 | | 4 | scp 时把 `scripts/x.py` 也推到**根目录** | 服务器多一份同内容副本 → 对账报"仅服务器" | scp 目标路径逐个核对 | | 5 | 把"下一号"写死在入口文档 | 并行改动 3 次打穿(83→85→87) | 一律"复跑取号" | | 6 | **只看根目录就说"本机没有这个文件"** | 实际在 `scripts/` 下 → 结论完全相反(今天两次) | 报"不存在/缺失"前先 `find` 全库 | | 7 | **把问题抛给用户前没确认它还在** | 服务器多余文件已被并行会话清掉 → 问了个**已消失**的问题 | 抛出前重新查一次;状态会被别人改变 | | 8 | 没顺着 grep 找权威档案就猜文件用途 | 直接读关联档案的 TL;DR 一句话就清楚,比猜快得多 | `grep -rn <文件名> --include="*.md"` → 读那条档案的头部 | --- ## 7. 自检清单(每次动知识库前后) **动手前** 1. 这个事实的**唯一权威**在哪一层?我是不是正准备在别处复制它? 2. 我要改的是**承诺现行**还是**历史**文件?历史的 → 不回改,追加"修正"小节。 3. 涉及 >10 文件?→ 先出清单(R7)。 **收尾** 4. 四件套**全绿**了吗? 5. 两处技能副本 md5 一致吗?推服务器了吗? 6. 临时/备份产物清了吗? 7. 复数入口都改成"复跑取号"了吗? --- ## 8. 文档的「无效信息」分类与高价值写法(2026-09-16 加) > **起因**:用户问「AI 会话生成的文档是否有无效信息?是否需要一套方法,写出**简单明了、高价值、且不影响模型阅读**的文档?」 > §4 处理的是「漂移」**一类**;本节把它扩成 **六类无效信息** + **不能删的红线** + **写作形态**。 ### 8.1 唯一判据(正反两面) > **去掉这一行,下一个会话会不会「做错事」或「变慢」?** > **会 ⇒ 必须留**(还要让它落在首屏);**不会 ⇒ 可删 / 可降级到归档。** 正面用法(决定"值不值得写"):**这行会改变读者的下一步动作吗?** 不会 ⇒ 它只是背景装饰,压缩或删。 ⛔ **别把"更简洁"当目标** —— 目标是**行为相关性**。把必要的「为什么」删掉,AI 会在同一处**反复摇摆**,那是负收益。 ### 8.2 六类无效信息(2026-09-16 全部亲见,不是理论) | # | 类型 | 当日实例 | 处置 | |---|---|---|---| | 1 | **与可执行体不符** | `stop-dialog-guard.py` 注释写「15 万/120」,代码是 `120000/80` | ⛔ 以**代码 / 实测**为准改注释,不是反过来 | | 2 | **过期结论仍占"生效位"** | 记忆里「hook 确实在生效(09-13 取证)」——当天已被推翻 | **不删**:标注「已推翻 + 新结论 + 日期」,保留纠偏轨迹 | | 3 | **同一事实多处重复** | 同一技能在本机 / 文档库 / 镜像三副本 | 收敛到**单一来源**,其余只留指针(§2) | | 4 | **过程流水挤掉结论** | 日志里「我做了什么」淹没了「现在是什么状态」 | **结论前置**;流水降级到日志 / 附录 | | 5 | **中间产物混进正式文档** | 项目根 `_tmp_*`、`_中间产物_待清理/`(239 文件) | 集中到归档区,永不进正式文档;收尾清 | | 6 | **只写"给人看的套话"** | 「这个很重要」「要注意」—— 不含任何判据 | 换成**可执行判据**:什么条件下、做什么动作 | ### 8.3 ⛔ 不能删的红线(「不影响模型阅读」的边界) **删「结论的装饰」,留「判断的依据」。** 以下五类删了会直接坏事: 1. **判据与阈值**(数字 / 边界条件 / 优先级) 2. **命令原文与路径** —— 删了 AI 得重新试错,这是**最贵的成本** 3. **反例与踩坑**(现象 → 根因) 4. **「为什么」(决策依据)** —— 删了会在同一处反复摇摆 5. **失效 / 作废标注** —— 删了会让旧做法「复活」 ### 8.4 高价值文档的形态(动笔前先定这五条) 1. **结论先行** —— 首屏 3 行给判定 2. **状态与流水分离** —— 状态(现在是什么)= 常驻;流水(怎么变的)= 追加 ⇒ **分文件放** 3. **一事实一处** —— 其余给指针 4. **可执行** —— 给命令 / 判据 / 路径;⛔ 不给"建议注意" 5. **排版** —— 按 `dsh-feature-first §5.4`(每节 ≤7 行 / 表格 ≤5 列 / **并列项各占一段**) ### 8.5 自检三问(贴出去之前过一遍) 1. **读者是「下一个会话」**(不是人)—— 它读完能**直接动手**吗? 2. 这份里**有多少行会改变下一步动作**?占比低 ⇒ 该压缩。 3. 我删掉的每一行,**有没有落在 §8.3 的红线**里? ### 8.6 「注入预算」维度 —— 长文件的后半段等于不存在(2026-09-16 加,实测) > §8.1–§8.5 用「**行为相关性**」判该不该留。另有一条**独立于内容质量**的约束: > **每轮注入是有上限的** —— 超出上限的部分宿主不会给模型,**效果上等于这段不存在**。 - **实测(2026-09-16)**:用户级 `MEMORY.md` 20,977 B / 11,712 chars,宿主**注入上限 ≈ 4,000 chars**。原排序下窗口只覆盖「钩子配置 + 环境路径」,**整节 `Preferences`(全部行为规则)落在窗口外** ⇒ 规则没写错,是**排序错**。 - **⇒ 判据升级**:一份「每轮都要生效」的文件要同时过 **两条** —— ① 每行都过 §8.1 的判据;② **体量 ≤ 注入上限**(或硬规则必须全部落在窗口内)。超限时**先重排、后删减**:重排零损失,删减有丢规则风险。 - **⛔ 不要用「删内容」解决超限**,正确顺序是: 1. **分类** —— 哪些是「每轮必须生效」(硬规则 / 事故级事实 / 禁令),哪些是「查阅型」(历史细节 / 取证过程 / 个别项目偏好) 2. **把硬规则整体排到最前**,使注入窗口正好覆盖它们 3. 查阅型内容留在窗口外**不算丢失**(本机仍可读),只需在其上方留一行指针 4. 重排仍不够才压措辞 —— 且**受压的必须是查阅型,不得压判据与命令原文**(§8.3) - **📌 排序契约(防复发)**:文件头必须显式写明「**注入上限 ≈ N 字符;排序即重要性;新增内容按序插入对应小节,⛔ 不要追加到末尾**」。少了这一行,下一次追加就会把重要规则顶出窗口 —— 这是**慢性失效**,没有任何报错。 - **适用面**:一切「每轮注入」的文件 —— `MEMORY.md`、`CODEBUDDY.md`、`.codebuddy/rules/*.md`、各技能的 `description`。 - **可复跑自检**:`wc -c ` ÷ ~1.8 ≈ 字符数,与上限比;**更直接的判据 = 看注入块结尾有没有被截断**(结尾被截断 ⇒ 已有内容在静默失效)。