Skip to content

fix(desktop): make Windows updates complete end to end - #84778

Closed
royalaid wants to merge 5 commits into
NousResearch:mainfrom
royalaid:fix/windows-updater-handoff
Closed

royalaid wants to merge 5 commits into
NousResearch:mainfrom
royalaid:fix/windows-updater-handoff

Conversation

@royalaid

@royalaid royalaid commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Motivation

On Windows, a Desktop update must replace files inside the managed Hermes virtual environment. A live Python process can keep those files mapped (.pyd native extensions, the Python launcher, or Hermes executables), so updating underneath it can leave the install half-replaced. Refusing that mutation is correct; making the user manually hunt down Hermes-owned descendants is not.

The current Desktop flow already stops the backend it directly owns and verifies that venv\\Scripts\\hermes.exe is unlocked. That does not prove the target installation has no remaining Python descendants. Field logs repeatedly show the shim unlocked while the existing venv-blocker scanner still reports 1–32 holders, including managed serve, gateway, MCP, ACP, and Python worker processes.

The same incident exposed a second failure mode: after the checkout updated successfully, a content-hash shortcut could skip rebuilding the packaged Desktop and relaunch stale code. The update UI then appeared to succeed even though the packaged commit lagged HEAD.

Fix

Keep the existing Windows update architecture, but make its ownership and success gates explicit:

  1. Release Desktop's tracked backend trees.
  2. Scan the target installation with the existing venv-blocker scanner.
  3. For scanner-proven holders only, run Windows taskkill /T /F on each distinct PID, settle, and re-scan for at most three passes.
  4. Prefer the staged Tauri Hermes-Setup.exe --update --branch <branch> handoff when it exists, restoring the branded blue updater window with per-step progress and live output.
  5. Use scripts/desktop-update/windows.ps1 only when no staged installer exists, preserving CLI/source installs.
  6. Force the updater's Desktop rebuild, then compare checkout HEAD with the packaged resources/install-stamp.json commit before relaunch. A mismatch is a failed update, not success.
  7. In the CLI packaging path, require the packaged install-stamp commit to equal checkout HEAD even when the renderer content hash is unchanged.

This is deliberately not a system-wide Python kill. Eligibility remains owned by the existing scanner: only processes it associates with the target Hermes installation are terminated, and the final scan is still the fail-closed gate.

Why the staged installer wins

The staged Tauri installer is the visible update surface users expect. The earlier Desktop selector resolved both candidates but always chose the repository PowerShell script, so the script silently shadowed Hermes-Setup.exe whenever both existed. Selection now has one tested precedence point: staged installer first, repository script fallback.

Pre-#74782 staged installers keep the existing marker pre-write compatibility path, so restoring installer precedence does not reintroduce the self-marker deadlock.

Related bugs and prior approaches

Report / PR Relationship to this PR
#61514 Persistent orphaned venv-resident children; this PR adds the missing scanner-verified force-drain action.
#74805 First-attempt process-table settling; bounded settle/re-scan covers the transient case.
#78037 Broader Windows pipeline proposal; this PR keeps the existing architecture and fixes the observed blocker, handoff, and stale-package invariants.
#75498 / #75556 / #75631 Tauri/marker handoff failures; compatibility behavior is preserved without VBScript or a private transport.

Windows identity repair

The update path also keeps the user-visible identity repair needed after a successful rebuild:

  • stamp Hermes.exe with Hermes file metadata and fail a Windows package if stamping fails;
  • set the packaged AUMID and taskbar relaunch details;
  • write System.Title = Hermes and System.AppUserModel.ID = com.nousresearch.hermes on Start Menu and Desktop shortcuts;
  • repair those shortcuts after an updater rebuild and on first launch of the upgraded app.

Verification

  • 87 focused Electron updater tests across seven files;
  • Electron main-process typecheck and focused lint/format checks;
  • 60 Rust bootstrap-installer tests;
  • focused Python package-commit invariant tests;
  • updater selector coverage for staged-first, script-only, and no-handoff cases;
  • stale checkout/package SHA coverage after a forced rebuild;
  • PR CI green on the current head.

Canary

The native Windows release candidate is built from fork-integration plus the staged-installer precedence change. The remaining live canary will record the visible click-through and verify, in one run:

  1. the scanner finds and force-drains target-install process trees;
  2. the blue Tauri updater appears instead of the script-only handoff;
  3. the updater completes and relaunches Hermes;
  4. the relaunched package install-stamp commit equals checkout HEAD.

No WSL path or bridge-quiesce bypass is part of the canary.

@alt-glitch alt-glitch added type/bug Something isn't working comp/desktop Electron desktop app (apps/desktop/*) comp/cli CLI entry point, hermes_cli/, setup wizard comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint tool/mcp MCP client and OAuth platform/windows Native Windows-specific behavior or breakage P3 Low — cosmetic, nice to have needs-decision Awaiting maintainer decision before any implementation sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-automation Sweeper risk: may affect CI, automerge, label sync, or maintainer automation labels Aug 12, 2026
@royalaid

Copy link
Copy Markdown
Contributor Author

Actually me here, just want to say I am still working on this specific PR as the fixes that were generated first used VBscript and other nonsense so I am still auditing the full update path and working to shave down the PR as it has a lot of changes that don't really need to be here

