Files
dsh_shenxian/dsh-server-docs/CODEBUDDY.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
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 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

110 lines
11 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.
# 文档库使用约定(**子目录指令 —— 只在读写本目录文件时加载**)
> 本目录 = 改造文档库的 **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 / 有·无请求体都要测 |