Files
workbuddy_skills/dsh-knowledge/references/00-知识库维护与纠偏.md
T
admin e03465c398 按用户令提交:把此前未纳管的 9 个技能目录一并入库
用户令逐字:「E:/ProgramData/.workbuddy/skills  提交仓库是指的这里」——
即本目录就是仓库(2026-10-07 已在本目录建仓,见当日日志 §22),本轮把余下未纳管的 9 个技能一并提交。

本次入库(9 个技能,46 个文件):
1、`AI HOT`
2、`draw-ui`
3、`dsh-diagnose`
4、`dsh-knowledge`
5、`dsh-local-env`
6、`dsh-opensource-release`
7、`dsh-workflow`
8、`oil-motion`
9、`skills-security-check`

提交前核对:
· **凭据类扫描**(`*.env` / `*token*` / `*.key` / `*secret*` / `*.pem`)⇒ **零命中** ✓;
· 体积合计约 20 MB(`draw-ui` 12M + `oil-motion` 6.5M 是大头,形态为配图/素材 ——
  仓库 `.gitignore` 里明写「`assets/*.png` 是内容不是产物」⇒ 属刻意入库);
· 运行产物仍按既定规则排除(`__pycache__` / `logs/` / `tmp/` / `.venv/` / `*.egg-info` / `uv.lock` / `.workbuddy/`)。
2026-10-08 22:29:08 +08:00

