Files
dsh_ai1net_server/交付物/IM群组-ui投放与线上取证操作单-20260923.md
admin c1b5e4d966 chore(工作区): 全量入库 + 补齐 .gitignore(以工作区为准)
- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次)
- .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…),
  目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪
- .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/)
- .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*)
- .gitignore 补:备份件(*.bak-*)
- 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
2026-10-10 23:13:22 +08:00

7.7 KiB
Raw Permalink Blame History

IM 群组 UI 插件投放 · 线上取证操作单

工作区:E:\ProgramData\AIProject\ai1net-dsh-server|线:IM 线(第 14 棒)|日期:2026-09-23 20:2x 插件:@dsh-local/im-conversation-tabs v0.1.0(E 单主交付,落点 = 实例内 dsh 会话页 tab) 投放物指纹:tgz sha256 c9b1184aca8eadd6c84316d2e79427546a65f59f0614a2ec9704c895a311bfb1(21,494 B) |lib/client.js md5 21fbc52fdedc9915238dd1c3f5c5e827(= 本机源 / 包内 / 47 共享层三处逐字一致)


一、服务端侧已完成(第 14 棒,⛔ 无需再做)

步骤 结果 证据
打包(tgz,package/ 布局) ✅ 包内 4 文件;三件齐(exports['./client'] / dsh.client.platform='web' / dsh.bundle.patch)断言 rc=0
admin 导入候选池 ✅ http=200 replaced:false · trustedOverride:false · compat.level=unknown(非 incompatible)· blocked 无 P0 ⇒ 未用信任放行;审计 audit_log id 360 upload_business_plugin
池内可见 ✅ 4 → 5 条 GET /api/plugins/business 命中 @dsh-local/im-conversation-tabs v0.1.0
发布到共享层(link: 装配前提) ✅ action:"created" 目录 /var/lib/dshs/bundled-plugins/_dsh-local_im-conversation-tabs(root:root,全 world-readable);fileRef = link:/var/lib/dshs/bundled-plugins/_dsh-local_im-conversation-tabs;审计 id 361 share_business_plugin
回滚素材 ✅ /opt/dsh/backups/plugins/_dsh-local_im-conversation-tabs/0.1.0.tgz
临时 admin 会话 ✅ 已删 deleted_sessions=1;临时文件(payload / 响应 / 暂存 tgz)零残留

⚠️ 为何必须做「发布到共享层」:装配协议 = link:(2026-09-23 拍板)⇒ profile 里写的是软链依赖,目标即共享层目录。只进候选池不发布,用户点启用会撞 plugin_bundle_missing(friendlyError 把它翻成「该插件尚未发布到共享包库,请先联系管理员完成发布」)⇒ 半成品投放。


二、待用户动作(3 步,约 2 分钟)

步 1 · 在实例内启用

实例 → 设置 → 功能管理 → 找到 @dsh-local/im-conversation-tabs → 打开开关。

  • 该插件未声明数据面(dataPlane.state = none)⇒ 不会被「未建库不许开启」门禁拦。
  • 点开后平台自动执行:写 profile(link: 引用)→ pnpm 建链 → 重启实例 + 探活(无需另做重启)。

步 2 · 确认实例真的带上了包(只读,一条命令)

ssh bt-server 'ls -la /var/lib/dshs/users/<你的 uid>/home/profiles/web/node_modules/@dsh-local/ | grep im-conversation-tabs'

期望:一行软链,形如 im-conversation-tabs -> …/bundled-plugins/_dsh-local_im-conversation-tabs;退出码 0。 (uid 查法:ssh bt-server 'ls /var/lib/dshs/users/',目录名 = 你的 userId。)

步 3 · 线上取证(浏览器,见第三节三条)


三、线上取证判据(生效链路第 ④ 关)

🔴 口径更正(本棒实测):IM 链路在服务端一条日志都不写 —— src/im/ws.ts / src/web/routes/im.ts / src/supervisor/proxy.ts 三处 process.stderr / console.* 零命中;reject() 只回一帧 error 再 destroy(),不落日志。⇒ 判据必须在客户端取,⛔ journalctl | grep bad-op 恒空(空 ≠ 没发生)。

