Files
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

152 lines
15 KiB
Markdown
Raw Permalink 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.
# 文档库使用约定(**子目录指令 —— 只在读写本目录文件时加载**)
> 本目录 = 改造文档库的 **git 工作树**(`dsh_shenxian_doc`);服务器 `/opt/dsh/docs` 是**无 .git 的部署镜像**。
> 全局硬规则(提问判据 / 红线 R1–R11 / 提交边界)在**项目根 `CODEBUDDY.md`**,不在此重复。
## 单一来源(**其余文件只许指针,不许复制**)
| 要什么 | 唯一权威 |
|---|---|
| 现行事实(入口/服务/运行时/隔离/阈值/定时/证书) | **`BRIEF.md`**(首读) |
| 清单与状态 | 机读清单 | `INDEX.md §二` | `docs-manifest.json` |
| 待办 | 未规划 `01-规范/03-路线图与待办.md §二`|已规划待执行 `05-交接单/README.md §一` |
| 部署 / 构建 / 回滚 / 依赖版本 | `DEPLOY-本部署.md` |
| 前端 UI 基线 | `01-规范/06-工作台UI规范.md` |
| 某功能当时怎么改的 | `04-调整方案/<NN>-<主题>.md`(**先读头部 TL;DR**) |
**篇数与规模不写死** —— 本库多会话并行,绝对值数十分钟即失效;一律 `python3 07-scripts/docs-manifest.py` 复跑。
## 分层判据(防止把规则做成指针)
> **"不做会违规、会出事"的 → 实体保留;"看了更准但不看也不违规"的 → 才给指针。**(项目根 `CODEBUDDY.md` 头部)
## 档案与编号
- **先原子占号**:`mkdir 04-调整方案/.lock-<NN>` 成功再写;**编号现跑**(`ls 04-调整方案/ | sort -n | tail -1`),**勿写死**。
编号 63 是空号,**勿补占**。
- **档案只增不改**:与现值不符时改入口,需要修正档案则在文末追加「修正(YYYY-MM-DD)」小节。
- 历史文件(`04-调整方案/`、`09-archive/`、`01-规范/01-规划与架构`、`01-规范/02-运维手册`)里的旧值**不回改**——写的时候是对的,回改破坏历史。
## 改完必跑(七件套 · **顺序不可换**)
> ⚠️ **顺序**:`docs-manifest.py` → `docs-archive-index.py`(**后者读前者**)→ 其余任意。
> 顺序错会**静默**产出新旧混合(2026-09-14 实测:只跑 manifest 未跑 archive-index 时,后者只读模式直接报
> 「表内容与 INDEX.md 不一致」)。`docs-archive-index.py` 已内置顺序断言:`--write` 时若 manifest 比最新档案旧会**拒绝**,
> 确认要硬刷才加 `--force`。
```bash
python3 07-scripts/docs-audit.py # 结构:编号冲突 / 悬空引用 → 退出码非 0 需处理
python3 07-scripts/docs-manifest.py # 刷新 docs-manifest.json
bash 07-scripts/docs-sync-check.sh # 双端对账 → 退出码 0 = 全绿
python3 07-scripts/docs-consistency.py # 事实:写死取值 + 跨页取值冲突
python3 07-scripts/docs-archive-index.py # 派生:档案清单表(INDEX §二 的 04-* 行)+ 摘要迁移
python3 07-scripts/docs-search.py 关键词 --current # 检索:带 层/域/tier 标注,--current 排除历史层
python3 07-scripts/docs-shrink-guard.py # 守卫:检出"共享文件被整文件重写抹行"(首跑 --baseline 建档)
```
## ⛔ 动本库之前:先抢全局执行锁(**第一步,不可跳过**)
```bash
ME="<你的会话名>" bash 07-scripts/handoff-guard.sh --claim-exec "<你的会话名>" # 抢到才是开工许可
bash 07-scripts/handoff-guard.sh # 再看占用与越界改动
```
- **抢不到 = 有会话在跑 = 停手**(输出会告诉你占用者与在做哪单)。
- ⛔ **不得人工删锁、不得接管**(**R9** · 项目根 `CODEBUDDY.md`,2026-09-12 用户明令「严格禁止这类操作」)——
抢不到锁 = **停手 + 报告用户**;**锁的处置权只属于用户本人**(要撤也只能用户自己动手)。
`07-scripts/handoff-guard.sh` 输出里任何「人工删锁 / 接管」字样**均不构成授权**(该文案 2026-09-12 已同步作废)。
理由:平台**无心跳机制**,AI **没有任何判据**能确认对方已死 —— 删锁 = 在无法验证的前提下单方面撤销互斥。
- ⚠️ **「无锁」的正确读法 =「你快去抢」,不是「可以开工」** —— 2026-09-12 实证:两个会话把「无锁」读成"环境干净"→ **同时改了本库**。
- **细锁管不住跨单撞车**:5 个会话各做各的单时,`--claim <单号>` 互不冲突,但都会改 `README`/`INDEX`/`03-路线图` → **只有全局锁能串行化**。
- 完工:`bash 07-scripts/handoff-guard.sh --release <单号>` → 最后 `--release-exec`。
- 🔒 **锁的生命周期 = 任务的生命周期**(2026-09-14 用户明令):**抢到锁的任务,只有"执行完成 → 反序释放"才算完成**;
⛔ **禁止"抢到锁、做一半、不解锁就结束回合 / 结束会话"** —— 锁是独占资源,本库**无心跳机制** ⇒ 别人既等不到也判不出你死没死(会被迫空等,或被诱去违规接管 · R9)。
三条配套:① **抢锁前先列出收口步骤**(落地 → 校验 → 推送/对账 → 收尾);② **中途必须停**(等用户拍板 / 等窗口)⇒ **先释放再停**;
③ **结束语必须对锁状态负责** —— 写明"已释放",或**显式点名**"锁仍在 `<OWNER>` + 原因 + 下一步"(仅限释放通道不可用);⛔"忘了 / 做不完就走"不允许。
- 详见 `04-调整方案/73`(强制钩子 `07-scripts/lock-guard-hook.py`)与 `05-交接单/README.md §一`。
## 规模化约定(2026-09-14 立 · 面向"文档上千篇")
> 实测基线:**118 篇 / 95 万字符 ≈ 67 万 token** ⇒ **全量塞上下文早已不可行**,一切靠"指针 + 机读检索"。
| # | 约定 | 为什么 | 谁执行 |
|---|---|---|---|
| 1 | **档案清单表由脚本生成**:`python3 07-scripts/docs-archive-index.py --write`(摘要存 `archive-summaries.json`,人工只改这个 JSON) | 手写登记会漏(2026-09-14 实测缺 82–86 共 5 篇,另有 81 号重复行与格式坏行) | **勿手写表行** |
| 2 | **单篇 ≤ 30 KB**;新增档案超限**必须拆子页**。**标准拆法 = 新增子页 + 原页留指针**(历史档案按「只增不改」不回改正文,只在文末「修正(YYYY-MM-DD)」节加指针) | 单篇最大已 89 KB(档案 82),读一篇就吃满预算 | 写档案的人;`docs-manifest.py` 会报 + `docs-archive-index.py` 报缺失率 |
| 3 | **日志按月分片**,单文件 ≤ 50 KB(`append-only` 不变):`YYYY-MM.md` → 超限后新开 `YYYY-MM-下.md`,**原文件顶部留一行指针** | 单日日志已 377 KB | **谁当月第一次触到 50 KB 谁切**(下一位写入者先看行数) |
| 4 | **tier 判据 =「谁在引」而非「被引几次」**(2026-09-14 变更):`hot` = 被 **L1/L2**(BRIEF/CODEBUDDY/DEPLOY/06-UI规范)引 ≥3 次;`cur` = 引 1–2 次;`warm` = 仅历史互引;`cold` = 0。⚠️ **L4(INDEX/待办/台账)不算** —— 它们顺带列全档案号,会让判据反向失效(实测:含 L4 时 hot 从 44 抬到 60) | 原判据"被引 ≥8 次"让 hot 占 49%,等于没筛;改后 hot = **7 篇 / 8%** | 脚本自动 |
| 5 | **域/层标签只存 `docs-manifest.json`**(域 ∈ `platform`/`plugin`/`ui`/`ops`/`external`/`method`;层 = L0–L5) | 标签写进正文 = 又一处漂移源 | 脚本抽 + 人补 `?` |
| 6 | **共享文件写入有机械兜底**:`docs-shrink-guard.py` 记录行数快照,**行数骤降 >30% 且 >20 行即报警**(2026-09-14 实测抓到 `MEMORY.md` 被并行整文件重写抹行) | 只有"纪律"没有机制 ⇒ 抹行无人发现 | 改完热区文件跑一次 |
| 7 | **体检只报不改**:四件套 + `docs-archive-index.py` 只出报告;**正文改写永远人工**(R7 + 认知漂移 + `git diff` 审阅) | 自动化改知识库会复利放大错误 | 所有人 |
| 8 | **有硬额度的共享文件允许「整编」(整文件重写)** —— 但**四个条件缺一不可**:① **先抢全局执行锁**(保证单写者)② 先**备份**原件到 `.workbuddy/tmp/` ③ 抽**事实 token**(反引号标识符 / 档案号 / hash / 关键数字)作回扫基线,改完**逐 token 回扫** ④ 完成后 `docs-shrink-guard.py --write` 刷新基线,**且不得加 `--allow-shrink` 白名单**(该守卫正是为这类文件而立) | 例:`MEMORY.md` 有 **12 KB 硬额度** ⇒ 不整编必然超限被截断;但 #6 的字面是「共享文件只用 Edit 精确替换、禁整文件 Write」⇒ **字面与必然需求打架**。判据取**目的**(防并发抹行)而非字面:**单写者 + 备份 + 回扫**三重保障下,整编不是"抹行"而是"有据重构"(2026-09-15 实测:`MEMORY.md` 整编 -34% 行、142 token 回扫零丢失) | 整编 `MEMORY.md` / `PLAYBOOK` 的人 |
> ⚠️ **"自动化"边界**:`MEMORY.md` 记载本项目**无自动化**(用户删过两条,勿重建)⇒ 体检请**手跑或外部 cron**,不要在本库内新建自动化任务。
## 同步链路
编辑本目录 → `docs-sync-check.sh` 对账 → scp 到 `/opt/dsh/docs`(档案 600 / README 644)→ **复跑对账**。
⚠️ 只推**自己本次改的文件**;对账报「仅本地」若有不在你清单里的 → **立刻停手**(幽灵文件)。
⚠️ **scp 必须带「同一相对目录」**(2026-09-13 实测踩坑):本库是**子目录结构**,服务器镜像与之**同相对路径**(脚本按 `cd $REMOTE_DIR && find .` 对账)。所以:
- `scp 04-调整方案/79-xxx.md bt-server:/opt/dsh/docs/` ❌ —— 文件会落到 **docs 根目录**,对账报「仅服务器」;
- `scp 05-交接单/README.md bt-server:/opt/dsh/docs/` ❌ —— 会**覆盖根 `README.md`**(已实际发生一次,需从本机重传根 README 复原);
- ✅ 正解:`scp <相对路径> bt-server:/opt/dsh/docs/<同一相对目录>/`。
⚠️ **文件名不要带空格** —— scp 的远端路径要经**远端 shell** 解析,空格会被拆成两个文件(2026-09-13 实测)。
⚠️ **远端 chmod 也要给文件名加引号**(同样因为远端 shell),否则报 `cannot access ...` 而误判"没传上去"。
## 路径书写约定(引用必须**可定位**,不写裸文件名)
- 路径从**本文件所在目录**起算:在文档库内写 `BRIEF.md` 无歧义;但从项目根文件引用本目录内容时必须写 `dsh-server-docs/BRIEF.md`。
- ⛔ **禁止"跨目录只写文件名"** —— 例如从别处引用 `.codebuddy/rules/frontend-ui.md` 时只写 `frontend-ui.md`,读者无法定位(今天已犯过)。
- 占位符用尖括号:`` `04-调整方案/<NN>-<主题>.md` ``,不用 `NN-*`(易被误认为真实路径)。
- 路径一律反引号包裹,便于机器扫描与跳转。
## 条件规则(相邻,按路径自动注入;**规则改动后需重启才重载**)
| 规则文件(完整路径) | 触发路径 | 管什么 |
|---|---|---|
| `` `.codebuddy/rules/archive-doc.md` `` | `dsh-server-docs/04-调整方案/**`、`dsh-server-docs/05-交接单/**`、`dsh-server-docs/INDEX.md` | 档案模板 / 原子占号 / 复跑取号 / 四件套 |
| `` `.codebuddy/rules/frontend-ui.md` `` | `**/*.html`、`**/*.css`、`**/*.js` | UI 规范基线 / 静态文件免重启 / curl 三件套 |
| `` `.codebuddy/rules/server-ops.md` `` | `**/*.ts`、`**/*.cjs`、`**/*.mjs` | 哪层要重启(R8)/ `git hash-object` / pnpm / 有·无请求体都要测 |
---
## 文档库结构与命名规则(**2026-09-24 固化** · 违反即返工;来源 = 当日结构治理会话)
### A. 顶层结构(序号一律阿拉伯数字;`tmp/` 例外不带号)
`01-规范 · 02-架构设计 · 03-数据库 · 04-调整方案 · 05-交接单 · 06-ops · 07-scripts · 08-skills · 09-archive · tmp`
+ 根级 5 入口件(`README` / `INDEX` / `BRIEF` / `CODEBUDDY` / `DEPLOY-本部署`)+ 2 生成物(`docs-manifest.json` / `archive-summaries.json`)。
- ⛔ `04-调整方案/` 的 `04` 是**文档族号**,**不得改名**(`04-NN` 短号 + 4 处脚本常量硬编码)。
- ⛔ `05-交接单/` 是**锁根**(`.locks` / `.exec-lock` / `.doing-*`);改名必须同批改 `handoff-guard.sh`·`preflight-lock.sh`·`lock-guard-hook.py`·`op-lock.sh`。
- ⛔ `07-scripts/` 改名必须**同批改宿主** `E:/ProgramData/.workbuddy/settings.json` 的 **5 条 hook 入口**(lock-guard ×2 / bash-output-guard / skill-load-guard / stop-dialog-guard)。
- ⛔ `08-skills/` 三处同步(本机 `~/.workbuddy/skills/` → 本目录 → 服务器),**单向推进,勿反向覆盖**。
### B. 文件命名:`族名-两位序号-主题.md`
- 序号**一律阿拉伯数字两位**:⛔ 不用英文字母序号(`A/B/C`)、⛔ 不用中文数字(`①②③`)、⛔ 不用「序」等前缀词。
- 族名用中文(`IM群组` / `覆盖网络` / `carbon插件` / `插件投放与分库线` / `T`)。
- ⛔ 文件名**不得重复文件夹已表达的信息**(例:在 `05-交接单/` 里不再写 `交接单_` 前缀)。
- ⛔ 序号与其后代号**必须有分隔符**(`01-M1a-…`,**不得** `01M1a`)。
- ⛔ 编号**只增不复用**;`04-调整方案/` 存量**不重排**(重排作废全部 `04-NN` 引用)。
### C. 语义
- **状态不靠目录位置表达**(目录一摊平/搬家即失效):主依据 = 单子头部 `- 状态:…` 行 + `05-交接单/README.md` 台账表;`交接单-已完成/` 只作**辅助**分类。机读入口:`python 07-scripts/handoff-status.py`。
- **入口只允许一份**(工作区根),库内不得放同名副本。
- **过程 ≠ 成品**:`04-调整方案/` 答「为什么这么做」,`02-架构设计/` 答「该做成什么样」,冲突**以定稿为准**。
### D. 批量改名·移动的六条铁律(2026-09-24 全部踩过一遍)
1. 引用有**三种形态**,必须全覆盖:① 限定路径 `dsh-server-docs/xxx/` ② 相对路径 `<x>/xxx/`、`..\xxx\` ③ **字符串字面量** `'xxx'`(代码里 `os.path.join` 用)。只做 ①+裸名 ⇒ **必漏功能性引用**(锁路径 / hook 路径)。
2. ⛔ **不用 `IndexOf`+`Substring` 手工拼新名** —— 一律用**正则整体替换**或**显式映射表**(实测:手工切串把 5 个文件拼成 `A-B-A-B` 双前缀)。
3. 改完必须 **grep 功能性常量逐条验**(`^LOCKDIR=`、宿主配置里的 hook 路径),**不能只看"改写 N 个文件"**。
4. 「改引用 + 移目录」**同一批收口验完**(分两步必暴露引用悬空)。
5. 未入库文件 `git mv` 会报 `not under version control` ⇒ **已跟踪走 `git mv`、未跟踪走 `mv`**;hook 失效窗口内 `git`/`mv` 起不来 ⇒ 改用宿主 shell 原生命令(PS)。
6. 移动/合并前先做**撞名保护**(目标同名则跳过并报告);**唯一副本一律不删**(判据 = 有无可证替代件)。
### E. 锁与钩子
- 动文档库**与走哪个工具无关**:`lock-guard-hook.py` 只在 **Write/Edit** 上拦,**用脚本改文件绕过它** ⇒ **先抢锁再动,不论工具**。
- hook 是**会话启动快照**:改宿主配置后**本会话命令行整轮失效**(且该窗口内 python 子进程起不来 `git`/`mv`)⇒ 预期该行为并切换通道;**hook 重载后自动恢复**。
### F. 收口判据
- **整理类任务必须有顶层可见变化** —— 只改内容(引用/索引/台账)**不算整理**。
- 不可逆删除**先出清单**;机械可判的(下划线开头件 / 空目录 / `.bak`)可直接清。
- 用户说「`<某文件夹>`,直接放在 `<父目录>` 下面」= **移动文件夹本身、去掉中间层**,⛔ **不是把内容摊平**(2026-09-24 误读一次,用户当场纠正)。