交接单按归属约定(正文落文档库、工作区只放指针)归档至 归档/交接单-20260924-归档/,含逐件判定 README: - 16 件已被文档库正式版取代(T09–T21 + 覆盖网络-24/25/26) - 4 件主题已被覆盖网络线入口汇总 - 7 件历史接续包/规划件 CODEBUDDY §9:收口清本棒 tmp、tmp 保留期 7 天、禁「待清理」中间态、 工作区入库只放文档与文件、不保留脚本副本、>60 KB 单文件须逐个判。
294 lines
23 KiB
Markdown
294 lines
23 KiB
Markdown
# 交接单 · 内容分发(块级内容寻址 · 同网段 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 行) |
|
||
| 本单状态 | **待执行** ⇒ 交**序 ㉔ 执行棒** |
|