Files
dsh_ai1net_server/归档/交接单-20260924-归档/交接单_在册收尾_20260917.md
T
admin 7bd1151c67 chore(工作区): 归档交接单 27 件 + 新增 CODEBUDDY §9 工作区卫生
交接单按归属约定(正文落文档库、工作区只放指针)归档至
归档/交接单-20260924-归档/,含逐件判定 README:
- 16 件已被文档库正式版取代(T09–T21 + 覆盖网络-24/25/26)
- 4 件主题已被覆盖网络线入口汇总
- 7 件历史接续包/规划件

CODEBUDDY §9:收口清本棒 tmp、tmp 保留期 7 天、禁「待清理」中间态、
工作区入库只放文档与文件、不保留脚本副本、>60 KB 单文件须逐个判。
2026-09-24 07:58:57 +08:00

455 lines
45 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.
# 交接单 · 在册收尾(Q5 + mksess 文档口径 + 技能三处同步 + 幕 4-A 临界项)(2026-09-17)
> **本单来源**:序 ⑯ 规划棒(automation `91c53ef8-c3f0-4bb3-9f0a-943790178176`,2026-09-17 16:36 起)。
> **本单定位**:**执行单**(8 段模板,可直接开工)。把「会合 / 中继拆分**复核结论**」+「**剩余在册项定序**」合并为**一个**执行棒 = **序 ⑰**。
> **本棒只出规划**:⛔ 未改任何代码、⛔ 未动 47 / 106、⛔ 未 commit / push;全部取证 = 只读命令(详见 §0.2)。
---
## §0 结论先行
### 0.1 复核结论(二选一 ⇒ **判「不做」**)
> **「会合 / 中继从 Manager 拆分」—— 判「不做」。原方案 `会合中继拆分_取证与改造方案_20260916.md` S0–S4 的四个耦合点(C1–C4)与两个改造步骤(S3 / S4)已**逐条**被后续序次覆盖,**未覆盖部分 = 无**。**
| 靶子 | 原方案描述 | 现状证据(只读取证) | 判定 |
|---|---|---|---|
| **C1** | 会合地址硬编码在 Worker 的 env(`DSHS_TUNNEL_TARGET` 写死在 `switch-C-worker.sh` + `/etc/dshs-worker.env`) | `src/config.ts:485-490`:`DSHS_RENDEZVOUS_URL` **优先**、`DSHS_TUNNEL_TARGET` 降为**兜底**(注释原文:「覆盖网络 S1:会合地址出 env」);`src/worker/agent.ts:158`、`src/worker/tunnel.ts:16` 同口径 | ✅ 已被 **序② P0-2(引导三级链)** 覆盖 |
| **C2** | 中继落点 = **Manager 的 loopback** + **两端同号** ⇒ 第三台机器无法直达、中继不可多实例 | `src/config.ts:498-500`:`DSHS_RELAY_DIAL_PORT_BASE=25000` / `SPAN=1000` / `POOL=64` ⇒ 落点在 **Manager 自己本机**的回环池;`src/net/relay/dialer.ts:11` 注释「Manager 也像 worker 一样**只拨出**一条 wss(`RelayClient` 的 `dialer` 模式)」 | ✅ 已被 **R5(会合可换机)** 覆盖 —— **这就是题面给的已知事实** |
| **C3** | 可达性登记把「经谁中转」磨掉了(`dsh_hosts.endpoint` 语义 ≠ worker 地址) | `src/net/rendezvous.ts:103-106`「按 `via` 选实现的注册表」+ `Reachability.via`(`:27` / `:65` / `:98`);`src/supervisor/remote-spawner.ts:21-48` 取址一律走 `agentBaseUrlOf()` | ✅ 已被 **S2 / P2(`dsh_hosts.via` 列)** 覆盖 |
| **C4** | 控制面 PG 也走同一条隧道 ⇒ 回滚面含 DB | 方案 **§8.1** 实测:106 与 47 的 worker env **都没有** `DSHS_TUNNEL_STATIC_PORTS` ⇒ **C4 前提不成立** | ✅ **前提不成立**,无需处理 |
| **S0** | 抽 `Reachability` / `Rendezvous` 接口 | `src/net/reachability.ts`(`agentBaseUrlOf()` = 全仓唯一取址入口,`:99`)+ `src/net/rendezvous.ts` 均在册 | ✅ 已落地 |
| **S1** | 会合地址出 env | 同 **C1** 行 | ✅ 已落地 |
| **S2** | `dsh_hosts` 增 `via` 列 | 同 **C3** 行 | ✅ 已落地 |
| **S3** | 中继落点命名空间可配(回环别名 `127.0.0.2`…) | 方案 **§9.1** 实测 `gatewayports no` ⇒ 别名方案**证伪**;已改「实例端口区间隔离」(`w-47` 20000+ / `w-106` 21000+)⇒ 连「两端同号」这个前提都没了 | ✅ **原设计已作废且被更强做法替代** |
| **S4** | 中继独立成单元 + 会合可换机 + 多实例 | `dshs-relay` **独立 systemd 单元**已常驻两台(47 / 106,只绑回环 `20080`);序⑥ S8 把 106 升格为第二中继;序⑦ 切流演练「杀 47 ⇒ 切到 106」实测通过;**sshd 反向隧道已下线且不可能重建** | ✅ 已被 **R2 / 序⑥ S8 / 序⑦ / 序④** 覆盖 |
**⇒ 处置**:在 `会合中继拆分_取证与改造方案_20260916.md` 头部**加一行状态标注**(`已由 R5 + 序②/②P3/④/⑥S8/⑦ 覆盖 ⇒ 仅存档,⛔ 勿再按 S0–S4 开工`),正文⛔ 不改(历史档案属性)。
⚠️ **顺带登记一条观察项(⛔ 本单不处置)**:SSH 隧道代码路径 `src/worker/tunnel.ts` 现已是**生产死路径**(47 同机不建隧道、106 走 `wss://` relay),是否删除 = **独立决策**(可能保留作 ssh 兜底变体)⇒ 只登记,**不定序**。
### 0.2 本棒取证(只读,共 3 条命令族;⛔ 未连任何池口、未动 47/106 配置)
| # | 命令(`cwd` = 代码仓 `D:/github/dsh_shenxian`) | 关键输出 |
|---|---|---|
| 1 | `grep -rn "DSHS_TUNNEL_TARGET\|32022" --include=*.ts src` + `grep -rn "DSHS_RENDEZVOUS_URL" --include=*.ts src` | C1 现状(`config.ts:485-490` 新变量优先 / 旧变量兜底) |
| 2 | `grep -rn "via" src/net/rendezvous.ts` + `grep -rn "25000\|dialer" src/net/relay/dialer.ts` + `grep -rn "DSHS_RELAY_DIAL" src/config.ts` | C2 / C3 现状(拨号池 `25000..26000`、Manager 只拨出) |
| 3 | `find src test scripts -name "*.bak-*"` + `git ls-files src/net/relay \| wc -l` + `git ls-files --error-unmatch <bak>` | Q5 真实范围 **5 个**(非 3 个);`src/net/relay` tracked = **0**(Q4 自证) |
### 0.3 剩余在册项定序(→ 本单 §5 的 S1–S4)
| 序 | 项 | 类型 | 为什么排在这个位置 |
|---|---|---|---|
| **S1** | **mksess 文档口径**(「DB 直插」→「PG 直插」) | 文档(操作性载体) | **必须最先**:它改 `skills/**` 正文,而 **S2 的镜像同步要把 S1 的产物一起带上** ⇒ 二者共用**一次 scp**(硬顺序) |
| **S2** | **技能 `dsh-auto-handoff-chain` 三处同步** | 文档 + 镜像 | 紧随 S1(同属 `skills/**` 面、共用一次 scp);且它是**自动接续链路**的载体 ⇒ 直接影响本线后续每一棒的可复现性 |
| **S3** | **Q5**:`.bak-seq7-*` 残留清理(**范围修正 = 5 个**) | 清理(零服务副作用) | 与 S1/S2 无依赖,但同属「零服务副作用批」⇒ 合在文档批一起做,省一次抢锁 |
| **S4** | **§8.8-2 临界项**:幕 4-A 耗时贴近 deadline | 演练采样(**唯一有副作用项**) | **放最后**:它会把 Manager 通道挪来挪去(幕 4)⇒ 前面三条全部完成后再动,收尾 `restart dshs` 归零不影响已完成工作 |
**排序一句话**:`S1 → S2`(硬依赖,共用一次镜像同步)→ `S3`(零风险清理,同批)→ `S4`(唯一动服务的一项,置末)。
### 0.4 ⛔ 本单**不写进执行范围**的项(只登记)
| 项 | 登记内容 |
|---|---|
| **Q4** | 代码仓 `src/net/relay/**` **untracked**(实测 `git ls-files src/net/relay \| wc -l` = **0**)⇒ 序⑭/⑮ 的修复与 `test/relay.test.mjs` **只存在于工作区、不在版本库**。**卡在「commit / push 授权」**,属**待用户拍板** ⇒ ⛔ 本单不执行、⛔ 执行棒也不得动,**只报告**。 |
| **presence / 房间层 / 内容分发定序** | 属「业务优先级」(§1 边界外 ①)⇒ ⛔ **本单不定序**;候选与优缺点登记见 **§3.3**。 |
| **骨干节点服务范围** | 入口 §4 既有待拍板项(A 只服务自己名下设备 / B 服务全网)⇒ 原样保留,本单不重复上抛。 |
---
## §1 目标
一次执行棒把**四条在册项**收干,全部满足「零生产值改动 + 可秒级回滚」:
1. **mksess 口径对齐实现** —— 文档库 / 技能 / 镜像里对 `/opt/dshs/mksess{,−guest}.cjs` 的「DB 直插(SQLite 旧库)」描述已过期(序⑬ Q1 实测已改 **PG**)⇒ 改成与实现一致的描述,避免 R4 验收手段被误述。
2. **技能 `dsh-auto-handoff-chain` 的「三处同步」从「从未建立」变为「已建立」** —— 现在**文档库无副本**(实测 ❌)。
3. **清掉代码仓 `.bak-seq7-*` 残留** —— 立起「`.bak` 只在执行期存在」这条规矩(序⑫ 已以身作则、仓内 `.bak` = 0,但代码仓仍有 5 个历史快照)。
4. **给「幕 4-A 耗时贴近 deadline」这条临界项落一个判据**(三档递进),并采 5 个样本自证是否仍临界。
**非目标**:⛔ 不 commit / 不 push(Q4 未授权);⛔ 不改任何生产值(`RELAY_FAILOVER_*` / `HB_SEC` / burst);⛔ 不做打洞、不改 worker 拨出方向、不重做任何已收官序。
---
## §2 只读前置(S0 必须先核实;任一条不符 ⇒ **停下报告**,⛔ 不硬闯)
| # | 核实项 | 命令(`cwd` 见括注) | 期望(本单规划时的实测值) |
|---|---|---|---|
| **P1** | 锁空闲 | `bash dsh-server-docs/scripts/handoff-guard.sh` | 报「空闲」;**抢锁后**再开工(抢不到 = 有会话在跑 ⇒ 停手报告) |
| **P2** | 代码仓基线未漂移 | `cd D:/github/dsh_shenxian && git rev-parse --short HEAD && git status --porcelain \| wc -l` | HEAD = **`640813e`**;总数 = **43**(17 M + 3 ?? + 余) |
| **P3** | `.bak` 真实范围 | `cd D:/github/dsh_shenxian && find src test scripts -name "*.bak-*"` | **5** 个:`src/net/relay/{client,directory,main}.ts.bak-seq7-20260917-112114` + `src/web/server.ts.bak-seq7-20260917-112114` + `src/worker/tunnel.ts.bak-seq7-20260917-112114`(⚠️ 均 **untracked**,实测 `git ls-files --error-unmatch` 报 pathspec 不匹配) |
| **P4** | Q4 自证(⛔ 只记录) | `cd D:/github/dsh_shenxian && git ls-files src/net/relay \| wc -l` | **0**(untracked 缺口仍在 ⇒ 本棒 ⛔ 不得 commit) |
| **P5** | mksess 命中面 | `cd D:/github/dsh_shenxian && grep -rn "mksess" dsh-server-docs/ \| grep -iE "sqlite\|直插\|dshs\.db\|旧库"` | 命中 **4 行**:`04-调整方案/77-…md:97`(**档案,⛔ 不改**)、`skills/dsh-change-workflow/SKILL.md:146/395/495`、`skills/dsh-env-bootstrap/references/常驻规则-快照.md:55` |
| **P6** | 技能三处现状 | `ls -d "E:/ProgramData/.workbuddy/skills/dsh-auto-handoff-chain"` + `ls -d D:/github/dsh_shenxian/dsh-server-docs/skills/dsh-auto-handoff-chain` | ① 本机 ✅ **存在**;② 文档库 ❌ **不存在**(与在册项一致);③ 镜像(47 `/opt/dsh/docs/skills/`)**待现取** |
| **P7** | 基线回归值 | 见 §6-E6 | `npm test` = **162 / 161 pass / 0 fail / 1 skip**;`--scene all` = **12 PASS / 0 SKIP / 0 FAIL**;`overlay-probe --table "…/参数表_覆盖网络_20260917.md"` = **12/12 · rc=0** |
⚠️ **ssh 一律显式 `-p 22`**(别名 `bt-server` 的 `32022` 是失效残留口);**取证落盘一律 `2>/dev/null`**(ssh 的 PQ 告警会污染行数判据);**106 的 ssh 偶发 `rc=255`**(MaxStartups 限流)⇒ 容许单次重试,⛔ 不放宽限流(命中 R5)。
---
## §3 范围
### 3.1 改哪些(三处文档面 + 一处代码仓清理)
| 面 | 具体对象 | 动作 |
|---|---|---|
| 文档库(代码仓内) | `dsh-server-docs/skills/dsh-change-workflow/SKILL.md`(3 行)、`dsh-server-docs/skills/dsh-env-bootstrap/references/常驻规则-快照.md`(1 行)、`dsh-server-docs/02-运维手册.md`(命中处) | 口径校正 |
| 文档库(新增) | `dsh-server-docs/skills/dsh-auto-handoff-chain/`(**新建目录**)+ `skills/README.md` / `skills/INDEX.md` 登记 | 新建 + 登记 |
| 本机技能 | `E:\ProgramData\.workbuddy\skills\**`(命中 **10 行**) | 口径校正(与文档库同内容) |
| 镜像 | 47 `/opt/dsh/docs/skills/**` | scp 同步(S1 + S2 产物 **一次**上) |
| 代码仓 | `src/{net/relay/web/worker}/*.bak-seq7-20260917-112114`(**5 个**) | 删除 |
| 观测口径 | `参数表_覆盖网络_20260917.md` §6(**仅在 S4 判据落地时**) | 新增余量判据(⚠️ **会改参数表指纹** ⇒ 必须在 §8.9 记录变更前后值) |
### 3.2 ⛔ 明确不做
- ⛔ **不 commit / 不 push**(Q4 未授权 ⇒ 本棒**零提交动作**,含"顺手提交 `.bak` 删除"也不行);
- ⛔ 不改任何生产值:`RELAY_FAILOVER_*` / `HB_SEC` / burst / deadline;
- 🔴 ⛔ **不许把 `RELAY_FAILOVER_COOLDOWN_MS=0` 写进任何回滚 / 演练 / 夹具路径**(看似合法、实际自锁);
- ⛔ 不改 `04-调整方案/**` 历史档案正文(D1 已定:只在操作性载体里写"档案口径已过期"的指针);
- ⛔ 不动 47 / 106 的 nginx / nft / systemd 单元 / env(**唯一例外** = §5 S4 的演练与收尾 `restart dshs` 归零,与序⑩–⑮ 同口径);
- ⛔ 不重做任何已收官序(①–⑮);⛔ 不做 presence / 房间层 / 内容分发;⛔ 不做打洞实现;⛔ 不改 worker 拨出方向。
### 3.3 范围外登记(⛔ 不定序、不决策 —— 属「业务优先级」)
| 候选 | 优点 | 缺点 |
|---|---|---|
| **presence** | 清单 §五 第 7 步;千台推演里**第一瓶颈**,做完才能谈"谁在线"类功能 | 仓库里**目前零应用层代码**(全仓唯一含 "presence" 字样的是 `src/net/relay/placement.ts`)⇒ 从零起步、工作量最大 |
| **房间层** | 是 presence 的下游、MMORPG 多人的前置 | ⛔ 无 presence 则无输入;依赖链在前 |
| **内容分发(块级内容寻址)** | 与 presence 无依赖、可独立做;直接吃"跨云 ~22 KB/s"这条实测短板 | 与游戏主线收益关系较远;块级寻址会引入新的存储/校验面 |
---
## §4 决策点
**待拍板项 = 空**(本单四条全部落在 §1「边界内自决清单」:实现路径 / 排查方法 / 文档技术内容 / 清理类)。以下为**已定项(可推翻)**:
| # | 已定项 | 理由 |
|---|---|---|
| **D1** | mksess 口径**只改操作性载体**(`02-运维手册.md` + `skills/**` + 本机技能),**⛔ 不改 `04-调整方案/*.md` 档案正文**;在 `02-运维手册.md` 的 R4 段写一行「档案 77 里的『DB 直插』为当时形态,现实现 = **PG 直插**」作勘误指针 | 档案的属性是**当时事实**,改写 = 销毁溯源;且档案命中面 7 个文件(R7 批量面)。B 方案(只改载体)明显更优 ⇒ 自决 |
| **D2** | Q5 范围**扩到 5 个**(含原单未记的 `src/web/server.ts.bak-seq7-*` 与 `src/worker/tunnel.ts.bak-seq7-*`) | 同类、同批、同为 **untracked 过期快照**(seq7 11:21 的快照,已被序⑧/⑨/⑭/⑮ 改写作废 ⇒ **无回滚价值**);只删 3 个 = 规矩只立一半,下次还要再开一单。R7 透明:本行即"先报告" |
| **D3** | 幕 4-A 判据取**三档递进**而非单一阈值:**p95 ≤ 24 s(deadline×0.8)= 健康**|**24–27 s = 临界(记入在册、⛔ 不判 FAIL)**|**> 27 s = 回头条件触发(停下报告)** | 观测样本 19.5 / 20.8 / 22.2 s,单阈值 24 s 有假红风险、27 s 又预警太晚 ⇒ 三档把"假红 vs 预警提前量"这个取舍**消解**掉了(既不失预警、也不误判) |
| **D4** | ⛔ 本单**不处理** `src/worker/tunnel.ts` 这条生产死路径(是否删 = 独立决策) | 删代码有风险、且它可能作为 ssh 兜底变体保留 ⇒ 只登记(§0.1 末) |
| **D5** | S4 若触发回头条件(p95 > 27 s),**⛔ 不许自行调 `RELAY_FAILOVER_DEADLINE_MS` / `HB_SEC` / burst** ⇒ 停下报告,重做四段分解(检测 / 首试 / 白等 / 建连)后定位 | 沿用序⑨ 已立的三条硬门(D1 / 生产值不可调 / 分解优先) |
---
## §5 步骤 S0–S5
### S0 · 只读前置 + 抢锁
- 跑 §2 的 **P1–P7** 全部核实;任一条不符 ⇒ **停下报告**。
- **抢锁**:`bash "D:/github/dsh_shenxian/dsh-server-docs/scripts/handoff-guard.sh" --claim-exec "覆盖网络线-序17执行棒"`。
- 抢到后再跑一次信息模式,记下占用与越界改动。
### S1 · mksess 文档口径校正(「DB 直插」→「PG 直插」)
- **先取准实现事实**(只读,1 条命令):`ssh -p 22 bt-server 'head -40 /opt/dshs/mksess.cjs'` ⇒ 确认落点是 **PG**、连接串来源 = env / `dshs.env` / `dshs.service.d`、**⛔ 不固化凭据**(序⑬ §9.2 已改)。
- **改哪些行**:按 §2-P5 的 grep 结果逐行改(**只改断言"存储机制"的行**;仅提及文件名、不涉机制的行**保持原样**)。
- 统一措辞(示例,⛔ 不写死凭据):`node /opt/dshs/mksess.cjs`(**PG 直插**,连接串取自 env / `dshs.env` / `dshs.service.d`;10 分钟;`user_agent=poc-curl2`)
- **本机 + 文档库两副本同改**(内容逐字节一致)。
- **判据**:
- `grep -rn "mksess" dsh-server-docs/ \| grep -iE "sqlite\|旧库"` = **0**(⚠️ 原本 0 命中的"旧库"也一并核)
- `grep -rniE "sqlite|旧库" <文档库 skills 与 02-运维手册> \| grep -c mksess` = **0**
- 两副本 `md5sum` 逐文件一致
- **回滚**:`git checkout -- <改动文件>`(文档库)+ 本机技能按 §7 备份还原。
### S2 · 技能 `dsh-auto-handoff-chain` 三处同步**建立**
- **① 核本机副本清单**:`ls -R "E:/ProgramData/.workbuddy/skills/dsh-auto-handoff-chain"` ⇒ 记下全部文件(`SKILL.md` + 可能的 `references/`、`scripts/`)。
- **② 建文档库副本**:逐文件复制到 `D:/github/dsh_shenxian/dsh-server-docs/skills/dsh-auto-handoff-chain/`(**逐文件 copy,⛔ 不用 `cp -r` 整目录覆盖**;⚠️ 文档库 `.gitattributes` = `* -text` ⇒ **保持纯 LF**)。
- **③ 登记**:改 `dsh-server-docs/skills/README.md` 与 `dsh-server-docs/skills/INDEX.md`,加上该技能行。
⚠️ **`INDEX.md` 是混合换行** ⇒ **字节级单行插入**,⛔ 不跑 `git checkout --`、⛔ 不做批量换行符转换。
- **④ 镜像同步**:scp 到 47 `/opt/dsh/docs/skills/`(**连同 S1 的改动物一次上**);同步前先抢锁(本棒已持锁)。
- **判据**:
- `diff -r` 两副本 = **0 差异**;逐文件 `md5sum` 一致(⚠️ 本机 `md5sum` 出 `hash *path`、远端出 `hash path` ⇒ 先 `cut -d' ' -f1` 再比)
- 镜像 `/opt/dsh/docs/skills/dsh-auto-handoff-chain/SKILL.md` md5 == 文档库 md5
- `grep -c "dsh-auto-handoff-chain" dsh-server-docs/skills/README.md` ≥ **1**(INDEX.md 同)
- **回滚**:删文档库新增目录 + 镜像改名还原备份(`README.md` / `INDEX.md` 用 `git checkout --`)。
- ⚠️ **本步自证价值**:这一条正是「长期在册」项 —— 此前该技能的"三处同步"**从未建立**,本步是**第一次**把它建起来;完成后在 §8.8 明确写"已建立",并在 `.workbuddy/memory/MEMORY.md` 的对应处("该技能三处同步从未建立(在册未办)")改为**已办**。
### S3 · Q5 清理 `.bak-seq7-*`(**5 个**)
- **前置(缺一不可)**:① `find src test scripts -name "*.bak-*"` 逐个确认属 **seq7-20260917-112114** 批次;② 确认**对应源文件存在**(`client.ts` / `directory.ts` / `main.ts` / `web/server.ts` / `worker/tunnel.ts`);③ 确认 `lib/` 内有**等价产物**;④ ⚠️ 记录一条事实:这些是 **11:21 的快照**,**已被序⑧/⑨/⑭/⑮ 改写作废 ⇒ 他们不是有效回滚点**(删除风险 = 零)。
- **怎么做**:逐个 `rm`(**5 个,逐个点名**,⛔ 不用通配符 `rm src/net/relay/*.bak-*`)。
- **判据**:
- `find src test scripts -name "*.bak-*" \| wc -l` = **0**
- `npm run build` **RC=0**(⛔ 未改任何源文件 ⇒ 产物指纹应与 S0 一致,可对账 `lib/net/relay/*.js` md5 不变)
- `npm test` = **162 / 161 / 0 / 1**(不退化)
- `git status --porcelain \| wc -l` **只减不增**(Δ ≤ 0;⚠️ `src/net/relay/` 整体是 `??` 一个条目 ⇒ **不能期望 −5**,判据落到 `find` 结果与 md5 上)
- **回滚**:`.bak` 不可再生 ⇒ 回滚动作 = 从当前源文件重新 `cp` 一份快照(⚠️ 语义不等价,仅作备案)。⇒ 故删除前**必须**完成前置 ④ 的书面记录。
### S4 · §8.8-2 临界项 —— 幕 4-A 余量判据化 + 稳定性采样
- **不改任何生产值**;只跑演练 + 落判据。
- **① 采样**:`node scripts/overlay-failover-drill.cjs --scene 4 --table "<工作区根>/参数表_覆盖网络_20260917.md"`(`DRILL_SAMPLE_N` = **5**)。
⛔ **只跑 `--scene 4`(构 A)**;⛔ 不跑 `4b` / `4c` / `ctrl`(`4c` / `ctrl` 已被序⑩ 整体移除并显式拒绝 —— 那是 `COOLDOWN_MS=0` 的诱发面)。
- **② 算判据**:对 5 个样本取 **p95**,按 §4-D3 三档判定:
- `p95 ≤ 24000 ms` ⇒ **健康** ⇒ 把判据写进参数表 §6(配套说明:分母 = `RELAY_FAILOVER_DEADLINE_MS` = 30000 ms);
- `24000 < p95 ≤ 27000` ⇒ **临界(记录,⛔ 不判 FAIL)** ⇒ 写进 §8.8 在册;
- `p95 > 27000` ⇒ 🔴 **停下报告**(⛔ 不许自行调任何生产值)⇒ 按 §4-D5 重做四段分解。
- **③ 零回归**:`--scene all` = **12 PASS / 0 SKIP / 0 FAIL**(幕 4-A / 4-C 全部 ≤ deadline);`npm test` 不退化。
- **④ 收口归零(本步的"回滚")**:演练会把 Manager 通道挪到 106 ⇒ **必须 `systemctl restart dshs` 归零回 47**,再跑 `overlay-probe` 确认 **12/12**、`ss -lntH 'sport >= :25000 and sport <= :25063' | wc -l` = **64**。
⚠️ 判"服务是否正常"要 `systemctl is-active dshs dshs-relay dshs-pg` —— 演练进行中某台 relay 是 `inactive`,那是**幕的正常态**。
- **回滚**:本步不改服务配置 ⇒ 回滚 = ① 参数表备份还原(指纹回到现值 `8f08e74b026e6e5b5e1b3db813f031ae`)② 演练坐标/env 残留清 0(`grep -r 'DRILL_' /etc/systemd/system/dshs.service.d/` = 0)。
### S5 · 收口(6 件,缺一即算未完成)
① 释放锁 `--release-exec`;② **陈述句**告知用户 + 登记下一棒一次性 automation(`scheduledAt` = 收口时刻 **+2~5 分钟**;⚠️ 下一棒 id **只能来自工具返回值**:先 `create` → 取 id → 再落盘);③ 把 `接续入口_覆盖网络线_20260916.md` §0 + §2 推进到再下一棒;④ 写工作区日志 `.workbuddy/memory/2026-09-17.md`(**append-only**);⑤ 在本单追加回报(§8 八小节);⑥ 输出指纹(§8.9)。
---
## §6 验收(逐条命令 + 期望 + 退出码;可被第三方复现)
| # | 项 | 命令(`cwd` 见括注) | 期望 |
|---|---|---|---|
| **E1** | S1 口径已对齐 | `cd D:/github/dsh_shenxian && grep -rn "mksess" dsh-server-docs/ \| grep -iE "sqlite\|旧库" \| grep -v "04-调整方案"` | **0 行**(⛔ 档案除外) |
| **E2** | S1 双副本一致 | 逐文件 `md5sum`(本机技能 vs 文档库技能,`cut -d' ' -f1` 后比) | **全同** |
| **E3** | S2 三处同步 | `diff -r "E:/ProgramData/.workbuddy/skills/dsh-auto-handoff-chain" "D:/github/dsh_shenxian/dsh-server-docs/skills/dsh-auto-handoff-chain"` + 镜像 `md5sum` | diff **0 行**;镜像 md5 == 文档库 md5 |
| **E4** | S2 登记 | `cd D:/github/dsh_shenxian && grep -c "dsh-auto-handoff-chain" dsh-server-docs/skills/README.md`(INDEX.md 同) | **≥ 1** |
| **E5** | S3 清理干净 | `cd D:/github/dsh_shenxian && find src test scripts -name "*.bak-*" \| wc -l` | **0** |
| **E6** | 零回归(三件套) | ① `cd D:/github/dsh_shenxian && npm.cmd test`(**必须 Node 22**)② `node scripts/overlay-failover-drill.cjs --scene all --table "<工作区根>/参数表_覆盖网络_20260917.md"` ③ `node scripts/overlay-probe.cjs --table "<工作区根>/参数表_覆盖网络_20260917.md"` | ① **162 / 161 / 0 / 1** ② **12 PASS / 0 SKIP / 0 FAIL** ③ **12/12 · rc=0** |
| **E7** | S4 余量判据 | `--scene 4` × `DRILL_SAMPLE_N`=5 ⇒ p95 | 落 §4-D3 三档之一;**> 27000 ms ⇒ 停下报告** |
| **E8** | 越界自证 | `cd D:/github/dsh_shenxian && grep -c 'COOLDOWN_MS=0' scripts/` + `git rev-parse --short HEAD` + `git status --porcelain \| wc -l` | `0`;HEAD 仍 **`640813e`**(⛔ 无 commit);总行数 **≤ 43** |
| **E9** | 收口归零 | `ssh -p 22 bt-server 'systemctl is-active dshs dshs-relay dshs-pg'` + `ssh -p 22 bt-server "ss -lntH 'sport >= :25000 and sport <= :25063' \| wc -l"` | 三个 `active`;池口 **64** |
---
## §7 回滚
| 对象 | 回滚动作 | 耗时 |
|---|---|---|
| S1 文档(文档库) | `git checkout -- dsh-server-docs/skills/dsh-change-workflow/SKILL.md dsh-server-docs/skills/dsh-env-bootstrap/references/常驻规则-快照.md dsh-server-docs/02-运维手册.md` | 秒级 |
| S1 文档(本机技能) | 执行前逐文件备份到 `_中间产物_待清理/seq17/skills-bak/` ⇒ `cp` 还原 | 秒级 |
| S2 文档库新增目录 | `rm -rf dsh-server-docs/skills/dsh-auto-handoff-chain`(⚠️ 纯新增 ⇒ 无溯源损失)+ `git checkout -- README.md INDEX.md` | 秒级 |
| S2 镜像 | `ssh -p 22 bt-server` 把 `/opt/dsh/docs/skills/` 备份目录改名还原 | 秒级 |
| S3 `.bak` 删除 | ⚠️ **不可逆**(原文件是过期快照、无回滚价值)⇒ 回滚 = 从当前源文件重建快照(仅备案)。**故前置 ④ 必须先写** | 秒级 |
| S4 参数表判据 | 参数表备份还原 ⇒ 指纹回 **`8f08e74b026e6e5b5e1b3db813f031ae`** | 秒级 |
| S4 服务态 | `systemctl restart dshs` 归零回 47(⛔ 不删 drop-in、⛔ 不改 cluster 配置) | 秒级 |
---
## §8 回报格式(执行会话按此回填;⛔ 缺一节即算未完成)
### 8.1 结论(1 行) :四条在册项逐条 ✅ / ❌(S1 / S2 / S3 / S4),+ 是否触发 S4 回头条件
### 8.2 只读前置 P1–P7 :逐条贴命令与输出(P3 的 5 个 `.bak` 逐个点名 + `git ls-files` 的 untracked 自证)
### 8.3 S1 口径校正 :命中行清单(文件:行 → 改前 / 改后)、0 命中的判据命令原文、⛔ 未动档案的自证
### 8.4 S2 三处同步 :本机副本文件清单(逐个 md5)+ 文档库 md5 + 镜像 md5(**三处对照表**)+ README/INDEX 登记原文
### 8.5 S3 清理 :`find` 前 / 后计数 + 5 个文件逐个名 + `npm run build` RC + `npm test` 计数 + "非有效回滚点"的书面记录
### 8.6 S4 临界项 :`--scene 4` 5 个样本原文 + p95 = ? ms ⇒ 落哪一档 + 判据是否落表(落表则给参数表指纹 变更前/后)
### 8.7 零回归 / 越界自证 :E6 三件套原文(含 `--scene all` 的幕 4-A / 4-C 两个毫秒值)+ E8(`COOLDOWN_MS=0` 计数、HEAD、`git status` 计数)
### 8.8 未过项 / 在册未办 :逐条写「现象 / 已做到哪一步 / 回头条件」;**Q4 原样转下一棒**(⛔ 只报告);§0.4 的三项登记原样保留
### 8.9 指纹(可复现核对口径)
- 本单前缀:`cd "E:/ProgramData/AI技能/aliyun-dsh-server" && sed '/^## §8 回报格式/,$d' 交接单_在册收尾_20260917.md | md5sum`
- 本单全文:`md5sum 交接单_在册收尾_20260917.md`
- 参数表(**D1 自证**):`sed '/^## §10 指纹/,$d' 参数表_覆盖网络_20260917.md | md5sum`(⚠️ **截断口径**,⛔ 不是全文件 md5;现值 `8f08e74b026e6e5b5e1b3db813f031ae`)
- 关键产物:`src/net/relay/{client,directory,main}.ts` + `src/web/server.ts` + `src/worker/tunnel.ts` 的 md5(**清理前后应不变** ⇒ 自证未改源文件)
---
## §9 执行回报(序 ⑰ 执行棒 · 2026-09-17 16:44–17:3x)
> 口径 = 按 §8 的九个小节逐条回填;本 §9 位于 §8 之后,**不进 §8 前缀指纹**。
### 9.1 结论(对应 §8.1)
**四条在册项逐条:S1 ✅ | S2 ✅ | S3 ✅ | S4 ⚠️ 落「临界档」(记录在册,⛔ 不判 FAIL)。**
**S4 回头条件是否触发:未触发**(p95 = 24477 ms < 27000 ms)⇒ ⛔ 未调任何生产值。
**范围遵守**:⛔ 未改任何生产值;⛔ 未改 `04-调整方案/**` 档案正文;⛔ 未重做已收官序 ①–⑮;⛔ 未做 presence / 房间层 / 内容分发;⛔ 未超 §3 范围。
**追加授权**:用户本轮明确「执行完毕后 同步到仓库」⇒ Q4(提交/推送授权)已解除并办结,见 §9.10。
### 9.2 只读前置 P1–P7(对应 §8.2)
| # | 核实项 | 实测 | 判定 |
|---|---|---|---|
| P1 | 锁空闲 | 报「空闲」;本棒 `--claim-exec "覆盖网络线-序17执行棒"` 抢到 | ✅ |
| P2 | 基线未漂移 | `HEAD = 640813e`;`git status --porcelain \| wc -l` = **43** | ✅ |
| P3 | `.bak` 真实范围 | 5 个(逐个点名见 §9.5) | ✅ 与单一致 |
| P4 | Q4 自证 | `git ls-files src/net/relay \| wc -l` = **0** | ✅(本轮已解除 → 见 §9.10) |
| P5 | mksess 命中面 | `grep -rn "mksess" dsh-server-docs/` 筛 `sqlite\|直插\|dshs.db\|旧库` = **5 行** ⇒ 落点 = 档案 77(⛔ 不改)+ `skills/dsh-change-workflow/SKILL.md`:146/395/495 + `skills/dsh-env-bootstrap/references/常驻规则-快照.md`:55 | ✅ |
| P6 | 技能三处现状 | ① 本机 ✅ 存在(`SKILL.md` + `scripts/chain_report.py`);② 文档库 ❌ 不存在;③ 镜像 ❌ 不存在(8 个技能、无此项) | ✅ 与在册项一致 |
| P7 | 基线回归值 | 见 §9.7 | ✅ |
**mksess 实现事实(只读,1 条 ssh;`-p 22` 显式)**:`/opt/dshs/mksess.cjs`(74 行)第 2 行即「临时会话直插(**PG 版**)」;第 4–6 行写明「原版直插 `/var/lib/dshs/dshs.db`(SQLite)… 集群化后权威库 = 47 的 PG13(`DSHS_DB_URL`),SQLite 只剩回滚用途」;第 9–10 行「连接串从环境读(`DSHS_DB_URL` env → `/etc/dshs.env` → `dshs.service.d/*.conf`),⛔ 不把凭据固化进本文件」;第 17 行 `require('/opt/dshs/node_modules/pg')`;`TTL_MS = 600 * 1000`。
⇒ **文档口径必须改成「PG 直插」**,与实现一致。
### 9.3 S1 口径校正(对应 §8.3)
**命中行清单(文件 : 行 → 改前 → 改后)** —— 文档库与**本机技能同内容逐字节一致**:
| 面 | 文件:行 | 改前 | 改后 |
|---|---|---|---|
| 文档库 + 本机 | `skills/dsh-change-workflow/SKILL.md:146` | `… mksess.cjs\` 直插临时 session,或…` | `… mksess.cjs\`(**PG 直插**)建临时 session,或…` |
| 文档库 + 本机 | `skills/dsh-change-workflow/SKILL.md:395` | `改用 \`mksess.cjs\` 直插临时 session 或…` | `改用 \`mksess.cjs\` **PG 直插**临时 session 或…` |
| 文档库 + 本机 | `skills/dsh-change-workflow/SKILL.md:495` | `(DB 直插,10 分钟,user_agent=poc-curl2)` | `(**PG 直插**,连接串取自 env / \`dshs.env\` / \`dshs.service.d\`;10 分钟;\`user_agent=poc-curl2\`)` |
| 文档库 + 本机 | `skills/dsh-env-bootstrap/references/常驻规则-快照.md:55` | `(\`mksess.cjs\` 直插)` | `(\`mksess.cjs\` **PG 直插**)` |
| 仅文档库 | `02-运维手册.md:211–214` | `# 测试 session 生成(门户 API 直调,10 分钟)` | 注释行补「**PG 直插**,连接串取自 env / dshs.env / dshs.service.d;10 分钟;user_agent=poc-curl2」+ **D1 勘误指针两行**(说明档案 77 与更早文档的描述属当时形态、写 `/var/lib/dshs/dshs.db`,集群化后权威库 = 47 的 PG13、那份文件仅回滚用) |
**判据原文**:
- **E1** `cd D:/github/dsh_shenxian && grep -rn "mksess" dsh-server-docs/ | grep -iE "sqlite|旧库" | grep -v "04-调整方案" | wc -l` = **0** ✅(⛔ 档案除外)
- **E1b** `grep -rniE "sqlite|旧库" dsh-server-docs/skills/ dsh-server-docs/02-运维手册.md | grep -c "mksess"` = **0** ✅
- **E2** 两副本逐文件 md5:`dsh-change-workflow/SKILL.md` = `338bf9534e5243f495e7d66f914371bf`(本机 = 文档库);`dsh-env-bootstrap/references/常驻规则-快照.md` = `e1a460b53cc4b62466107f8555946496`(本机 = 文档库) → **全同** ✅
- 行尾:5 个文件 CR 计数 **全 0**(纯 LF)✅
**⛔ 未动档案自证**:`04-调整方案/77-回到页面自检与就地恢复-恢复过程可见化.md:97` 原文**未改**(该行本就不含 `sqlite/旧库`,属 E1 的排除项)。
⚠️ **一处判据偏差(已按实质落点执行)**:§3.1 / §5-S2 写的登记文件路径为 `dsh-server-docs/skills/README.md` 与 `INDEX.md`,**实测 `skills/` 下无这两个文件** —— 真实登记文件在**文档库根** `dsh-server-docs/README.md` 与 `dsh-server-docs/INDEX.md`(内容形态与描述一致:技能表 + 「什么时候查什么」表 + 技能清单表)⇒ 按实质落点执行,判据 E4 落在根文件上。
### 9.4 S2 三处同步(对应 §8.4)
**① 本机副本清单**(`E:/ProgramData/.workbuddy/skills/dsh-auto-handoff-chain/`):
| 文件 | 字节 | md5 |
|---|---|---|
| `SKILL.md` | 18926 | `0c5c4103f8ffa8071ce29434654fa2d3` |
| `scripts/chain_report.py` | 8126 | `636c4f336864bc99c408e92577516f11` |
**② 文档库副本**(新建 `dsh-server-docs/skills/dsh-auto-handoff-chain/`,**逐文件 copy**、⛔ 未用 `cp -r`):
| 文件 | 本机 md5 | 文档库 md5 | 镜像 md5(47 `/opt/dsh/docs/skills/dsh-auto-handoff-chain/`) | 判定 |
|---|---|---|---|---|
| `SKILL.md` | `0c5c4103f8ffa8071ce29434654fa2d3` | 同 | 同 | ✅ 三处同值 |
| `scripts/chain_report.py` | `636c4f336864bc99c408e92577516f11` | 同 | 同 | ✅ 三处同值 |
- **E3** `diff -r "E:/…/skills/dsh-auto-handoff-chain" "D:/…/dsh-server-docs/skills/dsh-auto-handoff-chain"` = **0 行** ✅
- 行尾:两处 CR = **0**(纯 LF)✅(文档库 `.gitattributes` 的 `dsh-server-docs/** -text` 完好)
**③ 登记**(字节级单行插入,新行行尾跟随锚点行):
| 文件:行 | 内容 |
|---|---|
| `dsh-server-docs/README.md:37` | 技能表新增 `skills/dsh-auto-handoff-chain/` 行(v1.3.2 + 六件套骨架 + 登记门禁 + 五条实测防护 + `scripts/chain_report.py`;同步方向本机 → 此处) |
| `dsh-server-docs/INDEX.md:22` | 「什么时候查什么」新增 `**跑跨会话长任务(自动接力)**` 行 |
| `dsh-server-docs/INDEX.md:169` | 技能清单表新增 `— / ✅ / skills/dsh-auto-handoff-chain/SKILL.md` 行 |
- **E4** `grep -c "dsh-auto-handoff-chain" dsh-server-docs/README.md` = **1** ✅;`INDEX.md` = **2** ✅(≥ 1)
- ⚠️ `INDEX.md` 是**混合换行**(全文件 CR 计数 = 734)⇒ 全程**字节级**插入、**新行行尾跟随锚点**(两处锚点均为 LF)、⛔ 未做任何批量换行符转换、⛔ 未跑 `git checkout --`。
**④ 镜像同步**(S1 + S2 产物**一次上**;同步前远端备份):
- 备份 = `/opt/dsh/docs/.bak-seq17-20260917-164809`(5 个文件)
- 上传 7 个文件,md5 **逐条与本地一致**:`skills/dsh-change-workflow/SKILL.md` `338bf953…`|`skills/dsh-env-bootstrap/references/常驻规则-快照.md` `e1a460b5…`|`skills/dsh-auto-handoff-chain/SKILL.md` `0c5c4103…`|`…/scripts/chain_report.py` `636c4f33…`|`02-运维手册.md` `d6627843b67c72ddfd3b62b5cfd5e29f`|`README.md` `ddfd4d5fc890af0ee86d5442d8c0d610`|`INDEX.md` `5677883fd3777a225ae85af7c5c79fb7`
⇒ **该技能的「三处同步」由「从未建立」变为「已建立」**(此前文档库与镜像都无副本)。
### 9.5 S3 清理(对应 §8.5)
**前置四项(缺一不可)全部满足**:
① 5 个全属 **seq7-20260917-112114** 批次;
② 对应源文件 **5/5 存在**(`src/net/relay/{client,directory,main}.ts`、`src/web/server.ts`、`src/worker/tunnel.ts`);
③ `lib/` 内**等价比产物 5/5 存在**;
④ **书面记录**:这 5 个是 **seq7 11:21 的快照**,**已被序⑧/⑨/⑭/⑮ 改写作废 ⇒ 不是有效回滚点、删除风险 = 零**。
**删除前 → 后**:`find src test scripts -name "*.bak-*" | wc -l` = **5 → 0** ✅(**逐个点名 rm**,⛔ 未用通配符)
逐个名:`src/net/relay/client.ts.bak-seq7-20260917-112114` / `src/net/relay/directory.ts.bak-seq7-20260917-112114` / `src/net/relay/main.ts.bak-seq7-20260917-112114` / `src/web/server.ts.bak-seq7-20260917-112114` / `src/worker/tunnel.ts.bak-seq7-20260917-112114`
**判据**:
- `npm run build` **RC = 0** ✅
- `npm test` = **162 / 161 / 0 / 1** ✅(不退化)
- **lib 产物 md5 清理前后零差异** ✅(自证未改任何源文件):`client.js b8b29afba06ed6347cbefd29091f8c73`/`directory.js 3382ae677788d3bd1c026d4c71ca40ee`/`main.js 7531be9eeba5ced5928ff7747621d512`/`web/server.js b64fe76500249703e34934d274d0a151`/`worker/tunnel.js 5f2649b43b072812fbf5d910d91b0c22`
- ⚠️ `git status --porcelain | wc -l` **不减**(这 5 个全 untracked ⇒ 本来就不体现在 git status 里;判据落在 `find` 与 md5 上,与 §5-S3 的说明一致)
⚠️ **额外兜底(超出单子、零风险)**:删除前把这 5 份原件**复制**到 `E:/ProgramData/AI技能/aliyun-dsh-server/_中间产物_待清理/seq17/bak-archive/`(5 个文件,保持相对路径)⇒ 即使日后需要,仍有字节级副本可查。
### 9.6 S4 临界项(对应 §8.6)
**采样命令**:`node scripts/overlay-failover-drill.cjs --scene 4 --sample 5 --table "<工作区根>/参数表_覆盖网络_20260917.md"`(RC = 0;原文 = `_tmp_seq17_scene4.txt`)
⛔ 只跑 **`--scene 4`(构 A)**,⛔ 未跑 `4b` / `4c` / `ctrl`。
**5 个样本(切换耗时,ms)**:
| 轮 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| 耗时 ms | 20121 | 18772 | 21223 | 24477 | 20246 |
(5/5 全部在 `deadline = 30000 ms` 内侧;AUTH 就绪 4358 / 2272 / 2846 / 3652 / 2853 ms;目标恒为 `wss://106.54.21.172/dshs-relay`)
**p95 口径(⚠️ 两种口径分档不同,必须点名)**:
- **nearest-rank(保守,本次采用)**:`k = ceil(0.95 × 5) = 5` ⇒ 第 5 个 = **24477 ms** ⇒ 落 **临界档(24000 < p95 ≤ 27000)**
- 线性插值:`idx = 0.95 × (5−1) = 3.8` ⇒ `21223 + 0.8 × 3254` = **23826.2 ms** ⇒ 落 健康档
**⇒ 结论(按 §4-D3)**:**临界档 ⇒ 记录在册、⛔ 不判 FAIL、⛔ 不调任何生产值**。
⚠️ **两口径均 < 27000 ms ⇒ 回头条件未触发**(§4-D5 未被激活)。
**⇒ 判据未落参数表 §6** —— §5-S4 ② 规定只在「健康」档落表 ⇒ **参数表指纹保持不变**(`8f08e74b026e6e5b5e1b3db813f031ae`,见 §9.9),**D1 自证成立**。
阈值口径:`deadline = RELAY_FAILOVER_DEADLINE_MS = 30000 ms`;两档 = `deadline×0.8 = 24000` / `deadline×0.9 = 27000`。
### 9.7 零回归 / 越界自证(对应 §8.7)
**E6 三件套(全绿)**:
① `npm test`(Node 22)= **162 tests / 161 pass / 0 fail / 1 skipped**,RC = 0 ✅
② `--scene all` = **12 PASS / 0 SKIP / 0 FAIL**,RC = 0 ✅ —— 幕 4-A 两个毫秒值:**20419 ms**(停 47 ⇒ 切 106)与 **18333 ms**(一跳豁免切回 47);幕 4-C 实测 **18333 ms** / deadline 30000 ms
③ `overlay-probe --table "…/参数表_覆盖网络_20260917.md"` = **12/12 · rc = 0** ✅(OBS-01…OBS-12 全 PASS;OBS-11 = 必在 7 / 允许 4 / 区间 3 / 派生 2 / 实际 78,多出 0 / 缺失 0;OBS-09 本机:20000=401 w-106:45747=401)
**E9 收口归零**:`ssh -p 22 bt-server 'systemctl is-active dshs dshs-relay dshs-pg'` = **active / active / active** ✅;`ss -lntH 'sport >= :25000 and sport <= :25063' | wc -l` = **64** ✅
**E8 越界自证**:
- `COOLDOWN_MS=0` 精确计数 = **0** ✅(`grep -rn "COOLDOWN_MS" scripts/` 的命中**全部是「⛔ 不许置 0」的警示注释**,无任何实际赋值 —— 已逐行人工核)
- **HEAD = `640813e`(⛔ 本棒零 commit)** —— ⚠️ 该判据表内值为基线快照;本节其余项全绿后才按用户追加授权单独提交(§9.10),**提交发生在 E8 判据采集之后**
- `git status --porcelain | wc -l` = **49**(基线 43 + 6),**逐项可归因,无越界**:
- **+4 个 M**:本轮 S1/S2 把 4 个原本干净的文档改为 M —— `dsh-server-docs/02-运维手册.md`、`skills/dsh-change-workflow/SKILL.md`、`skills/dsh-env-bootstrap/references/常驻规则-快照.md`、`dsh-server-docs/INDEX.md`
- **+1 个 ??**:`dsh-server-docs/skills/dsh-auto-handoff-chain/`(S2 计划内新建)
- **+1 个 ??**:`_中间产物_待清理/`(演练脚本落盘产物;**⛔ 不在提交范围内**)
- ⇒ **M 项逐个都在计划内 ⇒ 无越界改动**
### 9.8 未过项 / 在册未办(对应 §8.8)
1. **S4 落「临界档」**(p95 = 24477 ms,nearest-rank 口径)。
- **现象**:5 个样本中 1 个为 24477 ms(超 `deadline×0.8 = 24000`),其余 4 个 18772–21223 ms。
- **已做到哪一步**:三档判据已立(§4-D3)、`--scene 4` × 5 采样已做、零回归三件套全绿、收口归零完成、⛔ 未改任何生产值。
- **回头条件(一出现必须回头解决)**:① p95(nearest-rank)**> 27000 ms**;② `--scene all` 的幕 4-A / 幕 4-C 出现 **FAIL**;③ 任何 `RELAY_FAILOVER_*` / `HB_SEC` / burst 值被调整。命中任一条 ⇒ 按 §4-D5 重做四段分解(检测 / 首试 / 白等 / 建连)后定位,**⛔ 不许自行调生产值**。
2. **Q4 —— 已解除(用户本轮授权)**:原「`src/net/relay/**` untracked ⇒ commit/push 需授权」由用户原话「执行完毕后 同步到仓库」解除 ⇒ 已 commit + push(§9.10);`git ls-files src/net/relay | wc -l` **0 → 15**。
3. **`src/worker/tunnel.ts` 生产死路径**(§0.1 末 / D4):⛔ 本棒未处置,**原样登记**(是否删 = 独立决策,可能保留作 ssh 兜底变体)。
4. **presence / 房间层 / 内容分发**(§3.3):⛔ 未定序 —— 属**业务优先级**(§1 边界外 ①)⇒ **需拍板**,候选与优缺点登记原样保留。
5. **骨干节点服务范围**(入口 §4 既有待拍板项 A/B):**原样保留**,本棒未重复上抛。
6. **`§8.8-1` 106 sshd MaxStartups 限流**:本轮 ssh **未遇 `rc=255`**(单次重试机制未触发);⛔ 未放宽限流(命中 R5)⇒ 仍在册。
### 9.9 指纹(对应 §8.9,可复现核对口径)
| 对象 | 值 | 判定 |
|---|---|---|
| **本单 §8 前缀** | `bab83b7219b2669d5a6e9f1acf782e1f` | **回填后未变** ✅(§9 在 §8 之后,不进前缀口径) |
| **本单全文** | 回填后见下(脚本输出) | — |
| **参数表**(截断口径 `sed '/^## §10 指纹/,$d' … \| md5sum`) | `8f08e74b026e6e5b5e1b3db813f031ae` | **未变** ✅(S4 落临界档 ⇒ 判据未落表 ⇒ D1 自证) |
| 覆盖网络线入口 | `接续入口_覆盖网络线_20260916.md`(§0 + §2 已推进,见 §9.11) | — |
**三处同步产物(本机 = 文档库 = 镜像)**:
- `skills/dsh-auto-handoff-chain/SKILL.md` = `0c5c4103f8ffa8071ce29434654fa2d3`
- `skills/dsh-auto-handoff-chain/scripts/chain_report.py` = `636c4f336864bc99c408e92577516f11`
- `skills/dsh-change-workflow/SKILL.md` = `338bf9534e5243f495e7d66f914371bf`
- `skills/dsh-env-bootstrap/references/常驻规则-快照.md` = `e1a460b53cc4b62466107f8555946496`
**仅文档库 + 镜像**:`02-运维手册.md` = `d6627843b67c72ddfd3b62b5cfd5e29f`|`README.md` = `ddfd4d5fc890af0ee86d5442d8c0d610`|`INDEX.md` = `5677883fd3777a225ae85af7c5c79fb7`
**S3 涉及的源文件(清理前后不变,自证未改码)**:
`src/net/relay/client.ts` = `6ffb117f3f6df1c2456641e176529ce8`|`directory.ts` = `d6dfcf1f1fbf388f994582d43bbb65ec`|`main.ts` = `7d5f915fcf0298e178e910d37863ef1d`|`src/web/server.ts` = `12f8dadd4a2e06ffaed70bddbd719999`|`src/worker/tunnel.ts` = `e84c0baab6e96da1208d9512a000cedc`
### 9.10 追加项 —— 同步到仓库(用户本轮明确授权 ⇒ Q4 解除)
**授权原话**:「执行完毕后 同步到仓库」(本棒执行期间用户明确下达)。
**提交清单核对(提交前逐项确认只含本线真实改动)** ⇒ 两个 commit:
| commit | 面 | 文件数 | 内容 |
|---|---|---|---|
| **`146c3d2`** | 代码 / 测试 | **53** | relay 子系统 `src/net/relay/**`(15 文件)+ `src/worker/relay-tunnel.ts` + `src/web/routes/overlay.ts` + 8 个 overlay 脚本 + 12 个测试 + `package.json` 等改动(`+16187 / −63`) |
| **`bc0dd2c`** | 文档库 | **10** | `02-运维手册.md`、`INDEX.md`、`README.md`、`scripts/stop-dialog-guard.py`、4 个技能文件(含 S1 的两处校正)+ **新增** `skills/dsh-auto-handoff-chain/**`(2 文件) |
- ⛔ **未用 `git add -A`**:逐路径 `git add src/ scripts/ test/ package.json` 与 `git add dsh-server-docs/`;**`_中间产物_待清理/` 未被提交**(提交后仍为唯一的 `??`)。
- **推前判定**:`git ls-remote origin refs/heads/master` 取**裸 sha** = `640813e84e5e48c56ca39d765d7b195884e58ebc`;`git merge-base --is-ancestor 640813e… HEAD` ⇒ **是祖先**(fast-forward,无分叉);`git push --dry-run` 显示 `640813e..bc0dd2c`。
- **推送结果**:`640813e..bc0dd2c master -> master`;推送后 `git ls-remote` = **`bc0dd2c96da88b1ee3a8450760b6cbb8ab92d845`** = 本地 `HEAD` ✅
- **Q4 缺口闭合自证**:`git ls-files src/net/relay | wc -l` = **0 → 15** ✅(序⑭/⑮ 的修复与 `test/relay.test.mjs` **首次进入版本库**)
- 行尾:`.gitattributes` 的 `dsh-server-docs/** -text` **完好**(文档库保持纯 LF)⇒ ⛔ 未做任何批量换行符转换。
### 9.11 收口六件核对
| # | 项 | 状态 |
|---|---|---|
| ① | 释放锁 `--release-exec` | ✅ 本棒收尾第一步执行 |
| ② | **陈述句**告知 + 登记下一棒 | ✅ 已陈述句告知;**⛔ 未登记下一棒** —— 理由见下 |
| ③ | 入口 §0 + §2 推进 | ✅ 已刷新(§2 的序⑰ 转存档 + 新增收官段) |
| ④ | 工作区日志 `.workbuddy/memory/2026-09-17.md` | ✅ append-only 追加 |
| ⑤ | 本单回填回报 | ✅ 本 §9(9.1–9.11) |
| ⑥ | 输出指纹 | ✅ §9.9 |
**⛔ 为何未登记下一棒(登记门禁)**:四条在册项清干后,**剩余项全部落在「需拍板」区** —— presence / 房间层 / 内容分发**定序**(= 业务优先级,§3.3)与**骨干节点服务范围**(入口 §4 的 A/B)。按用户明令的登记门禁(「**要用户拍板的,等拍了再登记**」,技能 `dsh-auto-handoff-chain §3.3`),**不登记下一棒**;拍板到手后再建。
⚠️ 技能的三处同步(S2)完成后,`dsh-auto-handoff-chain` 已同时存在于本机 / 文档库 / 镜像 ⇒ 上述门禁在**三处都可读取**。