Files
dsh_ai1net_server/docs/交接单/接续包_IM接入面收尾与插件对接答复_20260926.md
T
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

15 KiB
Raw Blame History

接续包 · IM 线 · 2026-09-26 00:32

接续点 · IM 线(插件接入面收尾 + 文档 + 对接答复) · 2026-09-26 00:32

  • 来源会话: 本会话(阿里云 dsh 平台开发会话) | 结束原因: 上下文 32.8 万强制收口

  • 原目标(用户本轮原话,不翻译、不缩写):

    1. 「创建接续会话把IM的改造优化处理完成」
    2. 「然后更新IM接入文档」
    3. 「并回复插件的对接文档」
  • 基线: HEAD=e6207aa(D:/github/dsh_shenxian,未 commit) | 远端 master = 未核(本会话未 push) | 域锁 = 无(已释放)

  • 产物(新会话必须逐一确认存在):

    • 代码面(D:/github/dsh_shenxian):src/im/sdk/types.ts(+206)· src/im/sdk/host.ts(+362)· src/im/sdk/binding.ts(新) · src/im/sdk/registry.ts(新) · src/im/sdk/index.ts · src/im/hub.ts(+36)· src/im/ws.ts(+84/−1)· src/web/routes/im.ts(+368)· sdk/im-plugin-host/index.mjs(新) + package.json
    • 测试(新):test/im-plugin-bridge.test.mjs(14 例)· test/im-backpressure.test.mjs(8 例)
    • 文档库(D:/github/dsh_shenxian/dsh-server-docs):01-规范/09-IM插件SDK与扩展点契约.md(§2 加第 8 项 · §3.5 接线器 · §6 修事务口径 · §8 判据四档 · §9 出向端口 · §10 跨进程接入 · §11 投递可靠性与容量)· 01-规范/08-插件开发与对接规范.md(修路由指针 + SDK 获取 + 09 指针 + §11 变更记录)
    • 评估/交付件(本工作区 交付物/):IM插件接入面-20260925.md · IM插件接入完备性审计-20260925.md · 用户组网群聊可行性评估-20260925.md · 端口与容量瓶颈评估-20260925.md · 端口决策与设备中继可行性-20260926.md · 扇出背压修复-20260926.md
  • 校验命令: cd /d/github/dsh_shenxian && npm run build && node --test test/im-plugin-bridge.test.mjs test/im-backpressure.test.mjs 2>&1 | tail -5 → 期望输出: 两个文件合计 22 例、fail 0(bridge 14 + backpressure 8)

  • 未完成(用户要的、还没做的 —— 优先于 AI 自己加的收尾):

    ✅ 本棒(「IM接入面收尾-20260926」· 2026-09-26 00:38–01:0x)收口状态

    已完成

    • 1-① 端到端真跑 ✅(真起平台 + 真 HTTP + 插件侧 SDK 走 5 端点): 脚本 tmp/im-bridge-e2e-20260926.mjs,23 例 / fail 0。⇒ 跑法 cd /d/github/dsh_shenxian && node <脚本绝对路径>。
    • 1-② 部署到 47 ✅:推 lib/im/** + lib/web/routes/im.js + sdk/**(⛔ 未带别的线的未部署改动)。 47 侧备份 /opt/dsh/backups/im-bridge-predeploy-20260926.tgz;重启 dshs = active; /api/im/plugins/bridge 与 /api/im/stats 均 401(= 路由已加载,非 404)。 ⚠️ 落地文件属主:tar 会保留本地 uid ⇒ 47 上新文件曾变 197108,已 chown -R root:root 修回。 (⛔ 下棒再推时给 tar 加 --owner=root --group=root,或推完立刻 chown。) ⚠️ 47 上另有先前就存在的非 root 文件(lib/web/routes/business-plugins.js、admin.js、 essential-plugins.js 等)——非本棒落地、未动,仅登记。 ⛔ 106 未部署(IM 宿主在 Manager 进程,Worker 不带 IM 路由)⇒ 按需为「不需要」。
    • 3 更新 IM 接入文档 ✅(部分):09 新增 §12 插件作者快速上手(五步 + 可跑片段 + 能做/不能做 + 四个必知坑 + 反向通道降级三条)。⛔ 未动任何已落章节(§2–§11 一字未改)。 ❌ 仍缺:可跑的最小示例工程(poc/business-plugins-im/ 三例仍是旧契约)。
    • 4 插件对接答复件 ✅:本工作区 交付物/插件对接答复件-20260926.md(⛔ 未改 dsh-plugin-partment 一字节)。

    🔴 本棒抓出并修掉一个真缺陷(新增,不在原接续包内)

    • 症状:插件走完登记后 frame() / say() 恒 plugin-unavailable。
    • 根因:routes/im.ts 的 bridgeAuth 把请求头里的包名(@dsh-local/im-plugin-demo) 直接当内部 id 去查注册表,而注册表按 pluginIdOf(包名)(im_plugin_demo)存 ⇒ 恒查不到。 ⇒ 出向面在生产上不可达(第 8 项等于白做)。
    • 为什么单测没抓到:test/im-plugin-bridge.test.mjs 刻意不碰真实网络(mock fetch + 直接把归一化 id 递给注册表)⇒ 从不经过这一层翻译。只有真 HTTP 才暴露。
    • 修法:bridgeAuth 现同时交 packageName(供"头与清单自洽"判)与 pluginId (供注册表查);两处 outboundPortFor 改用 auth.pluginId。改动仅限 routes/im.ts (内核四档不变:store.ts 零改动 / hub.ts 纯插入 / ws.ts 只动投递点 / routes/im.ts 纯插入 —— 本次属"修 bug"那类,故允许动既有逻辑,须有回归证据)。
    • ⚠️ 回归证据未入库:现为 tmp/ 脚本(接续包原口径即"临时脚本落 tmp/")。 若要永久回归⇒ 下棒需把它落成 test/im-plugin-bridge-e2e.test.mjs + 在 package.json 的 test/verify 各登记 1 处(A=B 各 1 行,⛔ 用 Edit 精确替换)。

    ⛔ 仍未完成(下棒依据)

    • 1-③ 生产标定背压阈值 ❌ 未做(缺真实读数):/api/im/stats 现为 401(admin 专属), 无 admin 会话读不到 peakPendingBytes;且当前无真实流量 ⇒ 读数恒 0,改了也是拍脑袋。 ⇒ 阈值保持 4 MiB 不变(保守起点),改参数入口已就绪(IM_SEND_BUFFER_LIMIT_BYTES,可注入)。 标定法(拿到 admin 会话或真实流量后照做):连读 GET /api/im/stats 的 peakPendingBytes 一段时间, 取其分位值作为阈值下限,改 drop-in 环境变量 → systemctl restart dshs(⛔ 不改代码)。
    • 2 反向通道 —— 🔴 2026-09-26 用户已拍板:必须补、且要做完整 (原话「都需要实现完整,才能让插件接入,否则两边都要返工」)。 本棒据此改了 09 §10.4 / §10.5 / §12.5 的口径(从"本期不支持"→"已定必须补")+ 同步 交付物/IM插件跨进程桥-20260925.md §5/§6 与 交付物/插件对接答复件-20260926.md, 并产出施工规格 接续包_IM反向通道实现_20260926.md。 ⚠️ 实现交执行棒(本棒受会话预算限制,⛔ 未动任何代码);⛔ 原文"不许拍成已定"的禁令至此解除 —— 因为是用户本人拍的,不是新会话替原会话拍的。
    • §1 对接单未消的 4 条(纯文档):#2 表声明入口(P1,需先定口径) · #4 移动端 · #5 错误码/自测清单/变更记录 · #8 内部编号 107/108。 ⚠️ 接续包原记「P1×2 已消」不准:实测 #1 已消、#2 未消(09 §4 仍有 tables: [{ 且全篇无 dsh.data.schema)。
    1. 🔴 IM 改造的收尾三件(= 用户「处理完成」的落地口径,按序): ① 端到端真跑验收 —— 桥的 5 个端点(/api/im/plugins/{register,unregister,out/frame,out/message,bridge})只过了单测,从未真跑;需在本机起平台+用 sdk/im-plugin-host 走一遍真 HTTP。 ② 部署到 47(+按需 106) —— 本机代码面完成,生产未部署(R8:开发环境服务器,动手前一句话说明即可)。 ③ 生产标定背压阈值 —— 现为保守起点 4 MiB;观测面 GET /api/im/stats 的 peakPendingBytes 拿到真实读数后改参数(⛔ 不改代码)。
    2. 🔴 **「反向通道」是否补 —— ⛔ 属待用户拍板,不许新会话替原会话拍成「已定」:
      • 现状:「插件单向发起」已通(登记 / 读 / 出向);「平台回头叫插件」未通(speakRules.check 发言规则、events.onEvent 事件回调)。
      • 原会话判断(可推翻):「不必急着补」—— 已有降级三条(规则参数写房间 config / 出向主动纠偏 / host.subscribe() 轮询替代事件回调,后者已实测够用)。
      • 若要补 ⇒ 需要平台 → 实例的反向调用面(含鉴权、超时、实例可寻址性),是新工作量。
    3. 更新 IM 接入文档(用户第 2 件事):09 已更新到 §11,但缺一份「插件作者快速上手」 —— 现在用法散在 §10.3,且没有可跑的最小示例工程(poc/business-plugins-im/ 三个示例是旧契约,未含第 8 项出向与跨进程桥)。
    4. 回复插件对接文档(用户第 3 件事):即 E:/ProgramData/AIProject/dsh-plugin-partment/对接单_平台侧-IM板块待优化与Macro改造可行性_20260925.md。⚠️ 那是别的工作区 ⇒ ⛔ 只能在本工作区产出「平台侧答复件」,由用户转交,⛔ 不得直接改那边一个字节。答复要覆盖:§1 九条(P1×2 + P2×3 已消,P2×2 + P3×2 待定)+ §2 Macro 改造可行性(第 8 项出向端口已具备,§2-3-1 高频广播已解决:frame 档不落库)+ §4 两个待拍板项的平台侧回答。
  • 下一步(第 1 个动作 = 具体命令):

    1. 先跑校验命令(见上)—— 不符即停、只报告。
    2. 读 交付物/IM插件跨进程桥-20260925.md 与 交付物/扇出背压修复-20260926.md(本会话两份最新落地件,含未完成项与设计取舍)。
    3. 端到端真跑(未完成 1-①):本机起平台(DSH_IM_WS 默认开)→ 写一个临时脚本用 sdk/im-plugin-host 的 createImPluginHost() 走 register → frame → say → 断言 ok:true(临时脚本一律落 tmp/,⛔ 不入库)。
    4. 部署(未完成 1-②)→ 标定(1-③)→ 文档(3)→ 答复件(4)。
    5. ✅ 未完成 2(反向通道)—— 用户已表态(2026-09-26:必须补、做完整)⇒ 下棒依据改为 接续包_IM反向通道实现_20260926.md(⛔ 不再是"先不碰")。
  • 关键决定(已定项 + 为什么 —— 防新会话推翻重来): ① 🔴 插件跑在「用户实例内」、IM 宿主在「平台进程」⇒ 跨进程 —— 依据:用户自配模型是起实例时写进实例的(credential_vault → spawn 写 settings.yaml),平台侧拿不到 ⇒ 插件必须在实例内。 ② 桥 = 插件「拨出」而非平台「打进」 —— 符合既有"拨出式"纪律(09 §2-6:⛔ 插件不开监听端口),且断连可退化为普通聊天。 ③ 登记只收「声明面」 —— check/onEvent/render/onAction 是函数、跨不了进程;函数侧回调留在实例内。 ④ 出向发言多一道闸 —— bot 必须是该房成员(同进程时必然成立,跨进程必须自己查);未注入成员判定 ⇒ fail-closed 拒。 ⑤ 🔴 背压:慢客户端不虚减 delivered —— write() 返回 false = 水位满(数据已排队、会送达)⇒ 若记成丢帧会污染观测。若用户要"慢客户端单独计 skipped"⇒ 是语义变更、需重新拍板。 ⑥ 判据分两类(已写进 09 §8):新增能力 ⇒ 纯插入;修 bug ⇒ 可改既有逻辑,但须「回归用例 + 新行为可观测 + 阈值可注入」。内核四档:store.ts 零改动 / hub.ts 纯插入 / ws.ts 允许改但被删行只限投递点 / routes/im.ts 纯插入。 ⑦ 端口 D8 = 用户拍板「先不开,后续有需要再开」(09-26)⇒ ⛔ 不当待办、⛔ 不催;群聊全走 443 中继,功能完整。 ⑧ 设备当中继:路径已存在(桌面端节点接入已实测),但中继方需"别人能连到它"=用户侧 NAT 门槛;推荐替代 = 设备主动拉(⛔ 不需任何端口)。⛔ 未排期。

  • 回滚点:D:/github/dsh_shenxian HEAD=e6207aa(本会话全部改动未 commit ⇒ git checkout -- <file> 即可回到干净基线);dsh-server-docs 同理;部署前须另做 47 侧备份(/opt/dsh/backups/)。

  • ⛔ 不要重做:

    • 扩展点第 8 项(出向端口)+ 面板动作 + 分片工具(types/host 已落,22 例测试覆盖)
    • 跨进程桥平台侧(registry.ts + 5 端点 + bridgeAuth)
    • 插件侧 SDK(sdk/im-plugin-host/index.mjs)
    • 背压修复(ws.ts 1 行改写 + hub.ts 计数 + 8 例)
    • 两处规范文档(09 已到 §11;08 已修指针)—— 只补「快速上手」,⛔ 不重写已落章节

§A 本轮(原会话)做了什么 —— 一句话

把「IM 基础」从插件接不进来改造成双向可接入:① 补出向出口(扩展点 8)② 补跨进程桥(登记 / 出向,插件侧 SDK 齐备)③ 修扇出背压隐患;并把两处规范同步到 §11。

§B 判据读数(原会话实测,供新会话对照基线)

  • npm run build rc=0
  • npm test = 626 / 616 过 / 5 败 / 5 跳过 —— ⚠️ 5 败是既有环境问题(投放线 test/shared-layer-sync.test.mjs 的 spawnSync tar EBUSY),与本线无关,⛔ 不要去修它(属投放线 lane)
  • 本线专项:test/im-plugin-bridge.test.mjs 14/14 · test/im-backpressure.test.mjs 8/8 · test/im-sdk.test.mjs 78/75 过 / 3 跳过(跳过 = spawnSync git EBUSY,已改具名跳过)
  • npm run check:layering rc=0 ✅ 无新增违规
  • 内核改动形态:src/im/store.ts 零改动;ws.ts 被删改的既有行只有 1 行(socket.write(textFrame(text)),正是背压修复点)

§C 工具纪律(本线踩过的)

  • ⚠️ 测试跑的是 lib/ 编译产物 ⇒ 改完必 npm run build(原会话踩过:hub.ts 新、ws.ts 旧混跑 ⇒ 症状像"注入无效",浪费两轮)。定位法 = 打印两个独立观测点(注入值 ✅ 但计数为 0 ⇒ 走的是旧代码)。
  • ⚠️ 本机 spawnSync git|tar EBUSY 会让测试假失败 ⇒ 取证类用例改 t.skip 具名跳过。
  • 🔴 改 package.json 一律用 Edit 精确替换,⛔ 不用「读-改-写整个 JSON」(会重排格式)。原会话实测侥幸未炸,但那是运气。
  • 🔴 (「接续包 md5」口径门禁)开工前重算 md5 与 prompt 里的一致才开工;不一致 ⇒ 停手报告。