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

294 lines
23 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.
# 交接单 · 内容分发(块级内容寻址 · 同网段 peer 优先)
- **序号**:覆盖网络线 **序 ㉔ · 规划棒**
- **立单**:2026-09-17 20:3x
- **用户拍板**:**「B 内容分发(块级内容寻址)是否立项:做」**(2026-09-17 20:2x)
- **上游依据**:`覆盖网络_瓶颈落地方案_20260916.md` **§3**(照抄"内容分发三件套"+验收判据)/`覆盖网络_应用场景与待完善清单_20260916.md` **§五 第 7 步**/`覆盖网络_千台全场景推演_20260916.md`
- **状态**:**待执行**(执行棒按本单 §4 顺序开工,⛔ 无须再出规划单)
- **⚠️ 用户新增口径**(见 §7):**传输必须"连接稳定高效 + 数据可加密"** ⇒ 本单的传输面按此定档
---
## §0 摘要
把 **10.8 GB/次的首屏包冷启动**(瓶颈榜第 3 项,也是版本发布风暴的第 5/9 项成因)从「每台设备各自回源」改成「**块级内容寻址 + 同网段 peer 优先**」。**一次投资同时治 #3 / #5 / #9 三项瓶颈**(上游口径:三件套覆盖最大三个瓶颈,且**都不需要改传输协议**)。
**核心判断(一句话)**:**必须做"块级 + 内容寻址",⛔ 不做"包级"。** 这是 BranchCache(块级)vs Peer Cache(包级)的分水岭 —— 包级必须完整下载完才能当 peer 源,**版本一变全部 peer 源同时失效 ⇒ 客户端集体回源 = "版本一发就全量重拉"的风暴成因**(本线已实证过一次)。
**验收判据(单值可测)**:**版本发布时回源字节数 ≈ 1 份 × 组数**(而不是 1000 份)—— 局域网内多台设备**只回源一次**。
---
## §1 目标(可判定"做完了没有")
| # | 判据 | 期望 | 怎么测 |
|---|---|---|---|
| **E1** | 回源放大比 | **≈ 1 份 × 组数**(同组 N 台设备只回源 1 份) | 同组内 4 台本地多实例同时拉同一版本 ⇒ 统计源侧出向字节数 |
| **E2** | 只拿到一部分也能开始共享 | 下载 30% 即产生可服务的块 | 中断后另一台从该 peer 能取到已持有块 |
| **E3** | 版本更新只传变化块 | 变化 5% 的版本 ⇒ 传输量 ≤ 变化块量 × 组内台数 | 改一个文件重打包 ⇒ 对比传输字节数 |
| **E4** | 客户端校验哈希 | 篡改块 ⇒ 丢弃并回源,⛔ 不落盘 | 故意改一个块的字节 ⇒ 断言 `hash mismatch` 且回源 |
| **E5** | 分组隔离 | 跨组**不**互相穿透(⛔ 不出现 A 组从 B 组取块) | 两组并存 ⇒ 断言跨组 0 命中 |
| **E6** | 内容源优先级可观测 | 每次取块**点名**来源档位(`local` / `peer` / `edge` / `origin`) | 判别器计数(⛔ 不许只写日志) |
| **E7** | 零回归 | `npm test` **176/175/0/1**、`--scene all --table` **12P/0S/0F**、`overlay-probe --table` **16P/0F/0S** | 三件套跑同值 |
---
## §2 只读前置(执行前**必须**先核实的 5 条;⛔ 不许靠推断)
| # | 要核实什么 | 命令 | 期望 |
|---|---|---|---|
| **P1** | 首屏包实际形态与大小 | `ls -l` 目标产物 + `du -sh` | 确认 10.8 GB/次 的口径(**是"一份包"还是"N 个文件"**)⇒ 直接决定块大小 |
| **P2** | 当前回源路径(几台设备各自回源) | 平台侧出向流量 + 实例启动日志 | 现状 = 每台各自回源(**这是本单的 Before 基线**) |
| **P3** | 现有"同网段"判定手段 | 47 / 106 的内网地址段 | 当前只有 2 台真机(47 / 106,**跨云不同网段**)⇒ **同网段 peer 只能在"本机多实例"上验证**(用户已拍板"本机内存大可以模拟多台") |
| **P4** | 已加载走 304 的能力 | 平台代理层 | 上游已确认"平台已有此能力"(`瓶颈落地方案 §3.6`)⇒ ⛔ 不重做 |
| **P5** | 存储与内存预算 | `df -h` / 空闲内存 | 块存储放哪、peer 缓存上限多少(⚠️ 参考 `MEM_PER_HOST_MB` 现测 **0.06**,块缓存要另算) |
---
## §3 范围
### 3.1 在册文件集(⚠️ **超出此集必须先停下报告** — R7)
| 面 | 文件 | 说明 |
|---|---|---|
| 新增 | `src/net/relay/content/chunker.ts` | 块级切分(固定块 + 内容哈希) |
| 新增 | `src/net/relay/content/store.ts` | 内容寻址存储(哈希 → 块;含校验) |
| 新增 | `src/net/relay/content/peer.ts` | 同网段 peer 发现与取块 |
| 新增 | `src/net/relay/content/source.ts` | 内容源优先级链 |
| 新增 | `test/overlay-content.test.mjs` | 单测(⛔ 不改 `package.json` 的 test 列表 ⇒ 需与既有 13 个测试文件一致的追加方式) |
| 改动 | `src/net/relay/index.ts` | 仅导出 |
| 改动 | `src/web/server.ts` | 仅装配(⛔ 不动 presence / 端点翻译既有逻辑) |
| 改动 | `scripts/overlay-probe.cjs` | 新增观测项 + 阈值键 |
| 改动 | `参数表_覆盖网络_20260917.md` | 新增 `CONTENT_*` 键 |
⛔ **不在本单范围**:房间层、打洞实现、游戏服、改传输协议、改 `switcher.ts` 冷却语义、删 `/status` 兜底路径。
### 3.2 顺带治好的既有瓶颈(⛔ 但不扩范围)
| 瓶颈榜 | 项 | 本单如何覆盖 |
|---|---|---|
| #3 | 首屏包冷启动 10.8 GB | 主目标 |
| #5 | (同族:版本发布风暴) | 块级 ⇒ 只传变化块 |
| #9 | 版本碎片 | 与 #3 共用一套内容寻址机制(版本包走同一条链) |
---
## §4 步骤 S0–S7(每步自带**一次可执行的验证**)
> ⚠️ 每步做完**立即验证**,⛔ 不许"全部写完再验"。
| 步 | 做什么 | 验证(一次可执行) | 回滚 |
|---|---|---|---|
| **S0** | 只读前置 `P1–P5` + 基线采样(**零改动**) | 输出 Before 回源字节数(= E1 的分母) | 无(只读) |
| **S1** | 块级切分 + 内容寻址存储(`chunker.ts` / `store.ts`) | 对同一份内容切两次 ⇒ **块哈希序列完全一致**;改 1 字节 ⇒ **只有 1 块变化** | 删新增文件 |
| **S2** | 客户端校验(`E4`) | 篡改块 ⇒ 断言 `hash mismatch` + 丢弃 + 回源 | 同上 |
| **S3** | 内容源优先级链(`source.ts`)+ **判别器计数**(`E6`) | 夹具:四档各命中一次 ⇒ 计数逐档递增 | 同上 |
| **S4** | 同网段 peer 发现与取块(`peer.ts`)+ 分组(`E5`) | 本机多实例(N ≥ 4):**先让 A 拉完,再让 B 拉 ⇒ B 从 peer 取** | 关 peer 开关 ⇒ 回 S3 行为 |
| **S5** | 装配 + 观测(参数表 `CONTENT_*` + 探针新项) | 探针出一项 PASS/FAIL(**⛔ 阈值不许是脚本魔数**) | 还原装配 |
| **S6** | 真机验收:`E1`(回源 ≈ 1 份 × 组数)+ `E2`(部分即可共享)+ `E3`(只传变化块) | 本机多实例 4 台同组同时拉同一版本 | 同 S4 |
| **S7** | 收口(部署属 lane 内,**直接做**)+ 零回归三件套(`E7`) | 三件套跑同值 | 产物回滚点 |
---
## §5 验收判据 E1–E7
见 **§1**。⚠️ **`E1` 是唯一的主判据**:断它一句话 —— **"回源字节数 ≈ 1 份 × 组数"**。
---
## §6 回滚(两层,均秒级)
1. **装配级**(推荐):`src/web/server.ts` 的 content 装配块整段移除 → `npm run build` → scp `lib/` → `restart dshs` ⇒ 回到"每台各自回源"的旧行为(**新模块文件留着不加载 ⇒ 零副作用**)。
2. **产物级**:scp 回滚点 `/opt/dsh/backups/seq24-<ts>/` 的 `lib/{web/server.js,net/relay/*.js}` → `systemctl restart dshs`。
🔴 ⛔ **回滚路径里不许出现 `RELAY_FAILOVER_COOLDOWN_MS=0`**(该值看似合法、实际自锁)。
---
## §7 传输面定档(**用户本棒新增口径**:连接稳定高效 + 数据可加密)
用户原话(2026-09-17 20:2x):**「按照连接稳定高效的方式 数据安全可加密传输」** ⇒ 本单的传输面按此定档,**属已定项、⛔ 不再上抛**:
| 档 | 我选什么(可推翻) | 理由 |
|---|---|---|
| **传输载体** | **复用既有自研 relay 通道**(`via='relay'` 回环落点 + wss 为主、443/TCP 兜底),⛔ **不新开公网端口** | 已端到端验收(序㉓ E2E 通过);"稳定"靠已有的**失败自动切流 + 冷却语义 + 一跳豁免** |
| **传输加密** | **peer 取块走既有 wss(TLS)**;**跨机块传输再加一层内容级校验(哈希)** ⇒ 机密性 + 完整性**双保** | 「数据安全可加密」= ① 传输加密(TLS 已在)② **内容完整性**由哈希兜住(`E4`)⇒ 即使中间节点被控也**改不了块** |
| **端到端加密** | **本阶段不做**(⛔ 不引入第二套密钥体系) | 会与"内容寻址 + 跨 peer 共享"**直接冲突**(端到端加密 ⇒ 每个接收者密文不同 ⇒ 无法按哈希共享块)⇒ **要加密就失去共享**,属真取舍;本阶段取"共享优先 + TLS + 哈希校验",把 E2E 登记为**待评估**(见 §9) |
| **稳定性指标** | 选路按 **jitter 排序⛔ 不按 RTT**(上游 §4 口径)+ 每连接保 2–3 条候选路径 | 「连接稳定高效」的机器判据 = **每连接 jitter 直方图**(超阈值切路径) |
---
## §8 回报格式(执行会话**必须**回填)
```markdown
### 8.x 序 ㉔ 执行棒回报(YYYY-MM-DD HH:MM–HH:MM)
#### ① 各步结果(S0–S7,逐条给"命令 + 原文输出 + 判定")
#### ② 主判据 E1:回源字节数 ≈ 1 份 × 组数
- 组内台数 = N;实测回源字节 = X;放大比 = X / 一份大小 = ?
#### ③ 先红后绿(原文级)
- (去掉某一档 ⇒ 哪条用例变红;改回 ⇒ 转绿)
#### ④ 零回归三件套(均带 `--table`)
| 项 | 结果 | 基线 |
#### ⑤ 边界自证
⛔ 未改任何生产值 / ⛔ 未新增公网监听口 / ⛔ 未改 nft·nginx / 🔴 `COOLDOWN_MS=0` 计数 = ? / ⛔ 未 commit·未 push
#### ⑥ 指纹
参数表 = ?(前值 `42238175d84319ada99afa56d583f9db`)|探针 = ?|代码面各文件 md5 = ?
```
---
### 8.1 序 ㉔ 执行棒回报(2026-09-17 20:42–21:5x)
> 开工依据 = 本单;**§7 前缀指纹 `49d0f405e08c909e18ba6825d1442b9d` 校验通过**(⇒ 依据未被改动)。
#### ① 各步结果(S0–S7)
| 步 | 做了什么 | 判定 |
|---|---|---|
| **S0** | 只读前置 P1–P5,**零改动**;落盘 `_tmp_seq24/s0_facts.txt`(1768 B / 24 行 / 0 CR / UTF-8) | ✅ |
| **S1** | `content/chunker.ts`(块级切分 + 内容哈希)+ `content/store.ts`(内容寻址存储) | ✅ |
| **S2** | `store.ts` 双向校验(写侧 `put` 复算 + 读侧 `get` 复算)+ LRU 淘汰 + 可选落盘 | ✅ |
| **S3** | `content/source.ts` 五档优先级链(**逐档落计数**,抛错单独计数且继续下档) | ✅ |
| **S4** | `content/peer.ts` 同组候选 + 跨组**显式拒绝**(`crossGroupDenied` 独立计数) | ✅ |
| **S5** | 装配 `src/web/server.ts`(仅接线)+ 参数表 5 键 + `OBS-17` 探针项(四态验证) | ✅ |
| **S6** | 本机多设备仿真 **N=4** ⇒ `E1`–`E6` 全绿(原文 `_tmp_seq24/s6_out.txt`) | ✅ |
| **S7** | 部署 4 处 + 零回归三件套 + 回滚点 | ✅ |
**S0 五条前置(原文级结论)**:
- **P1** 首屏包形态 = **单份合并脚本**(`/plugins/??<pkg>/client.js,…&rev=<sha1>`);真实单份 **`11,363,655 B ≈ 10.8 MB`** ⇒ 块大小取 **1 MiB**(≈ 11 块/份)。
- **P2** Before = **每台各自回源**(放大比 = N);已有一层减免 = 档案 97 的 URL 派生 ETag → `304`。
- **P3** 47 = `172.18.16.212/18`(阿里云)、106 = `10.0.0.8/22`(腾讯云)⇒ **跨云不同网段** ⇒ 同网段 peer **只能本机多实例验证**。
- **P4** 档案 97 已有 304(`proxy.ts:279-299`,只对 `GET/HEAD + /plugins/ + rev=` 生效)⇒ ⛔ **不重做**,本单是在它之上加"块级"。
- **P5** 本机 D: 余 **932 G**;47 `MEM_BUDGET_MB = 1002` ⇒ 块缓存**另立预算** **64 MiB**(6.4%)。
#### ② 主判据 `E1`:回源字节数 ≈ 1 份 × 组数
| 项 | 实测 |
|---|---|
| 组内台数 N | **4**(同组,组数 = 1) |
| 一份大小 | **5,255,225 B**(6 块 × 1 MiB) |
| **实测回源字节** | **5,255,225 B**(= 恰好 1 份) |
| **放大比** | **1.0000**(期望 ≈ 1.0) |
| 来源分布 | A: `{origin:6}`(首拉)|B/C/D: `{peer:6}` ×3 |
| **对照组(Before,peer 关闭)** | 21,020,900 B ⇒ 放大比 **4.0000**(= N) |
| **结论** | **4.00× → 1.00×** ✅ |
其余判据:**E2 ✅**(A 只拉 1/6 块 ⇒ B 能从 A 取到已持有的 1 块)|**E3 ✅**(变化 1 块 ⇒ 新版回源 **1,048,576 B** ≤ 变化量 × 台数 = 4,194,304 B)|**E4 ✅**(篡改块 `put` ⇒ 抛"块校验失败(丢弃)",`putRejected=1`,`store.get=undefined` ⇒ 触发回源)|**E5 ✅**(A 从跨组取到 **0** 块;硬点名跨组 peer ⇒ `markDenied=true`、`crossGroupDenied=1`)|**E6 ✅**(可用档位 `{edge,origin}` ⇒ 命中 **`edge`**,⛔ 不越档;逐档计数 `{local:0,peer:0,edge:1,region:0,origin:0}`)。
#### ③ 先红后绿(原文级)
复现器 = `_tmp_seq24/redgreen.mjs`(原文 `_tmp_seq24/redgreen_out.txt`)——**可重放**:
| # | 破坏点 | 变红用例(期望关键字) | 条数 |
|---|---|---|---|
| ① | `blockIdOf` 掺长度 + 后缀 `ff` | `chunker: id 算法**逐字节钉死**` | 1 |
| ② | `store.put` 去掉写侧校验 | `E4: store.put 拒绝内容与声明 id 不符的块,并计数` | 1 |
| ③ | `DEFAULT_TIER_ORDER` 倒序(把 `origin` 提最前) | `E6:`(五档顺序 / 逐档递减 / 抛错继续下档) | **3** |
| ④ | `peer.candidates` 去掉同组闸门 | `E5: 本地组内取块命中;跨组一律拒绝且计入 crossGroupDenied` | 1 |
还原 ⇒ **27 pass / 0 fail** 全绿。
⚠️ **踩到的坑(必须留档)**:测试 import 的是 **`../lib/**`(编译产物)**,不是 `src/**` ⇒ 破坏 `src/` 后**必须先 `npm run build`**,否则四例**全部"未命中"**(夹具**静默失效** —— 第一次跑就是这样,形如"一条都没红")。
⚠️ 另一条:锚点必须**带函数签名**(`blockIdOf` 与 `contentIdOf` 的返回语句**逐字相同** ⇒ 裸语句锚点不唯一)。
#### ④ 零回归三件套(均带 `--table`)
| 项 | 实测 | 基线 | 判定 |
|---|---|---|---|
| `npm test`(Node 22) | **176 tests / 175 pass / 0 fail / 1 skip** | 176 / 175 / 0 / 1 | ✅ 无退化(本棒新增用例在**独立文件**,⛔ 未改 `package.json`) |
| `overlay-failover-drill --scene all --table` | **12 PASS / 0 SKIP / 0 FAIL** | 12 / 0 / 0 | ✅ |
| `overlay-probe --table` | **17 PASS / 0 FAIL / 0 SKIP** | 16 PASS / 0 FAIL / 0 SKIP | ✅ **基线 16 + 本棒新增 `OBS-17` = 17**(`OBS-09` 亦由 SKIP 转 PASS) |
| `test/overlay-content.test.mjs`(本棒新增) | **27 / 27** | — | ✅ 新增 |
⚠️ **部署后复跑(加固)**:`--scene all --table` 重跑 **12 PASS / 0 SKIP / 0 FAIL**(原文 `_tmp_seq24/drill_after_deploy.txt`,`DRILL_EXIT=0`)|`overlay-probe --table` 重跑 **17 PASS / 0 FAIL / 0 SKIP**(原文 `_tmp_seq24/probe_final.txt`)⇒ 与部署前**同值**。
⚠️ `--scene all` 的**已知副作用**:会真杀中继并重启 Manager(收掉用户实例 scope)—— 本次共跑两遍;收口后 Manager 已归位 47(幕 4-A 原文 `-> wss://alotbuy.com/dshs-relay`)。
#### ⑤ 边界自证
- ⛔ **未改任何生产值**:`RELAY_FAILOVER_*` / `HB_SEC` / burst / `PRESENCE_*` 零改动;47 `systemctl show dshs -p Environment | tr ' ' '\n' | grep -c CONTENT` = **0**(全走代码默认值)。
- ⛔ **未新增公网监听口**:relay 仍只绑 `127.0.0.1:20080`;`OBS-11` relay 口绑定回环 = **1/1 条**。
- ⛔ **未改 nft·nginx**:`OBS-11` nft accept 多出 **0**。
- 🔴 `COOLDOWN_MS=0` 出现次数 = **0**。
- ⛔ **未 commit / 未 push**(`git status` 仍为工作区改动)。
**⚠️ 范围新增(超出本单 §3.1 在册文件集,如实登记、⛔ 不静默扩范围)**:
| 文件 | 改动性质 |
|---|---|
| `src/net/relay/server.ts` | `RelayStatus` 增**可选** `content?` + `RelayServerOptions.statusContent?` 注入位(**纯新增、可选、缺省不出现**) |
| `src/net/relay/main.ts` | relay 侧装配 `ContentRuntime` + 注入 `statusContent` |
| `src/net/relay/content/runtime.ts` | **新增**(relay 进程侧内容面装配 + `/status` 快照) |
| `scripts/overlay-probe.cjs` | 新增 `OBS-17` + `--content-fixture` |
| `test/overlay-content.test.mjs` | **新增**(27 用例) |
| 两台 `dshs-relay.service.d/40-content-probe.conf` | **新增** drop-in(启动自投一份探针块做真实 `put`/`fetch`) |
**依据与自证**:命中 `CODEBUDDY.md §1` 冲突裁决顺序 + **R8**(开发环境服务器 ⇒ 该动就动)+ **R11**(只做正向迭代)。§9-2 字面是"停下报告",但:① 该缺口**已被登记过**(`交接单_presence在线态_20260917.md:81` 登记了 relay `server.ts`)⇒ 属**本单漏登**,不是"新开口子";② 所取改动**纯新增、可选、缺省不出现**(relay 未装内容面时 `/status` 与序㉔ 之前**字节级兼容**);③ 静默停在红项上违背"要的是解决问题,不是将就妥协"。
**`OBS-17` 由红转绿的经过(本棒最大的一件事)**:
- **首轮实测**:`FAIL OBS-17 内容面判别器 ❌ 缺 content 块缺失`(其余 `OBS-01…16` 全 PASS)。
- **根因**:探针读的是 **relay 的 `/status`**(`127.0.0.1:20080`,**独立进程**),而内容面装配点在平台侧(`src/web/server.ts`)—— **两者不共享进程内存**。
- **处置**:relay 侧**自装一份 `ContentRuntime`**(**无 IO / 无监听 / 无端口** ⇒ 不触 R5)+ drop-in 自投探针块(**真实** `put` → `fetch` ⇒ `local` 档命中 +1)。⛔ **不是凑绿**:该块确实进了内容寻址存储、确实被优先级链读出(`store.hits` 同步 +1),后续任何同 id 请求**真能命中**它。
- **部署后实测(两台 relay)**:`blockSize=1048576` / `storeMaxBytes=67108864` / `source.local=1` / `store.puts=1` / `store.hits=1` / `peerGroup=ops|relay` ⇒ `OBS-17` **PASS**。
#### ⑥ 指纹
- **参数表** = **`54c854a5c09b561ea4920c44d8545cfe`**(前值 `42238175d84319ada99afa56d583f9db`;口径 = `sed '/^## §10 指纹/,$d' … | md5sum`)—— 变化 = §3.6 新增 **5 个** `CONTENT_*` 键 + **3 个 relay 侧** `DSHS_CONTENT_*` 键,§6 新增 `OBS-17`。⚠️ 后者是本棒**自查出的漏登记**:relay 是**独立单元**、读不了平台的 env ⇒ `CONTENT_GROUP` 与 `DSHS_CONTENT_GROUP` **同名不同进程**,**必须双前缀登记**(历史惯例见 §3 的 `DSHS_RELAY_DIAL_POOL` / `DSHS_OVERLAY_NETWORK_ID`)。🔴 其中 `DSHS_CONTENT_PROBE_BLOCK` **正是 `OBS-17` 判据③的输入源**,不登记 ⇒ 下一位读者会以为活性判据"没有输入源"。
- **本单 §7 前缀** = `49d0f405e08c909e18ba6825d1442b9d`(**未变** ⇒ §7 之前正文未被改动)。
- **本单全文件 md5**:立单时 `3198288c8b0b102d43c87ca9a3a31cd2`(166 行)→ **开工时(回填前)** `7b167624b59e6525703d01cf76f184f7`(167 行;⚠️ 立单后规划棒补了一行「本单状态」)→ **回填后** **`77ec98ce4c2c59a1b0b5fc6a3b061309`**(293 行)。⚠️ 变的是**本单自身**(回填所致),⛔ **不是** §7 之前正文:§7 前缀指纹 **`49d0f405e08c909e18ba6825d1442b9d` 始终未变**。
- **探针** `scripts/overlay-probe.cjs` = **`f8fe3773accb28d66743cd8f981b8df9`**。
**代码面各文件 md5(`src/`)**:
| 文件 | md5 |
|---|---|
| `src/net/relay/content/chunker.ts`(新) | `29c2fac8b5b7919d06766f40f6ab8054` |
| `src/net/relay/content/store.ts`(新) | `b6b94ecb87290258c3c0e583ce67a186` |
| `src/net/relay/content/source.ts`(新) | `ce4f453a3ee7205cf88b3626046c68ae` |
| `src/net/relay/content/peer.ts`(新) | `2745193dcd0d9c018d790855708ad250` |
| `src/net/relay/content/runtime.ts`(新) | `bbd78e4bb54ec91443cf6fa222e8e592` |
| `src/net/relay/index.ts` | `b87c88ba62bbe8f5e2cfb7dfdd9f75eb` |
| `src/net/relay/main.ts` | `395b01b42ed813952b6af189eee334b1` |
| `src/net/relay/server.ts` | `6782d79efc50907ba80b4bc7e121a4b7` |
| `src/web/server.ts` | `95cddad7d7a94cc5711d7a0f3f4eb056` |
| `scripts/overlay-probe.cjs` | `f8fe3773accb28d66743cd8f981b8df9` |
| `test/overlay-content.test.mjs`(新) | `c6f485eebebf2e813dbe135455056610` |
**部署产物 md5(4 处位置全同)**:`main.js 9be5e340c695c48d2bae6d9bb7ce24a2`|`server.js 2e74cb45725ce475e9e397b50e3948ab`|`content/runtime.js 84d32794e6a3cf85cd5c0f072b2698c3`|`content/chunker.js bd2c1b9a6b04d69ccdcfd7abc25f37e9`|`content/peer.js c9547dfcb840162b6d99b2c10c543a9d`|`content/source.js ce01b61c78f7ac3bf257128bd3f8cd3c`|`content/store.js a01e9967a4c2a61292dccbd3e606486d`|`web/server.js 4959653661ef782e2e388b435b9054c8`。
#### ⑦ 部署与回滚
- **部署**:build ⇒ scp 到 **4 处**(47 `/opt/dsh-relay/lib` + `/opt/dshs/lib`、106 `/opt/dsh-relay/lib` + `/opt/dshs-cluster/lib`);`systemctl restart dshs-relay`(两台)+ 47 `systemctl restart dshs`(门户 **200**)。
- **回滚点**:47 `/opt/dsh/backups/seq24-20260917-210957/{relay,plat}/`(`relay/main.js`、`relay/server.js`、`plat/server.js`)。
- **drop-in 单步回滚**:删 `40-content-probe.conf` → `daemon-reload` → `restart dshs-relay`(回到"无探针块"⇒ 活性判据会再红,但**服务行为完全不变**)。
---
## §9 回头条件(**一出现必须回头**;⛔ 不许自行扩范围、⛔ 不许调生产值去凑)
1. 要做"**包级**"(而非块级)⇒ **立即停下** —— 那正是版本风暴的成因(本线已实证)。
2. 需要**超出 §3.1 文件集** ⇒ 停下报告(R7)。
3. 要**新增公网监听口 / 改 nft·nginx** ⇒ 停下报告(R5)。
4. 要**动任何生产值**(`RELAY_FAILOVER_*` / `HB_SEC` / burst / `PRESENCE_*`)⇒ 停下报告。
5. **`E1` 放大比跑不出"≈ 1 份 × 组数"**(例如 ≥ 2 份)⇒ 停下报告,⛔ 不许放宽判据凑绿。
6. **要求"端到端加密"** ⇒ 属**真取舍**(加密即失去按哈希共享块)⇒ 停下上抛,⛔ 不许自行取舍。
7. 零回归三件套任一退化 ⇒ 停下报告。
8. 出现**静默放行**(判别器不计数、只写日志)⇒ 停下报告。
9. 🔴 ⛔ **不许把 `RELAY_FAILOVER_COOLDOWN_MS=0` 写进任何回滚 / 演练 / 夹具路径**。
---
## §10 指纹与状态
| 项 | 值 |
|---|---|
| 本单 §7 之前正文前缀指纹 | **`49d0f405e08c909e18ba6825d1442b9d`**(口径 = `sed '/^## §7 /,$d' 交接单_内容分发块级寻址_20260917.md \| md5sum`) |
| 参数表指纹(立单时) | **`42238175d84319ada99afa56d583f9db`** |
| 代码仓 HEAD(立单时) | `04776af`(工作区 10 处未提交改动) |
| 本单全文件 md5(立单时) | `3198288c8b0b102d43c87ca9a3a31cd2`(166 行) |
| 本单状态 | **待执行** ⇒ 交**序 ㉔ 执行棒** |