# 判据 命令 / 操作 期望(+退出码)
① 会话区被接管,tab 行出现 浏览器 DevTools Console:document.querySelectorAll('.imtabs-bar').length 1
② tab 行内容(dsh 会话 + 群组 tab) document.querySelectorAll('.imtabs-tab').length >= 1(首屏 = dsh 会话 tab;开群组 tab 后递增)
③ 🔴 协议对齐(原 P0 不复现) DevTools → Network → WS → /api/im/ws → Messages:看帧流水 出站只有 {"op":"subscribe"…} / {"op":"ping"} / {"op":"resume"…};入站首帧 {"op":"hello"…};不出现 {"op":"error","error":"bad-op"…}
④ 连接态健康 document.querySelector('.imtabs-conn').className 不含 imtabs-connBad(含 connWarn 视为未通过)
⑤ 槽位命中(失效时可见) document.querySelector('.imtabs-alert') null(非 null ⇒ 官方槽名又变了,见 .imtabs-alert 提示文案)
⑥ 房间消息真的渲染 在房间里发一条消息 → 群组 tab 内消息流 消息出现在列表中(游标补齐走 REST pull + WS resume,两侧按 m.id 去重)

判定口径:①②③④⑤⑥ 全过 ⇒ E 单「线上可见面」通过,E 单可判「已交付」;任一条不过 ⇒ 本项记「未通过」,把 ③ 的帧流水原文回传(那是定位 P0 类的唯一凭据)。


四、前置条件与两个已知缺口

  1. 🔴 实例在哪台机决定成败:
    • 实例在 47(Manager) ⇒ 共享层已就绪,直接可用 ✅(47 现有实例 = admin,uid 114801)。 ⚠️ 47 上该实例的 bwrap 当前没有 --ro-bind-try /var/lib/dshs/bundled-plugins(启动于 09-21 00:55,早于该绑定上线)⇒ 必须让它走一次重启(步 1 的启用动作自带重启,即已满足)。
    • 实例在 106(worker) ⇒ 共享层缺该包(106 只有 _dsh-local_storyforge / dsh-plugin-mcn-suite)⇒ 启用会失败。已知缺口:跨节点内容分发无平台侧通路(投放线 §5-2 记为「需单独立项」)。临时办法(手工同步,沿用第 8 棒做法):
      ssh bt-server 'tar -C /var/lib/dshs/bundled-plugins -czf - _dsh-local_im-conversation-tabs' \
        | ssh test106 'tar -C /var/lib/dshs/bundled-plugins -xzf - && chown -R root:root /var/lib/dshs/bundled-plugins/_dsh-local_im-conversation-tabs'
      ssh bt-server 'cat /var/lib/dshs/bundled-plugins/.manifest.json' | ssh test106 'cat > /var/lib/dshs/bundled-plugins/.manifest.json'
      
      (第二条会整体覆盖 106 的 manifest ⇒ 执行前先比对两边内容,只差新增那一条才可覆盖。)
  2. ⚠️ admin 实例 profile 里有一条陈旧软链(node_modules/@dsh-local/storyforge,09-21 建立,但 dependencies / bundles 里都已无该项)—— 第 8 棒探针残留。本轮只报告未动(R7)。与本次取证无关。

五、回滚(任一步出问题)

目的 动作
只关插件(保留投放) 实例 → 设置 → 功能管理 → 关掉开关(平台自动 pnpm remove + 重启探活)
撤出用户面(停止发布) POST /api/plugins/business/share 的逆操作:DELETE /api/plugins/business/:id/share(⛔ 若仍有用户启用会被 409 挡下 —— 这是设计)
彻底下架 DELETE /api/plugins/business/%40dsh-local%2Fim-conversation-tabs(清池行 + tgz)
换回旧包 回滚素材 /opt/dsh/backups/plugins/_dsh-local_im-conversation-tabs/0.1.0.tgz

六、本单未做 / 未验(⛔ 不假装做了)

  1. ⛔ 未替用户点启用 —— 「启用」是用户动作(投放语义 = 用户自助开通),本单只把可自动部分做完。
  2. ⛔ 未做网关部署(选型单 §十五 的 gateway 侧部署)|⛔ 未接在线态取数(stats().presenceIngest='not-wired')—— 两项与本次投放解耦,排在再后。
  3. ⛔ 未同步 106 共享层 —— 见 §四-1,属「跨节点内容分发」立项面;本单给出命令但未执行(避免无谓的多机生产改动)。
  4. ⛔ 未 commit / push / scp 源码 | ⛔ 未改 poc/im-conversation-tabs/** 与 src/im/** 任何一行 | ⛔ 未引新依赖 | ⛔ 未铺 profile。