Skip to content

fix(desktop): keep local tasks available during Host recovery - #5101

Merged
M4n5ter merged 3 commits into
mainfrom
fix/peer-reconnect-recovery
Sep 9, 2026
Merged

fix(desktop): keep local tasks available during Host recovery#5101
M4n5ter merged 3 commits into
mainfrom
fix/peer-reconnect-recovery

Conversation

@M4n5ter

@M4n5ter M4n5ter commented Sep 9, 2026

Copy link
Copy Markdown
Member
English

Summary

Local task entry can fail even when its Host is ready: offline Guest recovery bypasses backoff and invalidates the Owner catalog, while an abandoned runtime-host-deployments.json.lock makes the shared Host-list request time out. The latter also leaves Workspace settings without a default Host selection.

Keep recovery-phase notifications inside active dials; wake reconnects only when changed candidates or a restored connection provide a usable path. Log once when an outage begins and once when the connection recovers; keep failed-attempt counts, first/last failure times and the latest error in copied diagnostics instead of appending each retry, even when dial errors alternate. Exclude Guest status changes from Owner new-task catalog invalidation. New routes still resume Guest connections, changed errors remain visible, and Owner replacement still invalidates its catalog.

Use the existing process-lifetime OS lock for deployment reads/migrations and updates. After acquiring Desktop's single-instance authority, startup reclaims empty legacy directory markers before opening this store. Current writers remain protected; unexpected directory contents are retained, and saved deployments are unchanged.

Verification

  • Full npm run build, npm run typecheck, npm run lint, npm run format:check, and npx knip --workspace apps/desktop --workspace packages/ui passed.
  • 193 tests passed across 12 affected suites covering peer routing/recovery, Desktop connection management, Guest mounts, IPC, onboarding and task entry.
  • 120 tests passed across six follow-up suites covering deployment/profile/storage locks, Desktop recovery, copied diagnostics and the Local preload catalog. All four new lock cases failed before the fix, including the reported 10-second Host-list timeout; tests also verify that a live writer is not displaced and saved deployments survive forced process exit.
  • Alternating dial failures during one outage previously appended 22 logs; the regression now records one initial entry and one recovery summary. Copied diagnostics retain every failed attempt and the latest error, redact secrets, and a later outage is reported afresh.
  • Temporarily reverted all three original reconnect implementation files: all three targeted regressions failed. Restored the fix and reran the affected suites successfully.
Without fix:
  Empty recovery sweeps wake reconnects: 6 (expected 0)
  Repeated Guest error publications: 6 (expected 2 startup publications)
  Local catalog: "Runtime Host targets changed while ... loading"
With fix:
  Initial affected suites: 193 passed, 0 failed
  Follow-up affected suites: 120 passed, 0 failed
  Alternating failures during one outage: 1 initial log instead of 22

Live dev:peer smoke on macOS with the existing default State Root: Local was ready/available, the project picker opened, onboarding returned ready_with_history, and entering a draft enabled Send. The macOS instance is the Owner; this smoke does not reproduce the Windows Guest topology. Guest-offline behavior is covered by the regressions above; Windows hardware and a real cross-device outage were not tested.

AI use

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex — investigation, implementation, regression tests and PR preparation. The commit includes a Generated-by trailer.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No
简体中文

Summary / 概述

即使 Local Host 已就绪,本地新任务入口仍可能不可用:离线 Guest 的恢复通知绕过重连退避并反复作废 Owner 目录;残留的 runtime-host-deployments.json.lock 则会让共用的 Host 列表请求超时,使工作区设置也无法显示默认 Host。

将恢复过程通知保留给正在进行的连接尝试,仅在候选路径变化或连接恢复、提供可用路径时唤醒重连;每次持续断线只在开始和恢复时各记一条日志;重试失败次数、首次/最近失败时间和最新错误保留在可复制的诊断中,即使连接错误交替变化也不逐次追加日志。相同错误不重复广播,Guest 状态不再作废 Owner 的新任务目录。新路由仍能恢复 Guest 连接,变化后的错误仍会展示,Owner 替换仍会作废其目录。

部署文件的读取迁移和修改改用现有的进程生命周期 OS 锁。启动取得 Desktop 单实例权限后,在打开该存储前回收旧的空目录锁;活跃写入者仍受保护,锁目录里的异常内容会保留,已有部署不变。

Verification / 验证

  • 完整 build、typecheck、lint、format:check,以及 Desktop/UI 的 knip 检查通过。
  • 12 个相关测试文件共 193 项测试通过,覆盖 peer 路由恢复、Desktop 连接管理、Guest 挂载、IPC、onboarding 和新任务入口。
  • 后续六个相关测试文件共 120 项通过,覆盖部署/配置/存储锁、Desktop 恢复、诊断复制和 Local preload 目录。四个新增锁场景在旧实现上全部失败,其中复现了 10 秒 Host 列表超时;测试还验证不抢占活跃写入者,强制退出后恢复且已有部署保留。
  • 同一次断线中交替出现连接错误,旧实现追加 22 条日志;新实现只记开始时的一条,恢复时再记一条摘要。复制诊断保留全部失败计数和最新错误并脱敏,后续新断线会重新记录。
  • 暂时撤回原先三个重连实现文件的修复后,三个针对性回归全部失败;恢复修复后,相关测试重新全部通过。
修复前:
  空恢复检查唤醒重连 6 次,预期 0 次
  Guest 错误广播 6 次,预期仅启动阶段的 2 次
  Local 目录报错:读取过程中 Runtime Host 目标发生变化
修复后:
  初次相关测试:193 项通过,0 项失败
  后续相关测试:120 项通过,0 项失败
  同次断线中的交替错误:初始日志从 22 条变为 1 条

在 macOS 默认 State Root 上运行真实 dev:peer:Local 为 ready/available,项目选择器正常打开,onboarding 返回 ready_with_history,输入草稿后发送按钮可用。该 Mac 是 Owner,此检查不代表复现了 Windows Guest 拓扑;Guest 离线行为由上述回归测试覆盖,尚未进行 Windows 实机和真实跨设备断线测试。

AI use / AI 使用

  • 生成式工具没有实质性贡献
  • 生成式工具有实质性贡献

工具及范围:OpenAI Codex,参与调查、实现、回归测试及 PR 准备;提交包含 Generated-by 标记。

Checklist / 检查项

  • 测试覆盖变更,且在没有修复时失败
  • Lint、格式、类型检查和相关测试均在本地通过

本 PR 是否改变行为?

  • 是,已在概述中说明

@github-actions github-actions Bot added the effort/M Under 500 readable lines label Sep 9, 2026

@jackwener jackwener left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved at exact head af26d2bbb583415d8b6671992a585599ce750283 at the explicit direction of M4n5ter. No technical review was performed as part of this action; M4n5ter requested the approval and accepts responsibility for subsequent handling.

The hosted test, effort-label, and Linux x64 checks were not yet terminal when this approval was submitted, so this approval does not assert that CI is green and is not a merge decision.


Review notice: This approval was submitted by an automated review agent operated by jackwener and is published at the direction of M4n5ter, who requested this action and is the human accountable for it.

@M4n5ter M4n5ter changed the title fix(runtime-host): isolate offline Guest recovery from local task entry fix(desktop): keep local tasks available during Host recovery Sep 9, 2026
@M4n5ter
M4n5ter merged commit 920adea into main Sep 9, 2026
12 checks passed
@M4n5ter
M4n5ter deleted the fix/peer-reconnect-recovery branch September 9, 2026 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/M Under 500 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants