Files
dsh_ai1net_server/交付物/跨机错误消息放宽与两项只读取证-20260925.md
admin 318430c9e9 chore(工作区): 插件投放与分库线收口入库(第 35 棒 + 22:44 拍板落盘)
范围 = 本线(插件投放与分库线)产物 + 记忆类,共 27 件:
- 接续入口_插件投放与分库线(1 件):§0 新增 22:44 拍板行;§2 第 36 棒范围改 5 步、条件步转无条件
- 交付物(22 件):MCN 数据面接入阶段一/阶段二系列(含 B 案落地与 shadow 读数)、
  P0 修通与移动端真机验收、pnpm-EPERM、两机 lib 差异、共享层台账语义、
  基础插件身份与回滚、插件接入验收、插件数据面取数口、移动端迁包与字号扩面、跨机错误消息
- 记忆(4 件):2026-09-24 / 2026-09-25 日志、MEMORY.md、本棒 automation 执行记录

⛔ 未含他线在途改动(只报告、不代提交):机制层 CODEBUDDY.md / state.py /
.codebuddy/rules/server-ops.md、接续入口_IM线、接续入口_StoryForge验收线、
其余 29 个 automation 目录、docs/规则与载体/、归档/、接续包_*。
2026-09-25 23:06:29 +08:00

14 KiB
Raw Permalink Blame History

插件投放与分库线 · 第 23 棒(执行棒)落地件

工作区:E:/ProgramData/AIProject/aliyun-dsh-server | 日期:2026-09-25 12:1x–12:4x 代码基线:D:/github/dsh_shenxian(生产口径 dshs)/HEAD e6207aa 三件:① §5-12 跨机错误消息截断放宽(小改,已投两机)② §5-18「清理前必查」只读取证 ③ §5-22 本机 lib ↔ 部署面 3+7 差异定性 锁:插件投放与分库线-第23棒,域 = src/supervisor / test/remote-spawner.test.mjs / aliyun-dsh-server/接续入口_插件投放与分库线_20260922.md


一、第 1 件 · §5-12 跨机错误消息截断放宽(200 → 1200)

1-1 改了什么(一件文件 + 一个测试文件)

文件 改动
src/supervisor/remote-spawner.ts 新增导出常量 AGENT_ERROR_TEXT_MAX = 1200(带口径注释:只放宽保留长度,⛔ 不动重试次数/退避,⛔ 不改 4xx 不重试语义)|两处 text.slice(0, 200) ⇒ text.slice(0, AGENT_ERROR_TEXT_MAX)(行 299/303 两个分支:4xx 具名抛与 5xx lastErr)
test/remote-spawner.test.mjs 新增 T6/T7/T8(+3 例)

1-2 单测钉住的不变量

  • T6 4xx:973 字符正文逐字完整进 Manager 侧 message(旧口径只留前 200)——正对第 17 棒的现场(真根因只能从 worker journald 补)。
  • T7 边界:恰好 1200 字符一个不少;多 1 个字符即截到 1200(钉住"上限还在,不是关了限制")。
  • T8 5xx 分支:走同一上限,且 calls === 4(钉住"5xx 仍重试 4 次"这条既有语义未被本次改动碰到)。
  • ⚠️ T6 首发因夹具自身超上限(1453 > 1200)被断言挡住 ⇒ 已改 973 字符夹具;这正是该断言的价值(夹具错了会被抓出来)。

1-3 门禁与部署(✅ 判据 ①②③ 全绿)

判据 读数
① 放宽到 ~1200 ✅ AGENT_ERROR_TEXT_MAX = 1200,两处分支同用
② 单测 ✅ node --test test/remote-spawner.test.mjs = 8/8 通过(原 5 例 + 新 3 例)
③ 门禁 npm run build rc=0 | npm test = 592 tests / 590 过 / 0 败 / 2 跳过(第 21 棒 589/587/0/2 ⇒ +3)|npm run check:layering rc=0 ✅ 无新增违规(未归类 1 条 = src/platform-paths.ts,属既有基线)

部署(两机同一文件)

