176 lines
12 KiB
Markdown
176 lines
12 KiB
Markdown
# 移动端修复「迁包 → 重投 47/106」+ 真机视觉验收(第 16 棒)
|
||||
|
|
|
|||
|
|
> **工作区**:`E:/ProgramData/AIProject/aliyun-dsh-server`|**线**:插件投放与分库线|**日期**:2026-09-25
|
|||
|
|
> **依据**:`接续入口_插件投放与分库线_20260922.md §2「🎯 本轮动作(第 16 棒)」`
|
|||
|
|
> ⛔ 本棒未 commit / push;⛔ 未改 `src/web/routes/im.ts`;⛔ 未做 MCN 数据面接入改造。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、结论(先说判定)
|
|||
|
|
|
|||
|
|
| 件 | 判定 | 一句话 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 第 1 件 · 迁包 | ✅ **完成** | `mcn-mobile` 样式段已从**从未投放**的 `dsh-plugin-mcn` v0.1.0 整段平移进**线上真身** `dsh-plugin-mcn-suite`,38 个引用类名在目标包内**齐备 0 缺** |
|
|||
|
|
| 第 2 件 · 版本自增+重投 47/106 | ✅ **完成** | 0.3.13 → **0.3.14**;**47 + 106 共享层双双为 0.3.14**(106 由节点拉取机制一轮收敛);池内候选同步、回滚素材在位 |
|
|||
|
|
| 第 3 件 · 375×667 真机视觉验收 | ❌ **未通过(未取到真机读数)** | **不是代码问题,是链路上游断了**:已启用用户的实例仍指向**旧副本**,而平台的「重装配」操作**稳定失败**(两次复现)。⛔ 未宣称通过 |
|
|||
|
|
|
|||
|
|
🔴 **本轮最重要的产出 = 一条可复现的新缺陷**:**共享层更新对「已启用」的用户不生效,且平台没有可用的补救路径** —— 详见 §四。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、第 1 件 · 迁包(逐字平移,只改包名一处)
|
|||
|
|
|
|||
|
|
| 项 | 值 |
|
|||
|
|
|---|---|
|
|||
|
|
| 源 | `D:/dshworkspace/plugin_package/dsh-plugin-mcn/lib/client.js` 第 216–268 行(`//#region 移动端 / 窄屏兼容`) |
|
|||
|
|
| 目标 | `D:/dshworkspace/plugin_package/dsh-plugin-mcn-suite/lib/client.js`(插在 `var McnNav_module_css_default` 之前) |
|
|||
|
|
| 改动 | 仅 1 处:`el3.dataset.plugin = "dsh-plugin-mcn"` → **`"dsh-plugin-mcn-suite"`** |
|
|||
|
|
| 体量 | 段 3642 B / 53 行 → 剥行尾后 **3595 B**;目标 401936 → **405531 B** |
|
|||
|
|
| 语法 | `node --check` **OK**(Node 22.22.2) |
|
|||
|
|
|
|||
|
|
**三条自证**(脚本 `tmp/p16-port-mobile-20260925.py`,可重跑):
|
|||
|
|
|
|||
|
|
1. **类名齐备**:段内引用类名 **38 个**,目标包内缺失 **0 个** ⇒ 第 15 棒的"可移植性核对表"在**字节级**上被独立复核。
|
|||
|
|
2. **行尾一致**:源段是 **CRLF**、目标包是**纯 LF** ⇒ 已归一(产物 CR = 0)。⚠️ 首版没做归一,产物混入 53 个 CR,**已回滚重做**。
|
|||
|
|
3. **幂等**:目标已含 `data-plugin-css="mcn-mobile"` ⇒ 脚本直接 SKIP。
|
|||
|
|
4. **可回滚**:改前副本 `tmp/p16-backup-20260925/dsh-plugin-mcn-suite-client.js.bak`(401936 B)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、第 2 件 · 版本自增与重投(47 + 106)
|
|||
|
|
|
|||
|
|
### 3.1 重投前对账("别把别的漂移一起发出去")
|
|||
|
|
|
|||
|
|
**改前副本 md5 = `0955f6b8b70f0c1357d29395643fdeb6` = 47 共享层线上 `lib/client.js` md5** ⇒ 本地 suite ≡ 线上真身,**逐字无漂移**。
|
|||
|
|
|
|||
|
|
全包逐文件比对(323 项,按路径建索引,排除 `node_modules`):
|
|||
|
|
|
|||
|
|
| 差异 | 内容 |
|
|||
|
|
|---|---|
|
|||
|
|
| 内容不同 | **仅 `lib/client.js`**(就是本棒的改动) |
|
|||
|
|
| 仅本地 / 仅线上 | `tests/smoke.mjs`(本地有、不进包)/`pnpm-lock.yaml`(服务端安装时生成) |
|
|||
|
|
|
|||
|
|
⇒ **漂移面 = 1 个文件且是本棒的预期改动**。
|
|||
|
|
|
|||
|
|
### 3.2 打包(以池内 tgz 为基底,只替换 3 个文件)
|
|||
|
|
|
|||
|
|
| 项 | 值 |
|
|||
|
|
|---|---|
|
|||
|
|
| 基底 | `/var/lib/dshs/business-plugins/dsh-plugin-mcn-suite.tgz`(1989680 B,322 文件,顶层 `package/`) |
|
|||
|
|
| 新包 | `tmp/p16-pool/dsh-plugin-mcn-suite-0.3.14.tgz`(**1982036 B,322 文件**) |
|
|||
|
|
| sha256 | `3ca65153605b3c48f7de628d4754dc872b6f4fb7b617e9e57e704eb90bbab61c` |
|
|||
|
|
| 新旧差异 | **只差 3 个文件**:`package/lib/client.js`、`package/package.json`、`package/skills/.manifest.json`;**零增删** |
|
|||
|
|
|
|||
|
|
版本自增两处(该包「版本号唯一真源 = `package.json`」,`SUITE_VERSION` 由运行时读它 ⇒ 无字面量可改):
|
|||
|
|
`package.json` `version` → `0.3.14`(+ 变更史前置一条)|`skills/.manifest.json` → `suite: …@0.3.14`、技能 `version: 0.3.14`。
|
|||
|
|
⚠️ `files/bytes/sha256` 三项**未动**(技能载荷未变,只动版本字段)。
|
|||
|
|
🔴 **行尾坑(本棒第二次踩)**:Windows 上用 Python 写文本默认把 `\n` 转成 `\r\n` ⇒ 首版把 CRLF 写进了 `package.json` 与清单,**已回滚重做**(写时显式 `newline="\n"`,产物 CR = 0)。
|
|||
|
|
|
|||
|
|
### 3.3 上传递交(走平台正规口,非手改文件)
|
|||
|
|
|
|||
|
|
`POST /api/plugins/business`(admin 会话)→ **http=200**:`version 0.3.14`、`replaced: true`、`trustedOverride: false`、
|
|||
|
|
兼容性裁决 `level: ok`(`platformPkgs 240`、`sawPlatformRef true`);安全检测**只出 warning 未拦**(`[email protected]` / `network-egress@lib/client.js` / …)。
|
|||
|
|
|
|||
|
|
### 3.4 铺共享层(两段式:先预演、后确认)
|
|||
|
|
|
|||
|
|
* 预演(`confirm` 缺省)→ `conflict: true`,并**顺带暴露一条台账缺陷**(见 §四 P2)。
|
|||
|
|
* 确认 → `action: "replaced"`、`version 0.3.14`、`fileCount 657`、新 `treeSha256 f414df79…`、
|
|||
|
|
回滚素材 `/opt/dsh/backups/plugins/dsh-plugin-mcn-suite/0.3.14.tgz`。
|
|||
|
|
|
|||
|
|
**47 实况复核**:`lib/client.js` md5 = `d387089bd28c91cdbe46056e21288cbd`(= 本地新文件)、`mcn-mobile` 命中 **2 处**、`package.json` = 0.3.14、文件数 **657**(含 `pnpm install --prod` 重建的 `node_modules`)。
|
|||
|
|
|
|||
|
|
### 3.5 106 同步(走节点拉取机制,非手工 scp)
|
|||
|
|
|
|||
|
|
106 上手动触发一轮:`POST http://127.0.0.1:19000/shared-layer/pull`(带 `x-dsh-agent-token`)
|
|||
|
|
→ `{"stale":["dsh-plugin-mcn-suite"],"pulled":["dsh-plugin-mcn-suite"],"failed":[]}`
|
|||
|
|
→ 106 盘上 **0.3.13 → 0.3.14**、`client.js` md5 = `d387089…`。**一轮收敛**。
|
|||
|
|
|
|||
|
|
### 3.6 回滚
|
|||
|
|
|
|||
|
|
| 素材 | 位置 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 上一版(内容 = 0.3.13) | 47 `/opt/dsh/backups/plugins/dsh-plugin-mcn-suite/0.3.9.tgz`(md5 `f47a07b9a2a889770e35315e22156e90`) | ⚠️ **文件名叫 0.3.9、内容是 0.3.13**(见 §四 P2) |
|
|||
|
|
| 本棒投出的版本 | 同上目录 `0.3.14.tgz` | 内容是**新**包(share 时补落的语义错位,见 §四 P2) |
|
|||
|
|
| 回滚动作 | 用上一版 tgz 重走上传递交 + `POST /api/plugins/business/share {confirm:true}` | 共享层目录被整体替换 ⇒ 指向它的用户下一次 reconcile 生效 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、抓出的缺陷(⛔ 均未擅自修,按纪律只报告)
|
|||
|
|
|
|||
|
|
### 🔴 P0 —— 已启用插件拿不到共享层新版本,且平台无可用补救路径
|
|||
|
|
|
|||
|
|
**判据链(全部可复现)**:
|
|||
|
|
|
|||
|
|
1. **实例依赖形态**:admin 实例 profile 的 `dsh-plugin-mcn-suite` 声明为
|
|||
|
|
`file:/var/lib/dshs/users/cce6d1cd-…/home/.dsh-stage/dsh-plugin-mcn-suite.tgz`
|
|||
|
|
—— 是**一份 `.dsh-stage` 副本**(1989680 B = 旧版内容,09-20),**与共享层无关**。
|
|||
|
|
⇒ **共享层升到 0.3.14 对它零影响**,这与第 15 棒"修复落在没投放的包里"是**同一病根的下一层**。
|
|||
|
|
2. **正规补救路径 = 关掉再开**(`apply` 是全量裁决:已启用的项再发 `enabled:true` 判 `noop`,不会重装配)。
|
|||
|
|
3. **该路径稳定失败**:两次全量「关闭」均返回 `taskId`,各约 **52 s** 后 `{"status":"failed","stage":"失败","error":"安装失败,请重试或联系管理员"}`:
|
|||
|
|
* 任务 `0df1ea39ed3026c4`(08:32:38 → 08:33:30)
|
|||
|
|
* 任务 `3eb4b72b73373e07`(08:34:42 → 08:35:34)
|
|||
|
|
`/mine` 复核**仍为 `enabled: true`** ⇒ 平台**没有**把用户切到新版本的可用手段。
|
|||
|
|
⚠️ 已核实**不是**"暂存包缺失"(4 个 `.dsh-stage` 包全部在位)。
|
|||
|
|
4. **失败原因不可观测(第二条缺陷)**:`journalctl -u dshs` 在失败时段**只打了 HTTP 请求行**,pnpm 的 stderr / 装配失败原因**未落任何日志** ⇒ 用户与运维都只能看到"请重试",**无法定位**。本棒的根因**因此未能定位**。
|
|||
|
|
|
|||
|
|
**影响面**:凡是**已经启用**过某插件的用户,都停留在启用当时那份副本上 ⇒ 平台的「插件更新」对存量用户**不成立**;共享层只对"新启用"的用户有效。这条直接命中本线目标 P2("插件更新的情形要有定义")。
|
|||
|
|
|
|||
|
|
**建议落点(下一棒)**:① 给 `applyPlugins` 的 pnpm 失败路径补**可观测性**(stderr 落日志 + 失败原因回传到任务对象);② 定位失败根因(候选:47 的 egress 护栏挡住了平台自身的 registry 解析 / pnpm store 锁竞争);③ 重装配要能把 `file:` 形态换成 `link:`。
|
|||
|
|
|
|||
|
|
### 🟡 P1 —— 移动端真机视觉验收**仍未取得**(第 15 棒遗留,本棒被上面那条挡住)
|
|||
|
|
|
|||
|
|
**"能不能真渲染"这件事本棒已做成判定,且结论是"能"**:
|
|||
|
|
|
|||
|
|
| 探针 | 读数 |
|
|||
|
|
|---|---|
|
|||
|
|
| 47 侧浏览器 | ❌ 无(`chromium/chrome/firefox` 全无、无 playwright/puppeteer 缓存) |
|
|||
|
|
| **本机侧浏览器** | ✅ **有**:`C:/Program Files/Google/Chrome/Application/chrome.exe`(真 Chromium 内核) |
|
|||
|
|
| 平台门户 | ✅ `https://ai1net.com/portal.html` → 200 |
|
|||
|
|
| 实例 UI | ✅ `https://ai1net.com/u/<uid>/dsh/` → **200**,且平台**自动下发实例凭据** `Set-Cookie: dsh-auth-…` |
|
|||
|
|
| 实例地址 | `https://admin.ai1net.com/?token=…`(`/api/dsh/status` 直出,可直接作为渲染入口) |
|
|||
|
|
|
|||
|
|
⇒ **路径已通,只差"实例上跑的是新版本"这一步**。修好 P0 即可直接补做五条读数(无需再做任何环境建设)。
|
|||
|
|
|
|||
|
|
### 🟡 P2 —— 共享层清单与磁盘不同步 + 回滚素材命名语义错
|
|||
|
|
|
|||
|
|
* **清单 vs 盘**:本次预演读到的清单是 `version: "0.3.9"`、`tgzSha256 d14cd5fe…`、`treeSha256 cb1c73fb…`,而**盘上实际是 0.3.13 内容**(`package.json version = 0.3.13`、`client.js` md5 与池内 0.3.13 tgz 一致)。
|
|||
|
|
⇒ `authoritativeShared()` 拿这份 `treeSha256` 做节点对账 ⇒ **节点会永远判 `stale` / 反复重拉**。本棒 put 新版本后该条**自愈**(新 `treeSha256` 是现算的),但机制上的不同步来源未查明。
|
|||
|
|
* **回滚素材命名**:`doShare` 里补落的备份路径用 **incoming 版本号** 命名、内容取 **incoming 的 tgz**
|
|||
|
|
(`backupTgz = <backupDir>/plugins/<flat>/<version>.tgz` 且 `copyFileSync(existing.tgzPath, …)`,而 `existing` = **上传后**的池条目)
|
|||
|
|
⇒ 产出的 `0.3.14.tgz` **是"新包的自拷贝",不构成"回到上一版"的素材**;真正可回滚的那份躺在 `0.3.9.tgz` 里(名字与内容不符)。
|
|||
|
|
⇒ 建议:备份应记**被替换**的那一版,或名字带上"replaced"语义。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、复现命令(第三方可照抄)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# ① 共享层版本与字节
|
|||
|
|
ssh bt-server 'grep -m1 "\"version\"" /var/lib/dshs/bundled-plugins/dsh-plugin-mcn-suite/package.json'
|
|||
|
|
ssh bt-server 'md5sum /var/lib/dshs/bundled-plugins/dsh-plugin-mcn-suite/lib/client.js' # 期望 d387089bd28c91cdbe46056e21288cbd
|
|||
|
|
ssh test106 'md5sum /var/lib/dshs/bundled-plugins/dsh-plugin-mcn-suite/lib/client.js' # 应与 47 同值
|
|||
|
|
# ② 池内候选
|
|||
|
|
ssh bt-server 'ls -la /var/lib/dshs/business-plugins/dsh-plugin-mcn-suite.tgz' # 期望 1982036 B
|
|||
|
|
# ③ 实例依赖形态(P0 判据)
|
|||
|
|
ssh bt-server 'python3 -c "import json;print(json.load(open(\"/var/lib/dshs/users/cce6d1cd-b376-4304-80f0-0e1c58c9ffde/home/profiles/web/package.json\"))[\"dependencies\"][\"dsh-plugin-mcn-suite\"])"'
|
|||
|
|
# 期望输出 file:…/.dsh-stage/dsh-plugin-mcn-suite.tgz ← 即「未指向共享层」
|
|||
|
|
# ④ 重装配失败复现(需要 admin 会话):全量 apply 一条 enabled:false,随后轮询
|
|||
|
|
# GET /api/plugins/mine/task/<taskId> → 约 52 s 后 status=failed / "安装失败,请重试或联系管理员"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**本棒用到的临时脚本**(均在 `tmp/`,可重跑):`p16-port-mobile-20260925.py`(迁包)· `p16-build-0314.py`(改版打包)· `p16-hash-list.py` / `p16-cmp.py`(逐文件对账)· `p16-pull-106.sh`(触发节点拉取)· `p16-cleanup.sh`(清临时会话与临时物)。**只读**工具:`p16-reach.sh`(连通性探路)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、清理与合规
|
|||
|
|
|
|||
|
|
| 项 | 状态 |
|
|||
|
|
|---|---|
|
|||
|
|
| 临时 admin 会话 | ✅ **已删**(`DELETE FROM sessions WHERE user_agent='p16-mksess'` ⇒ rowCount 1,复核残留 **0**) |
|
|||
|
|
| 47 `/tmp` 临时物 | ✅ **零残留** |
|
|||
|
|
| 实例半状态 | ✅ **无**:实例 running、profile 依赖**未被改动**(两次失败均未落盘) |
|
|||
|
|
| 47/106 服务 | ✅ 正常(共享层 0.3.14、池 0.3.14) |
|
|||
|
|
| 装配协议 / `plugin-assembly.ts` | ✅ **零改动** |
|
|||
|
|
| 可见面开关 | ✅ 未开;⛔ 未开任何新口 |
|
|||
|
|
| `src/web/routes/im.ts` | ✅ **零改动**(IM 线 D 单判据 2 冻结遵守) |
|
|||
|
|
| commit / push | ✅ 未做 |
|