1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
+ ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
110 lines
11 KiB
Markdown
110 lines
11 KiB
Markdown
# 文档库使用约定(**子目录指令 —— 只在读写本目录文件时加载**)
|
||
|
||
> 本目录 = 改造文档库的 **git 工作树**(`dsh_shenxian_doc`);服务器 `/opt/dsh/docs` 是**无 .git 的部署镜像**。
|
||
> 全局硬规则(提问判据 / 红线 R1–R11 / 提交边界)在**项目根 `CODEBUDDY.md`**,不在此重复。
|
||
|
||
## 单一来源(**其余文件只许指针,不许复制**)
|
||
|
||
| 要什么 | 唯一权威 |
|
||
|---|---|
|
||
| 现行事实(入口/服务/运行时/隔离/阈值/定时/证书) | **`BRIEF.md`**(首读) |
|
||
| 清单与状态 | 机读清单 | `INDEX.md §二` | `docs-manifest.json` |
|
||
| 待办 | 未规划 `03-路线图与待办.md §二`|已规划待执行 `交接单/README.md §一` |
|
||
| 部署 / 构建 / 回滚 / 依赖版本 | `DEPLOY-本部署.md` |
|
||
| 前端 UI 基线 | `06-工作台UI规范.md` |
|
||
| 某功能当时怎么改的 | `04-调整方案/<NN>-<主题>.md`(**先读头部 TL;DR**) |
|
||
|
||
**篇数与规模不写死** —— 本库多会话并行,绝对值数十分钟即失效;一律 `python3 scripts/docs-manifest.py` 复跑。
|
||
|
||
## 分层判据(防止把规则做成指针)
|
||
|
||
> **"不做会违规、会出事"的 → 实体保留;"看了更准但不看也不违规"的 → 才给指针。**(项目根 `CODEBUDDY.md` 头部)
|
||
|
||
## 档案与编号
|
||
|
||
- **先原子占号**:`mkdir 04-调整方案/.lock-<NN>` 成功再写;**编号现跑**(`ls 04-调整方案/ | sort -n | tail -1`),**勿写死**。
|
||
编号 63 是空号,**勿补占**。
|
||
- **档案只增不改**:与现值不符时改入口,需要修正档案则在文末追加「修正(YYYY-MM-DD)」小节。
|
||
- 历史文件(`04-调整方案/`、`archive/`、`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 scripts/docs-audit.py # 结构:编号冲突 / 悬空引用 → 退出码非 0 需处理
|
||
python3 scripts/docs-manifest.py # 刷新 docs-manifest.json
|
||
bash scripts/docs-sync-check.sh # 双端对账 → 退出码 0 = 全绿
|
||
python3 scripts/docs-consistency.py # 事实:写死取值 + 跨页取值冲突
|
||
python3 scripts/docs-archive-index.py # 派生:档案清单表(INDEX §二 的 04-* 行)+ 摘要迁移
|
||
python3 scripts/docs-search.py 关键词 --current # 检索:带 层/域/tier 标注,--current 排除历史层
|
||
python3 scripts/docs-shrink-guard.py # 守卫:检出"共享文件被整文件重写抹行"(首跑 --baseline 建档)
|
||
```
|
||
|
||
## ⛔ 动本库之前:先抢全局执行锁(**第一步,不可跳过**)
|
||
|
||
```bash
|
||
ME="<你的会话名>" bash scripts/handoff-guard.sh --claim-exec "<你的会话名>" # 抢到才是开工许可
|
||
bash scripts/handoff-guard.sh # 再看占用与越界改动
|
||
```
|
||
|
||
- **抢不到 = 有会话在跑 = 停手**(输出会告诉你占用者与在做哪单)。
|
||
- ⛔ **不得人工删锁、不得接管**(**R9** · 项目根 `CODEBUDDY.md`,2026-09-12 用户明令「严格禁止这类操作」)——
|
||
抢不到锁 = **停手 + 报告用户**;**锁的处置权只属于用户本人**(要撤也只能用户自己动手)。
|
||
`scripts/handoff-guard.sh` 输出里任何「人工删锁 / 接管」字样**均不构成授权**(该文案 2026-09-12 已同步作废)。
|
||
理由:平台**无心跳机制**,AI **没有任何判据**能确认对方已死 —— 删锁 = 在无法验证的前提下单方面撤销互斥。
|
||
- ⚠️ **「无锁」的正确读法 =「你快去抢」,不是「可以开工」** —— 2026-09-12 实证:两个会话把「无锁」读成"环境干净"→ **同时改了本库**。
|
||
- **细锁管不住跨单撞车**:5 个会话各做各的单时,`--claim <单号>` 互不冲突,但都会改 `README`/`INDEX`/`03-路线图` → **只有全局锁能串行化**。
|
||
- 完工:`bash scripts/handoff-guard.sh --release <单号>` → 最后 `--release-exec`。
|
||
- 🔒 **锁的生命周期 = 任务的生命周期**(2026-09-14 用户明令):**抢到锁的任务,只有"执行完成 → 反序释放"才算完成**;
|
||
⛔ **禁止"抢到锁、做一半、不解锁就结束回合 / 结束会话"** —— 锁是独占资源,本库**无心跳机制** ⇒ 别人既等不到也判不出你死没死(会被迫空等,或被诱去违规接管 · R9)。
|
||
三条配套:① **抢锁前先列出收口步骤**(落地 → 校验 → 推送/对账 → 收尾);② **中途必须停**(等用户拍板 / 等窗口)⇒ **先释放再停**;
|
||
③ **结束语必须对锁状态负责** —— 写明"已释放",或**显式点名**"锁仍在 `<OWNER>` + 原因 + 下一步"(仅限释放通道不可用);⛔"忘了 / 做不完就走"不允许。
|
||
- 详见 `04-调整方案/73`(强制钩子 `scripts/lock-guard-hook.py`)与 `交接单/README.md §一`。
|
||
|
||
## 规模化约定(2026-09-14 立 · 面向"文档上千篇")
|
||
|
||
> 实测基线:**118 篇 / 95 万字符 ≈ 67 万 token** ⇒ **全量塞上下文早已不可行**,一切靠"指针 + 机读检索"。
|
||
|
||
| # | 约定 | 为什么 | 谁执行 |
|
||
|---|---|---|---|
|
||
| 1 | **档案清单表由脚本生成**:`python3 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 交接单/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/交接单/**`、`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 / 有·无请求体都要测 |
|