项 47 106
目标 /opt/dshs/lib/supervisor/remote-spawner.js /opt/dshs-cluster/lib/supervisor/remote-spawner.js
投前 md5 269d3d20ffceb726298434972a349d56(20564 B) 同左(逐字一致)
投后 md5 e9ab05d92a8666459aa486e6893e1bf5(21529 B) 同左
三方一致 ✅ 本机 = 47 = 106 = e9ab05d9… ✅
备份 /opt/dsh/backups/lib-p23/iZrj99af19cibck1ge93tqZ-pre-p23-20260925-122854.tgz(sha256 0089585e6f4e910e…)+ 同名 .manifest + 单文件副本 /opt/dsh/backups/lib-p23/VM-0-8-opencloudos-pre-p23-20260925-122855.tgz(sha256 d6f71f98efd5191d…)+ .manifest + 单文件副本
生效 ✅ restart dshs ⇒ active · NRestarts=0 · 门户 HTTP 200 · journald dshs listening on http://127.0.0.1:3080 ⛔ 未重启(中断在线用户 ⇒ 待窗口)⇒ 待重启面 47 → 48 件
  • ⛔ 未重启 106(约束遵守);⛔ 未 commit / push;⛔ src/web/routes/im.ts 零改动;⛔ 未手改任何用户 home 下的 profile / .pnpm。
  • 47 重启时旧进程停止阶段有一次 dshs.service: Failed with result 'timeout'(优雅退出超时),新进程随即 Started 并监听 3080、门户 200、NRestarts=0 ⇒ 判为生效,如实记录。
  • dshs-worker(47)未重启:lib/supervisor/remote-spawner.js 在 worker 模块图内(cli.js worker 静态 import web/server.js),但 RemoteSpawner 的唯一实例化点 = lib/web/server.js:38 的 Manager 侧装配 ⇒ 对 worker 行为零影响。
  • ⚠️ 本棒无"长错误消息"真机读数 —— 该路径需要一次真失败的跨机调用才可观察。⛔ 不宣称运行面验收通过;本件判据 = 代码面 + 单测 + 部署面三方 md5 一致,均已取到。

二、第 2 件 · §5-18「清理前必查」只读取证(⛔ 未执行清理)

目标 profile:/var/lib/dshs/users/cce6d1cd-b376-4304-80f0-0e1c58c9ffde/home/profiles/web(已启用 dsh-plugin-mcn-suite 的那台 admin 实例;运行身份 dsh-cce6d1cdb376430480f0,uid 114801) ⛔ 全程只读:未删/未改任何软链、未改 profile、未动 .pnpm。

2-1 判据① 命中文件与命中处(含行号)

