Files
dsh_ai1net_server/交付物/插件数据面取数口-真机验收与接线缺陷-20260925.md
T
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

170 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 插件数据面取数口 · **47 真机验收** + 抓出接线缺陷(2026-09-25 · 第 15 棒)
> **一句话**:把第 14 棒落地的「运行时取数口」部署到 47 并**真机跑通**(四拒一空 + 回读 **7/7 PASS**),
> 过程中抓出**一条会让取数口对全部插件失效的接线缺陷**(已修 + 已复验);
> 第 2 件(MCN 移动端视觉验收)**未通过 —— 前提不成立**:移动端修复落在**未投放的包**里。
> **归属线**:插件投放与分库线|**会话**:插件投放与分库线-第15棒|**交接单**:无(本棒为执行棒)
---
## 一、本轮做了什么
| # | 事项 | 结果 |
|---|---|---|
| 0 | 开工门禁 + 域锁 | preflight 判【D】2 个 → 归类后抢锁成功(域 `aliyun-dsh-server/接续入口_插件投放与分库线_20260922.md` + `aliyun-dsh-server/.workbuddy`) |
| 1 | 部署取数口到 47 | ✅ 5/5 md5 逐字一致 + `restart dshs` + 服务 active、门户 200 |
| 2 | 数据面取数**真机验收** | ✅ **7/7 PASS**(四拒 + 一空 + insert→find 回读;归属列真值直连核) |
| 3 | 抓出并修复**接线缺陷** | ✅ 已修 `src/web/routes/plugin-data.ts` + 重投 + 复验 |
| 4 | MCN 移动端视觉验收 | 🔴 **未通过 —— 前提不成立**(修复不在已投放的包里,详见 §五) |
| 5 | 夹具清理 | ✅ **零残留**(池 5 / 插件库 0 / 台账 0 / 会话 0 / tgz 已删) |
---
## 二、部署面证据(47 · `/opt/dshs`)
| 文件 | 47 与本地 md5 | 说明 |
|---|---|---|
| `lib/web/server.js` | `fcbbb9b3476499ba2d97841f0e6ebaed` | 与 47 原版**只差 7 行**(就是 `pluginDataRoutes` 的 import + `register` +注释)—— 已逐行 diff 确认 |
| `lib/db/plugin-data/runtime.js` | `45daf7c5b2b6163e3d1e1fd110dca36d` | 新增 |
| `lib/db/plugin-data/registry.js` | `44d3b5c424f7bc27a930454a945f6f06` | 新增 |
| `lib/web/routes/plugin-data.js` | `a03394088f4ad90e571d4b5ede7a5f95` → 修复后 `fac8f4dfe0d5710705de6d614275c77e` | 新增 → 修复 |
| `sdk/im-plugin-client/index.mjs` | `4a1a160156a90cc07696332fcc99d0cd` | 新增(落 `/opt/dshs/sdk/`) |
- **备份**:`/opt/dsh/backups/lib-p15/47-pre-p15-20260925-074345.tgz`(投放前)。
- **重启**:`systemctl restart dshs` → `active`、`NRestarts=0`、门户 `200`。
- **部署前先做了漂移比对**(避免把别的棒的东西带上线):`business-plugins.js` / `worker/agent.js` / `leased-spawner.js` / `config.js` 四件**与本地逐字一致** ⇒ 只投必要项。
- ⚠️ **106 未部署**(本轮范围 = 47;取数口是 Manager 侧路由 ⇒ 106 不影响本轮验收)。
---
## 三、真机验收读数(47 · 调用者 = `guest`,插件身份头 = 包名)
夹具 = 一次性探测包 `dsh-plugin-pdprobe`(user 域 + room 域各一表;声明过平台**真校验器** → `level=ok`)。
| 断言 | 期望 | 实测(HTTP 200 + 契约体) |
|---|---|---|
| ① 写他人 `user_id` | 拒 | `ok:false, reason:bad-args`,detail=`不得写入他人的 user_id(归属列由内核注入)` |
| ② room 表缺 `room_id` | 拒 | `ok:false, reason:bad-args`,detail=`房间维度表必须带 room_id` |
| ③ 缺主键列 | 拒 | `ok:false, reason:bad-args`,detail=`缺少主键列「probe_key」(它是本表的行标识)` |
| ④ 带 `created_at` | 拒 | `ok:false, reason:bad-args`,detail=`审计列「created_at」由内核维护,⛔ 不可自写` |
| ⑤ 非成员读 room 表 | **0 行** | `ok:true`,`value:[]` ⇒ **0 行** |
| ⑥ `insert` 正常行 | ok | `ok:true` |
| ⑦ `find` 回读一致 | 1 行且字段一致 | `ok:true`,`value` 1 行,`note='v1'`、`payload={a:1}` |
**归属注入直连核**(不靠响应自证):`p_dsh_plugin_pdprobe_probe_user.user_id` **全部等于**
调用者本人 `4092b965-…`;`probe_room` 行数 = **0**。
**DDL 侧证**(迁移回显):`PRIMARY KEY ("user_id", "probe_key")` ⇒ **`id` = 声明第一列**、`归属列 + 第一列` 复合键
(无代理自增 id)—— 与 `DB-03 §五` 口径一致,**首次在真机上被看见**。
**对照**(负例):给**无声明**的真插件取数 ⇒ `409 plugin-data-unavailable / no-declaration`(不是 500,不是"假装成功")。
---
## 四、🔴 抓出的接线缺陷(P0 级 · 已修 + 已复验)
**现象**:库建好(`state=ready`)、插件身份头合法、鉴权通过 —— 但取数一律
`409 no-declaration`:`插件「dsh_plugin_pdprobe」不在候选池或包内无数据面声明`。
**根因(两个名字空间被混用)**:
| 名字空间 | 取值 | 谁在用 |
|---|---|---|
| **池键 / 台账键** | **原始包名**:`dsh-plugin-pdprobe`、`@dsh-local/storyforge` | `business_plugins.id`、`plugin_datastores.plugin_id`(建库口、门户都用它) |
| **`pluginId`(归一化)** | 去 scope + 下划线化:`dsh_plugin_pdprobe` | `pluginIdOf()`;用于**算库名/表名前缀** |
取数口把**归一化后的 id** 交给了 `PluginDataRegistry`,而 registry 内部拿这个值去
`findBusinessPlugin` / `findPluginDatastore` **精确查**这两张表 ⇒ **永远查不到** ⇒
**任何插件**调取数口都只会得到 `no-declaration`(不是这一个夹具的问题)。
**为什么单测没抓到**:`test/plugin-data-runtime.test.mjs` 用**假执行器**,直接构造声明对象,
**绕过了路由层的 id 归一化** ⇒ 这条路径只有在真机上才会被走到。
**修法(最小)**:`src/web/routes/plugin-data.ts` 两处
- `resolvePluginPort`:`pluginId: pluginIdOf(pkgName)` → `pluginId: pkgName`(原始包名)
- `/plugin-data/status`:查表用原始包名,**对外仍回归一化 `pluginId`**(响应契约不变)
**复验**:`npm run build` rc=0|`node --test test/plugin-data-runtime.test.mjs test/im-plugin-client.test.mjs` → **24/24 过**
|重投 + 重启 → **7/7 PASS**(同 §三)。
> ⛔ **未 commit / 未 push**(遵守本棒约束);改动留在 `D:/github/dsh_shenxian` 工作树(`plugin-data.ts`)。
---
## 五、🔴 第 2 件(MCN 移动端视觉验收)—— **未通过:前提不成立**
**验收目标**(入口 §2 原文):`D:/dshworkspace/plugin_package/dsh-plugin-mcn/lib/client.js` 的 `mcn-mobile`
样式段 → 375×667 下工作台独占、能退出、无横向溢出、聚焦不缩放、横屏可用。
**真机取证(为什么做不了)**:
| 检查 | 结果 |
|---|---|
| 线上**真身**是哪个包 | 池与共享层里的都是 **`dsh-plugin-mcn-suite` v0.3.13**(`/var/lib/dshs/bundled-plugins/dsh-plugin-mcn-suite`) |
| 该真身含修复吗 | **否** —— `lib/client.js` 里 `mcn-mobile` 命中数 = **0**(`mcnNav_split` = 4) |
| 本地 suite 含修复吗 | **否** —— 本地 `dsh-plugin-mcn-suite/lib/client.js`(0.3.13 · mtime 09-20 22:12)`mcn-mobile` = **0** |
| 修复改在哪个包 | `dsh-plugin-mcn` **v0.1.0**(本地 `lib/client.js` mtime 09-25 05:18)—— 该包**从未投放** |
⇒ **移动端修复改在了「不是线上真身」的包里**。所以"重投插件 + 实例重启"**无从生效**:
线上跑的一直是 suite,它里面没有这段样式。**故本件不做视觉验收,也不宣称通过**(无真机读数不得宣称)。
**整改路径(可机械执行 —— 已核对可移植性)**:
`mcn-mobile` 段是一段**运行时注入的 `<style>`**(`document.head.appendChild`,`data-plugin-css="mcn-mobile"`),
选择器全部是 `.mcnNav_*` / `vvModal` 族。已逐个核对它在 suite 里的存在性:
| `.mcnNav_split` | `.mcnNav_panel` | `.mcnNav_resizer` | `.mcnNav_close` | `.mcnNav_btn` | `.mcnNav_mask` | `.mcnNav_modal` | `.mcnNav_stats` | `.mcnNav_input` | `vvModal` |
|---|---|---|---|---|---|---|---|---|---|
| 4 | 3 | 3 | 2 | 12 | 3 | 10 | 2 | 2 | 2 |
⇒ **类名齐备 ⇒ 可整段平移**(把同一段注入进 suite 的 `lib/client.js`,`dataset.plugin` 改成 suite 名)。
⚠️ 重投前**必须先验**本地 suite 与线上 suite 逐字一致(否则会把别的漂移一起发出去);
⚠️ 版本要自增(`0.3.13` → `0.3.14`)并同步 `lib/skills-installer.js` 的 `SUITE_VERSION` 与 `skills/.manifest.json`(该包「版本号唯一真源」口径)。
---
## 六、第 3 件(可选 · MCN 数据面接入改造)—— **未做**
超本轮范围(`lib/db.js` 红线扫描 21 处、且须「先建库再投放」)。按入口 §2 的口径**留给后续棒**。
---
## 七、清理与零残留(夹具全清)
| 项 | 清理后读数 |
|---|---|
| 候选池 | **5**(回到原值,夹具行 0) |
| 插件库 `dshs_pl_*` | **0** |
| `plugin_datastores` | **0** |
| `plugin_data_audit`(夹具) | **0** |
| 临时会话(`poc-curl2`) | **0** |
| 夹具 tgz / 备份目录 | **已删** |
| 服务 | `active` |
⚠️ 夹具在池内存活约 **2 分钟**(`07:56–07:59` 量级),期间登录用户理论上可在「功能管理」看到它 ——
已删除,无残留。**这是本轮唯一一处对线上可见面的临时触碰**,主动记录。
---
## 八、未闭环 / 下一棒
1. 🔴 **MCN 移动端修复的「迁包 + 重投 + 375×667 视觉验收」**(见 §五)—— 本线唯一排定的下一棒。
2. **跨节点形态**:worker 上的实例 → Manager 侧数据面仍缺「实例→控制面」身份通道
(本轮验收是**同机/本机**形态)⇒ 属既有缺口(`DB-03 §六` 自认),未动。
3. **106 未部署**本轮产物(Manager 侧路由,不影响本轮验收)。
## 九、可复现命令
```bash
# 部署(三件产物 + server.js)
scp lib/web/server.js bt-server:/opt/dshs/lib/web/server.js
scp lib/db/plugin-data/{runtime,registry}.js bt-server:/opt/dshs/lib/db/plugin-data/
scp lib/web/routes/plugin-data.js bt-server:/opt/dshs/lib/web/routes/
ssh bt-server 'systemctl restart dshs'
# 验收(夹具搭建 + 7 条断言 + 零残留清理)
scp tmp/15棒-夹具/dsh-plugin-pdprobe-0.0.1.tgz bt-server:/var/lib/dshs/business-plugins/
scp tmp/15棒-夹具/pd-probe-47b.mjs bt-server:/tmp/ # 或第 15 棒工作区 tmp/15棒-夹具/
ssh bt-server '/usr/local/bin/node /tmp/pd-probe-47b.mjs'
ssh bt-server 'bash -s' < tmp/15棒-夹具/remote-cleanup.sh
```