Files
dsh_ai1net_server/dsh-server-docs/交接单/README.md
T
admin d2ef362a98 feat(overlay): 覆盖网络线 序㊾ —— 探针观测面改「两台中继并集」(附 序㊽ 源码/文档补提交)
序㊾(本棒):
- scripts/overlay-probe.cjs:OBS-01 / OBS-08 / OBS-09 的数据源由「只读 47 中继」
  改为「按两台中继取并集」,消除 worker 归属漂移时的假红 / 假 SKIP
  · endpoints 以 network:hostId:port 为键合并,online 取「或」、localPort 取在线那一侧
  · used 按 network/hostId 去重计数(不求和,避免凭空放大在册数)
  · localPort 属中继机回环落点 ⇒ 按归属分机探活(106 侧落点由 106 机上探)
  · derived(OBS-11)保持 47 视角;阈值与判据一律未放宽
  · OBS-16 计数约束:对 47 /status 的读取仍为三次、Δ 只取 47 的 counters;
    对端 106 的采样为独立一次,落在第三次采样之后,不进 (status2, status3] 门窗口
  · 新增 --peer-status-fixture(并集的对端那一半)与「并集不可取证」强制留痕
- 交接单《覆盖网络-序45-低熵块治理-测熵与实现》§16 全节(§8 前前缀逐字未变)
- 参数表 §11.16 补记(§10 现算指纹未变,值格未动)

附(前几棒已完成并已部署、但尚未入仓的源码 / 文档):
- src/net/relay/content/*.ts、src/net/relay/index.ts、main.ts:块级寻址 C 域分离
- src/supervisor/orchestrator.ts、src/worker/agent.ts:日志采集与巡检(方案 C)
- test/overlay-content.test.mjs:随附用例(npm test = 200 pass / 0 fail / 1 skipped,Node 22)
- scripts/dshlog.mjs(跨机日志取证)、scripts/overlay-entropy.cjs(熵探针)
- dsh-server-docs/04-调整方案/129、133;INDEX.md / docs-manifest.json / 交接单 README 登记
2026-09-19 05:35:35 +08:00

157 lines
30 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** |
| `覆盖网络-序24-内容分发块级寻址.md` | ⏳ **待执行**(2026-09-17 20:4x 立单) | 🔄 已登记 automation `91251b14-9ee8-42a9-9d89-8559b7af75ed`(**2026-09-17 20:42** 起) | 首屏包冷启动改造:**块级内容寻址 + 同网段 peer 优先**(内容源优先级链 本地→同网段 peer→边缘缓存→分发点→公网源)。**主判据 `E1` = 版本发布时回源字节数 ≈ 1 份 × 组数**。🔴 **必须块级,⛔ 绝不做包级**(包级 = 版本一发即全量重拉风暴) | **代码** `src/net/relay/content/{chunker,store,peer,source}.ts` + `index.ts`/`web/server.ts`/`scripts/overlay-probe.cjs`/参数表;**文档** 本单 §8 | 用户拍板 2026-09-17:「**B 内容分发(块级内容寻址)是否立项:做**」;依据 `覆盖网络_瓶颈落地方案_20260916.md §3`;**§7 前缀 `49d0f405e08c909e18ba6825d1442b9d`** |
| `覆盖网络-序25-实例逐步拉起.md` | ⏳ **待执行**(2026-09-17 20:4x 立单;**待 序㉔ 收口时登记下一棒**) | ⛔ 未登记(等 序㉔ 收口) | Manager(portal)重启后**逐步接管既有实例**,而不是启动即清空。⚠️ **关键事实**:`orchestrator.ts:208` 构造函数里 `cleanAllStaleScopes()` ⇒ 现在**portal 一启动就把全部实例 scope 清掉** ⇒ 本单 = 把「清空」换成「接管」。**主判据 `E1` = 重启后实例数不变** | **代码** `src/supervisor/orchestrator.ts`(`cleanAllStaleScopes` / `cleanStaleScopes` 一带);**文档** 本单 §8 | 用户拍板 2026-09-17:「**Manager 重启后是否自动拉起既有实例:逐步拉起**」;三条硬约束(⛔ 不许删 `cleanStaleScopes(uid)`/⛔ 不许改成"什么都不做"/⛔ 不许"重启后重新 spawn 一遍");**§7 前缀 `d9d48121e68faa00e1da17ad8fea36ad`** |
| `覆盖网络-序26-骨干稳定选路与加密.md` | ⏳ **待执行**(2026-09-17 20:4x 立单;**待 序㉕ 收口时登记下一棒**) | ⛔ 未登记(等 序㉕ 收口) | 骨干节点服务范围落地:**连接稳定高效**(jitter 选路 + 2–3 候选路径 + 中继余量 30%+ + ≤10 成员全互联)+ **数据安全可加密传输**(TLS 已在 + 签名/哈希完整性 + 元数据最小化)。**主判据 `E1` = jitter 更低但 RTT 更高的候选被选中** | **代码** 新增 `src/net/relay/jitter.ts` + `directory.ts`/`switcher.ts`(只加"jitter 劣化即切",⛔ 不改冷却语义)/`server.ts`/`scripts/overlay-jitter.cjs`/参数表;**文档** 本单 §8 | 用户拍板 2026-09-17:「**入口 §4 骨干节点的服务范围:按照连接稳定高效的方式 数据安全可加密传输**」;判定 = **A 起步、口径按 B 的质量标准建设**;**§8 前缀 `dbcbe633aa1aef92f4c35c77fad3ec11`** |
| `覆盖网络-序45-低熵块治理-测熵与实现.md` | 🟡 **部分执行**(**§5 步骤 1 + 2 完成** · 2026-09-18 22:2x · 序㊺ 执行棒)—— 🔴 **`M1` 实测判「D 的作用面为空 ⇒ D 本轮不实现」**(首屏包 23 块 **0 个低熵块**、60 份真实内容 **0 份低熵**);⛔ 未改 `src/**` 一行 | ✅ 已登记 **序㊻ 执行棒(C 域分离 + 判据重裁)** automation `aab9e357-8101-4011-b829-bf9f4a459bf7`(一次性 · 2026-09-18 22:33) | 低熵块治理:**先补测「低熵块种类数 / 体积 / 占首屏包比例」**(🔴 从未测过)→ 再落 **C 域分离**(per-network keyed hash)+ **D 非确定性**(首选 **D-1 稀释域**)。🔴 **第一步是测熵、⛔ 不是改码** —— 切分是**定长 1 MiB** ⇒ 首屏包内几乎无纯低熵块,**必须加子窗口腿防假绿** | **代码** `src/net/relay/content/{chunker,crypto}.ts` + `blockIdOf` 调用点 + `scripts/overlay-probe.cjs` + 参数表;**文档** 本单 §一 行 / `INDEX.md` | 用户拍板 2026-09-18 21:28:「**采纳 C + D;B(OPRF / SA-MLE)降级为可选加强、⛔ 本轮不立项**」;方案 = `04-调整方案/133`;调研 = 工作区根 `调研_MLE加密去重最优方案_20260918.md`;**§8 前缀 `be548afc3340583b2b63ca254bcf550f`** |
> **🔒 占用怎么声明(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`**;完工反序释放。