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

9.2 KiB
Raw Permalink Blame History

第 18 棒落地件 · 共享层自足性转正 + 回滚残留 + 移动端第 ④ 条(2026-09-25)

线:插件投放与分库线(入口 接续入口_插件投放与分库线_20260922.md) 棒次:第 18 棒 · 执行棒(automation ed2b5e61-25b9-4b97-849c-1e0b204b669e) 代码基线:D:\github\dsh_shenxian(生产口径 dshs)|⛔ 未 commit / push 结论:第 1 件 ✅(判据 ①②③ 全绿)|第 2 件 ✅(判据成立,另发现"缺失侧"未覆盖 ⇒ 已上报)|第 3 件 ✅ 5/5(含本次修的第 ④ 条)


一、第 1 件 · 共享层自足性从探针转为正式修法

病:共享只读包库 <flat>/node_modules 里只有插件自己的依赖、零个 @deepseek-ai ⇒ link: 形态下实例从共享层加载宿主代码必报 Cannot find package '@deepseek-ai/dsh-llm' ⇒ 实例 crash-restart ⇒ 探活判"实例未能启动"⇒ 插件被自动禁用。

修法(唯一一份实现落在 ③ 能力层,① 入口层复用)

落点 内容
src/supervisor/plugin-assembly.ts 新增 resolveDshPackageRoot()(解析顺序:env 显式覆盖 → 平台配置的 dsh bin 解软链 → npm root -g)、resolveHostDshScopeDir()、ensureSharedScopeLink()、healSharedLayerSelfSufficiency()
src/web/routes/business-plugins.ts doShare 目录就位后调用 healSharedLayerSelfSufficiency(root)(刻意放在 hashTree 之后 ⇒ 指纹不含软链,不引起重拉)+ 审计与响应体带 sharedSelfSufficiency 摘要
src/worker/agent.ts syncSharedLayerOnce 每轮幂等自愈(worker 是独立单元,Manager 与 worker 各自把关)
src/web/dsh-install.ts 该文件原有一份 dsh 根解析副本 ⇒ 下沉到 ③ 层复用,删本地副本(代价:不再是"零内部 import",验证改走 scripts/verify-dsh-install.mjs)

软链落点 = 包目录内 <flat>/node_modules/@deepseek-ai,⛔ 不落共享层根 —— 否则 syncSharedLayerOnce 的 onDisk 对账面会把 node_modules 当"多出来的产物"上报 extra。

判据与读数(真机,47 = bt-server / 106 = test106)

# 判据 读数
① 删掉人工探针链后重新 share ⇒ 共享层自带解析链 响应 sharedSelfSufficiency.scope = /usr/local/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai,linked = ['_dsh-local_im-conversation-tabs','_dsh-local_storyforge','dsh-plugin-mcn-suite']
② 47 + 106 两端都成立 47 三包 scope 均 LINK 可解(240 项);106 三包 scope 均 LINK → /usr/lib/node_modules/...(两机 npm root -g 路径不同 ⇒ 必须各机本地解析,⛔ 不能由 Manager 算好随包分发)
③ 重新启用 mcn-suite ⇒ 实例加载 0.3.15、任务 success、rejected:[] off 任务 a524537251ff570a = success;on 任务 28dd88e4c391cad6 = success、rejected:[]、实例探活通过;journald:[mcn-suite] loaded v0.3.15(host 面 2 个:mcn, voxemw-cloud) + skills ensured: 装 [email protected](升级自 0.3.14);/api/dsh/status = running:true port:20000 restarts:0

⛔ 未污染对账面:共享层根没有多出 node_modules;hashTree/hashTreeAt 本就不计符号链接 ⇒ treeSha256 不变 ⇒ 不触发节点重拉。


二、第 2 件 · 回滚残留

病:restoreProfile() 只还原 package.json/pnpm-lock.yaml/cordis.patch.yml ⇒ 回滚后 node_modules 与声明不一致。

修法:新增 declaredNamesIn(snap)(dependencies ∪ dsh.profile.bundles,快照解析失败 ⇒ 取空集宁可不删)+ pruneOrphanDepLinks(dir, snap)(只删软链、只删未声明、跳过 . 开头与真目录、scoped 目录下钻),在 restoreProfile() 末尾调用。单测钉住四条不变量:声明内不删 / bundles 内不删 / 真目录不碰 / .pnpm 不碰。

判据:回滚后 node_modules/<pkg> 与 dependencies 一致(至少不残留无主软链)⇒ ✅ 成立。

🔴 本棒实测到的另一半(⛔ 未修,已上报):残留有两个方向。本次 off 动作在真机上撞 pnpm remove 失败(见 §四-1),结果是声明还在、node_modules/dsh-plugin-mcn-suite 软链被删掉了 —— 实例启动直接崩: Error: dsh: cannot resolve profile bundle "dsh-plugin-mcn-suite" from the dsh installation or <profile> ×5 ⇒ crash-loop-circuit-open(冷却 600 s)。 pruneOrphanDepLinks 只治"多",不治"缺"。建议修法(下一棒,小改):restoreProfile() 里对声明中的 link: 依赖做一次确定性重建(link: 目标就在快照里,纯 symlinkSync,不需要跑 pnpm、不碰 .pnpm 实体)⇒ 两个方向都收敛。

