- 本件新增 §9:落盘四处 / 事故与无损复原 / 提交推送对账 / 文档库侧 / automation / 锁
- 日志追加上节「收口(06:4x–06:5x)」:提交 2a1226c · 推送 · 对账 0 0 · 仅 3 件入库 · 未碰他线
判据留档要点
- 入口被清 0 字节事故:复核命令 git hash-object == git rev-parse HEAD:<file>(1d44073b…)
- 新增铁律:禁用 open(...,"wb").write(表达式) 复合式(open 先截断,表达式后求值)
- docs-sync-check ❌ 差异 21+4 全为他线在途,非本线引入
21 KiB
2026-09-26
覆盖网络线 / IM 线 · 端口拍板 + 设备当中继可行性(承接 09-25 深夜,用户两条口径 · 只读 · 零代码)
用户口径:「1、先不开端口,后续有需要再开」「2、还有可以让性能和网速高的设备当中继,比如另一个会话开发的 dsh桌面客户端版本」
拍板 ①:D8 云安全组「先不开」(已定 · 已落两处载体)
- 落点:
接续入口_覆盖网络线_20260916.md §0(新增 2026-09-26 首行)+ 状态层MEMORY.md。 - 🔴 性质变化:D8 由「唯一在册红 / 待用户操作」→「用户已知并主动搁置」,⛔ 不再当待办;重开条件 = 要做跨节点内容分发(插件内容 / 大文件 / 镜像同步)时一并定。
- 影响面(⛔ 别误传):真机打洞率仍 0 ⇒ 内容面跨节点分发的带宽节省(潜力 75%(4 节点)– 93.75%(16 节点))暂拿不到;⛔ 不影响群聊 / 房间 / 消息 / 历史 / 在线态 / 插件 —— 全走 443 中继,功能完整。
- 📌 口径澄清(重要 · 上一轮我表述错过一次):
relay-direct= 443 兜底中继入口(⛔ 不是 P2P);UDP21100-21115只服务 P2P ⇒ 中继走 443 ⇒ 功能不用开端口。(原文取证:addr-override.ts注释「443/TCP 兜底 · 去 CF」)
拍板 ②:设备当中继 —— 🔴 路径已存在,但要分清两个角色
- 现成基础(实证):中继白名单
dialers: Map<network, Set<hostId>>默认拒绝 ⇒ 加节点=配置动作;一键加入(overlay-node-join.cjs/overlay-node-admit.cjs)+ 分组准入已落地;桌面端节点接入已实测(dsh-ai1net-desktop/docs/S2_覆盖网络节点接入编排与守护实测报告_20260920.md—— 守护 / 退避自愈 / 开机自启全就位);lib/net/relay/main.js同一入口既起客户端(--client)也起服务端(--server= 中继)。 - 🔴 两个角色必须分清:拨出方(
--client)✅ 已实测、不需可达;中继 / 被拨入方(--server)⚠️ 未实测、需要"别人能连到它"。 - ⚠️ 设备当中继也有自己的"端口问题":用户侧 NAT / 路由器端口映射 / 打洞 —— ⛔ 不是云安全组那件事,但同源;✅ 同局域网 / 组织内网场景几乎零门槛(可直接用)。
- 与既有路线关系:已拍板「引入 Centrifugo 类外部连接层」支持多实例 ⇒ 本设想 = 把连接层节点来源从"只由平台提供"扩展为"平台 + 用户自备高性能设备" ⇒ 与既有方向一致,⛔ 不改架构。
🔴 推荐替代路径(⛔ 不需要任何端口):设备主动拉(fan-out on read)
服务器收消息 → 只落库 + 广播小信令 → 各设备拨出去拉(拨出不需可达)。
- 优势:卸载同一块扇出成本,却不需要用户侧任何网络前提;延迟略增(一次往返)。
- 前提:需把固定间隔轮询改成「信令触发 + 增量拉」—— IM 线第 14 棒的插件
subscribe轮询已是雏形(⚠️ 那一版是固定轮询,随设备数线性,属我引入的负载)。
建议推进顺序(技术项 · 可自决)
① 先做「设备主动拉」改造 → ② 同时在局域网小范围试「设备当中继」(零公网前提、验证中继服务端角色)→ ③ 跨公网中继留到确实需要时(与"是否重开端口"一起定)。
产出与边界
- 产出 ⇒
交付物/端口决策与设备中继可行性-20260926.md(含拍板 / 角色区分 / 替代路径 / 顺序)。 - 承接件 ⇒
交付物/端口与容量瓶颈评估-20260925.md(含 🔴 扇出背压隐患:ws.ts的send()丢弃socket.write()返回值 ⇒ 慢客户端内存无界;单点即可打垮服务器,建议先修)。 - ⛔ 零代码改动、未部署、未 commit/push、未动 47/106、未动云安全组、未改桌面线一个字节(只读)。⛔ 未登记下一棒。
IM 线 · 第 15 棒(执行棒)✅ 扇出背压修复(用户拍板 A 案)
用户口径:「A 方案」(= 现在修背压)。会话
IM线-第15棒-扇出背压修复|域锁 2 域(src/im·test/im-sdk.test.mjs),收口后已释放。
修的是什么(前一轮查出的隐患)
src/im/ws.ts 的 send() 丢弃 socket.write() 返回值、也不看水位 ⇒ 慢客户端(弱网 / 故意不读)让待写缓冲无界增长 ⇒ 单点即可把进程内存顶爆(丢的不只是那条消息,是整个进程)。
交付(1 新 3 改 · 改动形态极干净)
- 改
src/im/ws.ts(+84 / −1):新增常量IM_SEND_BUFFER_LIMIT_BYTES(4 MiB,= 单帧上限的 4 倍)+ 运行时选项sendBufferLimitBytes(可注入 ⇒ 可测、可按真实水位标定);send()加三道:①write()返回 false ⇒hub.noteBackpressure(writableLength)且仍算已投递 ② 水位 > 上限 ⇒noteBackpressure+noteBackpressureClose+ 具名断开(1013 send-buffer-overflow)+ 落im_send_buffer_overflowwarn 日志 ③ 恰等于上限 ⇒ 不断开。 🔴 关键:ws.ts被删改的既有行只有 1 行 —— 正是socket.write(textFrame(text))(可机械断言)。 - 改
src/im/hub.ts(+36 / −0 纯插入):HubStats加backpressureEvents/peakPendingBytes/closedByBackpressure;counters同步加;新增noteBackpressure()/noteBackpressureClose()(只记账、⛔ 不抛、⛔ 不做 I/O)。stats()用展开语法 ⇒ 自动带上。 - 新
test/im-backpressure.test.mjs(8 例)。 - 改根
package.json(test/verify各登记 1 处;numstat仍 2/2 ⇒ 上一棒的 Editor 替换法生效 ✅)。
判据读数
npm run build rc=0|node --test test/im-backpressure.test.mjs = 8 / 8 过 / 0 败|npm test = 626 / 616 过 / 5 败 / 5 跳过(基线 618/608 ⇒ +8 全为本棒;5 败仍是投放线 tar EBUSY,⛔ 未增一败)|check:layering rc=0 ✅ 无新增违规|store.ts 零改动。
🔴 两条设计取舍(可推翻)
write()=false不虚减delivered—— false 的含义是"水位满",数据已排队、会送达 ⇒ 若记成 skipped,"送达数"会随客户端网速变小、污染观测与判据 3。⇒ 记账归记账,投递语义不变。- 阈值可注入而非写死 —— 本值是保守起点(未标定)⇒ 注入化让"标定后改参数"不必改代码。
🔴 判据演进(已写进 09 §8)
「修 bug」与「新增能力」判据不同:新增能力 ⇒ 纯插入;修 bug ⇒ 允许改既有逻辑,但必须同时:① 既有语义有回归用例(本棒 = delivered === onlineIn)② 新行为可观测(计数/峰值/断开数)③ 阈值可注入。142 §五-6 意图不变(⛔ 不为场景改内核,只许"接扩展点"+"修内核自身缺陷")。
⚠️ 一条实测教训(值得复用)
测试跑的是 lib/ 编译产物 ⇒ 我改完 ws.ts 后忘记重新 build,导致 hub.ts(新的)与 ws.ts(旧的)不一致 ⇒ 测试连挂两次,症状是"断言该断开却投递了"而诊断输出显示注入值正确 ⇒ 一度误以为是 Node 属性遮蔽问题。✅ 定位法:打印两个独立观测点(注入值 ✅ 但 backpressureEvents=0)⇒ 一眼看出"读到的值对、但走的是旧代码" ⇒ 改完必 build。
另附一条真知识:Node 的 writableLength 是原型 getter(非实例自有属性),实例级 Object.defineProperty 可覆盖;子类原型 getter 也有效(本夹具用实例 getter 最稳)。
文档同步
01-规范/09-…契约.md:§8 判据表升级为四档(store 零改动/hub 纯插入/ws 允许改但删除行只限投递点/routes 纯插入)+ 新增 §11「投递可靠性与容量边界」(11.1 背压三条行为与判据 / 11.2 阈值依据与观测面 / 11.3 容量实测读数与单房上限)。
边界
⛔ 未部署、⛔ 未动 47/106、⛔ 未 commit/push、⛔ 未动云安全组、⛔ 未改 A–E 五单结论。⛔ 未登记下一棒。
⚠️ 生产标定未做:阈值仍为保守起点(4 MiB)⇒ 建议在真实流量下取一轮 peakPendingBytes 后校准(属观测/调参,⛔ 不是代码改动)。
🔴 一条待用户确认的连锁影响:原先"背压后 delivered 会小于 onlineIn"的预期没有发生(因为设计上不虚减)⇒ 若后续要"按慢客户端计 skipped",那是语义变更,需重新拍板。
🔴 收口(32.8 万上下文强制)· IM 线 → 已开自动接续
用户本轮三件事(原话):「创建接续会话把IM的改造优化处理完成」「然后更新IM接入文档」「并回复插件的对接文档」。
已落
- 接续包 ⇒
接续包_IM接入面收尾与插件对接答复_20260926.md(md5da0721b2bb28150e57ee423c6c3dfff5,2026-09-26 00:32 冻结)。 - 接续棒 ⇒ automation
a31da051-9d0b-445b-b232-9f5617ff1fe9(一次性 ·scheduledAt = 2026-09-26T00:38·cwds = ["E:/ProgramData/AIProject/aliyun-dsh-server"]正斜杠)。- ✅ cwds 形态已实测确认(view 了 09-24 那条 IM 接续棒)= 正斜杠 + 大写盘符 ⇒ 与状态层口径一致;⚠️ IM 线入口 §0 头部那条「小写盘符 + 反斜杠」的规定与实测不符,以实测为准(⛔ 未改入口那句,待专门清理)。
- prompt 含口径门禁 md5、开机四步、工具上限 40。
- 入口 ⇒
接续入口_IM线_20260922.md §0追加本回合收口行(背压修复 + 三份评估 + 接续登记)。 - 今日日志 ⇒ 本文件上述各节。
接续包的三项「未完成」(新棒依据)
- IM 改造收尾三件:① 桥 5 端点端到端真跑(只过单测、从未真跑)② 部署 47(R8,动手前声明)③ 生产标定背压阈值(改参数、⛔ 不改代码)。
- 🔴 反向通道(发言规则 / 事件回调)= 待用户拍板 —— ⛔ 新棒不许替原会话拍成「已定」、⛔ 不许自决补做;用户未表态则收口时再上抛。原会话判断(可推翻):不必急着补(降级三条已够:房间
config/ 出向纠偏 /host.subscribe()轮询)。 - 文档 + 答复:09 已到 §11,缺「插件作者快速上手」(用法散在 §10.3,且
poc/business-plugins-im/三个示例是旧契约,未含第 8 项出向与跨进程桥);插件对接答复件只能在本工作区产出、由用户转交(⛔ 不得改dsh-plugin-partment一个字节)。
边界
⛔ 未部署 / 未 commit / 未 push / 未动 47/106 / 未动云安全组。本会话不再开新任务(成本按当前水位线性放大)。
IM 接入面收尾棒(00:38–01:0x)
- 承
接续包_IM接入面收尾与插件对接答复_20260926.md(md5 已校);域锁 4 域,本棒自释放。 - 端到端真跑(本棒核心):
tmp/im-bridge-e2e-20260926.mjs真起平台 + 真 HTTP + 插件侧 SDK,23 例 fail 0。 顺带抓出真缺陷并修:src/web/routes/im.ts的bridgeAuth把请求头里的包名当内部 id 查注册表, 而注册表按pluginIdOf(包名)存 ⇒ 出向恒plugin-unavailable(第 8 项在生产不可达)。 单测抓不到的原因:test/im-plugin-bridge.test.mjs刻意 mock fetch、直接递归一化 id,不经过这层翻译。 ⇒ 判据沉淀:"注册面"的纯单测不能替代"经过鉴权层翻译"的真 HTTP 验收。 - 部署 47:
/opt/dshs推lib/im/**+lib/web/routes/im.js+sdk/**;备份/opt/dsh/backups/im-bridge-predeploy-20260926.tgz; 重启dshs= active,/api/im/plugins/bridge、/api/im/stats均 401(路由已加载)。106 不需要(IM 宿主在 Manager)。 ⚠️ 坑:本机 tar 会保留本地 uid ⇒ 47 上落地文件属主变197108,须chown -R root:root修回;下次加--owner=root --group=root。 - 文档:09 新增 §12「插件作者快速上手」(只增不改);答复件
交付物/插件对接答复件-20260926.md。 - 未做:① 背压阈值生产标定(需 admin 会话/真实流量)② 反向通道(待用户拍板)③ 09 的 #2/#4/#5/#8 四条纯文档整改 ④ 可跑的最小示例工程。
第 36 棒续作二 · 规划棒(2026-09-26 06:29–06:5x)· 会话 p36c-platform-versioning
用户原话:「你就是平台线,看看如何修复(还有 worker 如何更新包,是不是应该有个机制,现在的网络结构各种节点和设备,如何进行版本管理和包更新机制)」⇒ 授权扩到平台线,但本轮按「规划与执行分离」只读取证 + 出方案,⛔ 未改 src/** 一行。
取证要点
- 机制骨架齐全(⛔ 不是「没有机制」):worker
启动即拉 + 定时轮询(src/worker/agent.ts:816-819)、POST /shared-layer/pull(:812,带 agent token)、主流程syncSharedLayerOnce(:373)、对账POST /api/plugins/shared/node/sync(:422-427)、Manager 对账面(src/web/routes/business-plugins.ts:373-428)、权威清单.manifest.json、对账快照.node-sync-reports.json。 - 🔴 超时根因(D1):
src/worker/agent.ts:376const timeoutMs = opts.timeoutMs ?? 20000—— 对账面(:426)与产物下载面(:508)共用同一 20 s 常量 ⇒ 2.0 MB 包跨云拉不完 ⇒AbortError: The operation was aborted due to timeout(与 106 上报串逐字吻合)⇒ 106 永远停在旧版。 - 其余缺陷:D2 无重试退避 · D3 失败历史不可见 · D4 只有「最新一份」版本 · D5 无 channel/定向 ⇒ 不能灰度 · D6 设备(桌面端)不在分发链上 · D7 无全局版本矩阵视图 · D8 台账与实时视图不一致。
产出
$WS/交付物/版本管理与包更新机制-现状与方案-20260926.md —— 现状取证(带行号)+ 8 条缺陷 + 三层方案(A 止血/B 版本管理机制/C 跨区拓扑)+ 只读前置 + 决策点 + 8 段交接要素。⇒ 同时是下一棒的「唯一执行单」。
🔴 未登记下一棒
§5 有 1 项待拍板(修到什么程度:只修超时 A / A+全局视图 C / A+完整版本管理 B)⇒ 依「要用户拍板的,等拍了再新建接续会话」⛔ 未登记 automation。我的倾向:A 先落、C 紧随。
IM 反向通道定案棒(06:3x)
- 用户拍板:「都需要实现完整,才能让插件接入,否则两边都要返工」⇒ 反向通道(平台 → 插件)必须补、做完整。
- 本棒只定案不实现(会话预算 18 万+,硬约束)⇒ 产出施工规格
接续包_IM反向通道实现_20260926.md(含设计已定项/文件清单/验收/回滚/开工命令)+ 登记执行棒 automationcce748b8。 - 设计要点(已定项):实例侧 SDK 长轮询拉取(保持"拨出式",⛔ 平台不打进实例、⛔ 不需实例可寻址、⛔ 不新增凭据);
speak.check同步(带 deadline)·event.deliver异步(不阻塞消息流); 超时缺省放行(与同进程binding.ts口径逐字一致,⛔ 不新增"不可达即冻结房间")+ 具名计数;契约可声明onTimeout:'deny'(回合制必须声明);每实例有界队列,满则丢最旧并计数。 - 口径同步 3 处:09 §10.4/§10.5/§12.5 ·
交付物/IM插件跨进程桥-20260925.md §5/§6·交付物/插件对接答复件-20260926.md §0。 - 🔴 实测发现:
p36c-platform-versioning会话持src/web、aliyun-dsh-server/交付物、.workbuddy、05-交接单域 ⇒ 执行棒必须先preflight-lock.sh;src/web未释放时先做不冲突部分(新文件/文档),routes/im.ts放最后。 - 教训(沿用):跨进程能力的单测替代不了真 HTTP 验收(本线 09-26 已实证一次)。
插件投放与分库线 · 第 36 棒续作三 · 拍板落地棒(2026-09-26 06:36)· 会话 p36d-platform-versioning
拍板原话(用户本人 · 06:36)
「C 方案,然后B,这次就用版本更新机制去更新网络上各节点,子节点和设备」
口径(⛔ 别被方案里的层名混淆)
- 用户说的 C 案 = 层 A(止血 20 s↔300 s/按大小动态/重试退避/失败留痕)+ 层 B-1~B-4(版本目录化/channel 灰度/定向钉版/设备纳入)。
- 随后做 的 B 案 = 层 B-5(全局版本矩阵视图)。
- 层 C 跨区拓扑本次不做(属覆盖网络线架构层),但实现须兼容其口径:每区 Manager 各持内容源、节点只向本区拉、同版本号须字节一致。
- 收尾必须真跑一次分发:
[email protected](含以后版本)→ 47 本机 worker + 106 子节点 + 设备(桌面端),读数验证(w-106对账快照stale/failed清空)。 - 🔴 执行棒第一件事 = 取证设备(桌面端)侧载体(承缺陷 D6「设备不在分发链上」):桌面端有无「包/插件目录 + 拉取入口」、凭据走哪条。有 ⇒ 按同一对账协议接入;没有 ⇒ 具名报告缺口 + 给最小接入方案,⛔ 不硬造。
产出(本棒只做记录落地,⛔ 未改 src/**)
- 唯一执行单
交付物/版本管理与包更新机制-现状与方案-20260926.md:§5 改为「🔴 已拍板」+ §8 执行棒细化(§8.1 S1→S4 顺序表/§8.2 未知项三条/§8.3 既有纪律)⇒ 14,893 B。 - 入口
接续入口_插件投放与分库线_20260922.md:§0 落 06:36 拍板行(最新一行 = 执行依据)+ §2 落「续作二/续作三」注 ⇒ 343,592 → 已含两节,977 → 986 行。 $DOC/05-交接单/README.md §一第 44 行(04 单状态行)追加 06:36 拍板 + §8 细化 + 执行棒登记。- ✅ 执行棒 automation =
da73ab87-fb2f-47f0-a8d8-8ea3ad35eb19(一次性 ·2026-09-26T06:52);本线入口 automation35e1bfbc-…保持PAUSED。
🔴 本棒事故(已自愈 · 值得进技能)
tmp/p36/patch-c3.py 步 1 成功(交付件 §5/§8 落盘),步 2 报 TypeError: sequence item 11: expected a bytes-like object, str found(NEW0 漏 .encode("utf-8"))。真正的伤害不在那行 TypeError —— 复合式 open(P,"wb").write(b"\n".join(parts)) 的求值顺序是 先 open()(立即截断!)→ 再求值 join(),join 抛错 ⇒ 入口被清成 0 字节。
- 发现方式:事后
wc -c得0(若只看脚本 traceback 只会以为"没写进去")。 - 复原:
git checkout -- <入口>;HEAD 版 = 341,330 B / 968 行、含 06:29 规划棒行、且远端对账0 0⇒ 无损;复原后git hash-object==git rev-parse HEAD:<file>=1d44073b…。 - 判据(新增铁律):改共享文件只准 Edit 精确片段替换,或「先算全量 bytes 再一次性写」;⛔ 禁用
open(...,"wb").write(表达式)复合式(表达式求值前文件已被清空)。同源风险:任何"写前先 open 再算内容"的写法都有此坑。 - ✅ 补救:改用 Edit 工具做三处插入(入口 §0/§2、README §一),不再走整文件覆盖。
边界
⛔ 未改 D:/github/dsh_shenxian/src/** 一行(只读取证);⛔ 未 ssh 真机做任何变更(本棒纯记录落地 + 收口);⛔ 未碰他线 src/web·routes/im.ts。
收口(06:4x–06:5x)
- 提交
2a1226c(docs(平台线): 版本管理与包更新机制 拍板落地(C案→B案 · 执行棒登记))→ 推送a38d8b6..2a1226c master -> master(rc=0)→ 对账git rev-list --left-right --count origin/master...HEAD=0 0、HEAD == origin/master✅。 - 仅 3 件入库:本件 + 本线入口 + 本日志;
git diff --cached --name-only自查无tmp//中间产物/05-交接单;⛔ 未git add -A、⛔ 未代提交他线(CODEBUDDY.md/state.py/.codebuddy/rules/server-ops.md/.workbuddy/memory/MEMORY.md/他线接续入口_*全部未纳入)。 - 文档库侧:本线唯一改动 =
$DOC/05-交接单/README.md §一第 44 行;git check-ignore -v⇒.gitignore:45整目录忽略、未跟踪 ⇒ 按既有口径不入库(⛔ 未-f)。推送前docs-sync-check.sh= ❌(一致 268/不一致 21/仅本地 4/仅服务器 0),差异面全为他线在途(07-scripts/*、08-skills/*、CODEBUDDY.md、01-规范/09、02-架构设计/*、04-调整方案/*、05-交接单/*)⇒ 非本线引入、交文档库同步线处置。 - automation:
35e1bfbc(第 36 棒入口)=PAUSED✅;da73ab87(执行棒)=ACTIVE·2026-09-26T06:52✅(收口 06:44 + 8 min,落在 5~8 min 窗口内)。 - 锁:域锁
p36d-platform-versioning反序释放(先--release-publish→ 最后ME="p36d-platform-versioning" --release-exec)。 - 📄 收口证据全文(命令原文 + 输出原文 + 退出码)⇒ 本件 §9。