Skip to content

fix(desktop): let the launch-owner guard retire the owned Host on quit - #4756

Open
me2seeks wants to merge 1 commit into
mainfrom
fix/4730-quit-guard-close-authority
Open

fix(desktop): let the launch-owner guard retire the owned Host on quit#4756
me2seeks wants to merge 1 commit into
mainfrom
fix/4730-quit-guard-close-authority

Conversation

@me2seeks

@me2seeks me2seeks commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Closes #4730. Review context: #3709 comment confirming the guard-detach root cause and the corrected scope after #4709.

Summary

  • Stop releasing the candidate launch barrier in RuntimeHostDesktopManager.#close(). Releasing detached the launch-owner guard at the exact moment it was the close authority, so the guard ignored the IPC disconnect that would otherwise have closed the Host — an owned ephemeral Host could survive a full quit.
  • Quit no longer drives retirement. prepareRuntimeHostQuit only probes Host activity to feed the interruption-consent dialog; the guard closes the owned Host after the Desktop process exits. The synchronous retirement drive, waitForProcessExit PID polling, and the force-terminate recovery path are removed from the quit flow.
  • The Host reports upgradeBlockingActivity in host.diagnostics.query (optional field; decoded as unknown when absent) so the consent question stays answered by the same authority that gates host.upgrade.prepare.
  • A guard-triggered close now records the retirement reason, so launcher loss exits 0 instead of looking like a crash.

Protocol epoch moves 112 → 113 for the additive diagnostics key: older Clients reject the unknown key on exact decode, so the pair refuses at the handshake.

Why

#4730's guaranteed-timeout symptom was neutralized by #4709's observation margin, but the root cause was untouched: #close() still released the barrier unconditionally. The driven retirement #3706 added becomes a transitional wrapper; this PR deletes it from the quit path while keeping retireOwnedLocalHost for the Desktop update-install and managed-service setup flows, which genuinely need a driven retirement.

Behavior change

  • Quit with a clear owned Host: no retirement drive, no exit wait; the guard closes the Host after process exit.
  • Quit with active work: unchanged consent dialog (copy now also promises durable recovery); on confirm, quit proceeds and the Host drains via the guard with its own shutdown deadline as the bound.
  • Probe failure (wedged Host) no longer blocks quit — the guard plus the Host-side deadline bound the outcome, so the retry/force/cancel recovery dialog is removed.

Verification

  • npm run build
  • npm --workspace @maka/desktop run typecheck
  • npx biome check on all changed files
  • node --test apps/desktop/dist/main/__tests__/*.test.js (2092 passed)
  • node --test packages/runtime-host/dist/__tests__/*.test.js (1677 passed, 12 platform skips)

AI use

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

Tool(s) and scope: Maka assisted investigation, implementation, tests, and review; the commit includes the required 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 — quit no longer drives or waits for Host retirement; the launch-owner guard is the close authority.
  • No

@me2seeks
me2seeks requested a review from Astro-Han September 4, 2026 09:17
@github-actions github-actions Bot added the effort/L Under 1000 readable lines label Sep 4, 2026
@me2seeks
me2seeks force-pushed the fix/4730-quit-guard-close-authority branch from 28f9bda to f98e93a Compare September 5, 2026 08:11

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

Reviewed current head f98e93ace880bd392608dbc3bad7b00fc3d1c4e3 (OPEN, MERGEABLE). No P0–P2; one P3 below. Gate stays NO-GO on red hosted test, which fails on an untouched spec.

P3 — the PR body understates the protocol epoch bump

The body says protocol epoch 109 → 110, but the exact diff is packages/runtime-host/src/protocol/index.ts:104 going 112 → 113. Please correct the description so reviewers checking compatibility against the stated numbers do not look at the wrong range.

Gate note (not attributed to this change)

Hosted test fails on the untouched apps/desktop/e2e/quote-selection.spec.ts:22,79-81; windows_recovery passes. Until that red is re-run or waived by maintainers, the gate cannot close either way.

What was checked on this head

Exit cleanup, launch-owner ownership, host resource reclamation, concurrent/reentrant and failure-recovery paths. What I could not judge: real Windows quit-path behavior with a live owned host was not reproduced locally.


Automated review notice: This comment was posted by an automated review agent operated by Astro-Han. It is not an independent human review and does not replace one.

简体中文

本条结论全部来自 @Luna-Deep-Qronos 的审查。我自己没有读这份 diff;我核的是当前 head 有没有漂移、以及 exact-head 的 CI 状态。当前 head 是 f98e93a,可合并。P3 是正文写的 epoch 数字跟实际 diff 对不上,改一下描述。另外线上 test 红在没动过的用例上,门禁等维护者处理。

Desktop quit unconditionally released the candidate launch barrier in
RuntimeHostDesktopManager.#close(), which detached the launch-owner
guard at the exact moment it was the close authority: the guard then
ignored the IPC disconnect that would otherwise have closed the Host,
so an owned ephemeral Host could survive a full quit.

Quit no longer drives retirement. prepareRuntimeHostQuit only probes
Host activity to feed the interruption-consent dialog, and the guard
closes the Host after process exit. The synchronous retirement drive,
the PID polling, and the force-terminate recovery path are removed.

The Host reports upgradeBlockingActivity in host.diagnostics.query so
the consent question stays answered by the same authority that gates
host.upgrade.prepare, and a guard-triggered close now records the
retirement reason instead of exiting like a crash.

Closes #4730.

Generated-by: Maka
@me2seeks
me2seeks force-pushed the fix/4730-quit-guard-close-authority branch from f98e93a to 851407f Compare September 5, 2026 09:57
@me2seeks

me2seeks commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (851407f). The two hosted test failures on the previous head were both Desktop transcript e2e specs untouched by this change (quote-selection, then transcript-scroll-cost on the re-run); main has since landed #4782 (dev renderer dep-optimizer generation) and #4831 (scroll assertion fix), so this run carries those. Epoch stays 112 → 113. P3 from the review (stated epoch numbers) was fixed in the body earlier.

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

Labels

effort/L Under 1000 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(desktop): quit retirement always times out before the Host can exit

2 participants