恢复过程(走平台正规口,未手改 profile):off→on 循环重跑,两次任务均 success ⇒ pnpm install 自动重建软链 ⇒ 实例重启探活通过。⛔ 全程未手工 ln -s、未手改 package.json/.pnpm。


三、第 3 件 · 移动端第 ④ 条(聚焦不缩放)+ 五条重跑

改了什么(插件真源 D:/dshworkspace/plugin_package/dsh-plugin-mcn-suite/lib/client.js,mcn-mobile 段第 ③ 条)

.mcnNav_input,.mcnNav_select,.mcnNav_textarea,.v1rksel,.dvAcc_input,.dvAcc_select,.dvAcc_textarea{font-size:16px!important}
.mcnNav_panel input:not([type=checkbox]):not([type=radio]),…,.mcnNav_page select,…,.dvAcc_page textarea{font-size:16px!important}

理由:.dvAcc_* 基础样式用 font:var(--dsw-font-s-14) 简写且按需注入(可能晚于本段)⇒ 必须 !important;SELECT.v1rksel 此前不在任何移动端规则内 ⇒ 13.33px。

投放链:版本 0.3.14 → 0.3.15(package.json + skills/.manifest.json 两处真源)⇒ 以池内 0.3.14 tgz 为基底确定性重打(322 文件,变化面恰 3 个文件,自证基底 md5 ≡ 线上 d387089b…)⇒ POST /api/plugins/business ⇒ 两段式 share(action:"replaced"、treeSha256 939206c76abb…、fileCount 657)⇒ 47/106 共享层双双 0.3.15(106 首轮 stale→pulled)⇒ 47 四件、106 两件 md5 逐字一致 ⇒ restart ⇒ 门户 200 / worker 401。

五条真机读数(tmp/p17-visual.mjs,零依赖 CDP 驱动本机真 Chrome,视口 375×667 + 横屏 667×375)

# 判据 读数 判定
① 工作台独占 开面板后 navCount=1,面板盒 {x:56,y:0,w:319,h:667};会话区 display:none ✅
② 能退出 二次点 .mcnNav_trigger ⇒ URL #/mcn→/、navCount 1→0、会话区复原(现版 UI 不渲染 .mcnNav_close ⇒ 用等价判据) ✅
③ 无横向溢出 scrollWidth==innerWidth(竖 375=375、横 667=667,溢出 0) ✅
④ 聚焦不缩放 工作台内唯一可见表单控件 SELECT.v1rksel 计算字号 = 16px(修前 13.33px);注入样式段文本级取证:style[data-plugin-css="mcn-mobile"] 命中新规则 ✅
⑤ 横屏可用 667×375:面板 {x:56,y:0,w:611,h:375},溢出 0 ✅

零点:style[data-plugin-css="mcn-mobile"] 计数 = 1 ⇒ 新段确在浏览器里生效(不是"以为改了")。


四、两条新发现(⛔ 未擅自修,已写进 §2 后续)

  1. 🔴 pnpm remove/install 在真 profile 里会偶发失败(exit 255,--reporter silent 把原因全吞掉) —— 第 16/17/18 棒累计三次(09:01 apply timeout、09:05 isolate install 失败、09:56 remove 失败)。本棒已排除的假设(全部实测反证,别再重复走):㈠ 共享包目录内多出的 node_modules/@deepseek-ai 软链(A/B 对照双双 rc=0)㈡ 真实路径条件(真实路径副本 rc=0)㈢ worker 的最小 spawn 环境(env -i PATH=… HOME=… rc=0)㈣ 祖先目录不可 scandir(/var/lib/dshs 与 /var/lib/dshs/users 是 711 ⇒ 该 uid r 位确实没有,但实测不影响 pnpm 运行)㈤ 磁盘 / inode(23 GB 可用)。⇒ 高度指向并发/时序(同一 store 下并发 pnpm、或与共享层拉取重叠)。下一次复现时的正解动作:给失败路径补一次 --reporter default 重跑(现在 --reporter silent 结构上让 pnpmExecError 拿不到任何正文)—— 属 plugin-assembly.ts 的小改。
  2. 🟡 restoreProfile() 不重建缺失的 link: 软链(见 §二 的红框)⇒ 今日真实致实例崩溃。

五、门禁与卫生

  • npm run build rc=0|npm test = 575 tests / 573 过 / 0 败 / 2 跳过(基线 449/447/2;新增 6 个用例:软链补建与幂等 / 悬空与指错 / 真目录不碰 / no_scope 零改动 / 全量补含老包且不落共享层根 / 回滚清无主软链)|check-layering ✅ 无新增违规(现存 5 条全在基线内)。
  • 部署备份:/opt/dsh/backups/lib-p18/{47,106}-pre-p18;插件回滚素材 /opt/dsh/backups/plugins/dsh-plugin-mcn-suite/0.3.15.tgz。
  • 清理:临时 admin 会话残留 0(两机 /tmp/p18* 残留 0)|⛔ 未 commit/push、⛔ src/web/routes/im.ts 零改动、⛔ 未手改用户 home 下的 profile / .pnpm。