Skip to content

fix(desktop): recover Runtime Host reads after reconnect - #3280

Open
sunheyi6 wants to merge 4 commits into
apache:mainfrom
sunheyi6:codex/fix-runtime-host-recovery
Open

fix(desktop): recover Runtime Host reads after reconnect#3280
sunheyi6 wants to merge 4 commits into
apache:mainfrom
sunheyi6:codex/fix-runtime-host-recovery

Conversation

@sunheyi6

Copy link
Copy Markdown
Contributor

Summary

  • replay transcript range reads against the current Desktop replica after Runtime Host replacement
  • make app:info a reconnectable read so project metadata queries survive connection loss
  • surface reconnect failures, candidate exit details, and top-level Runtime Host lifecycle errors
  • add regression coverage for a stale transcript generation request completing on the replacement replica

Root cause and behavior change

The Runtime Host database was healthy. The visible task-read failures came from an incomplete recovery path after the Host connection was lost: some reads remained bound to the dead connection, while transcript navigation rejected requests solely because the replacement replica had a newer generation.

After this change, eligible reads wait for the replacement connection, and durable transcript sequence requests continue against the current replica. The added diagnostics also make future Host exits and reconnect failures observable instead of leaving only downstream connection_lost errors.

Validation

  • npm --workspace @maka/runtime-host run build
  • npm --workspace @maka/desktop run build:main
  • Desktop Runtime Host observer/manager/reconnecting IPC tests: 56 passed
  • Runtime Host execution candidate tests: 3 passed
  • Runtime Host reconnecting connection tests: 9 passed
  • Biome check on all changed files
  • git diff --check

Known local-only result: the owned-candidate suite passed 5/6; its prompt-exit timing test exceeded the 2-second election deadline on this Windows environment and was terminated by the test harness. The changed launcher code only observes the existing exit event and does not alter shutdown control flow.


中文说明

本次问题不是 runtime.sqlite 损坏,而是 Runtime Host 断线后的恢复链路不完整:部分读取仍然发往旧连接,聊天记录请求也会因为后台换代而直接报错。

修改后,可重试的读取会等待新连接;旧代聊天记录请求会交给当前副本实际执行。同时补充了重连失败、子进程退出码/信号和顶层生命周期异常日志,方便后续定位真正的退出原因。

@sunheyi6
sunheyi6 marked this pull request as ready for review August 20, 2026 03:30

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks — separating "the database is healthy" from "the recovery path never rebound these reads" is the right diagnosis, and making app:info reconnectable is clearly correct. Reviewed exact head 2f89bcde025db8127dd89f1916e5bd47bd620b7b.

My concern is with how the transcript fix is expressed rather than with the intent. The guard was removed rather than narrowed, which leaves the invariant the new comment asserts unowned by any code, and the new test asserts that the stale request runs, not that it returns the right slice. Details inline, along with a note on the new logging.

No CI checks are currently reported for this head.

Review disclosure: this review was prepared with Claude Code, which read the diff at this head, traced generation through the observer and the preload transcript contract, and checked the surrounding reset path. The reproductions are code reading, not execution. The human contributor reviewed it before posting.

Comment thread apps/desktop/src/main/runtime-host-session-observer.ts Outdated
Comment thread packages/runtime-host/src/client/launcher.ts Outdated

@likun666661 likun666661 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.

Requesting changes on the current head. The app:info reconnectable-read change and the diagnosis that durable transcript sequence is not a Desktop replica generation both look sound. There is one blocking recovery gap inline: the new Host-epoch fence is never advanced in the preload handle after open() returns, so a real Host replacement turns all later range reads into permanent failures until the whole handle is recreated. Please make the range identity follow reset batches (or explicitly reopen the handle) and cover a post-open Host-epoch change.

Scope note, non-blocking: the candidate-exit/reconnect logging is useful but orthogonal to the read repair and substantially widens this PR. If it stays here, please keep reconnect errors generalized/redacted and isolate embedder-provided exit sinks so diagnostics cannot throw through the child-process event listener.

Review performed against fc7a9890.

Comment thread apps/desktop/src/preload/preload.ts Outdated
sunheyi6 and others added 3 commits August 20, 2026 21:56
- narrow the transcript range guard to the Session and host epoch,
  dropping generation from the range request contract so reads keep
  working across replica replacement and stale Hosts reject instead of
  reading a different slice
- route candidate-exit diagnostics through a caller-provided onExit sink
  instead of console in the launcher library; Desktop manager owns the
  sink and candidate-entry logs the generalized lifecycle error message
The range request closure captured the open-time host epoch forever, so
after a reset installed a replacement Host every subsequent range request
sent the stale epoch and the Main-process guard rejected it. Track a
mutable generation+hostEpoch identity alongside the handle: initialized
from the open result, adopted from accepted reset batches, and used by
every range request. Requests already dispatched with the old epoch still
fail closed on the guard.
The rebase onto upstream main pulled in workflow updates; keeping the
fork branch free of workflow changes so this PR does not touch
.github/workflows.
@sunheyi6
sunheyi6 force-pushed the codex/fix-runtime-host-recovery branch from e32f6a7 to 9f7a41a Compare August 20, 2026 14:03

@sunheyi6 sunheyi6 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants