Files
dsh_shenxian/dsh-server-docs/08-skills/dsh-knowledge-upkeep/SKILL.md
T
admin e6207aa691
build / build-and-scan (push) Waiting to run
chore(仓库对齐): 文档库结构治理 + IM/插件线落地
文档库:目录改为编号制(01-规范/02-架构设计/03-数据库/04-调整方案/
05-交接单/06-ops/07-scripts/08-skills/09-archive),顶层散文件归入 01-规范/;
INDEX.md 与 docs-manifest.json 重刷(档案 146 篇);旧目录名引用全量对齐。

IM 线:src/im/**(SDK / hub / store / presence / ws / gateway-token)、
src/web/routes/im.ts、src/db/plugin-data/**、src/supervisor/plugin-assembly.ts
及对应 test/**。

插件线:poc/{im-agent-bridge,im-connection-gateway,im-conversation-tabs,
business-plugins-im,carbon-mcp-probe}、src/web/routes/{sessions,overlay-device}.ts、
src/net/relay/{device-grant,instance-credential}.ts。

仓库卫生:清出 40 个历史误入库 / 已改名文件(34 个交接单归档 + 6 个旧结构,
本地均有副本);dsh-server-docs/.gitignore 补 tmp/;交接单不入库(政策)。
2026-09-24 07:25:16 +08:00

32 KiB
Raw Blame History

name, description, version, updated_at, last_change, agent_created
name description version updated_at last_change agent_created
dsh-knowledge-upkeep dsh 平台文档库 / 项目知识的**维护与纠偏方法**。当发现「文档与现状不符」「同一事实多处打架」「知识越积越碎」「AI 忘了某条规则」「要收敛或重构知识库结构」时使用;也用于定期体检。**技能集专项**:说「**这么多技能会不会话能准确调用 / 挑不对技能 / 技能太多不好维护**」时 ⇒ **直接看 §9「技能集可用性体检(10 层取证法)」**。核心 = 六层知识结构(L0-L5,**L0.5 架构定稿见 §1.1**)+ **分层判据(实体 vs 指针)** + Lint 四件套 + **漂移处理 SOP** + **自动化的边界(检测可自动,改写不可自动)** + 今天踩过的 5 个反例 + **§8.6「注入预算」维度**(每轮注入有上限 ⇒ 长文件后半段等于不存在;**先重排、后删减**)+ **§9 技能集体检 10 层(含"规则写下来了但没技能接得住"这一最易漏层)**。**配套:`dsh-architecture-lifecycle`(架构定稿层与收敛流程)· `dsh-feature-first`(谁定什么)· `dsh-decision-method`(怎么定得对)· `dsh-change-workflow`(怎么落地)。** 1.0.0 2026-09-24 【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` 字段。 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-规范/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)

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-运维手册。

建议补跑(不在四件套内,但会毁可读性)—— 编码合法性

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 轮工具调用)。

⛔ 最容易漏的不是单子,而是"单子之外"的过期口径(本轮真漏过一次):

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. 排版 —— 按 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 <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 会命中,其中:

  • 「只做被明确要求的事」—— 该规则已写在 agent-operating-rules §5.3 正文里,但历史原话里出现 62 次、12 个 description 一个都没命中;
  • 「先抢锁再动手」「技术讨论不谈法规」「要的是解决问题不是将就妥协」「不要放 D 盘」「文档直入主题」「点名主体别用代词」同类。

⇒ 这是 skill-load-guard.py 同族问题的另一种形态:那个治"用户点名了方法但技能没被加载",这个治"用户点名了规则但技能没被匹配"。规则写在文件里 ≠ 会在正确的时机被取用。

修法:给承载该规则的技能补 description 触发词(用用户的原话措辞,⛔ 不要用书面语),并写明这是高频场景。

9.3 ⚠️ 判据漏词会伪装成技能盲区(最容易自我误导)

实测:第 7 层第一次跑出「命中 0 = 55.8%」,看着像大面积失效;改进关键词表后降到 42.9%。 ⇒ 差值全是我的判据漏词,不是技能缺陷。

铁律:报"盲区"之前,必须先用目标技能的 description 原文核验一遍(grep 那几行),确认不是我自己的关键词表不全。 ⛔ 不许把"我判据里补的词"当成"技能已覆盖" —— 这两者完全不同(本次差点犯:我在分析判据里给 agent-operating-rules 补了"成本/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//"))—— ⛔ 别用「技能名出现在这一行里」判命中(别的技能行常在描述里提到它 ⇒ 会把登记挂到错行)。旧副本先备份到 /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)。正确写法两条并列:

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)。

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)。