Files
dsh_shenxian/dsh-server-docs/交接单/README.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

153 lines
26 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.
# 交接单(规划会话 → 执行会话)
- 日期:2026-09-11(2026-09-12 增「待执行清单」)
- 状态:✅ **启用**(本目录是「方案规划」与「落地执行」的唯一传递面)
- 触发:用户口径「执行任务时间太久 → 一个会话做任务规划,另一个会话执行」
> **本目录只在「要执行某个任务」时读**;日常对齐现状请读 `BRIEF.md`。
> **待执行 = 本目录**(`交接单/*.md`);**已完成 = `archive/交接单-已完成/`**(首次完成后自动出现)。
> 完成后:单子头部状态改 ✅ 并附证据 → `git mv` 归档 → 在 `INDEX.md §四` 归档表加一行。
---
## 一、待执行清单(**唯一来源 = 本表**)
| 单子 | 状态 | **占用者 / 开始** | 一句话 | 冲突域 | 依赖 |
|---|---|---|---|---|---|
| `T01-档案16阶段3-4-实例内我的技能.md` | ✅ **已完成并归档**(2026-09-15,执行会话 `T01我的技能-0825`) | `—`(已释放) | 实例内「我的技能」(上传/启停/删除);**形态修正 = 并入既有「功能管理」内分组**(不新开 section)+ 阶段 4 权限收口复核 | **代码**(`poc/business-plugins`)+ profile 层 + 实例重启;**文档** `README`/`INDEX`/`03-路线图` | 决策点 1 = **A 扩展 `business-plugins`**(已定)|**证据**:档案 **100**;插件 **0.3.21** 已投放两实例;`npm run verify` 全绿;06 §7 三段式全绿(壳页 combo 含 `@dsh-local/business-plugins`、`rev=533537bbc02b`、bundle 200 · 11,363,655 B 含新特征);端到端 **19/19**(共享技能 409 / 非 zip 400);阶段 4 收口 = 未新增 section、未改角色补丁 ⇒ 可见性不变 |
| `T02-文档库收尾-编号消歧与INDEX瘦身.md` | ✅ **已完成并归档**(2026-09-12,并行执行会话) | `—`(已释放) | 37a/37b/38a/38b 编号消歧(+ 2 个脚本 **8 处**正则)+ INDEX 瘦身 + 事实校正 | 纯文档 | — **证据**:4 文件已改名;`scripts/docs-{audit,manifest}.py` 正则已支持 `[a-z]?`;INDEX **28,805 → 7,468 字符**(≤10K 达标);audit【1】冲突 0、【2】标题号不符 0、【6】无悬空;陈旧表述("服务器唯一源"/`aliyun-work-space`/"下一号 = 20"/`8355e99`)已归零;**已归档 `archive/交接单-已完成/`** |
| `T03-plugin_package整合为单插件并投放.md` | ✅ **已完成并归档**(2026-09-13 18:0x;原状态:🔄 进行中 —— 步骤 1–9 已完成;**候选池上传已完成 —— 现行池内版本 = `dsh-plugin-mcn-suite @0.3.9`**(09-13 00:02 上传;历史:22:0x 曾传 0.3.1 → 实例启用失败,根因 = peer 依赖被 pnpm 按公开 registry 解析;22:2x 加 `peerDependenciesMeta.optional` 修复后重传,HTTP 200 / `replaced:true` / `compat.level=ok`)。⚠️ **09-13 07:1x 复核**:0.3.2→0.3.9 期间连修:漏声明 `xlsx` 依赖、client 注册层 id、`inject` 语义);**admin 侧已装 0.3.9 且 host 面 3 个注册加载通过**;**guest `bundles` 仍未含 mcn-suite**(⚠️ **07:4x 用户尝试启用 → 失败**:装上后实例探活不通过(**内存不够**),失败路径上又触发**档案 79 的 P0 缺陷**(orchestrator 退出)⇒ 已**手工回滚 profile** 并验证实例恢复)⇒ 「guest 启用」仍待做,**前置 = 先修档案 79 + 解决堆容量**(用户已定:**暂不改配额档位**)) | `—`(**已释放**;原由 `exec-session-B` 持有,接管自卡死的 `exec-session-A`) | 7 个自研插件整合成 1 个功能插件包(`dsh-plugin-mcn-suite`);**业务技能随包投放**(用户要求「不分开管理」) | **代码**(新建整合包 + 打包脚本)+ **平台候选池**(上传/下架)+ 实例重启;**文档** `README`/`INDEX`/`03-路线图` | ✅ 决策已定(2026-09-12 用户拍板):① 不进 social-workbench ② 进 voxemw ③ 多入口并列 ④ **技能随包投放**(§4.1)⑤ v0.3.0。**进度**:产物已出 `D:\dshworkspace\plugin_package\dist\dsh-plugin-mcn-suite-0.3.0.tgz`(438 条目 / 1.90 MB / md5 `f98a3303…`);路由 48+6+7 条 ✓;**本地 smoke 17 组全绿** ✓;上传扫描 **P0=0** ✓;死引用 **0** ✓;**待执行**:**用户在实例「功能管理」里启用**(用户动作,平台不代劳)→ 启动实例 → §八验收 → 归档。⚠️ **2026-09-13 阻塞**:启用会因**同堆内存不够**致探活失败,并触发**档案 79 的 P0 缺陷** ⇒ 先修 79 + 解决容量后再启用 |
| `T04-并发治理落地-commit常态化与服务器侧锁.md` | ✅ **已完成并归档**(2026-09-12 15:10,`exec-session-C`) | `—`(已释放) | 并发治理落地:commit 常态化 / 服务器侧操作锁 / 权限统一 700·600 | **git**(本机提交,不 push)+ **服务器**(建锁目录 / chmod)+ `scripts/` | ① 文档库 git 基线提交 + 此后只提自己改的文件 ② 服务器侧操作锁(`/opt/dsh/state/.op-lock/`)③ 交接单目录权限统一 700/600|决策已定(用户「A 按最佳方案」);基线提交需"静态窗口" |
| `T05-插件兼容性预检.md` | ✅ **已完成并归档**(2026-09-12 16:35,`exec-session-D`,commit `8d19e89`) | `—`(已释放) | 插件在**导入/上传时**即判定与平台 dsh 的兼容性(semver 依赖判据 + 运行时导出符号判据),不再等实例崩 | **代码** `src/web/{plugin-compat.ts,routes/*.ts}` + build + 重启;**文档** `README`/`INDEX`/`03-路线图` | 方案见 **`04-71`**;⚠️ 与改 `orchestrator.ts` 的并行会话**冲突域重叠 → 必须串行** |
| `T06-模型设置页-多厂家条目可开关.md` | ✅ **已完成并归档**(2026-09-13 23:5x,`craft-session-T06`) | `—`(已释放) | 平台自建「设置 → **模型设置**」:条目**各自开关、可同时启用** + 官方「模型」分区对全角色隐藏 + spawn 时把「已启用条目」落地到实例 `.credentials.yaml` / `settings.yaml` | **代码** `src/db/*`、`src/web/{model-landing.ts,server.ts,routes/auth.ts}`、`ensure-role-profile-patch.cjs`、`poc/business-plugins`(**0.3.11**) + `systemctl restart dshs` + `ensure-biz-plugins --all --restart`;**文档** `README`/`INDEX`/`03-路线图` | ✅ 无阻塞(口径用户已定);证据与判据见 **`04-87`**;⚠️ 本轮**顺手修掉两颗雷**:角色补丁脚本的整文件覆盖会抹掉 admin 另两个平台块、`verify-mem-model` 的陈旧断言 |
| `T07-内置dsh安装路径探测.md` | ✅ **已完成并归档**(2026-09-14 05:0x,`craft-session-installpath` + `craft-session-tailclear`) | `—`(已释放) | 修 **P1 静默失效**:三处把内置 dsh 安装目录写死 ⇒ 在 `npm root -g` = `/usr/lib/node_modules` 的发行版上,厂家目录读空 / 兼容性预检安全网失效 / 目录选择器 import 抛错 | **代码** 新增 `src/web/dsh-install.ts` + 三处调用点(含 `poc/workspace-scoped-picker`)+ 插件 `business-plugins` **0.3.13** / `workspace-scoped-picker` **0.1.5** + build/restart/铺发;**文档** `04-88` + `README` 补 3 个 env | ✅ 无阻塞;**由开源导出会话提出**(它抢不到锁按 R9 停手),源仓独立复核后经用户「确认修改」落地。⚠️ 复核时**发现提出方漏了第 3 处**、且其 env 名是导出侧的 ⇒ 均已纠正 |
| `T08-集群化落地-兼容单例模式.md` | ✅ **已完成并归档**(2026-09-15 18:0x,`exec-cluster-1a`) | `—`(已释放) | 把平台改造成「1 组 Manager(≥2 台,也支持单活)+ N 台 Worker + 共享归属状态」的集群形态;**硬约束 = 全程兼容单例模式** + 每步可单独回滚。**证据**:S0–S7 全绿(冒烟 6/8 与开工基线相同 · 5 个端到端 · lease 单测两后端 10/10)|**真跨机演练**(47 Manager / 106 Worker,跨云)✅|**域名形态访问** ✅|**2026-09-15 17:4x 生产整体切换**(47=Manager+本地 Worker w-47、106=Worker w-106、控制面库=47 的 PG13;存量用户留 w-47、新用户落 w-106;**回滚=删 drop-in**)。⚠️ **残留小项**(已登记 `03-路线图 §二`):`join-worker.sh` 一键装机 · 隧道服务化(心跳重建)· 集中日志/metrics · `smoke-domain` 定性。详见 §9–§16 | **代码**(`src/supervisor/`、`src/db/`、`src/cli.ts`、`src/fs/`)+ **服务器**(**106 另起一套**测试环境;**47 不动**)+ **文档**(本单 + 完工时的 `04-调整方案/101`) | 设计单一来源 = 项目根 `集群化改造方案_Manager-Worker_20260914.md`(19 节);**决策 D1–D5 已定**(双活+支持单活 / 存储可插拔 / 自建 PG / 跨云只当测试床 / 测试环境用 106);⏳ **仅 D6「生产拓扑最终落点」需用户拍板**,且**不阻塞 S0–S5** |
> **🔒 占用怎么声明(2026-09-12 新增,防两会话撞车)**:开工前先**原子占位** ——
> `mkdir 交接单/.doing-<单号>`(`mkdir` 原子:**成功=你拿到;报 File exists=已有人在做 → 停手,别开工**),
> 回来把本表「占用者 / 开始」填上(会话标识 + `HH:MM`);完工 `rmdir 交接单/.doing-<单号>` + 状态改 ✅。
> 查当前占用:`ls -d 交接单/.doing-* 2>/dev/null`。标记是**纯本机目录**(空目录不会 scp 出去),两会话同机所以够用。
> **⚠️ 占位与台账必须"同一动作"完成(2026-09-12 实证)**:T03 10:14 就占了位,但 §一 台账那行直到 **12:59** 才改成「执行中」→ 中间 **2.5 小时里别人看台账会以为没人做**,随时可能重复开工。所以:`--claim` 之后**立刻**把该行状态改「🔄 执行中」并把「占用者 / 开始」填上。`handoff-guard.sh` 的 **【1b】已能自动检出这种不一致**(硬失败)。
> **🔐 两级锁(2026-09-12 新增,用户建议)** —— 一把粗、一把细:
> - **粗 = 全局执行锁 `交接单/.exec-lock`**:**同一时刻只允许一个执行会话**去动「文档 / 代码 / 服务器」。这是**默认工作模式**(本库共享入口文件多、且要动生产)。
> - **细 = 单级占用锁 `交接单/.doing-<单号>`**:标记"这个单归谁做",供台账与接管使用(冲突域真不重叠时才允许两单并行)。
> - 顺序:**开工 `--claim-exec` → `--claim <单>`**;**完工 `--release <单>` → `--release-exec`**(锁最后放)。
> - ⚠️ **「无锁」的正确读法 =「你快去抢」,不是「可以开工」**(2026-09-12 实证:`handoff-guard.sh` 输出「无全局锁」被读成"环境干净",
> 结果**两个会话同时改了本库** —— 无实际损害,但属**流程失效**)。**看到"无锁" ⇒ 下一个动作就是 `--claim-exec`**;
> **抢不到 = 有人在跑 = 停手**。抢锁是原子的,**抢到才是开工许可**。
> - 检查:`ME="<你的会话名>" bash scripts/handoff-guard.sh <单号>` —— 【1c】会告诉你全局锁在谁手上;不设 `ME` 时**一律按"别人的锁"处理**(保守)。
> **✍️ 写者归属(每个文件只有一个写者;2026-09-12 补)** —— 「占用锁」防的是"同一单",下表防的是"跨单撞同一文件":
>
> | 文件 | 唯一写者 |
> |---|---|
> | `交接单/<单号>.md` | **该单的执行会话**(规划会话只读) |
> | `交接单/README.md` §一 状态表 | **各自只改自己那一行**(规划会话加新单 = 新增一行;执行会话改状态 = 改自己那行) |
> | `交接单/README.md` 其余章节(约定) | 谁改谁先读、**只用 Edit 精确替换** |
> | `04-调整方案/`、`INDEX.md`、`BRIEF.md`、根 `README.md`、`03-路线图与待办.md` | **执行会话**(规划会话只读) |
> | `skills/dsh-change-workflow/SKILL.md` | **其工作副本持有者**(单向往本库推进,勿反向覆盖) |
> | `scripts/`、`ops/` | 谁新增谁负责(新增文件天然无冲突;改已有文件先跑 guard) |
**⚠️ 两单必须串行(2026-09-12 更新)**:T01 与 T03 都要动代码与实例、都要改 `README.md` / `INDEX.md` / `03-路线图与待办.md`、都要**原子占档案号**。按 `skills/dsh-change-workflow` 的「多任务并行调度协议」(**并行度由冲突域决定,不由任务数决定**)→ **同一时刻只放一个执行会话**。(T04 已完成归档,其"基线提交触及所有人文件"的风险已消除。)
**建议顺序:T03 → T01**(T04 已完成并归档,不再在序列内)。
- **T03 先做**:收益最大(7 包归 1),决策已全部拍板,只差"上传候选池 → `guest` 启用 → 验收 → 归档"。
- **T01 最后**:依赖 T03 之后的候选池 / 实例状态;决策点 1 已定,无阻塞。
> **分工边界(防双源漂移)**:`03-路线图与待办.md` 管「**平台还没做、也还没规划**的事」;本表管「**已经规划成单、等执行**的事」。同一个事项在两边都出现时,**状态以本表为准**,`03-路线图` 那行只保留指针。
---
## 二、单子必填 8 段
| # | 段 | 写法要求 |
|---|---|---|
| 1 | **目标** | 一句话,可判定"做完了没有" |
| 2 | **只读前置** | 执行前必须先核实的 3–5 条事实,**给命令与期望输出**,不让人推断 |
| 3 | **范围** | 改哪些文件;**并明确"不动什么"**(防止顺手扩大) |
| 4 | **决策点** | 已定的写「已定(谁定的/依据)」;未定的写「开跑前问用户」 |
| 5 | **步骤** | 有序编号,**每步自带一次可执行的验证** |
| 6 | **验收** | 命令 + 期望输出(含退出码),可被第三方复现 |
| 7 | **回滚** | 具体命令或副本路径 |
| 8 | **回报格式** | 执行会话必须回填的证据(命令、输出、commit) |
> **判断标准**:执行会话**不读规划会话的上下文**也能开工。凡需要"你懂的"才写得通的句子,都是没写清。
> **⚠️ 写引用/数字的两个坑(2026-09-12 三次实证,写单子时必看)**
> 1. **不要在「档案」二字后面直接跟一个字符类**(例:写成 `档案` + `3[78]`、`档案` + `6[01]`)—— `docs-audit.py` 的引用正则会把它们读成**裸旧号**(`3` / `6`)→ **永久悬空、audit 退出码非 0**(T02 执行会话踩 1 次、规划会话踩 2 次,**连本条警告的第一版也踩了**)。要举例请写 `档案 (37|38)`,或在中间加反斜杠阻断匹配。
> 2. **基线/阈值数字必须带"取数时间 + 复核命令",不写死绝对值** —— 会被并行改动打穿(实证:T02 里写死的 `INDEX=25,581` 在 40 分钟内变成 28,805)。
## 三、执行会话的硬要求
0. **⚠️ 先确认没有别的会话在写同一文件(2026-09-12 新增)**:本库**多个会话并行**工作已是常态(实证:同日 T01 被两会话先后编辑、T02 与 T03 由两会话同日产出、`交接单/README.md` 被双方先后改动)。冲突域重叠的单子**必须串行**(§一),但**跨单子仍会撞同一批文件**(`INDEX.md` / `README.md` / `BRIEF.md` / `03-路线图` / 本 README / `skills/…/SKILL.md`)。开工前必须:
- ① `git -C dsh-server-docs status --short` + `bash scripts/docs-sync-check.sh`(退出码 0)→ 看清**有没有不属于你的未提交改动**;
- ② `ls -la --time-style=+%H:%M <要改的文件>` → **mtime 比你上次看到的新 = 别人刚动过** → **先读最新内容再改**;
- ③ **共享文件只用 Edit 做"精确片段替换",禁止整文件 Write 覆盖** —— 别人改了同一处时 **Edit 会失败**,这就是**天然的冲突检测**;确需整文件重写(如 INDEX 瘦身)→ **先确认无人在改** + **先留回滚点**(`cp x x.bak-<ts>`,或先 `git commit` 留下 HEAD)+ 改完立即 commit。**注意 Write 覆盖是静默的、没有检测能力,这类操作是并行期最危险的一步**。
- ④ **改完立即 `git commit`(本机,不 push)** —— 本库目前**长期不提交**,等于**没有冲突检测能力**(无法靠 pull/merge 发现撞车)。**提交是"给下一个会话留路标",与"推送上线"是两件事**(推送仍需用户明确说)。
- ⑤ **推服务器前必须复跑 `docs-sync-check.sh`;报「仅本地」的文件若不在你本次改动清单里 → 立刻停手**(2026-09-12 事故实证:我把**已被对方归档移走**的 `T02` 单子又推回服务器,制造出"幽灵文件",靠对方后续同步才清掉)。这类"迟到的推送"是本库最容易发生的并行事故。
- ⑥ **不要"重放"别人的文件**:只推**你自己本次生成/修改**的文件。看到别人的新文件想"顺手一起推" → 先问,对方可能正处在半成品状态。
1. **开跑前拉齐**:`bash scripts/docs-sync-check.sh`(退出码 0);读单子「只读前置」与 §一 的冲突域/依赖。
2. **新增档案必须原子占号**:`mkdir <目录>/.lock-<NN>` 再写("先 ls 再写"两次撞号实证 → `skills/dsh-change-workflow/SKILL.md:250`)。
3. **收尾四件套**:`python3 scripts/docs-audit.py`(**退出码 0**)+ `python3 scripts/docs-manifest.py`(刷新机读清单)+ `bash scripts/docs-sync-check.sh`(0)+ **推送前 `MINE="<我改的文件...>" PUSH=1 bash scripts/handoff-guard.sh`(幽灵文件硬判定,**2026-09-12 因漏此步把已归档文件推回服务器**)**。
4. **回填**:§一 本行状态改 ✅;勾销 `03-路线图` 对应行;更新 `INDEX.md §二` 状态行与 `README.md` 的「下一号」。
5. **提交边界**:**推送需用户明确说"推送"**(沿用既有红线,见 `README §红线` 第 3 条与用户约定)。
6. **单子归档**:`git mv 交接单/<单> archive/交接单-已完成/<单>`(`archive/交接单-已完成/` 首次完成时创建)。
7. **服务器镜像**:本目录新增/修改的文件同样要 scp 到 `/opt/dsh/docs`(root 600,README 类保持 644)——规划会话**不 scp**,这一步一律由执行会话做。
8. **预检工具(2026-09-12 新增,把上面 0–② 变成一条命令)**:`scripts/handoff-guard.sh`(只读)
- 占位 / 释放:`bash scripts/handoff-guard.sh --claim T03 "exec-session-A"` / `--release T03`
- 开工检查:`MINE="交接单/README.md 交接单/T03-*.md" bash scripts/handoff-guard.sh T03`
- 推送前检查:同上再加 `PUSH=1`(启用【4】的**幽灵文件硬判定**:对账结果里「仅本地」的文件若有未声明的 → 直接失败)
- 判据与设计:**mtime 只作提示(分不清谁改的)**;硬判定只有两处 —— ① **别人的占用锁**;④ **「仅本地(待推送)」清单里含未声明文件**(= 幽灵文件风险,2026-09-12 就是这么把已归档的文件推回服务器的)。② 越界改动只作提示(本库长期脏,无法作为判定依据)。退出码 1 = 不可放行。
9. **会话生命周期 = 一个单(2026-09-12 新增)**:**一个执行会话只做一个单;该单 ✅ + 归档 + 双端一致之后,就地结束这个会话**,新任务开新会话。
理由(实证):会话越长寿,越容易拿**过期快照**当事实 —— 同一天里,T02 单子写死的 `INDEX=25,581` 在 40 分钟内变成 28,805;`BRIEF.md` 至今仍写 `512M` 而实际已是 384 MiB。**新会话用交接单冷启动,比老会话带着旧上下文续跑更准**。
10. **🔒 执行中冻结单子(2026-09-12 新增)**:单子被 `.doing-<单>` 持有期间,**只有持有者可以改该单子文件**;规划会话与其它执行会话**一律只读**。需要补充意见 → 写进 `.doing-<单>/OWNER` 的"待并入"段,或等锁释放后再改。**今天实测过这个风险面**:规划会话 09:20–09:45 在改 T03,执行会话 10:14 才锁它 —— 时序上是安全的(先改完再开工),但**反序就会撞**。
11. **接管必须无损:`OWNER` 是交接凭证(2026-09-12 新增,来自 T03 的 `A 卡死 → B 接管` 实战;⚠️ **「接管」这个动作本身现已受 R9 限制** —— 见第 13 条末,**不得由 AI 自行发起**)**:`OWNER` 至少写四项 —— ① 占用者 ② 开始时间 ③ **进度(做到第几步 / 已完成哪几段)** ④ **产物位置与 md5 + 下一步**。接管者**先读 OWNER 与单子回报段,再续做**,不要从头重来。示范(T03 实际写的):`exec-session-B(当前会话,接管自 exec-session-A)`,台账里补了"步骤 1–9 已完成、产物 `dsh-plugin-mcn-suite-0.3.0.tgz`(438 条目 / 1.90 MB / md5 `f98a3303…`)、待执行 = 上传→启用→验收→归档"。
12. **并行干活、串行登记(收口单点)**:确有多单并行时,各自的**档案占号**(`.lock-<NN>` 原子)与**各自 §一 行**可以并行;但 **`INDEX.md`、`03-路线图与待办.md`、根 `README.md` 的"登记动作"由单一收口会话统一做**(沿用 `skills/dsh-change-workflow` 的"收口在主会话"规则)—— 因为这几个入口文件是全库唯一的双写热点。
13. **🔐 全局执行锁:一次只允许一个执行会话(2026-09-12 新增,用户建议)** —— 单级锁只管"同一单别被两人做",**管不住跨单撞共享文件、更管不住服务器态并行**(重启/drain/改 env 会让在线用户掉线)。所以补一把**全局粗锁**:
- **开工**:`bash scripts/handoff-guard.sh --claim-exec "exec-session-B" T03`(抢不到 = 已有会话在跑 → **停手**,输出会直接告诉你占用者/开始时间/在做哪单);
- **完工**:`bash scripts/handoff-guard.sh --release-exec`(**放在最后**:回填 → 改自己 §一 行 → commit → 推服务器+対账 → 归档 → 再放锁);
- **检查**:`ME="<会话名>"` 时 guard 会区分"自己的锁"(提示别忘释放)与"别人的锁"(硬失败);**不设 `ME` 一律按别人的处理**(保守);
- **⛔ 接管:AI 不得自行接管,更不得删锁**(**R9**,2026-09-12 用户明令「严格禁止这类操作」)——
抢不到锁 ⇒ **停手 + 报告用户**;**锁的处置权只属于用户本人**(要撤也只能用户自己动手)。
下条的「读 `OWNER` + 台账进度」**只用于**「用户已点头、且用户自己撤锁之后」的续做;
**不得**以「持有者疑似已死 / 卡住 / 太久没动 / 只在只读分析没产出」为由单方面撤锁 ——
平台**无心跳机制,AI 没有任何判据**。(本条原文为「读 OWNER → **人工删锁** → 自己 `--claim-exec`」,**已作废**。)
- **它同样覆盖服务器操作**:任何要重启 / drain / 改 env·quota / 铺插件 / 改 nginx·nft 的动作,都先持这把锁(与 §六 的服务器侧锁是同一件事的两种落地,先做哪个都行,别两套并存)。
## 四、规划会话的边界(本目录的作者)
- 只读**本地**文档与本地只读命令;**不 ssh、不改码、不重启服务、不 scp**。
- 产出后必须自检:`python3 scripts/docs-audit.py` 退出码 0(交接单自身也是被扫描的 md)。
- 事实一律标注单一来源(档案号 / 文件:行),不写"我记得"。
## 五、为什么这样分(2026-09-11 实证)
| 原因 | 证据 |
|---|---|
| **上下文挤** | 一次改造的规划要读 5–10 万 tokens,执行要读源码 + 日志 + 复跑;同一会话混做,两头都慢 |
| **并行踩坑** | 同一天两次「两通道并行改同一批文件」造成损失:`03-路线图` 被旧快照覆盖跳号;**两个编号各被两份档案占用**(37/38,→ T02) |
| **交付面单一** | 单子成为唯一传递面,两边都不需要对方的历史;也让"做没做"可被第三方核对 |
**与既有机制的关系**:`skills/dsh-change-workflow` 的六阶段中,**阶段 0–2(需求/调研/规划)留在规划会话,阶段 3–5(开发/验证/归档)交执行会话**;冲突域与并行度规则仍按该 skill 的「多任务并行调度协议」执行。
## 六、**服务器侧也要锁**(2026-09-12 新增;比文档冲突严重,待落地)
前面 §一–§三 治的是**文档冲突**(丢的是文字,可重写)。但所有会话**共用一台服务器**,且下面这些操作**跨会话没有任何互斥**:
| 高危操作 | 影响 | 现状 |
|---|---|---|
| `systemctl restart dshs` / `drain` / 停 `dsh-*.scope` | **在线用户当场掉线**(档案 58/59 已两次引发报障) | ✅ 已加锁(须先占位) |
| 改实例 env / `MemoryMax` / bwrap 参数 | 全部实例行为变化,用户无感知到异常 | ✅ 已加锁(须先占位) |
| 批量铺插件 / 改 profile patch / `/opt/dsh/docs` 之外的生产文件 | 可能触发崩溃循环(档案 25 前例) | ✅ 已加锁(须先占位) |
| 改 nginx vhost / 证书 / nft | 全站可达性 | ✅ 已加锁(须先占位) |
**✅ 已实施(2026-09-12,见 `交接单/T04-*.md` 与 `scripts/op-lock.sh`)**:加第二把锁,**粒度到"平台操作"而不是"文件"**:
- 约定文件 `<repo>/.doing-platform`(或服务器侧 `/opt/dsh/state/.op-lock`,取"跨机可见"之利);
- 内容 = 占用者 + 操作摘要 + 影响面(谁会被断、断多久)+ 预计时长;
- **凡 §六 表里任一类操作,开工前必须先占位**;占位失败 = 有别的会话正在动线上,**停手**;
- 与 §三 第 0 条的差别:文档冲突靠 `git status/mtime` 能看出来,**服务器态变更看不出来**(`systemctl` 不会告诉你 10 分钟前谁重启过)→ 只能靠显式锁。
> **✅ 落地记录(2026-09-12 15:07,T04)**:锁根 `/opt/dsh/state/.op-lock/`(root 700,内含使用约定 `README`)已建立;工具 `bash scripts/op-lock.sh {claim|release|status}` 已就位并**实测往返通过**(占位 → status 显示 🔴+OWNER → 释放 → 无人占用 ✓)。
> **开工前必做**:`bash scripts/op-lock.sh status` 无人占用才继续;占位失败 = 有会话在动线上 → **停手**。
> 顺序仍为:**先抢文档库全局锁 `--claim-exec` → 再占服务器侧锁 `op-lock.sh claim`**;完工反序释放。