# 命中处 形态
1 .pnpm/@dsh-local+business-plugins@file+..+..+.dsh-stage+business-plugins-0.3.25.tgz/node_modules/@dsh-local/business-plugins/lib/client.js:56 var React = require("react")
2 .pnpm/@dsh-local+portal-entry@file+..+..+.dsh-stage+portal-entry-0.5.6.tgz_…/node_modules/@dsh-local/portal-entry/lib/client.js:67 var React = require("react")
3 .pnpm/@[email protected]_…[email protected]/node_modules/@deepseek-ai/dsh-client-ui-renderer/lib/client.js:10 let react = require("react")
4 包自身内部(react/react-dom 的 cjs/*、[email protected]、[email protected]、@deepseek-ai/dsh-client-ui-primitives/lib/index.js:8-9、@softspark/dsh-file-preview/lib/types/client/*.js:2) 这些消费者在自己的 .pnpm/<pkg>/node_modules 自带 react ⇒ 不经兜底

全树剥离"自身包内部 / dist/assets 浏览器包 / lib/client.js"后剩余 51 条命中,全部属上述四类;四个包的 main(lib/index.js,服务端半边)零命中。

2-2 判据② 「包自己声明的依赖」 vs 「顶层兜底」——判别器实测

Node 解析优先级:① .pnpm/<pkg>/node_modules ② .pnpm/node_modules(提升层)③ <profile>/node_modules(顶层兜底所在)。以该实例 uid 运行 require.resolve(只解析、不执行模块):

解析起点 react 落点
<profile> 本身 <shared>/dsh-plugin-mcn-suite/node_modules/.pnpm/[email protected]/node_modules/react/index.js
<profile>/node_modules/dsh-plugin-mcn-suite ↑同一落点(自己的 store)
<shared>/dsh-plugin-mcn-suite ↑同一落点(自己的 store)
@dsh-local/business-plugins ↑同一落点(⇒ 本次解析经顶层兜底链)
@dsh-local/portal-entry ↑同(经兜底)
@deepseek-ai/dsh-client-ui-renderer ↑同(经兜底)
  • 包自己声明的依赖:共享层 dsh-plugin-mcn-suite/package.json 第 32–34 行声明 react / react-dom / xlsx,其 .pnpm 树内自带三件 ⇒ 解析不经过顶层兜底。
  • 顶层兜底:只有那 3 个 .pnpm/<pkg>/node_modules 里没有 react 的消费者(① 优先级落空、② 提升层 .pnpm/node_modules 里三件都没有)⇒ 解析落到 <profile>/node_modules/react ⇒ 兜底链确实在解析路径上(实测三处落点全部 = 兜底链的实解目标)。
  • 兜底目录自身现状:.dsh-module-fallback/node_modules/ 内只剩 3 条链(xlsx/react/react-dom → 共享层 dsh-plugin-mcn-suite/node_modules/*),另有 4 个空目录(@deepseek-ai/@shikijs/@types/@ungap,各 0 项)= 历史残留。
  • 三条链的字节级 mtime = 09-25 10:14:57(⛔ 非 §5-18 记的 09-08;09-08 是目录 mtime)⇒ 近两日内被平台装配动作刷新过(真值以本行实测为准)。

2-3 判据③ 结论句

结论 = 有真依赖,但依赖方全在「浏览器半边」;Node 运行期无消费者。

依据:3 个命中者全是 lib/client.js(浏览器半边)——

  • @dsh-local/business-plugins/lib/client.js 头部原文:dsh client bundles 以普通脚本形式执行,向 window.__ModuleLoader__ 注册 factory;首次 import 时惰性物化 factory(require)
  • @deepseek-ai/dsh-client-ui-renderer/lib/client.js 首行:window.__ModuleLoader__.load({ id: …, factory: (require) => { … } })

⇒ 它们的 require("react") 由**浏览器侧模块表(window.__ModuleLoader__)**满足,不读 node_modules 磁盘。加一条反向证据:grep -rln "__ModuleLoader__" /opt/dshs/lib = 0 文件(平台服务端代码里根本没有这个加载器)⇒ 服务端不解析 client bundle 的 require。

边界(哪些没判到)

  1. 只核了这一个 profile(profiles/web)与共享层 4 个包;另一台 profile 9f3a1c47-…(uid 100010)没有这三条链(ABSENT),故不在讨论范围。
  2. ⛔ 未展开 @deepseek-ai/dsh 官方包的客户端宿主实现(只读未做)——若它在服务端预解析 client bundle 依赖,结论需修正。
  3. 结论对当前这一版 profile 内容成立;profile 重建 / 插件版本升级后需重测。
  4. ⛔ 未做"删掉链再跑"的 A/B(会改实例解析面,属清理动作)。

2-4 给拍板的输入(⛔ 本棒不清理)

清理的实际影响面 = 只动 3 个浏览器半边包在 require.resolve 语义上的可见性;Node 运行期无消费者 ⇒ 风险低,但非零(见边界 2、3)。另:这三条链目前每个装配周期都要被 quarantineSharedLayerLinks 临时摘一次(第 20 棒的修法),清掉可省这一步 —— 但该修法本身已保证装配不受影响,所以"省一步"不构成必须清理的理由。


三、第 3 件 · §5-22 本机 lib ↔ 部署面 3+7 差异定性(⛔ 未投任何件)

本机 lib = 09-25 12:23 构建(本轮 npm run build 产物)/两机部署面 = IM 版 09-23 20:59(两机逐字相同)。

3-1 ① 那 7 件是否被引用 ⇒ 死件 / 活件

件 两机现状 部署面引用面 判定
im/gateway-token.js .d.ts .js.map 三件全缺 grep -rn gateway-token <lib>/**/*.js = 0 命中 ⇒ 部署面的旧版 web/routes/im.js 不引用它 死件(当前无引用者)✅ 不是活缺口
web/essential-plugins.d.ts .js.map 缺(.js 两机在:6606 B / 09-25 10:45:57) 两个引用者已能解析:web/routes/admin.js:10、web/routes/business-plugins.js:20 (from '../essential-plugins.js') 纯声明/映射边车(runtime 零影响)
web/routes/plugin-data.d.ts .js.map 缺(.js 两机在:15523 B / 09-25 08:04:57) 引用者已能解析:web/server.js:55 (from './routes/plugin-data.js') 同上

🔴 一条必须记住的耦合(本件新出):本机 lib/web/routes/im.js:42 已 import … from '../../im/gateway-token.js' ⇒ 新版 im.js 与 im/gateway-token.* 必须同批投;⛔ 单投 im.js 会让实例在启动期 ERR_MODULE_NOT_FOUND。当前两机构成"旧 im.js + 无 gateway-token"的自洽态,没有人处于半投状态。

3-2 ② 3 件运行时 .js 谁更新

件 本机(12:23 构建) 两机(09-23 20:59) 谁更新
im/backends/gateway.js 16241 B 12077 B 本机
im/connection-backend.js 4154 B 3342 B 本机
web/routes/im.js 47262 B 36738 B 本机
  • 两机三件逐字相同(md5 相同、mtime 均 2026-09-23 20:59:31)⇒ 两机部署面 = 同一版 IM 构建(scp 保留源 mtime,故该时间 = 源构建时间,非投放时间)。
  • 代码仓 git log 无法作区分判据:IM 面整体落在同一 commit e6207aa(chore(仓库对齐): 文档库结构治理 + IM/插件线落地)⇒ 以构建时间 + 体积为判据。
  • 差异成因 = 本机含 IM 线 09-23 之后的改动,含本件新出的 gateway-token 抽取。

3-3 ③ 结论表与建议

归类 件 本线可否补
IM 线未投放件(⛔ 不归本线) im/gateway-token.{js,d.ts,js.map}(3 件,须与新版 im.js 同批) ⛔ 不补(单投即事故;同批属 IM 线投放面)
IM 线未投放件(⛔ 不归本线) 3 件运行时 .js 的新版本 ⛔ 不补(src/im/** + src/web/routes/im.ts 属 IM 线 lane,且 im.ts 有冻结口径)
声明/映射边车(死件) web/essential-plugins.{d.ts,js.map}、web/routes/plugin-data.{d.ts,js.map}(4 件) 可补但无收益:两机运行面为纯 node,无 TS 消费者;.js.map 只影响调试栈 ⇒ 建议不投(投 = 制造 4 件永远用不上的文件)

本线无"部署面活缺口" ⇒ 第 3 件无需任何落地动作;后续若要投,只能由 IM 线按"im.js + gateway-token.* 同批"排棒。


四、卫生与未闭合项

卫生(逐条遵守):⛔ 未 commit / push |⛔ src/web/routes/im.ts 零改动 |⛔ 未重启 106 |⛔ 未手改用户 home 下 profile / .pnpm |⛔ 未清 .dsh-module-fallback 软链(只取证)|⛔ 未改 D:/github/dsh_shenxian/lib 之外的别线产物 |✅ 47 /tmp 无残留(探针脚本已 trap 清理且已复核)|✅ 取证脚本全部落在本工作区 tmp/。

未闭合

  1. 🔴 106 待重启面 = 48 件(原 47 件 + 本轮 1 件)⇒ 生效待用户给窗口。
  2. ⚠️ 第 1 件无真机长错误消息读数(需一次真失败的跨机调用)⇒ 未宣称运行面验收。
  3. ⚠️ 第 2 件结论有 4 条边界(见 §2-3),其中"官方客户端宿主是否在服务端预解析依赖"未展开。
  4. ⚠️ 第 3 件两机 lib 树里的 33 条部署备份残留仍未处置(第 22 棒记,属"部署卫生"独立议题)。

复现命令:tmp/p23-item2-probe{,2,3,4,5}.sh(第 2 件五批)|tmp/p23-item3-probe.sh(第 3 件,两机同一脚本)|tmp/p23-deploy-backup.sh <代码根>(投前备份)。