457 lines
40 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.
# 知识库 / 项目知识的维护与纠偏
> **归属**:技能 `dsh-knowledge` · 详情档(主干 `../SKILL.md`)
> **本档覆盖**:原技能 `dsh-knowledge-upkeep` **全文**(正文 286 行 + frontmatter 变更历史)
> **provenance**:本机版 + 文档库版的「作用域 / 宿主落点对照」块(DSH ↔ WorkBuddy 路径互译)
> **搬运方式**:**逐行未改**;内部附件链接已改写为 `dsh-knowledge-upkeep/<附件名>`(附件在本目录下)
> ⚠️ 原技能 `dsh-knowledge-upkeep` **已合并退役** ⇒ 见到该名按本档读。
---
> 🔵 **作用域(2026-09-26 从 WorkBuddy 用户级技能迁入)**:本技能描述的是 **dsh 平台项目**的作业方法,已提升为 DSH 全局技能,供任何会话发现与加载。
> ⚠️ 正文里的**宿主路径与脚本位置是迁移时的旧值**(如 `~/.workbuddy`、`CODEBUDDY.md`、`07-scripts/`、`文档库`)。~~在 DSH 上以**当前工作区的规则文件**与 `$DSH_HOME` 下的实际落点为准~~ 🔴 **2026-10-02 纠正:宿主是 WorkBuddy、不是 DSH;`$DSH_HOME` 本机已悬空** ⇒ 以**当前工作区的规则文件** + `E:\ProgramData\.workbuddy\skills\` 下的实际落点为准;⛔ 不要把正文里的旧路径当现行事实。
> ⚠️ 冲突时:**工作区规则 > 本技能**。
### 🔴 宿主落点对照 —— ⚠️ **本节方向已作废(2026-10-02 纠正)**
> 🔴 **左右方向与现状相反,⛔ 不要再照它执行。** 下表是 **2026-09-26 从 WorkBuddy 迁往 DSH 当时**
> 的形态(让人把 `~/.workbuddy/08-skills/<n>/` 换成 **`$DSH_HOME/skills/<n>/`**)。
> **现状**:宿主是 **WorkBuddy**(不是 DSH);技能真身就在 `E:\ProgramData\.workbuddy\skills\<n>\`;
> 而 `$DSH_HOME`=`E:\ProgramDSH\.dsh` 在本机**目录已不存在**(悬空老值,只剩环境变量还留着)。
> ⇒ 正确方向是 **WorkBuddy ← DSH**:正文里见到 `$DSH_HOME/skills/<n>/`,换成
> **`E:\ProgramData\.workbuddy\skills\<n>\`**。
**下表保留仅为留痕(右列=已作废的旧落点)**:
| 正文里的旧路径 | ~~DSH 侧实际落点~~(**已作废**) |
|---|---|
| `~/.workbuddy/08-skills/<n>/`、`.workbuddy/08-skills/<n>/` | ~~**`$DSH_HOME/skills/<n>/`**(技能根,被 watch,改动下一请求生效)~~ 🔴 **作废:方向反了**,现行落点=**`E:\ProgramData\.workbuddy\skills\<n>\`** |
| `.workbuddy/memory/MEMORY.md`、`~/.workbuddy/MEMORY.md` | **`$DSH_HOME/AGENTS.md`**(全局,每轮注入)/工作区 `AGENTS.md`(项目级) |
| `.workbuddy/memory/YYYY-MM-DD.md`(按日记忆) | **无对等物** ⇒ 教训写进本技能 `references/` 或项目台账「实测教训」节 |
| `CODEBUDDY.md`(项目常驻规则) | **同一份文件仍生效**(已在 preset 覆盖里加入 DSH 的指令候选),无需改名 |
| `07-scripts/<x>.py`(文档库脚本) | 同左,但**路径必须写全**:`D:\github\dsh_shenxian\dsh-server-docs\07-scripts\<x>.py` |
| `~/.workbuddy/settings.json` 的 hooks | **`$DSH_HOME/hooks/hooks.json`** + `dsh-guard.py` |
| WorkBuddy `automation_*` / 积分口径 | **无对等物**(见 `dsh-auto-handoff-chain` 的不可移植清单) |
> 🔴 **表尾收口(2026-10-02 补)**:**上表每一行的右列都属同一"迁往 DSH"的旧形态,一律作废** ——
> 尤其第 2 行(`$DSH_HOME/AGENTS.md`)与第 6 行(`$DSH_HOME/hooks/hooks.json`):本机**没有 `$DSH_HOME`**。
> 已实测的现行落点只有三条,照这三条找:
> ① **技能根** = `E:\ProgramData\.workbuddy\skills\<n>\`;
> ② **hook 注册面** = `E:\ProgramData\.workbuddy\settings.json` 的 `hooks` 段(2026-10-02 实测:本轮就是往那儿加的第 6 条);
> ③ **记忆** = 用户级 `~/.workbuddy/MEMORY.md`(跨项目)+ 工作区 `<工作区>/.workbuddy/memory/`(按日 + 长期)。
> ⛔ 上表左列里凡写 `$DSH_HOME/…` 的,**不要再当落点用**;`E:\ProgramDSH\` 整树已于 2026-09-28 删除
> (见 `dsh-local-env/references/01-环境引导与迁移.md` §"同名影子树")。
> ⚠️ 正文其余处出现的旧路径属**历史记录**(当时的事故与实测),**保持原样不改** —— 改写历史记录等于造假。
---
# 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-规范/01-规划与架构` + 早期档案 | 年 | 按需 |
| **L1 现行值** | 现在到底是什么(域名/配额/端口/路径/阈值) | **`BRIEF.md`** | 周 | 首读 |
| **L2 规则** | 必须遵守(提问判据/红线/提交边界) | **`CODEBUDDY.md`** | 很少 | **自动注入** |
| **L3 方法** | 怎么想、怎么做 | 3 个 dsh 技能 | 月 | 按需触发 |
| **L4 状态** | 现在在哪(待办、落差) | `05-交接单/` + `.workbuddy/memory/MEMORY.md` | 天 | **自动注入** |
| **L5 历史** | 怎么变成现在这样 | `04-调整方案/` + `09-archive/` | **只增不改** | 按需 |
### 1.1 L0.5 架构定稿(2026-09-21 补)
⚠️ **L0 与 L1 之间还有一层**,原表漏了,导致**架构级结论无处安放** ⇒ 只能塞进 L5 过程档案 ⇒
「后续会话看不全、同一架构多版口径」。
| 层 | 内容 | 唯一权威 | 变更频率 |
|---|---|---|---|
| **L0.5 架构定稿** | 架构级的「**现在该做成什么样**」(成品,可直接据此施工) | **`02-架构设计/`** | **中**(架构本身变才改) |
- **L0(为什么这样设计)** vs **L0.5(该做成什么样)**:前者是**原理**,后者是**目标形态**;
L0.5 比 L0 变得勤,比 L1(现值)稳。
- **L0.5 与 L5 的分工**:L5 记录「当时怎么想的」(**会过时、⛔ 不回改**),
L0.5 声明「现在该做成什么样」(**不轻易变、冲突以它为准**)。
- 🔴 **完整机制(目录契约 / 命名 / 收敛五步 / 状态块纪律)⇒ 技能 `dsh-architecture-lifecycle`**,
本表只登记层位,⛔ 不在此重复规则。
**三条铁律**
1. **每个事实只有一个权威** —— 其余文件**只许写指针,不许复制数字**。
2. **L5 冻结** —— 历史档案里的旧值**不回改**(写的时候是对的,回改破坏历史);需要修正时**在文末追加「修正(YYYY-MM-DD)」小节**,并改 L1 的现值。
3. **校验必须能查"事实一致性"** —— 否则前两条必然失守。
---
## 2. 分层判据:**什么必须实体,什么可以只给指针**
> **"不做会违规、会出事"的 → 实体保留;"看了更准但不看也不违规"的 → 才给指针。**
| 处理 | 内容 |
|---|---|
| **实体保留**(压缩不许删语义) | 提问判据 · 红线 R1–R8 · 提交边界 · 规划/执行分离 · 并发纪律 · **会导致事故的实测事实** · 环境要点 |
| **只给指针** | 平台现状与历史细节 · UI 规范全文 · 档案模板细则 · 某功能的实现内幕 |
⚠️ **指针必须绑定可识别的动作**,否则"去查"不会发生:
`当你要写前端页面 → 先读 06-UI规范`,而不是 `详见 06-UI规范`。
---
## 3. Lint 四件套(可复跑,退出码可接 CI)
```bash
python3 07-scripts/docs-audit.py # 结构:编号冲突 / 标题号不符 / 悬空引用
python3 07-scripts/docs-manifest.py # 刷新机读清单 docs-manifest.json(含被引次数/tier)
bash 07-scripts/docs-sync-check.sh # 双端对账(本机 ↔ /opt/dsh/docs)
python3 07-scripts/docs-consistency.py # 事实:写死取值 + 跨页取值冲突
```
**`docs-consistency.py` 的设计要点**(写它时踩过的坑,别重踩):
- 只查**高置信**模式。首版把「旧域名」「旧配额」当违规 → **几乎全是误报**(库里都是"旧域已 301" / "512M→384M" 的合法表述)。
- **引号感知**:引号内的匹配 = **引用历史**,不是断言,不算违规。
- 判据 = 「**承诺现行**的文件不许含已废止/写死/矛盾的取值」;
**历史豁免**:`04-调整方案/**`、`09-archive/**`、`01-规范/01-规划与架构`、`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 时把 `07-scripts/x.py` 也推到**根目录** | 服务器多一份同内容副本 → 对账报"仅服务器" | scp 目标路径逐个核对 |
| 5 | 把"下一号"写死在入口文档 | 并行改动 3 次打穿(83→85→87) | 一律"复跑取号" |
| 6 | **只看根目录就说"本机没有这个文件"** | 实际在 `07-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/`(旧 `_tmp_*` 已归位)、`待清理/`(原中间产物区) | 集中到归档区,永不进正式文档;收尾清 |
| 6 | **只写"给人看的套话"** | 「这个很重要」「要注意」—— 不含任何判据 | 换成**可执行判据**:什么条件下、做什么动作 |
### 8.3 ⛔ 不能删的红线(「不影响模型阅读」的边界)
**删「结论的装饰」,留「判断的依据」。** 以下五类删了会直接坏事:
1. **判据与阈值**(数字 / 边界条件 / 优先级)
2. **命令原文与路径** —— 删了 AI 得重新试错,这是**最贵的成本**
3. **反例与踩坑**(现象 → 根因)
4. **「为什么」(决策依据)** —— 删了会在同一处反复摇摆
5. **失效 / 作废标注** —— 删了会让旧做法「复活」
### 8.4 高价值文档的形态(动笔前先定这五条)
1. **结论先行** —— 首屏 3 行给判定
2. **状态与流水分离** —— 状态(现在是什么)= 常驻;流水(怎么变的)= 追加 ⇒ **分文件放**
3. **一事实一处** —— 其余给指针
4. **可执行** —— 给命令 / 判据 / 路径;⛔ 不给"建议注意"
5. **排版** —— 按 `session-mechanism §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 <file>` ÷ ~1.8 ≈ 字符数,与上限比;**更直接的判据 = 看注入块结尾有没有被截断**(结尾被截断 ⇒ 已有内容在静默失效)。
## 9. 技能集可用性体检(**10 层取证法**,2026-09-22 立 · 可复跑)
> **什么时候用**:技能越攒越多后,怀疑「会话还能不能准确挑对技能」「这么多技能好不好维护」时。
> **一句话判据**:技能是**按 `description` 匹配、按需加载**的 ⇒ 体检的对象是 **description 的区分度**,不是技能正文写得好不好。
### 9.1 十层(每层一个脚本,落盘跑,⛔ 别用 `python -c`)
| 层 | 查什么 | 关键判据 |
|---|---|---|
| 1 | description 全量 + 探针词重叠 | ⚠️ **探针词太宽必假阳性** —— "文档""规则""会话"这类泛词必然命中一堆技能 |
| 2 | **精确提取引号内触发短语** | **零重复 + 零包含** = 设计层区分度健康 |
| 3 | 真实说法 → 命中谁 | 期望技能**不在**命中集 = ❌ 真缺陷(比"撞"严重) |
| 4 | 三处一致性 / 引用 / 版本 / 体量 | 三处 md5 必须**零差异** |
| 5 | 引用上下文逐条看 | 报出的"悬空引用"**必须逐条看原文语境** —— 插件名 / 工作区名 / npm 包名全是假阳性 |
| 6 | 自然说法覆盖率 | 盲区 = 用户会这么说但 description 没写 |
| 7 | **用历史会话原话做验证集** | 最强的一层,见 §9.3 |
| 8 | 盲区二分 + 补漏词重跑 | 追问型(<8字 / 含指代且<40字)**属正常**;只查独立型 |
| 9 | **用户明确定过的规则**是否接得住 | 见 §9.2 —— 最容易漏、后果最重 |
| 10 | frontmatter 结构校验 | 字段**唯一性**(重复字段会让解析取到哪个不确定)+ 版本 x.y.z |
### 9.2 🔴 最高价值的一层:规则写下来了,但没技能接得住
**做法**:把用户**明确定过、且已写进规则文件**的硬要求逐条列出,用**各技能 description 原文**做字面检查 ⇒ 谁都不含 = **真盲区**。
**实测(2026-09-22)**:12 个技能里,**7 条规则没有任何 description 会命中**,其中:
- 「**只做被明确要求的事**」—— 该规则**已写在 `session-mechanism §5.3` 正文里**,但历史原话里出现 **62 次**、12 个 description 一个都没命中;
- 「先抢锁再动手」「技术讨论不谈法规」「要的是解决问题不是将就妥协」「不要放 D 盘」「文档直入主题」「点名主体别用代词」同类。
⇒ **这是 `skill-load-guard.py` 同族问题的另一种形态**:那个治"用户点名了方法但技能没被加载",这个治"用户点名了规则但技能没被匹配"。**规则写在文件里 ≠ 会在正确的时机被取用。**
**修法**:给承载该规则的技能**补 description 触发词**(用用户的原话措辞,⛔ 不要用书面语),并写明这是高频场景。
### 9.3 ⚠️ 判据漏词会**伪装成技能盲区**(最容易自我误导)
**实测**:第 7 层第一次跑出「命中 0 = 55.8%」,看着像大面积失效;改进关键词表后降到 **42.9%**。
⇒ 差值全是**我的判据漏词**,不是技能缺陷。
**铁律**:报"盲区"之前,**必须先用目标技能的 description 原文核验一遍**(`grep` 那几行),确认不是我自己的关键词表不全。
⛔ **不许把"我判据里补的词"当成"技能已覆盖"** —— 这两者完全不同(本次差点犯:我在分析判据里给 `session-mechanism`(内 `references/作业规矩/`) 补了"成本/token",而它 description 里根本没有这些词,是真盲区)。
### 9.4 撞点怎么判:**不是所有撞都要消**
- ❌ **恶性撞**:撞了但**偏向错误的一方**(该加载的没加载)⇒ 必须修。
修法 = ① 补上缺的说法 ② 给两边都加**「⚠️ 与 `对方` 的边界」**说明(**双向指认**)⇒ 会话加载任一个都能看到分诊规则。
⚠️ 实测:仅补词会让撞点"数量变多"(原来只命中错的一方,现在两边都命中)—— 但**性质变好**了,别被计数误导。
- ✅ **良性撞**:多个技能**分工互补**(判类型 / 怎么定案 / 怎么落地),多加载一个是好事。**不要为了"看起来干净"去削它们。**
### 9.5 两条自己踩过的坑
- 🔴 **改 frontmatter 后必须数一遍字段出现次数**:本次改 `description` 时 `old_string` 少截一行 ⇒ **产生了两个 `last_change`**。⚠️ 无人守这个唯一性 ⇒ 改完逐字段清点(或用 §9.1 第 10 层脚本)。
- 🔴 **`python -c` 里带反引号会被 shell 吃掉**(本次改 README 时 pattern 匹配 0 行、**静默无效果**)⇒ 一律**落盘 `.py`** 再跑。
## 10. 技能重组:千行技能拆分(主干 + 详情档,2026-09-22 立 · **可复跑**)
> **与 §9 的关系**:§9 = **体检**(发现技能集的问题)|§10 = **整改**(把过长技能拆开)。两者是同一职责的两端。
> **触发**:某技能 `SKILL.md` 已到千行级(≈≥800 行)。**判据**:它长不是因为内容多,而是因为**判据与详情混在一起** —— 每次加载都吃掉大量上下文,而其中大半是长表、实测记录、历史细节。
**目标形态**:`SKILL.md` = 判据 + 流程主干 + 命令骨架;长表 / 案例 / 实测记录 / 历史细节 ⇒ `references/<两位序号>-<主题>.md`。**原位只留一行指针**(点名该档覆盖的章节),每档带头:`归属 / 本档覆盖 / 主文件指针 / 原行段`。
**四条硬约束**(用户要求「功能效果不受影响」):
1. **内容守恒** —— 拆分前后总行数不变(可机械校验);⛔ **不许借机删任何判据 / 命令 / 事故事实**。
2. **判据实体常驻** —— 按 §2 分层判据:「不看会导致违规/事故的」**必须留在主干**,其余才可下沉。
🔴 **口径:判据常驻 > 行数目标**。判据密集的技能,`≤350 行`可能**结构上不可达**(实测:`dsh-opensource-release` 的硬规则实体 R-O1–R-O17 + 事故清单 + 事实 + 授权 + 验证八件套 ≈ **453 行**)⇒ 达不到就**如实报告并给出数字**,⛔ 不许为凑行数把硬规则降级成指针。
3. **每档自包含** —— 头里写明「本档覆盖哪些原章节 + 原行段」,让跨档引用可定位。
4. **三处同步 + 登记跟改** —— 本机 `.workbuddy/08-skills/<n>/` → 文档库 `08-skills/<n>/` → `/opt/dsh/docs/08-skills/<n>/`(**600 root:root**);`README.md` / `INDEX.md` 加「详情已拆到 `references/`」。
🔴 **登记两处易漏**:① **服务器上也有根登记副本**(`/opt/dsh/docs/README.md` · `/opt/dsh/docs/INDEX.md`,600 root:root)⇒ 三处同步**要连它们一起推**,别只推 `08-skills/`(实测:skills 16 文件三方一致,根登记却落后一整轮);② 表格行**按行首单元格匹配**(`l.startswith("| `08-skills/<n>/`")`)—— ⛔ 别用「技能名出现在这一行里」判命中(别的技能行常在描述里提到它 ⇒ 会把登记挂到错行)。旧副本先备份到 `/opt/dsh/backups/docs-skills/`(根登记 → `/opt/dsh/backups/docs-root/`)。
**执行四步(纯机械搬运,逐行未改)**:
1. **先备份 = 回滚点**:`tmp/_keep-<日期>/split-bak/<技能>-SKILL.md`。
2. **取行号**:列出全部 `^#{1,3} ` 标题 + 行号 ⇒ **只按整节/整段**划搬运区间,区间⛔ 不得重叠。
3. **跑 `07-scripts/split_skill.py`**(**声明式规格 ⇒ 纯搬运**;脚本自校验「行数守恒 / 逐行包含 0 丢失 / 节可寻址 / frontmatter 唯一」,并把结果 print 成摘要)。**可重复跑**:永远从备份重建 ⇒ 不会二次切割。
4. **同步 + 三方对账**:本机 / 文档库 / 服务器 **逐文件三方 md5 比对**,`不一致 0` 才算完成。
**四项验收(缺一不可)**:① 守恒(主干内容 + 详情行数 = 原行数)② 三处 md5 一致 ③ 原**每一个标题**在新结构里可寻址 ④ frontmatter 唯一、`version` 不变。
**🔴 下沉必带的副作用 —— 跨档引用会断头**:正文里的 `见 §8 坑 9` / `见坑 36` / `见下表:X` 这类编号引用,目标一进详情档就没人接得住(实测一次抓到 **5 处**)。**修法** = 主干末节加一张「详情档 × 覆盖的原章节 × 原行段」表,编号按这张表定位。
**执行清单与实测数据 ⇒ `references/10-技能重组-千行拆分.md`**;通用拆分器 ⇒ `07-scripts/split_skill.py`(`--spec <json>`)。
## 实测坑(2026-09-20)· 新增目录的文档命名 vs docs-audit 编号
- `docs-audit.py` 的编号正则是 **`^(\d+[a-z]?)-`(只看文件名,不看所在目录)** ⇒ 在**新目录**里用 `01-/02-/03-` 命名会与 `04-调整方案/01..03` **撞号**,结论变 **RC=1**(【1】档案编号冲突)。
- ⇒ 新增目录的文档一律用**非数字前缀**(如 `DB-00-…`);**标题里可继续保留序号** —— 检查【2】只在"文件名与标题**都**解析出编号"时才比较。
- 附带两条(同日同批踩到):**跨下划线的标识符替换不要用 `\b`**(`\bV12\b` 匹配不到 `SQLITE_V12`,`_` 是 word 字符);**改共享 md(`INDEX.md` / `05-交接单/README.md` 等)必须字节级单行插入** —— 该库存在 CR/LF 混排文件(`INDEX.md` CR=5/LF=270),整文件 Write 会把行尾**静默改写**。
- 收口三件套仍是:`docs-audit.py` **RC=0** + 新档**纯 LF**(`CR=0`)+ 改共享文件后核对 `CR` 计数**未变**。
## 11. 归档镜像结构治理与双端对账(2026-09-24 立 · 可复跑)
**适用**:文档库目录改名 / 结构重排后,让服务器归档镜像(`/opt/dsh/docs/`)与本机镜像对齐,并让 `docs-sync-check.sh` 真正归零。
### 11.1 先做三分表,不要凭「路径不在」下判断
判定服务器独有文件前,先把服务器路径按改名规则**映射**成规范路径,再按两维交叉分类:
| 映射后路径在库 | 内容(归一化 md5)在库 | 归类 | 动作 |
|---|---|---|---|
| 是 | 是 | 已一致 | 不动 |
| 是 | 否 | **服务器旧版** | 用库版本覆盖 |
| 否 | 是 | 改名 / 搬路径 | 迁到新路径 |
| 否 | 否 | **真独有** | 归档保留,⛔ 不删 |
⚠️ 只按「路径不在库」列「服务器独有」会把**改名**误判成**独有**(实测:路径级报 121 个独有,内容级降到 22 个,其中 17 个是真正的历史旧档)。
### 11.2 判「旧名残留」必须带负向后顾
`grep "调整方案/"` 会把**正确的新前缀** `04-调整方案/` 一并命中 ⇒ 假阳性(实测:裸 grep 报 14 个文件,精确正则报 **0**)。正确写法两条并列:
```python
re.compile(r'(?<![0-9A-Za-z_\-])调整方案/') # 库内相对路径
re.compile(r'/opt/dsh/docs/调整方案/') # 服务器绝对路径(前导 / 需单列一条)
```
⚠️ 负向后顾里**含 `/` 会漏掉** `/opt/dsh/docs/旧名/` 形态 ⇒ 绝对路径必须单列。同类的假阳性还有:relay 日志里的 `host=ops/w-106`、git 仓库路径 `HEAD:scripts/x.cjs`、散文里的「交接单 / 接续包」、`~/.workbuddy/skills/`、`/api/skills/{shared,mine}`、`src/host/skills/plugin.ts` —— 这六类**不是**文档库段名。
### 11.3 判「两端一致」必须忽略行尾
Windows `\r\n` vs Linux `\n` 会让 `diff` **整块报差异**,但归一化(`\r\n→\n`)后 md5 **逐行相同**。只信值比较,⛔ 不信 `diff` 退出码。
### 11.4 改目录名后的**必查清单**(本线实测漏过其中两项)
1. **功能性常量**:锁脚本 `LOCKDIR / LOCKEXEC / LOCKSROOT`、宿主 hook 的 `paths` 与命令、`.gitignore`。
2. **自检脚本的前缀常量**:`docs-manifest.py`(档案号前缀)· `docs-audit.py`(编号扫描范围)· `docs-consistency.py` · `docs-archive-index.py` · `docs-search.py`。⚠️ **rc=0 也可能是「扫到了空目录」** —— 前缀写旧名时判定恒空 = **静默假绿**(实测:manifest 输出「0 篇档案」还判「与 INDEX 一致」)。
3. **`.codebuddy/rules/*.md` 的 `paths:` glob**(条件规则不匹配 ⇒ 静默不生效)。
4. **生成物需重建**:`docs-manifest.json` 是**派生数据**(含 `counts.chars`),任何 md 改动后必须重建并**双推**,否则对账恒报「内容不一致」(实测差异 83 字符 = 修复造成的字符增量)。
5. **对账脚本的排除项**:运行态(`tmp/`、`05-交接单/.locks/`、`.doing-*`、`.exec-lock*`)必须排除,否则永远「仅本地 N 个」。
6. **技能文档的自指约定**:技能正文写死的服务器归档位(如 `/opt/dsh/docs/08-skills/<name>/SKILL.md`)。
7. 🔴 **工作区「搬家 / 收口」时的脚本内绝对路径常量** —— `diff -rq` 只比**内容**,**查不出「脚本里写着旧工作区绝对路径」这类路径级引用**(2026-09-27 实测:两份工作区副本内容 0 差异,但两个自测脚本的 `DEVKIT` 常量仍指向旧副本 ⇒ 在新副本跑 = **假验证**,实际执行的是别人的脚本)。两步做法:① `grep -rn "<旧工作区绝对路径>"` —— ⚠️ **必须显式扫隐藏目录**(ripgrep 默认跳过 `.workbuddy/` 这类,漏扫则整类缺陷不可见);② 修成 **`${VAR:-<新路径>}` 兜底形态**,让下次搬家用环境变量覆盖即可,⛔ 不必再逐个改脚本。
### 11.5 服务器侧改造的安全姿势
- **动手前**:`tar czf /opt/dsh/backups/docs-pre-restructure-<ts>.tar.gz -C /opt/dsh docs`(全量快照)。
- **扩量推进**:先把新结构解包就位(只增),再把旧结构 **`mv` 到 `/opt/dsh/backups/docs-old-structure-<ts>/`** —— ⛔ 不用 `rm` ⇒ 可回滚、零信息丢失(真独有文件随之留档)。
- **改名后必须复查运行时依赖**:`systemd` / `/etc/dshs.env` / `crontab` / `bashrc` / 平台代码(`/opt/dshs/src` 等)/ 实例 profile —— 全 grep 一遍旧路径。实测本平台**零引用**(`/opt/dsh/docs` 是纯归档位),但这条不能省:结论要靠取证,不靠「应该是归档位」。
- **权限**:目录 `700` / 脚本 `755` / 其余 `600`,`root:root`。
### 11.6 验收判据
`docs-sync-check.sh` 报 **「双端一致 ✅」**(一致 N / 内容不一致 0 / 仅本地 0 / 仅服务器 0)+ 库内五件套 rc=0(`docs-consistency` / `docs-archive-index` / `handoff-status` / `docs-audit` / `docs-manifest`)。
---
## 变更历史(原 frontmatter · 逐字保留)
```text
name: dsh-knowledge-upkeep
description: dsh 平台文档库 / 项目知识的**维护与纠偏方法**。当发现「文档与现状不符」「同一事实多处打架」「知识越积越碎」「AI 忘了某条规则」「要收敛或重构知识库结构」时使用;也用于定期体检。**技能集专项**:说「**这么多技能会不会话能准确调用 / 挑不对技能 / 技能太多不好维护**」时 ⇒ **直接看 §9「技能集可用性体检(10 层取证法)」**。核心 = 六层知识结构(L0-L5,**L0.5 架构定稿见 §1.1**)+ **分层判据(实体 vs 指针)** + Lint 四件套 + **漂移处理 SOP** + **自动化的边界(检测可自动,改写不可自动)** + 今天踩过的 5 个反例 + **§8.6「注入预算」维度**(每轮注入有上限 ⇒ 长文件后半段等于不存在;**先重排、后删减**)+ **§9 技能集体检 10 层(含"规则写下来了但没技能接得住"这一最易漏层)**。**配套:`dsh-architecture-lifecycle`(架构定稿层与收敛流程)· `session-mechanism`(谁定什么 / 怎么定得对,内 `references/02-功能优先协作协议.md`)· `dsh-change-workflow`(怎么落地)。**
version: 1.0.0
updated_at: 2026-09-24
last_change: 【2026-09-24 新增 §11「归档镜像结构治理与双端对账」—— 本线完成服务器 `/opt/dsh/docs` 归档镜像的结构改造(A 方案)后沉淀:三分表判定法(映射后路径 × 内容交叉分类)· 负向后顾正则(裸 grep 会把新前缀 `04-调整方案/` 命中 ⇒ 假阳性)· 两端比对忽略行尾 · 改名后必查六项(功能性常量 / 自检脚本前缀 / 条件规则 paths / 生成物重建 / 对账排除项 / 技能自指)· 改造安全姿势(全量 tar + 旧结构 mv 归档,⛔ 不 rm)。】先前 2026-09-22 按要求统一版本号】frontmatter `version` → `1.0.0`(原 v1.4.0);正文与历史中的版本号为当时记录,未改动。此前 v1.4.0(2026-09-22):新增 **§9「技能集可用性体检(10 层取证法)」** —— 起因:用户问「这么多 dsh 技能会不会话能准确使用 + 后续方便维护」,用 10 层递进取证回答。要点:① 体检对象是 **description 的区分度**(技能按需匹配加载);② **§9.2 最高价值层 = 查"用户明确定过的规则有没有技能接得住"** —— 实测 12 个技能里 7 条规则无任何 description 命中(「只做被明确要求的事」历史原话出现 62 次且已写在本技能正文里,却接不住);③ **§9.3 判据漏词会伪装成技能盲区**(55.8% → 42.9% 全是我的关键词表不全,⛔ 不许把"我判据里补的词"当成"技能已覆盖");④ **§9.4 撞点分恶性/良性** —— 只有"偏向错误一方"才是缺陷,互补分工的撞不要消;⑤ §9.5 两条自踩的坑(改 frontmatter 必数字段出现次数;`python -c` 带反引号会被 shell 吃掉)。顺带补齐缺失的 `last_change` 字段。
agent_created: true
```
---
## 变更历史(**对侧副本** frontmatter · 逐字保留 · 来自 `dsh-knowledge-upkeep` 的 文档库 版)
> ⚠️ 本档正文取自**另一侧**(超集);此处补上对侧副本的版本史,⛔ 以保证不丢任何事实。
```text
name: dsh-knowledge-upkeep
description: 项目知识与文档库的维护纠偏方法:知识分层、实体与指针的取舍、漂移处理、注入预算治理(超限先重排后删减)、技能集可用性体检。触发场景:发现文档与现状不符、同一事实多处打架、知识越积越碎、AI 忘了某条规则、注入被静默截断,或要收敛重构知识库结构时。
version: 1.0.0
updated_at: 2026-09-24
last_change: 【2026-09-24 新增 §11「归档镜像结构治理与双端对账」—— 本线完成服务器 `/opt/dsh/docs` 归档镜像的结构改造(A 方案)后沉淀:三分表判定法(映射后路径 × 内容交叉分类)· 负向后顾正则(裸 grep 会把新前缀 `04-调整方案/` 命中 ⇒ 假阳性)· 两端比对忽略行尾 · 改名后必查六项(功能性常量 / 自检脚本前缀 / 条件规则 paths / 生成物重建 / 对账排除项 / 技能自指)· 改造安全姿势(全量 tar + 旧结构 mv 归档,⛔ 不 rm)。】先前 2026-09-22 按要求统一版本号】frontmatter `version` → `1.0.0`(原 v1.4.0);正文与历史中的版本号为当时记录,未改动。此前 v1.4.0(2026-09-22):新增 **§9「技能集可用性体检(10 层取证法)」** —— 起因:用户问「这么多 dsh 技能会不会话能准确使用 + 后续方便维护」,用 10 层递进取证回答。要点:① 体检对象是 **description 的区分度**(技能按需匹配加载);② **§9.2 最高价值层 = 查"用户明确定过的规则有没有技能接得住"** —— 实测 12 个技能里 7 条规则无任何 description 命中(「只做被明确要求的事」历史原话出现 62 次且已写在本技能正文里,却接不住);③ **§9.3 判据漏词会伪装成技能盲区**(55.8% → 42.9% 全是我的关键词表不全,⛔ 不许把"我判据里补的词"当成"技能已覆盖");④ **§9.4 撞点分恶性/良性** —— 只有"偏向错误一方"才是缺陷,互补分工的撞不要消;⑤ §9.5 两条自踩的坑(改 frontmatter 必数字段出现次数;`python -c` 带反引号会被 shell 吃掉)。顺带补齐缺失的 `last_change` 字段。
agent_created: true
```