Files

56 lines
5.2 KiB
Markdown
Raw Permalink Normal View History

# 26 · dsh 升级耦合点与回归清单
- 日期:2026-09-11
- 触发:用户问「这些改动是否影响 dsh 原始包?dsh 更新是否会覆盖这些改动?」
- 结论一句话:**官方包目录零改动**(红线 R2 保持);dsh 升级**不会覆盖**我们的改动,但会带来**契约失效**风险 —— 我们有 **6 类耦合点**,升级前后必须按本清单回归。
- 状态:清单建立(升级时逐项执行)
---
## 一、dsh 原始包是否被改动?—— 未改动(实测证据)
| 检查 | 结果 |
|---|---|
| 官方包内是否含我们的标识(`workspace-scoped-picker` / `dshs` / `freshAuthUrl` / `crash-restart`) | ❌ **无命中** |
| 官方包内是否有 2026-09-10 之后被修改的文件 | ❌ **无**(安装后未动) |
| 安装版本 | `@deepseek-ai/[email protected]` |
**所有改动的落点都在 dsh 之外**:
| 层 | 落点 | 与 dsh 升级的关系 |
|---|---|---|
| 编排器(自研) | `/opt/dshs`(`src/supervisor/*`、`src/web/routes/*`、`scripts/*`、`poc/*`) | 不在官方目录内;升级不覆盖 |
| profile 层(dataRoot) | `<userRoot>/home/profiles/web/{cordis.patch.yml, package.json(bundles), node_modules/@dsh-local/*}` | 同上;但**引用官方 row id / 继承官方 seam** |
| 实例运行环境 | 编排器 spawn 的 bwrap 参数(ro-bind/dir symlink/私有 tmp/unshare-pid) | 与 dsh 无关,但 dsh 的运行时假设相关 |
| 系统层 | nginx vhost(域名/缓冲/压缩/真实 IP)、systemd 单元(`dshs`/`dsh-egress`)、`/etc/dshs.env`、certbot | 与 dsh 无关 |
> 结论:**升级不会"覆盖"我们的改动**(没有可覆盖的内容);真正的风险是"我们依赖的官方契约变了"。
## 二、六类耦合点(升级必查)
| # | 耦合点 | 依赖的官方契约 | 失效表现 | 检查方式 |
|---|---|---|---|---|
| **C1** | profile patch 引用官方 **client 行 id**(`ui-settings-models`、`ui-settings-plugins`、`ui-settings-plugin-inventory`、`ui-cordis`;档案 09/15) | 行 id 稳定 + `disabled: true` 语义 | id 改名/移除 → 静默失效(普通用户又能看到被收归的设置)或报错 | `--dump-config` 不可靠;**看浏览器设置面板**是否仍隐藏 |
| **C2** | ~~`directory-picker` 行~~(已回滚,不再改) | 官方 host 行 id + **dual-face**(该行同时挂载 host 后端与客户端对话框) | 曾实测:disable 后客户端对话框消失 → 点击无反应 | 现为官方默认 `[]`,无需检查;若将来做自建对话框需重新评估 |
| **C3** | 自建插件 `@dsh-local/workspace-scoped-picker`(继承官方 `DirectoryPicker` seam) | seam 基类路径(`…/dsh-host-directory-picker/lib/index.js`)+ capability 契约 | 基类路径/契约变化 → 插件加载失败 | 加载标记 `[workspace-scoped-picker] loaded root=…`(**当前未挂载,风险为 0**) |
| **C4** | 自建插件 `@dsh-local/portal-entry`、`@dsh-local/business-plugins`(client bundle) | client bundle 契约:`exports["."]`/`exports["./client"]`、`dsh.client.{platform,inject}`、**禁 `exports.default`** | 面板消失、或实例启动失败 | 看设置面板是否有「平台管理」「功能插件」分区;看实例启动是否有 loader 报错 |
| **C5** | 编排器 bwrap **合成根**(补 `--symlink usr/bin /bin` 等) | dsh 运行/沙箱后端对标准根布局的假设(`dsh-sandbox-local` 在 Linux 走 bwrap→Landlock,Landlock 需内核 ≥5.13) | 实例内 bash 工具被拒:`no sandbox backend is usable` | 在实例内让 AI 跑一条 `ls` |
| **C6** | 编排器 proxy 的 **401 / not_running 自动恢复** | dsh 的 401 文案与响应码、launch token 形式、`-auto` 行为 | 又出现死端页 `dsh web authentication required` 或裸 JSON `{"error":"not_running"}` | 实例重启后刷新旧标签页,应自动 302 带新 token |
| (辅助) | `storages/workspace.json` schema(v2) | dsh 存储单元版本 | 我们已**不再写入**该文件(seed 已废弃)→ 风险已消除 | 无需检查 |
## 三、升级流程(在档案 07 基础上补充)
1. **仍禁止自动升级**(档案 07 红线):先走"升级测试 → 评估 → 修复"独立流程。
2. 升级前:`git -C /opt/dshs tag pre-dsh-upgrade-<版本>`;备份 `nftables-dsh-egress.nft`、`dshs.env`、nginx vhost、各 profile 的 `cordis.patch.yml`。
3. 升级后按 §二 六项逐条回归(每项都有"检查方式")。
4. 任一项失败:优先用**回滚包版本**(pin 回旧版 dsh),再排修复;不要带病放量。
5. 若新增耦合点,**同步更新本档案**。
## 四、本次(2026-09-11)已确认的"升级友好"设计
- 自建插件的**加载标记**(`[workspace-scoped-picker] loaded …`):升级后可一眼判断插件是否仍能加载;
- ⚠️ **不建议**给更多插件加"加载日志",但**建议**给 `portal-entry` / `business-plugins` 也各加一行加载标记(下次改造时顺手做),使 C4 的回归从"看 UI"变成"看日志"。
## 五、红线遵守
本档案为**只读核查 + 文档**,未改动官方包任何内容;R2(不改官方 dsh 主程序与缓存)保持满足,R1(不自动升级)继续有效。