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 一律写「远程服务器」。
5.2 KiB
5.2 KiB
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 基础上补充)
- 仍禁止自动升级(档案 07 红线):先走"升级测试 → 评估 → 修复"独立流程。
- 升级前:
git -C /opt/dshs tag pre-dsh-upgrade-<版本>;备份nftables-dsh-egress.nft、dshs.env、nginx vhost、各 profile 的cordis.patch.yml。 - 升级后按 §二 六项逐条回归(每项都有"检查方式")。
- 任一项失败:优先用回滚包版本(pin 回旧版 dsh),再排修复;不要带病放量。
- 若新增耦合点,同步更新本档案。
四、本次(2026-09-11)已确认的"升级友好"设计
- 自建插件的加载标记(
[workspace-scoped-picker] loaded …):升级后可一眼判断插件是否仍能加载; - ⚠️ 不建议给更多插件加"加载日志",但建议给
portal-entry/business-plugins也各加一行加载标记(下次改造时顺手做),使 C4 的回归从"看 UI"变成"看日志"。
五、红线遵守
本档案为只读核查 + 文档,未改动官方包任何内容;R2(不改官方 dsh 主程序与缓存)保持满足,R1(不自动升级)继续有效。