Skip to content

fix(gateway): make shutdown diagnostics cross-platform - #64215

Open
mudrii wants to merge 1 commit into
NousResearch:mainfrom
mudrii:fix/process-test-portability
Open

fix(gateway): make shutdown diagnostics cross-platform#64215
mudrii wants to merge 1 commit into
NousResearch:mainfrom
mudrii:fix/process-test-portability

Conversation

@mudrii

@mudrii mudrii commented Jul 14, 2026

Copy link
Copy Markdown

Summary

  • replace the GNU-only timeout dependency in shutdown diagnostics with a self-contained shell watchdog
  • avoid GNU-specific ps --sort and add a macOS load-average fallback
  • make the signal-handler worker test recognize macOS zombie processes via BSD ps

Why

Stock macOS does not provide GNU timeout, /proc/loadavg, or GNU ps --sort. The diagnostic subprocess therefore failed before collecting anything, while zombie workers could be misclassified as alive by the test helper.

Verification

  • scripts/run_tests.sh tests/gateway/test_shutdown_forensics.py tests/hermes_cli/test_signal_handler_kanban_worker.py
  • 33 passed, 0 failed
  • ruff check passed
  • git diff --check passed

…s-platform

Two test suites failed on macOS despite passing on Linux:

* tests/gateway/test_shutdown_forensics.py::test_spawns_subprocess_and_writes_output
  spawn_async_diagnostic invoked GNU coreutils 'timeout', which is not
  present on macOS (and not on stock Git Bash).  The Popen immediately
  raised FileNotFoundError and the function returned None.  Replace the
  external 'timeout' wrapper with an in-script watchdog: a backgrounded
  subshell that sleeps for timeout_seconds then SIGKILLs the parent
  shell.  A foreground 'trap ... EXIT' cancels the watchdog on clean
  exit so fast runs don't pay the sleep.  Net contract matches the
  prior GNU-timeout behaviour.  Also drop the GNU-only
  'ps --sort=-pcpu' and 'cat /proc/loadavg' for BSD-equivalent
  variants (sysctl -n vm.loadavg) so the script runs on macOS too.

* tests/hermes_cli/test_signal_handler_kanban_worker.py::test_sigterm_with_kanban_task_env_terminates_quickly
  _is_alive_like_dispatcher only inspected /proc/<pid>/status on Linux.
  On macOS a SIGTERM'd + os._exit'd worker leaves a zombie whose PID
  still answers os.kill(pid, 0) successfully, so the polling loop
  never observed a transition to dead and the test timed out after 2s.
  Mirror the production _pid_alive helper in hermes_cli/kanban_db.py:
  keep the /proc-based check on Linux and add a BSD-style
  'ps -o stat=' probe on darwin that treats any 'Z' in the stat field
  as dead.  Both branches use a tight timeout so a wedged ps can't
  stall the polling loop.

Verification: pytest -q tests/gateway/test_shutdown_forensics.py
tests/hermes_cli/test_signal_handler_kanban_worker.py — 33 passed,
10 consecutive runs, no flakes.  ruff check clean for both files.
Copilot AI review requested due to automatic review settings July 14, 2026 06:17

Copilot AI 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.

Pull request overview

This PR improves gateway shutdown diagnostics and related tests to work on macOS by removing GNU/Linux-specific dependencies (timeout, /proc/loadavg, and GNU ps --sort) and adding portable fallbacks. This helps ensure shutdown forensics actually run and that the kanban worker “alive” detection test treats zombie processes as dead on macOS.

Changes:

  • Replace GNU timeout usage in shutdown diagnostics with an inline bash watchdog that self-terminates after timeout_seconds.
  • Remove GNU ps --sort usage and add a macOS-compatible load average fallback (sysctl -n vm.loadavg).
  • Update the kanban worker signal-handler test helper to detect zombie state on macOS via ps -o stat=.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
gateway/shutdown_forensics.py Makes the async shutdown diagnostic script self-timeout and adds macOS-compatible loadavg collection.
tests/hermes_cli/test_signal_handler_kanban_worker.py Extends the test’s “pid alive” helper to treat macOS zombie processes as dead.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 247 to +248
"echo '--- ps auxf (top 60 by cpu) ---'; "
"ps auxf --sort=-pcpu 2>/dev/null | head -60; "
"ps auxf 2>/dev/null | head -60; "
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery labels Jul 14, 2026

@teknium1 teknium1 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 for the focused portability fix. The current-head premise is still present: gateway/shutdown_forensics.py:258 invokes GNU timeout, and the PR target files have not changed since base 226e8de827a669e8ffa7035b27d70c19e44b1208.

Problems

  • gateway/shutdown_forensics.py:248 now runs unsorted ps auxf, but the preceding diagnostic heading still says top 60 by cpu. This makes the captured shutdown log inaccurate. This matches the existing Copilot inline observation.

Suggested changes

  • Rename the heading to reflect unsorted output (for example, first 60), or add a genuinely portable CPU-ordering path with a fallback.

The Darwin zombie probe in the test helper aligns with current production handling at hermes_cli/kanban_db.py:6119-6133.

Automated hermes-sweeper review.

"echo '--- date ---'; date -u +%Y-%m-%dT%H:%M:%SZ; "
"echo '--- ps auxf (top 60 by cpu) ---'; "
"ps auxf --sort=-pcpu 2>/dev/null | head -60; "
"ps auxf 2>/dev/null | head -60; "

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.

The preceding heading still says top 60 by cpu, but this fallback is no longer CPU-sorted. Please rename it to describe the actual unsorted output (for example, first 60) or restore a portable ordering path.

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

Labels

comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants