fix(update): venv-blocker scan truncated cmdlines, breaking the gateway exemption and dead-ending Desktop updates - #82158
Merged
Conversation
…oke the gateway exemption _detect_venv_python_processes() returned cmdline_raw[:120]. Gateways autostarted via the managed-runtime interpreter carry a >120-char exe path (.hermes-runtime\python\generation-...\cpython-3.11-...), so the truncated cmdline ended inside the exe path, before '-m hermes_cli.main gateway run'. The Desktop preflight's pausable-gateway exemption (_scan_venv_blockers._is_pausable_gateway) therefore never matched, the gateway was reported as a blocker, and every Desktop update aborted with 'Update didn't finish' even with all windows closed — the updater's own gateway pause never got a chance to run. Fix: return the full cmdline from the detector and truncate only at display time (_format_venv_python_holders_message and the scan's JSON cmdline field, after redaction). Reproduced live on Windows 11: scan reported blocked=true for '...cpython-3.1' (truncated); after the fix the same gateway pair scans clear with pausable_gateways=2.
Contributor
૮ >ﻌ< ა ci reviewran on a827aae
|
Collaborator
Duplicate of #78094. Both patches preserve the complete venv-holder command line for gateway classification and truncate only displayed diagnostics, fixing the same long-path Windows update blocker. |
6 tasks
5 tasks
teknium1
added a commit
that referenced
this pull request
Aug 9, 2026
…te trees without pre-signalling Follow-up to #82179 addressing helix4u's review comment (#82179 issuecomment-5229441571). Three parts: 1. Desktop teardown (salvaged from #77436, @4adwentures): the update hand-off's releaseBackendLock() sent SIGTERM to the primary backend BEFORE taskkill /T. If the launcher exits first, Windows can no longer enumerate its descendants and they survive holding the venv — the Electron path that creates the orphan #82179 then has to repair. New stopBackendTreesForUpdate() tree-kills the live root first, with the behavioral vitest from #77436. The scanner half of #77436 is deliberately NOT taken (superseded by #82158's full-cmdline scan). 2. Tree-aware orphan classification: _orphaned_desktop_backend_pids() previously refused the whole holder set when any holder had a live parent. But the scanner legitimately returns an orphaned serve root AND its descendants (the venv trampoline's uv-managed interpreter worker — which carries the same backend argv — plus .hermes-runtime children). Those have a live parent: the orphan root itself. Now holders inside an accepted orphan root's tree fold into that root (only roots are returned; taskkill /T reaps descendants), and live-parent backends defer to the ancestry check instead of refusing outright. Anything outside an orphan tree still refuses. 3. Tests for the mixed shapes: root+managed-runtime child, grandchild depth, non-descendant stray alongside an orphan root (still refuses), descendant exited mid-classify. E2E on a real Windows box: spawned a detached backend-shaped orphan that itself spawned children (3 python descendants); the scanner-shaped mixed holder set classified to [root], taskkill /T reaped root and all descendants. The live Desktop backend on the box still classified None (refusal preserved). The first E2E attempt caught exactly the trampoline/worker case the mocks missed — the live worker re-execs with the same backend argv and a live parent — which is what part 2 fixes. Co-Authored-By: 4adwentures <296413879+4adwentures@users.noreply.github.com>
This was referenced Aug 9, 2026
kotasiddharth
pushed a commit
to kotasiddharth/hermes-agent
that referenced
this pull request
Aug 9, 2026
…te trees without pre-signalling Follow-up to NousResearch#82179 addressing helix4u's review comment (NousResearch#82179 issuecomment-5229441571). Three parts: 1. Desktop teardown (salvaged from NousResearch#77436, @4adwentures): the update hand-off's releaseBackendLock() sent SIGTERM to the primary backend BEFORE taskkill /T. If the launcher exits first, Windows can no longer enumerate its descendants and they survive holding the venv — the Electron path that creates the orphan NousResearch#82179 then has to repair. New stopBackendTreesForUpdate() tree-kills the live root first, with the behavioral vitest from NousResearch#77436. The scanner half of NousResearch#77436 is deliberately NOT taken (superseded by NousResearch#82158's full-cmdline scan). 2. Tree-aware orphan classification: _orphaned_desktop_backend_pids() previously refused the whole holder set when any holder had a live parent. But the scanner legitimately returns an orphaned serve root AND its descendants (the venv trampoline's uv-managed interpreter worker — which carries the same backend argv — plus .hermes-runtime children). Those have a live parent: the orphan root itself. Now holders inside an accepted orphan root's tree fold into that root (only roots are returned; taskkill /T reaps descendants), and live-parent backends defer to the ancestry check instead of refusing outright. Anything outside an orphan tree still refuses. 3. Tests for the mixed shapes: root+managed-runtime child, grandchild depth, non-descendant stray alongside an orphan root (still refuses), descendant exited mid-classify. E2E on a real Windows box: spawned a detached backend-shaped orphan that itself spawned children (3 python descendants); the scanner-shaped mixed holder set classified to [root], taskkill /T reaped root and all descendants. The live Desktop backend on the box still classified None (refusal preserved). The first E2E attempt caught exactly the trampoline/worker case the mocks missed — the live worker re-execs with the same backend argv and a live parent — which is what part 2 fixes. Co-Authored-By: 4adwentures <296413879+4adwentures@users.noreply.github.com>
ma1138569845
pushed a commit
to ma1138569845/dechnicAuditor-agent
that referenced
this pull request
Aug 10, 2026
…te trees without pre-signalling Follow-up to NousResearch#82179 addressing helix4u's review comment (NousResearch#82179 issuecomment-5229441571). Three parts: 1. Desktop teardown (salvaged from NousResearch#77436, @4adwentures): the update hand-off's releaseBackendLock() sent SIGTERM to the primary backend BEFORE taskkill /T. If the launcher exits first, Windows can no longer enumerate its descendants and they survive holding the venv — the Electron path that creates the orphan NousResearch#82179 then has to repair. New stopBackendTreesForUpdate() tree-kills the live root first, with the behavioral vitest from NousResearch#77436. The scanner half of NousResearch#77436 is deliberately NOT taken (superseded by NousResearch#82158's full-cmdline scan). 2. Tree-aware orphan classification: _orphaned_desktop_backend_pids() previously refused the whole holder set when any holder had a live parent. But the scanner legitimately returns an orphaned serve root AND its descendants (the venv trampoline's uv-managed interpreter worker — which carries the same backend argv — plus .hermes-runtime children). Those have a live parent: the orphan root itself. Now holders inside an accepted orphan root's tree fold into that root (only roots are returned; taskkill /T reaps descendants), and live-parent backends defer to the ancestry check instead of refusing outright. Anything outside an orphan tree still refuses. 3. Tests for the mixed shapes: root+managed-runtime child, grandchild depth, non-descendant stray alongside an orphan root (still refuses), descendant exited mid-classify. E2E on a real Windows box: spawned a detached backend-shaped orphan that itself spawned children (3 python descendants); the scanner-shaped mixed holder set classified to [root], taskkill /T reaped root and all descendants. The live Desktop backend on the box still classified None (refusal preserved). The first E2E attempt caught exactly the trampoline/worker case the mocks missed — the live worker re-execs with the same backend argv and a live parent — which is what part 2 fixes. Co-Authored-By: 4adwentures <296413879+4adwentures@users.noreply.github.com>
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…te trees without pre-signalling Follow-up to NousResearch#82179 addressing helix4u's review comment (NousResearch#82179 issuecomment-5229441571). Three parts: 1. Desktop teardown (salvaged from NousResearch#77436, @4adwentures): the update hand-off's releaseBackendLock() sent SIGTERM to the primary backend BEFORE taskkill /T. If the launcher exits first, Windows can no longer enumerate its descendants and they survive holding the venv — the Electron path that creates the orphan NousResearch#82179 then has to repair. New stopBackendTreesForUpdate() tree-kills the live root first, with the behavioral vitest from NousResearch#77436. The scanner half of NousResearch#77436 is deliberately NOT taken (superseded by NousResearch#82158's full-cmdline scan). 2. Tree-aware orphan classification: _orphaned_desktop_backend_pids() previously refused the whole holder set when any holder had a live parent. But the scanner legitimately returns an orphaned serve root AND its descendants (the venv trampoline's uv-managed interpreter worker — which carries the same backend argv — plus .hermes-runtime children). Those have a live parent: the orphan root itself. Now holders inside an accepted orphan root's tree fold into that root (only roots are returned; taskkill /T reaps descendants), and live-parent backends defer to the ancestry check instead of refusing outright. Anything outside an orphan tree still refuses. 3. Tests for the mixed shapes: root+managed-runtime child, grandchild depth, non-descendant stray alongside an orphan root (still refuses), descendant exited mid-classify. E2E on a real Windows box: spawned a detached backend-shaped orphan that itself spawned children (3 python descendants); the scanner-shaped mixed holder set classified to [root], taskkill /T reaped root and all descendants. The live Desktop backend on the box still classified None (refusal preserved). The first E2E attempt caught exactly the trampoline/worker case the mocks missed — the live worker re-execs with the same backend argv and a live parent — which is what part 2 fixes. Co-Authored-By: 4adwentures <296413879+4adwentures@users.noreply.github.com>
blut-agent
pushed a commit
to blut-agent/hermes-agent-fork
that referenced
this pull request
Aug 11, 2026
…te trees without pre-signalling Follow-up to NousResearch#82179 addressing helix4u's review comment (NousResearch#82179 issuecomment-5229441571). Three parts: 1. Desktop teardown (salvaged from NousResearch#77436, @4adwentures): the update hand-off's releaseBackendLock() sent SIGTERM to the primary backend BEFORE taskkill /T. If the launcher exits first, Windows can no longer enumerate its descendants and they survive holding the venv — the Electron path that creates the orphan NousResearch#82179 then has to repair. New stopBackendTreesForUpdate() tree-kills the live root first, with the behavioral vitest from NousResearch#77436. The scanner half of NousResearch#77436 is deliberately NOT taken (superseded by NousResearch#82158's full-cmdline scan). 2. Tree-aware orphan classification: _orphaned_desktop_backend_pids() previously refused the whole holder set when any holder had a live parent. But the scanner legitimately returns an orphaned serve root AND its descendants (the venv trampoline's uv-managed interpreter worker — which carries the same backend argv — plus .hermes-runtime children). Those have a live parent: the orphan root itself. Now holders inside an accepted orphan root's tree fold into that root (only roots are returned; taskkill /T reaps descendants), and live-parent backends defer to the ancestry check instead of refusing outright. Anything outside an orphan tree still refuses. 3. Tests for the mixed shapes: root+managed-runtime child, grandchild depth, non-descendant stray alongside an orphan root (still refuses), descendant exited mid-classify. E2E on a real Windows box: spawned a detached backend-shaped orphan that itself spawned children (3 python descendants); the scanner-shaped mixed holder set classified to [root], taskkill /T reaped root and all descendants. The live Desktop backend on the box still classified None (refusal preserved). The first E2E attempt caught exactly the trampoline/worker case the mocks missed — the live worker re-execs with the same backend argv and a live parent — which is what part 2 fixes. Co-Authored-By: 4adwentures <296413879+4adwentures@users.noreply.github.com>
33hodl
pushed a commit
to 33hodl/hermes-agent
that referenced
this pull request
Aug 12, 2026
…te trees without pre-signalling Follow-up to NousResearch#82179 addressing helix4u's review comment (NousResearch#82179 issuecomment-5229441571). Three parts: 1. Desktop teardown (salvaged from NousResearch#77436, @4adwentures): the update hand-off's releaseBackendLock() sent SIGTERM to the primary backend BEFORE taskkill /T. If the launcher exits first, Windows can no longer enumerate its descendants and they survive holding the venv — the Electron path that creates the orphan NousResearch#82179 then has to repair. New stopBackendTreesForUpdate() tree-kills the live root first, with the behavioral vitest from NousResearch#77436. The scanner half of NousResearch#77436 is deliberately NOT taken (superseded by NousResearch#82158's full-cmdline scan). 2. Tree-aware orphan classification: _orphaned_desktop_backend_pids() previously refused the whole holder set when any holder had a live parent. But the scanner legitimately returns an orphaned serve root AND its descendants (the venv trampoline's uv-managed interpreter worker — which carries the same backend argv — plus .hermes-runtime children). Those have a live parent: the orphan root itself. Now holders inside an accepted orphan root's tree fold into that root (only roots are returned; taskkill /T reaps descendants), and live-parent backends defer to the ancestry check instead of refusing outright. Anything outside an orphan tree still refuses. 3. Tests for the mixed shapes: root+managed-runtime child, grandchild depth, non-descendant stray alongside an orphan root (still refuses), descendant exited mid-classify. E2E on a real Windows box: spawned a detached backend-shaped orphan that itself spawned children (3 python descendants); the scanner-shaped mixed holder set classified to [root], taskkill /T reaped root and all descendants. The live Desktop backend on the box still classified None (refusal preserved). The first E2E attempt caught exactly the trampoline/worker case the mocks missed — the live worker re-execs with the same backend argv and a live parent — which is what part 2 fixes. Co-Authored-By: 4adwentures <296413879+4adwentures@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
Desktop update aborts every time with "Update didn't finish — Update aborted: another Hermes process is using this installation: PID … python.exe C:\….hermes-runtime\python\generation-…\cpython-3.1" even with every Hermes window closed. The 'stray' process is the user's own autostarted gateway — which the updater is fully capable of pausing itself (
_pause_windows_gateways_for_update), and which the preflight exemption (#0bec37aef / #f3edd0e53) exists to exempt.Root cause
_detect_venv_python_processes()(hermes_cli/update_cmd.py) returnscmdline_raw[:120]. Gateways launched via the managed-runtime interpreter have a >120-char exe path, so the truncated cmdline ends inside the exe path — before-m hermes_cli.main gateway run._is_pausable_gateway()can't match it, the gateway is reported as a blocker, and the update dead-ends forever.Reproduced live on Windows 11 (the truncated cmdline literally ends at
cpython-3.1, exactly what the user's error dialog shows):Fix
_format_venv_python_holders_messageand the scan's JSONcmdlinefield (after redaction).Validation
tests/hermes_cli/test_scan_venv_blockers.py+test_update_venv_health.py: 29 passed on Windows.{"blocked": false, "pausable_gateways": 2}.