# DeepSeek Harness 持续兼容策略 适用插件:`dsh-branch-visualizer` 当前 adapter:`dsh-preview-2026-08` 基准核对:2026-08-21,DeepSeek Harness `0.1.0-rc.8` / `master` ## 目标 Harness 仍处于实验阶段,本插件不能假设一次适配后接口永久稳定。兼容设计的目标是: 1. 小改只修改 adapter 或 contract; 2. 大改可以并存新旧 adapter,核心业务不重写; 3. 缺少某项能力时只关闭对应功能,不让整个插件静默崩溃; 4. 诊断信息足以判断缺失能力,同时不泄露用户数据; 5. 每次升级都有可重复的契约核对、构建、测试和 UI 冒烟流程。 ## 分层边界 ```text Harness unstable surface ├─ package/profile manifest ├─ Cordis service keys and events ├─ client slots and props ├─ session/subagent/agent DTOs └─ navigation and mutation methods │ ▼ src/platform/adapters// ├─ host.ts └─ client.ts │ ▼ src/shared/ stable internal contract │ ┌─────────┴─────────┐ ▼ ▼ src/host/ src/client/ data + mutations canvas + layout + actions ``` 硬规则: - DSH host service key 和 agent event key 只写在 `platform/adapters/*/host.ts`; - DSH client service key 和 slot 名只写在 `platform/adapters/*/client.ts`; - 外部 DTO 先收敛到 `shared/dsh-contract.ts`,wire DTO 由 `shared/contract.ts` 定义; - 布局、缓存、HTTP guard、标题校验和归档业务不得根据 DSH 版本号分支; - 不能用 `try/catch` 静默吞掉必需能力缺失并继续写数据;写能力缺失时应返回稳定错误码。 ## 当前依赖契约 ### Host | 能力 | 当前契约 | 缺失时行为 | | --- | --- | --- | | 会话列表 | `sessionQuery.listSessions()` | 快照不可用,返回可重试错误 | | 标题快照 | `sessionQuery.readTitleSnapshots(ids)` | 节点退回显示 ID,诊断标记缺失 | | 活跃改名 | `sessionTitle.rename(session,title)` | 尝试冷改名;两者都缺则关闭改名 | | 冷改名 | `sessionQuery.readSession` + `sessionPersistence.append` | 返回 `SERVICE_UNAVAILABLE` | | 归档 | `workspaceRegistry.archiveSession(id)` | 关闭归档 | | 归档列表 | `workspaceRegistry.archivedSessionIds` | 不能可靠标记归档,诊断标记缺失 | | 子代理 | `listChildren` / `listDescendants` | 不标子代理;归档不级联 | | Agent 状态 | `agents.list/get` + `agent/*` 事件 | 节点状态退化为 `cold` | ### Client | 能力 | 当前契约 | 缺失时行为 | | --- | --- | --- | | 入口槽位 | `conversation.session.header.utilities` | 不显示入口 | | Overlay | `shell.overlay` | 不显示画布 | | 常规跳转 | `sessions.open(id)` | 显示跳转错误 | | 子代理跳转 | `sessions.openSubagent(address)` | 退回 `open(id)`,失败则提示 | | 工作区列表同步 | `workspaces.archiveSession(id)` | Host 已归档,client 列表等待自身刷新 | | Timer | `timer` | 使用安全的浏览器计时退化路径 | ## 变更等级与处理方式 ### A. 兼容性小改 示例:新增字段、方法仍存在、事件增加可选字段。 处理:放宽最小类型、添加能力探测和回归测试;adapter ID 可以不变,插件只升 patch 版本。 ### B. 名称或形状变化 示例:service key 改名、slot 改名、event payload 包裹层变化、导航参数变化。 处理: 1. 复制当前 adapter 为新目录,例如 `dsh-preview-2026-10`; 2. 在新 adapter 内完成旧 contract 到新 API 的转换; 3. 保持 `src/host`、`src/client` 和 wire contract 不变; 4. 给新旧 adapter 各自添加契约夹具测试; 5. 装配层根据可靠的 manifest/能力选择 adapter,不使用猜测性的版本字符串比较。 ### C. 子系统被替换 示例:HTTP route 改为官方 typed remote、session event store 重做、slot 系统被替换。 处理:为变化面建立新 port/adapter,不同时重构业务。先让新旧 transport 或 mutation port 并存,通过同一组 contract tests;新路径完成真实 UI 冒烟后再删除旧路径。 ### D. 安全或数据语义不确定 示例:无法判断工作区归属、append 的原子/序列语义改变、archive 变成不可逆删除。 处理:默认关闭对应写功能。读图可降级,写操作不能用猜测继续执行。 ## 升级操作清单 1. 记录 Harness commit/tag、Node 版本和包管理器版本。 2. 核对根 `package.json` 的 `engines`、`dsh.bundle.patch` 和 `dsh.client`。 3. 核对 CLI 的 Git 插件安装、`prepare` 与 `pnpm.allowBuilds` 行为。 4. 核对 Cordis loader 的 package identity、`apply`、`inject` 和 disposer。 5. 核对 Host 表中的服务方法与事件 payload。 6. 核对 Client 表中的 ModuleLoader、slots、props 和导航方法。 7. 更新/新增 adapter,不在核心模块加版本判断。 8. 更新 `ADAPTER_ID`、`CLIENT_ADAPTER_ID` 和能力测试。 9. 执行 `npm run verify`。 10. 从干净 Git checkout 安装到临时 profile,重启 Harness。 11. 完成真实 UI 冒烟矩阵并保存版本化结果。 12. 更新 README 的兼容日期、已知限制和 release notes。 ## UI 冒烟矩阵 | 场景 | 期望 | | --- | --- | | 插件启用/禁用 | 槽位和样式正确注册/释放,无重复入口 | | 默认打开 | 只加载可见会话,当前会话立即高亮 | | 普通跳转 | Promise 完成后再切换高亮,失败保持原状态 | | 子代理跳转 | 使用完整 `SubagentAddress` | | 归档链隐藏 | 可见后代连接最近可见祖先,模式 1 双虚线、模式 2 断开 | | 显示归档 | 完整父链和归档样式可见 | | 活跃/冷改名 | 标题刷新正确;冲突不覆盖新数据 | | 批量归档 | 工作区外 ID 整批拒绝;部分失败可见 | | Agent 状态 | running/idle/disposed 依次正确 | | 大工作区 | 不出现请求风暴、无限缓存或页面持续卡死 | ## 诊断与回滚 诊断端点:`POST /brvis/api/diagnostics`,必须带插件的 JSON/header 安全边界。输出只包含: - 插件版本; - adapter ID; - 能力状态; - 缺失能力列表; - 生成时间。 遇到 Harness 大改时: 1. 禁用不确定的 mutation; 2. 保留只读图或明确显示“不兼容”; 3. 回退到最后一个已验证的插件 tag/Harness 组合; 4. 在独立 adapter 分支完成适配; 5. 只有自动测试和真实 UI 都通过后才更新兼容声明。