fix(update): hard-stop when Windows hermes.exe shim stays locked - #68821
fix(update): hard-stop when Windows hermes.exe shim stays locked#68821smfworks wants to merge 1 commit into
Conversation
|
Thanks for targeting the post-quarantine path. The defect is still present on current main: Suggested changes
The update pipeline was mechanically extracted after this branch, so salvage should retain the current Automated hermes-sweeper review. |
5a9a059 to
5bf3f09
Compare
Sweeper response — salvageability=highHead:
VerificationRebased on current |
Verification Summary (adversarial 6-check — PASS)Head: 1–6 PASS. Locked-shim hard-stop + reboot_required regression; no uv/pip install in that path. |
|
Stewardship ping — verified this fix is still needed on current
The PR adds |
5bf3f09 to
f50bcf4
Compare
Stewardship follow-up — rebased onto current
|
f50bcf4 to
3629782
Compare
When quarantine cannot free venv entry-point shims, abort install with holder PIDs and remediation instead of continuing into WinError 32 x3 and a doomed ZIP fallback (NousResearch#68760). Deferred OS rename paths also block install until the machine is restarted — the shim path remains locked for uv.
3629782 to
2281496
Compare
|
Restored source + tests onto current |
On Windows `hermes update` can never complete. `hermes` is launched
through a distlib console-script launcher, which is not a thin redirect:
it spawns `venv\Scripts\python.exe` as a child, hands it the launcher's
own path as the script, and blocks. Every invocation is two processes:
hermes.exe (pid A, holds Scripts\hermes.exe as its running image)
\_ python.exe (pid B, runs hermes_cli.main)
The update ends in `uv pip install -e .`, which rewrites the console-
script shims -- including the one pid A has mapped. Windows refuses to
replace a running image, so uv fails with "The process cannot access the
file because it is being used by another process. (os error 32)". The
git path fails, the ZIP fallback fails identically, and no retry can
succeed: nothing pid B does releases the lock, because the holder is its
parent.
Remove the hazard rather than race it. Before the update touches
anything, re-launch it as a detached `python -m hermes_cli.main`
grandchild and let pids B and A exit. The grandchild waits for the
launcher to disappear, then updates against an ordinary unlocked file:
hermes.exe (A) --> python.exe (B) --> python.exe (C, detached)
exit exit waits for A, then updates
Hooked into cmd_update after --check (which installs nothing) and before
the update lock is acquired: a trampolining parent that had already
written the lock marker would release it moments later while the
grandchild ran unlocked, since the grandchild's acquire() sees its
still-live parent as an ancestor and would run under a claim about to
vanish.
stdin is DEVNULL so the detached updater cannot race the reclaimed shell
for keystrokes. That also selects the existing non-interactive path, so
local changes follow updates.non_interactive_local_changes (default
stash) rather than prompting where nobody can answer.
Off Windows maybe_trampoline() returns False immediately and behavior is
unchanged; POSIX replaces a running executable's inode atomically.
Verified on Windows 11 / Python 3.11.15 / uv, non-elevated: before, four
consecutive failed updates; after, the launcher exits, the grandchild
completes the update, and no os error 32 occurs on either path.
Scoped deliberately to the trampoline. The residual case where another
process holds a shim, and cleanup of the reboot-deferred rename entries
that case queues, are addressed by NousResearch#68821 and NousResearch#85942 respectively and
are not duplicated here.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FGLv7LyNrpaPm4ciGqhyxD
Summary
Fixes the failure mode in #68760: when
venv/Scripts/hermes.execannot be renamed out of the way,hermes updateused to continue into uv/pip, print WinError 32 three times, then fall back to ZIP which hits the same lock.Preflight concurrent/venv holders already exist; the gap was the post-quarantine path: if rename + restart-schedule leave the shim locked, install must hard-stop with PIDs and remediation — not hope uv succeeds.
Changes
_quarantine_running_hermes_exenow returns(moved, blocked)blockedincludes failed renames and deferred OS rename locks (path still occupied until restart)_run_quarantined_installraisesHermesShimLockedErrorwhenblockedis non-emptytaskkillone-liner, restart guidance when applicablecmd_updateexits 2 onHermesShimLockedErrorTest plan
Closes #68760