settings.yaml 一次性迁移在启动竞态下全数失败且永不重试:4 个配置段静默丢失(0.1.7-rc.1,rc.2 仍在,附根因与修复建议) #7814
Replies: 4 comments
|
Independent confirmation from a different environment: Windows 11, Node 24.17.0, source launch (not macOS, not a global npm install), on 0.1.7-alpha.2 — the same silent loss. What I can add to your analysis:
I filed the same defect separately as #7672 (Windows, before rc.1) — two independent reproductions on different platforms, so it is not environment-specific. One note for the fix: because the import runs from |
|
补充一个独立于启动竞态的成因 —— 迁移失败不止一种机制。 我在 0.1.7-rc.2 上逐节核对了
B 的实际映射: C 我觉得值得单独说一句: 我遇到的具体实例: 建议:
|
|
更正上面这条评论里的一处 —— 我把「旧节名与真实 entry id 的对应关系」写成了「代码里的映射」,这是错的。
const LEGACY_SECTION_ENTRIES = {
"ui-developer-tools": "ui-settings",
"ui-onboarding": "ui-settings-general",
shell: process.platform === "win32" ? "pwsh-sandbox" : "bash-sandbox"
};导入时查表是逐字兜底的(
另一处要收紧的表述: 其余(504/506 两个抛错点及其在 |
|
Your correction matches what I see from the other side: my loss was mode B, and I can name both ends of it.
On mode A I cannot confirm it as my cause, but its precondition exists on Windows too: walking my source checkout hit One addition to the three modes, if useful: mode B also covers a rename in the product itself — a section that imported cleanly on one release stops matching as soon as the entry id changes, which makes B self-inflicting on upgrades rather than only on hand-written config. My separate report reaching the same conclusion is #7672; linking the two may help whoever picks this up. |
Uh oh!
There was an error while loading. Please reload this page.
settings.yaml 一次性迁移在启动竞态下全数失败且永不重试:4 个配置段静默丢失(0.1.7-rc.1 实测,rc.2 仍在;附根因与修复建议)
1. 基本信息
@deepseek-ai/dsh-settings/lib/index.js的importLegacyDocument与 rc.1 逐字相同)settings.yaml升级到 profile 配置体系的用户settings.yaml.imported原件、两版源码对比2. 结论摘要
importLegacyDocument()把settings.yaml改名为.imported之后才开始逐段写入 profile;而写入依赖的configEditor服务在「端口占用 + HMR reload」的启动竞态下处于 inactive 状态,于是每一个配置段都抛cannot get required service "configEditor" in inactive context。由于文件已被改名,导入逻辑永远不会重试——实测 4 个配置段(含全部 LLM provider 与模型选择)全部丢失,设置界面一片空白,用户唯一的线索是日志里 4 条warn。这不是「部分失败」而是原子性倒置:迁移的提交点(改名)发生在所有写入之前。3. 关键时间线
startup-2026-09-24T02-44-10.011Z-….logimportLegacyDocument将settings.yaml改名为settings.yaml.imported~/.dsh/settings.yaml.importedsettings: section %s … was not imported+ 4 条错误栈.imported)4. 问题清单
logger.warn,设置界面无任何提示 → 用户只看到"配置没了"configEditor服务在 loader 尚未 active 时被调用,竞态窗口内必然抛错settings.yaml.imported残留但无任何机制消费它(既不重试也不提示可恢复)catch后继续)与全段失败(同一批 warn)在日志里长得一样,难以区分严重程度5. 预期与实际
.imported无人消费.imported(✅ 这点是对的)但无法续传cannot get required service "configEditor" in inactive context(对用户无指导性)6. 根因分析
已确认事实(源码 + 日志双向验证):
importLegacyDocument()的顺序是rename(settings.yaml → settings.yaml.imported)→for 每段 update()。JSDoc 自述:"The document is renamed before the first write, so a partial import never repeats"——防重复的代价是失败后永不重试。update()→write()需要configEditor服务;该服务在 loader context 未 active 时抛cannot get required service "configEditor" in inactive context(栈:write:502 ← update:472 ← importLegacyDocument:356)。ui-onboarding、ui-theme、llm-pi-ai、agent-default-model),错误完全相同 → 不是某段数据问题,是写入通道整体不可用。for循环把每段错误 catch 后仅logger.warn,函数正常返回,imported文件保留——但没有任何代码路径会再次读取它。高概率根因:
importLegacyDocument挂在ctx.root.loader.await().then(…)上,但本次启动叠加了端口占用 + HMR reload,loader 的 settle 信号到来时 configEditor 所在 context 已进入/仍处于 inactive(详见dsh-settings/lib/index.js:339的调用点)。「await settle」不等于「服务可用」。待研发确认:
configEditor的 active 判据是什么?HMR reload 后是「短暂 inactive」还是「直到下次事件循环」?(决定修复用重试还是用等待)7. 研发排查建议
importLegacyDocument入口与write()处各加一行状态日志(ctx.fiber.state、configEditor可用性),用端口占用复现一次即可确认竞态窗口宽度;loader.await()resolve 时各服务的 active 时序(是否有ctx.lifecycle/activated钩子可用);.imported的消费方——预期是 0 处(我这边已确认 rc.1/rc.2 均无);8. 修复建议(按优先级)
rename;或改为「成功一段、从.imported删一段」的进度式迁移(部分失败可续传,天然幂等)。9. 验收标准
importLegacyDocument执行前人为置configEditor不可用(或按 §6 竞态复现),断言:settings.yaml仍在原处(或.imported被还原),且下一轮启动导入成功;settings.yaml/settings.yaml.imported均不存在;中途任意失败后二者至少存在一个且内容不丢。10. 原始证据附录
A. 事发日志(
~/.dsh/logs/startup-2026-09-24T02-44-10.011Z-….log,4 段同构,节选 2 段;路径已脱敏):B. 被改名的原件结构(
settings.yaml.imported,字段值略去——含 provider 配置,仅供内部排查):C. 源码对照(0.1.7-rc.1 与 0.1.7-rc.2 的
dsh-settings/lib/index.js该函数逐字相同):附:我们的临时恢复方案(供其他撞到的用户参考)
手工把
.imported里的 4 段按当前 profile 的条目形态写回cordis.patch.yml(即importLegacyDocument本应写入的目标),一次恢复成功。建议官方在修复前于升级文档里注明:若升级后设置空白,检查~/.dsh/settings.yaml.imported并手工恢复——数据都在,只是没人消费它。All reactions