Files
dsh_shenxian/dsh-server-docs/04-调整方案/75-插件评估新增托管友好性与资源成本两个维度.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
   保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
   工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
   必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
   + ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
   ⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
   验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

123 lines
6.4 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.
# 75 · 插件评估新增「托管友好性」与「资源成本」两个维度(2026-09-12)
- 日期:2026-09-12
- 状态:📋 **标准已立(本档只立标准,未改预检脚本)**
- 触发:`dsh-univer-office` 静态预检判 `ok` 却在平台上完全不可用,且加载成本 **+65.1 MiB** → 用户提出「把这个作为插件评估和改造的一个点」
- 范围:**评估维度**(候选池导入预检)+ **改造规范**(自研 / 改造插件)
- 关系:**接续档案 71**(插件兼容性预检:依赖范围 + 导出符号),本档是**新增维度**,不改变其机制与分级语义
---
## 一、为什么需要(案例暴露的两个盲区)
`dsh-univer-office` 在**档案 71 的静态兼容性预检里判 `ok`**(依赖与导出符号全满足)——**但它在平台上完全不可用**:
| 预检现状 | 案例暴露的盲区 |
|---|---|
| 查 semver 依赖范围 | ✅ 通过(依赖没问题) |
| 查运行时导出符号 | ✅ 通过(符号都在) |
| ❌ **不查「它假设的部署形态」** | 把 `http://127.0.0.1:${port}` 交给浏览器 → **托管平台必然失效,且平台侧无法补救** |
| ❌ **不查资源成本** | 加载 `rss` **+65.1 MiB**(实测)= 实例配额的 1/6 |
**⇒ 兼容 ≠ 可用。** 需要补两个维度。
---
## 二、新维度 A:托管友好性(Hostability)
### 判据(一句话)
> **插件的一切对外交互,是否都能走「平台已有的那一条入口」?**
> 即:**浏览器侧只用相对路径;实例侧不依赖本机 loopback 上的网络服务。**
### 检查项
| ID | 检查 | 检测方法(复用档案 71 的 `walkJs` 框架) | 等级 |
|---|---|---|---|
| **H1** | bundle 里出现硬编码 loopback 服务地址 | 文本扫描 `127.0.0.1:<port>` / `localhost:<port>` | 🟡 出现即警告 |
| **H2** | **client bundle 里出现绝对 URL**(`http://` 字面量) | 只扫 client 侧产物;命中即「会交给浏览器」 | 🔴 **阻断** |
| **H3** | 自建网络监听且非 unix socket | 扫描 `listen(` / `createServer` 参数形态 | 🟡 需人工确认是否 loopback-only |
| **H4** | 交付浏览器的 URL 由 Host 生成,还是客户端自行拼接 | 人工研判(架构文档 + client 代码) | 🔴 若客户端自拼绝对地址 |
**为什么 H2 是阻断级**:绝对地址一旦交给浏览器,在托管平台上**必失效**——跨机器(`127.0.0.1` 指向用户本机)+ HTTPS 混合内容会被浏览器硬拦,**且平台侧无补救手段**(不能靠配置、不能靠反代)。这正是本案例的死因。
### 反面样板(本案例实测)
```js
viewerUrl = `${gateway}/?file=...` // ← 交给浏览器的绝对 URL
gateway = `http://127.0.0.1:${port}` // ← 硬编码 loopback,且被浏览器 iframe 使用
```
**两条独立阻碍,缺一都打不开**:
1. **Host → Gateway**:实例内进程 uid 100002 → `127.0.0.0/8` 被 nft `reject with tcp reset`
2. **Browser → Gateway**:绝对 loopback URL,浏览器在用户电脑上 → **即使解封第 1 条也打不开**
### 正面样板(同一插件内)
- **Client**(浏览器模块):只走 `/univer-api/*` 同域相对路径 → ✅ 平台可反代
- **平台自研 ×3**:加载成本 **0.0 MiB**、无自建监听 → ✅
---
## 三、新维度 B:资源成本(Resource Cost)
| 项 | 判据 | 方法 |
|---|---|---|
| **加载内存** | 插件 `import` 后的 `rss` 增量 | 隔离 cgroup 内逐个 `import` 实测(`node --expose-gc`,`MemoryMax` 兜底) |
| **标注阈值** | **> 30 MiB → 标注**;**> 60 MiB → 强提示** | 同上 |
### 实测基线(guest 实例,2026-09-12)
| 插件 | rss 增量 |
|---|---|
| `dsh-univer-office` | **+65.1 MiB** |
| `libsql`(间接依赖) | +7.8 MiB |
| 平台自研 ×3(portal-entry / workspace-scoped-picker / business-plugins) | **0.0 MiB** |
| `puppeteer-core`(仅 import 主入口、未启动浏览器) | **0.0 MiB** |
**⇒ 成本由「装了什么」决定,不是「装了几个」** —— 一个重型插件 ≈ 无穷多个轻量插件。
**⇒ 平台自研插件的 0.0 MiB 是正面基线**,应作为自研插件的验收参考。
---
## 四、改造规范(自研 / 改造插件必须满足)
| # | 规范 | 理由 |
|---|---|---|
| **R-a** | **对外入口唯一**:浏览器可达面全部挂在 Host 的 webServer(同域相对路径) | 复用平台反代,零新增暴露面 |
| **R-b** | **内部通信走 IPC**:unix domain socket 或 stdio,**不用 TCP loopback** | 不经 IP 层 ⇒ nft 管不到;天然无端口冲突 |
| **R-c** | **不新增监听端口** | 多租户同主机下,端口 = 跨租户风险 + 端口漂移 |
| **R-d** | **重型依赖懒加载**:原生绑定、引擎等改 `await import()` | 实测有效:`puppeteer-core` 仅 import 主入口 = **0.0 MiB** |
| **R-e** | 交付浏览器的地址**一律由 Host 生成且为相对路径** | 绝对地址在托管平台必失效 |
---
## 五、落地方式(**未实施,待排期**)
| 步 | 动作 | 落点 |
|---|---|---|
| 1 | 兼容性预检加 **H1/H2** 静态扫描(复用 `walkJs`) | `dsh-server-docs/scripts/plugin-compat-check.mjs` |
| 2 | H2 命中 → 判 `blocked`,理由「向浏览器交付绝对地址,托管平台不可用」 | 同上(沿用档案 71 的分级语义) |
| 3 | 资源成本:预检阶段先做**静态体积提示**(解包后 `artifacts/` 体积),精确值留隔离实测 | 同上 |
| 4 | 自研插件按 §四 规范执行(**T03 的 MCN suite 起适用**) | `交接单/T03` |
> ⚠️ 本档**只立标准**。改预检脚本属**生产代码变更**,须另立交接单执行(**规划与执行分离**)。
---
## 六、与既有档案的关系
| 档案 | 关系 |
|---|---|
| 71(兼容性预检:导入/上传即判定) | **本档是其新增维度**,机制与分级语义沿用,不替换 |
| 66(业务插件 P0 误报 → admin 显式信任) | 本档 🟡 级沿用「放行 + 标注 + admin 可见」口径 |
| 70(anysearch 不兼容致崩溃循环) | 同属「预检盲区导致线上事故」,本档是**系统性补盲** |
| 74(实例内存治理:V8 堆限 256→160) | §三 资源成本维度与 74 的配额治理同源 |
---
## 七、决策记录
- **2026-09-12** · 用户提出「把这个作为插件评估和改造的一个点」→ 本档立标准
- **待定**:是否立即实现 §五 步骤 1–3(需另立交接单)