Repository navigation
Description
受影响的功能
远程同步 → 「从远端合并到本机」(sync-merge-apply)写回 profile patch(plugins / mcp 适配器)
插件版本
0.8.0
DSH 版本
桌面版 2.0.22-next(内核 dsh 0.2.2-rc.1 / Electron 44.7.0 / Node v24.21.0)
操作系统
Windows 11 专业版(build 28000)/ AMD64
DSH 的启动方式
桌面客户端(D:\DSH NEXT),非 WSL、非 CLI
问题描述
执行一次「从远端合并到本机」之后,$DSH_HOME/profiles/desktop/cordis.patch.yml 中所有 - insert: 块被整份摊平成顶层 - id: xxx 行(文件首行就是插件自己写的 # rewritten by dsh-config-manager import (original comments not preserved))。
DSH 的 patch 语义是:
- 顶层
- id: X→ 覆盖 / 修改已存在的条目; - insert:块成员 → 新增条目。
于是所有「bundle 层里本来不存在、只能靠 - insert: 新增」的条目,全部变成「修改一个不存在的条目」,DSH 每次加载都打 warn 并丢弃:
patch: entry "mcp-blender" not found
patch: entry "mcp-rea" not found
patch: entry "magpie-mcp-magpie-image" not found
patch: entry "magpie-mcp-minimax" not found
实际后果:4 个 MCP server 全部从 DSH 面板消失(设置 → Skill & MCP 列表为空),blender / rea / magpie-image / minimax 四条通道全断。
同一个文件里的 ui-*、llm-*、permission、imagegen 等条目毫发无伤 —— 因为它们本来就在 bundle 层(package.json 的 dsh.profile.bundles)里存在,被写成顶层行恰好是合法的 update。「只有纯新增条目全灭、其余全部存活」这个规律就是本 bug 的指纹,也是它不容易被发现的原因。
根因(已定位到行)
lib/index.js 的 PatchFileFacade.applyPatchChanges(file, changes)(第 1488 行起):
- 读现有文档,把每个
- insert:块的成员摊平塞进rows/order(1471-1541 行); - 然后统一按顶层行输出(1557-1568 行):
// lib/index.js:1557
// 3. Rebuild: every id row is emitted as a top-level row. The loader treats
// a top-level { id, name } row exactly like an `- insert:` block member
// (dsh-base patch precedent), so the document stays semantically equal.
const out = [];
for (const id of order) {
const raw = rows.get(id);
if (raw !== undefined)
out.push(raw);
}
const text = '# rewritten by dsh-config-manager import (original comments not preserved)\n'
+ dumpPatchDocument(out);
await atomicWriteFile(p, text);第 1557-1559 行注释里的前提不成立。dsh-base 的「顶层 {id, name} 行能生效」只在该 id 已存在于某个 bundle 层时成立(顶层行覆盖它);对 profile 里不存在的 id,loader 会判成「找不到条目」并丢弃 —— 也就是上面那串 not found。新增语义只有 - insert: 有,两者并不等价。
顺带,同一条路径还会:
- 整份重写文件 → 原有注释全丢、引号风格统一;
- 值层面出现空值归一化(实测 7 处
""→null:agency-agents.config.customTeams[0].constraints/.coordinatorPrompt、imagegen.config.channels[0/1].preset/.subscription、bili-scroll.config.personaPrompt); - 事务自检全绿:
state: COMMITTED、commit.validated: true、validationWarnings: [],每步消息还写着「MCP server X 已写入 patch,重启后生效」。用户完全看不出已经写坏。
复现步骤
- DSH 桌面版,profile
desktop;profiles/desktop/cordis.yml是空列表,插件条目全部来自package.json的dsh.profile.bundles; - 在 profile patch 里放几个
- insert:块(本例是 4 个 MCP server),确认 DSH 正常加载、面板能看到它们; - 面板点「从远端合并到本机」,勾上 MCP 连接器 / 插件分区,执行合并;
- 看
profiles/desktop/cordis.patch.yml:- insert:数量变成 0,MCP 条目变成顶层行; - 文件写完后数秒内,DSH 日志出现上述 4 条
not foundwarn,MCP 从面板消失。
本机实测时间线(UTC;北京时间 = UTC+8):
| 时间 | 事件 |
|---|---|
| 2026-11-11T01:35:11Z | DSH 自己的 recovery 快照里,该文件仍是 3 个 - insert: 块(干净态) |
| 2026-11-11T03:22:12Z | 事务 e186fe1b 开始,operationType: sync-merge-apply,plannedSteps: ["patch:imagegen","mcp:blender","mcp:rea","mcp:magpie-image","mcp:minimax"] |
| 2026-11-11T03:22:19.402Z | 该事务 COMMITTED,文件被重写 |
| 2026-11-11T03:22:24.075Z | DSH 打出第一条 patch: entry "mcp-blender" not found(提交后 4.7 秒) |
同一天又合并两次(03:24:04、03:24:40),每次都重新摊平一遍 —— 100% 可复现,不是时序巧合。另外 2026-11-04T06:04:26Z 的 recovery 快照里也出现过同样的 insert=0 + - id: mcp-blender 被摊到顶层第 64 行,说明这不是一次性事故。
建议修法
applyPatchChanges 重建文档时,对每个 id 先判断它是否已存在于生效的 patch 链(bundle 层 + 本文件之外的层)中:
- 已存在 → 照旧输出顶层行(覆盖语义);
- 不存在 → 重新包成
- insert: [ { id, name, ... } ](或保留它原先所在的 insert 块),绝不能把纯新增条目提升到顶层。
插件里已有现成的判断工具可以复用:patchRowActivates(raw, name)(lib/index.js:410-417,它已经兼容「单行 + insert 块成员」两种形态),以及 readPatchLines() / loadPatchDocument() 读取各层 patch 的能力。
另外建议把「原本在 insert 块里、这次被提升到顶层」的 id 收集起来写进 commit.validationWarnings(或直接拒绝这次写入),这样至少用户能看见,而不是一路绿勾。
影响面
只要用户的 profile 里有靠 - insert: 新增的条目(MCP server 是最常见的一类),一次「从远端合并到本机」就会把它们全部打成失效。本机这一次的受害者:4 个 MCP server + 4 个 dsh-ops-* 激活行 + 1 个本地插件激活行。
需要日志原文、patch 文件前后对照或事务 JSON 的话我可以在评论里补。
分诊状态(2026-11-11,AI triage)
结论:缺陷成立,已复现 —— 不是推测。 三条论断逐条复核通过:① 宿主 patch 合并循环里,只有不带 id 的 insert 块才走新增(data.push(...clone)),顶层行只按 id 覆盖已存在条目、查不到就打 patch: entry %C not found 丢弃;② DshPatchFileFacade.applyPatchChanges 确实把 insert 成员摊平进顶层行,其注释「顶层 {id,name} 行 ≡ insert 成员」与宿主源码冲突;③ 一条 update 即触发,不需要多次合并(用已发布 lib/index.js 做的单测级复现:insert 归零、注释丢失、name 变裸名、transport 消失)。
同时确认的第二个独立缺陷:buildMcpPatchLine() 按白名单重建 patch 行,不写 transport、name 不带 @deepseek-ai/ scope —— 摊平修好后这一条仍然存在。
事务为什么全绿:patch 行项无文件 rel ⇒ external: rel === null ⇒ beforeFp/afterFp 恒 null,校验只能空过(既有可证限制)。这条写路径缺的是写后语义自检。
实施状态:无。 工作树无相关改动、git log --all 无 #133 提交、CHANGELOG 无条目、.dsh/issue-ledger.md 无 133 行、版本仍为 0.8.0(= 报告版本)。本次分诊未改任何业务代码。
证据笔记:docs/evidence/profiles-and-instances.md → 「profile patch 的 insert 与顶层行不等价(#133,2026-11-11 源码核实)」(宿主语义原码引文、复现、修复判据、存疑项)。
维护者拍板(2026-11-11):Q1–Q3 全按推荐
- Q1:摊平与 MCP 字段损失(
transport+ scoped name)一起修,分两个提交、两条验收;同轮更新docs/contracts/bundle-format-v1.md的 mcp 白名单。 - Q2:写前拒绝——某次写入若会把原本的 insert 成员提升为顶层行,整笔拒绝、文件逐字节不变;不自动改用户文件,存量坏文件走插件自拍快照恢复。
- Q3:补写后语义自检(重读断言 insert 成员仍在 insert 块内),覆盖 sync-merge-apply / import-apply / mcp / plugins / prompts 全部写入口。
下一步:标签转 bug + ready-for-agent,实施单(Agent Brief)见本票评论。
未验证:宿主是否接受裸名 dsh-mcp-client 解析到 @deepseek-ai/dsh-mcp-client;报告者观察到的 7 处 "" → null 归一化本机未复现。
Activity
github-actions commentedon Nov 11, 2026
感谢反馈!🙏 我通常会在 48 小时内回复;这条已加上
needs-triage,进度会体现在标签上。Thanks for the report! I usually reply within 48h. This issue is labeled
needs-triage; progress shows up in the labels.如果还没写,补上这几项能少好几轮来回 / Adding these saves round trips:
LingYingNX commentedon Nov 11, 2026
补充:可复核的原始证据
只补证据,不改正文结论。以下路径都在本机 DSH 数据目录下,全部可以自己复现。
1. 日志:这 4 条 MCP 的
not found是本次合并"引入"的统计
~/.dsh/logs/desktop-next-2026-11-11.0.jsonl里event = "log"且message以not found结尾的记录:4 条 MCP 在整个日志里第一次出现就是
2026-11-11T03:22:24.075Z,也就是事务提交(03:22:19.402Z)后 4.7 秒、落在同一个 run(e25e8d99-6008-41ca-b8e7-c60b98ad11c0,01:34:56 启动、05:41:53 结束)里;而上面 6 条来自更早的 run(788fb7dc),两者互不相干 —— MCP 不是"一直就坏",是这一刻才坏的。提交后第一屏原文(注意 sequence 122 是这次写入之后 patch 的第一次重新加载):
{"time":"2026-11-11T03:22:24.075Z","runId":"e25e8d99-6008-41ca-b8e7-c60b98ad11c0","sequence":122,"source":"host.kernel.root","event":"log","level":"warn","message":"patch: entry \"mcp-blender\" not found"} {"time":"2026-11-11T03:22:24.075Z","sequence":123,"level":"warn","message":"patch: entry \"mcp-rea\" not found"} {"time":"2026-11-11T03:22:24.075Z","sequence":124,"level":"warn","message":"patch: entry \"dsh-ops-shell\" not found"} {"time":"2026-11-11T03:22:24.075Z","sequence":127,"level":"warn","message":"patch: entry \"dsh-ops-discovery\" not found"} {"time":"2026-11-11T03:22:24.075Z","sequence":128,"level":"warn","message":"patch: entry \"magpie-mcp-magpie-image\" not found"} {"time":"2026-11-11T03:22:24.076Z","sequence":129,"level":"warn","message":"patch: entry \"magpie-mcp-minimax\" not found"} {"time":"2026-11-11T03:22:24.076Z","sequence":130,"level":"warn","message":"patch: entry \"pixiv-duty\" not found"}2. 事务 JSON:它自己认为一切正常
~/.dsh/dsh-config-manager/transactions/completed/e186fe1b-2f25-4df5-9269-33ad38f663f7.json(先把复盘用到的字段摘出来,字段名与原文件一致):
{ "operationType": "sync-merge-apply", "packageVersion": "0.8.0", "state": "COMMITTED", "createdAt": "2026-11-11T03:22:12.353Z", "updatedAt": "2026-11-11T03:22:19.403Z", "snapshotId": "c80f89f7-f213-4f53-86c5-96220a293fab", "plannedSteps": ["patch:imagegen", "mcp:blender", "mcp:rea", "mcp:magpie-image", "mcp:minimax"], "commit": { "at": "2026-11-11T03:22:19.402Z", "validated": true, "validationWarnings": [] }, "rollback": { "attemptedAt": null, "full": false, "failed": [], "entryDone": {} }, "recovery": { "attemptedAt": null, "outcome": null, "reason": "", "attempts": 0 } }steps里 5 步全是status: "done",文案还是"MCP server X 已写入 patch,重启后生效",而且beforeFp和afterFp都是null:即:事务层手里没有任何"内容真的变了 / 没变"的指纹,却给了
validated: true+ 空validationWarnings。这是"用户完全看不出已经写坏"的直接来源。3. 插件自己在写入前 0.9 秒拍下的快照
同一个
snapshotId的目录~/.dsh/dsh-config-manager/snapshots/c80f89f7-f213-4f53-86c5-96220a293fab/snapshot.json:"createdAt": "2026-11-11T03:22:19.049Z"(比写入早 0.9 秒)hostFileBackups中有profiles/desktop/cordis.patch.yml的写入前完整副本(blob,9016 字节)。我把它和 DSH 自己在 01:35:11Z 存的 recovery 副本逐字节比对:完全相同 → 可以当作写前状态- insert:3 个、顶层- id:27 个;mcp-blender在第 61 行、缩进 4(insert 成员):entries里 5 条全部"existed": true,before保存的就是这份完整值(含transport和带 scope 的name)—— 说明插件写之前手里就有正确数据:{ "kind": "patchLine", "adapter": "mcp", "ref": "mcp-blender", "file": "profiles/desktop/cordis.patch.yml", "before": { "id": "mcp-blender", "name": "@deepseek-ai/dsh-mcp-client", "config": { "serverName": "blender", "transport": "stdio", "command": "C:\\Users\\LYNX\\.local\\bin\\uv.exe", "args": [ "tool", "run", "--from", "mcp-for-blender", "mcp-for-blender" ] } }, "existed": true }4. 写入之后(DSH 自己在 05:42:01Z 存的 recovery 副本)
- insert:0 个、顶层- id:31 个 —— 27 + 4,算术正好等于被提升的 4 条。同一条mcp-blender变成了缩进 0 的顶层行:四条前后对照:
顺带两个同一次写入里的差异(同样的 4 条才有,未被提升的条目没有):
name的@deepseek-ai/scope 丢了:'@deepseek-ai/dsh-mcp-client'→dsh-mcp-client;而同一份文件里其它补丁行(例如- id: ui-settings-general的name: '@deepseek-ai/dsh-client-ui-settings-general')scope 完好。transport字段被整个丢掉(stdio/streamable-http)。magpie-mcp-minimax是transport: streamable-http+url,少了 transport 之后靠什么判定传输方式我不确定,但这不像是"语义等价"的重写。这两点是从"写前 blob vs 写后 recovery 副本"的 diff 里读出来的;如果
transport/ scope 是别处有意归一化,请忽略,但它们确实都发生在 03:22 这一次写入之后。5. 手动复核(大约 5 分钟)
~/.dsh/dsh-config-manager/transactions/completed/里找operationType: "sync-merge-apply"的那个 JSON,记下snapshotId;~/.dsh/dsh-config-manager/snapshots/<snapshotId>/snapshot.json,在hostFileBackups里找profiles/<profile>/cordis.patch.yml,读它的blobPath—— 那个 blob 就是写入前的原文件;profiles/<profile>/cordis.patch.yml比- insert:的条数:写前 3、写后 0。一行统计(PowerShell):
上面涉及的三个文件(事务 JSON、写前快照、以及写前/写后两份 patch 副本)如果需要我打包贴出来,或者要我补其它片段(例如
exportAppliedSections之后的文件内容、连续多次合并的对比),说一声就行。LingYingNX commentedon Nov 11, 2026
补充:
transport/ scopedname丢失不是 YAML 归一化,而是写回函数的固定输出补一条代码级定位,方便把“摊平”和“字段丢失”一起修。以下基于 0.8.0 的
lib/adapters/mcp.js:buildMcpPatchLine(lineId, server)(106-123 行)构造config时只写入serverName;streamable-http分支只写url/headers,stdio 分支只写command/args/env/cwd,没有任何地方写transport。{ id: lineId, name: 'dsh-mcp-client', config }(122 行),没有保留@deepseek-ai/scope。McpAdapter.applyItem(404-425 行)对Create和Update都会调用buildMcpPatchLine,再执行applyPatchChanges;所以即使before中的原行已有transport: stdio|streamable-http和带 scope 的 name,一次Update也会按上面的模板重写,而不是保留原值。这正好对应补充评论里看到的两个差异:
mcp-blender的transport消失、name变成dsh-mcp-client。它们是buildMcpPatchLine的固定输出,不是 diff / YAML 层的偶发归一化。另外,
@max-null/dsh-skill-mcp-center/dist/service.js:421只接受entry.options.name === '@deepseek-ai/dsh-mcp-client';如果只修applyPatchChanges的顶层摊平、仍让buildMcpPatchLine写短名,MCP 面板可能还是空。建议回归测试至少包含两条:
mcp-blender写回后保留transport: stdio+ scoped name;magpie-mcp-minimax保留transport: streamable-http+url+ scoped name。若短名是有意设计,也请在代码注释里说明下游如何映射。xiajiajun516 commentedon Nov 11, 2026
分诊笔记(2026-11-11)
已查阅范围:本票正文与 3 条评论;仓内既有笔记
docs/evidence/profiles-and-instances.md(cordis.patch.yml方言与拒覆盖)、docs/evidence/recovery-console.md(external step 无指纹)、docs/contracts/bundle-format-v1.md的 mcp 白名单、docs/contracts/compat-matrix.mdR15、docs/known-issues/known-limits.md§3、.out-of-scope/(仅 README)、.dsh/issue-ledger.md、git log --all;以及本机D:\Apps\DSH\resources\app.asar里内嵌的 patch 合并循环源码。既有笔记没有一份写到 insert 与顶层行的语义差别,所以最后这项是新查的。核实:成立,并且复现了。
insert不带id时data.push(...clone)+buildMap(clone),这是唯一的新增路径;带id的 insert 只往已存在 group 的config里 push。非 insert 行一律entryMap.get(id):查不到 →patch: entry %C not found丢弃;name与目标不一致 →patch: name mismatch … skipping。⇒ 顶层行只覆盖、绝不新增,src/index.ts里那句 “dsh-base patch precedent” 的注释前提是反的。DshPatchFileFacade.applyPatchChanges载入时把 insert 成员塞进rows/order,重建时统一输出顶层行(与你读到的lib/index.js同一处,源码在src/index.ts)。.tmp/repro-133.cjs用已发布的lib/index.js(DshPatchFileFacade+buildMcpPatchLine),在临时 home 造「1 个顶层行 + 1 个 insert 块(mcp-blender,带 scoped name 与transport: stdio)+ 1 行注释」,跑一次update→ insert=0、顶层 2 行、注释丢失、name变dsh-mcp-client、transport整行消失。不需要多次合并,这也解释了你同一天三次合并为什么次次复现。顺带确认的第二个缺陷(独立于摊平):
buildMcpPatchLine()按白名单重建 patch 行,只输出serverName+url/headers或command/args/env/cwd;不写transport,name也不带@deepseek-ai/scope。这条界线写在docs/contracts/bundle-format-v1.md的 mcp 一节里,属于「按现有契约也不会保留」的字段损失 —— 要修得连契约一起改。「事务全绿」不是本 bug 独有:patch 行项没有文件
rel⇒external: rel === null⇒beforeFp/afterFp恒 null,校验只能空过(docs/evidence/recovery-console.md已记录这条可证限制)。要挡住这类写入,靠指纹不行,只能加写后语义自检。实施情况:无。 工作树无相关改动、
git log --all无 #133 提交、CHANGELOG 无条目、.dsh/issue-ledger.md无 133 行、版本 0.8.0 = 你报告的版本。本次分诊没有改任何业务代码。重复实现检查:查过 patch 写路径(
applyPatchChanges/patchRowActivates/patch-layers.ts/boot-rescue.ts)。「按层身份决定顶层还是 insert」这套判断只有boot-rescue.ts在写救援挂载时做对过(新增只写- insert:块;包已在bundles时一行都不写),没有可直接复用的完整实现。证据笔记:
docs/evidence/profiles-and-instances.md,新节「profile patch 的insert与顶层行不等价(#133,2026-11-11 源码核实)」(宿主原码引文、复现、修复判据、存疑项)。票正文也补了「分诊状态」一节。待你拍板
❓ Q1 修复范围:只修「insert 被摊平」,还是把
buildMcpPatchLine的字段损失(transport+ scoped name)一起修?➡️ 建议一起修、但分成两个提交两条验收:两个缺陷在同一次写入里打坏同一个文件,分两次发版会让中间版本的用户照样拿不到完整修复;字段那条要同步改
docs/contracts/bundle-format-v1.md。❓ Q2 已写坏的 profile 怎么兜底:自动改回去、写前拒绝、还是只告警?
➡️ 建议不自动改用户文件:写前若能判定「原本在 insert 里的 id 会被提升到顶层」,就直接拒绝这次写入并给出可操作错误(插件自拍快照里就有写前副本,回滚路径清楚);存量的坏文件靠快照恢复 + 文档说明。自动重写别人手写的 patch 文件,风险大于收益。
❓ Q3 要不要连「写后语义自检」一起做:写完重读并断言「原本在 insert 块里的 id 仍在 insert 块里」,不满足就 warning 或回滚;覆盖
sync-merge-apply/import-apply/ mcp / plugins / prompts 全部写入口。➡️ 建议要。patch 行项天然没有指纹,这是这条写路径唯一能自我证明的防线,也是这次「一路绿勾」直接的成因。
回复之后我会做:Q1–Q3 都按推荐 ⇒ 打
ready-for-agent并贴 Agent Brief(验收判据 + 范围边界);只修摊平、或你要自己实现 ⇒ready-for-human;需要我再补宿主侧证据(裸名能否解析)⇒ 先needs-info。当前标签保持bug+needs-triage,不替你拍板。xiajiajun516 commentedon Nov 11, 2026
Agent Brief
类别:
bug一句话: patch 文档重建必须保留「顶层行 = 覆盖、
- insert:块 = 新增」的语义,且 MCP 写回不得丢transport与 scoped name。当前行为:
sync-merge-apply、import-apply、MCP/插件/提示词的 Create 与 Update 全部共用同一个门面)在重建文档时把所有- insert:块的成员提升为顶层- id:行。patch: entry "…" not found丢弃);只有不带 id 的 insert 块才新增。于是所有纯新增条目(典型是 MCP server)在写入后的下一次加载里全部失效,而 bundle 层本来就有的条目因为顶层行恰好合法而毫发无伤。一条 update 就够触发,不需要多次合并。serverName与按 type 分支的url/headers或command/args/env/cwd,丢掉transport,name也不带@deepseek-ai/scope。rel,beforeFp/afterFp恒 null),用户看不到写坏。期望行为:
- insert:块里。原本是 insert 成员的 id,写后必须仍是 insert 成员。not found。config.transport(stdio / streamable-http 原值)与name: '@deepseek-ai/dsh-mcp-client';对已有行做 Update 时也不得把它们抹掉。commit.validationWarnings或回滚,不再出现「全绿但写坏」。关键接口:
DshPatchFileFacade.applyPatchChanges(file, changes):现签名保留;changes的action已经区分insert/update/remove,但三种都按顶层行输出 —— 需要让insert(以及任何目标 id 不在生效链里的写入)真正落到 insert 块,update才用顶层行。readEffectivePatchLines/resolveWriteLayer/locatePatchLineLayer提供层身份,patchRowActivates已兼容「单行 + insert 成员」两种形态 —— 分流判断必须复用它,不要再写第二份形态识别。buildMcpPatchLine(lineId, server):返回的 patch 行需要携带transport与完整name;同时确认读侧(patch 行 → MCP 条目)能读回这两项,避免写读不一致。rescuePatchText已经示范正确形状(新增只写 insert 块;包已在bundles时一行都不写,因为同 id 重复会让 loader 抛错)—— 分流逻辑要与它同口径。验收判据:
patch: entry "…" not found,面板可见该 server。transport: stdio;streamable-http 型保留transport: streamable-http+url;两者name均为@deepseek-ai/dsh-mcp-client。validated: true+validationWarnings: []」却已写坏的结果(要么 warning 可见,要么回滚)。sync-merge-apply、import-apply、MCP 适配器、插件/提示词适配器(同一门面,用真实文档往返断言)。范围之外:
!!js方言读写与「存在但解析不了就拒覆盖」的现有逻辑。""→null的归一化本机未复现,不在本票范围内处理。承接: 本票正文的事故时间线与评论里的日志/事务 JSON 证据仍然有效,作为回归夹具的取材来源。
xiajiajun516 commentedon Nov 11, 2026
已修复(本地主干,待发版)
两个提交,按 Brief 的验收判据逐条落地:
74539bd— insert 块不再被摊平:写回改为「按原文档的归属重排」,insert 成员留在块里、顶层行仍是顶层行,update不改归属、新增按动作进块;落盘之前做两道闸:结构自检(重建后 id 身份必须与计划一致)与跨层提升守卫(另一层 insert 里已有的 id 不许被写成顶层行)——任一不过即拒写、文件逐字节不变,报host.patchRefusePromote/host.patchSemanticDrift。06daa26— MCP 写回补齐字段:每行显式写config.transport(= 条目type)与 scoped 行名@deepseek-ai/dsh-mcp-client;读侧先认transport,缺该字段的旧行才回落「有没有 url」的猜测,存量行不受影响。验证
npm run typecheck通过(提交 1、2 各一次)。npm test:tests 5574 / pass 5572 / fail 0 / skipped 2;其中src/utils/workdir-lock.test.ts的「不同工作副本互不阻塞」在负载下抖动过一次,单文件重跑 10/10 绿(与本改动无关的时序用例)。src/core/patch-document.test.ts9 例(纯函数)、src/index.facade.test.ts3 例真机(含「跨层提升拒写且文件不变」)、src/adapters/mcp.test.ts补 http 分支与读侧优先级。行为变化(发版说明会写进 CHANGELOG)
- insert:块里,重启不再patch: entry not found。文档同轮更新:
docs/contracts/bundle-format-v1.md的 mcp 写回形状、CHANGELOG.md的## [Unreleased]两条、docs/evidence/profiles-and-instances.md的 #133 节补「修复落点」。标签:
bug+confirmed(已核实、修复待发版);发版后回版本号并换fixed。checkpoint: 记录 #133 待发版
xiajiajun516 commentedon Nov 11, 2026
已在 v0.8.1 修复并发布。
现在从远端合并或导入配置后,profile patch 里
- insert:块中的纯新增条目(MCP server 等)不会再被摊平成顶层行,重启后不会再整条 not found 消失;同时 MCP 写回行会带上连接类型与完整包名(@deepseek-ai/dsh-mcp-client),升级后不用手动改配置文件。升级:
自证:升级并重启后,把之前读不到的 MCP server 重新合并一次,然后重启 DSH —— 服务器仍在列表里、能连上,即为修复生效。
chore(ledger): #133 已在 v0.8.1 发布并回复