@royalaid
royalaid force-pushed the fix/windows-updater-handoff branch 2 times, most recently from 922258f to a62cc5d Compare August 13, 2026 10:17
@royalaid
royalaid marked this pull request as ready for review August 13, 2026 10:53
@royalaid
royalaid requested a review from a team August 13, 2026 10:53
@royalaid
royalaid force-pushed the fix/windows-updater-handoff branch 2 times, most recently from 1012154 to d9d8dd6 Compare August 13, 2026 22:38
@dontcallmejames

Copy link
Copy Markdown
Contributor

Windows reproduction / design constraint from a real affected installation:

  • The original false positive was a long managed-runtime gateway argv truncated before -m hermes_cli.main gateway run classification; 0b33ee88e / fix(update): classify venv holders on the full cmdline, truncate only for display #78188 address that independently.
  • After that fix, the remaining update coordination problem is the Desktop-owned python -m hermes_cli.main serve backend racing the handoff, plus normal ACP-client descendants (for example Buzz-launched hermes-acp.exe) holding managed-runtime files.
  • The safe policy should be: identify and coordinate only the Desktop-owned backend; re-scan; then refuse unknown/ACP/external holders with an actionable result. Avoid runtime-wide or scanner-wide taskkill /T /F, because unrelated workloads can legitimately use the managed runtime.

I verified a successful Windows in-app path as: update action → Desktop clean exit → updater exit code 0 → Desktop relaunch. The durable design should retain that atomic handoff while preserving the no-broad-kill boundary.

@royalaid
royalaid force-pushed the fix/windows-updater-handoff branch from e270ac6 to c912255 Compare August 15, 2026 12:36
Select only the canonical nested PowerShell updater for the visible Update flow and fail closed to the manual command when it is absent. Preserve the staged installer solely for the existing packaged bootstrap-recovery path.
@royalaid
royalaid force-pushed the fix/windows-updater-handoff branch from c912255 to 339504f Compare August 15, 2026 13:20
@Enough1122

Copy link
Copy Markdown
Contributor

AI code review — automated review for reference, author can ignore or act on any point.

fix(desktop): make Windows updates complete end to end

  • apps/bootstrap-installer/src-tauri/src/bootstrap.rs (resolve_windows_desktop_exe_for_machines): when no candidate matches a runnable PE machine, the code falls back to all existing candidates (let eligible = if matching.is_empty() { existing } else { matching }) and picks the newest. On an x64 host whose build produced only win-arm64-unpacked/Hermes.exe, the updater would relaunch an executable the host cannot run — and verify_packaged_desktop_commit (update.rs) would happily verify that wrong-arch package because the stamp matches. Consider returning None when existing is non-empty but matching is empty, so the rebuild-verification path surfaces the problem instead of launching an un-runnable binary.
  • hermes_cli/main.py (_detect_venv_python_processes): force_drain_eligible is exe_norm.startswith(venv_prefix) — i.e. any process executing from this venv's interpreter is a tree-kill target during update, including a user's manually started hermes serve, a gateway, or a long-running CLI session, not just the Desktop-owned backend. The PR's own design note says to "identify and coordinate only the Desktop-owned backend; re-scan; then refuse unknown/ACP/external holders." The current eligibility is broader than that stated policy — suggest narrowing it to desktop-spawned backends, or documenting the wider blast radius in the scanner output.
  • apps/desktop/scripts/after-pack.mjs: the hook now propagates identity-stamp failures so a build hard-fails when rcedit/stamping is unavailable or transiently broken. Intentional per the identity invariant, but note the Windows update build now depends on the rcedit tool being present and healthy at pack time; a transient failure aborts the entire update rather than just shipping a stock icon. Consider a retry or a clearer preflight error (e.g., "rcedit unavailable") so the failure mode is diagnosable.
  • Minor: commit verification now exists in two places reading two different stamp files — the Rust gate reads resources/install-stamp.json beside the packaged exe (update.rs) while the Python build decision reads desktop-build-stamp.json under HERMES_HOME (hermes_cli/main.py _desktop_build_needed). Both drive the same invariant; worth a comment cross-referencing them so they don't drift.

@alt-glitch alt-glitch added P2 Medium — degraded but workaround exists and removed comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint labels Aug 15, 2026
@alt-glitch alt-glitch added area/install-update Installer, updater, packaging, wheels, doctor comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint tool/mcp MCP client and OAuth needs-decision Awaiting maintainer decision before any implementation sweeper:risk-automation Sweeper risk: may affect CI, automerge, label sync, or maintainer automation and removed tool/mcp MCP client and OAuth P3 Low — cosmetic, nice to have needs-decision Awaiting maintainer decision before any implementation sweeper:risk-automation Sweeper risk: may affect CI, automerge, label sync, or maintainer automation labels Aug 15, 2026
@royalaid

Copy link
Copy Markdown
Contributor Author

Superseded by #92879 — rebased onto current main after ~1,700 commits of drift, and reduced to the core fix: a consent-gated, authenticated drain of the Hermes processes that block a Windows update, so a blocked update finally has a way forward instead of a dead-end dialog. The new revision extends the safeToStop blocker taxonomy that main shipped in the meantime, and answers the review feedback here in its body.

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

Labels

area/install-update Installer, updater, packaging, wheels, doctor comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) needs-decision Awaiting maintainer decision before any implementation P2 Medium — degraded but workaround exists platform/windows Native Windows-specific behavior or breakage sweeper:risk-automation Sweeper risk: may affect CI, automerge, label sync, or maintainer automation sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows tool/mcp MCP client and OAuth type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants