From f43b976209ea45511424cdfd2f9446b8cea7733d Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Thu, 3 Sep 2026 17:28:02 -0700 Subject: [PATCH] fix(ci-fallout): repoint the in-container docker test, two windows-only tests and the desktop exe-integrity patches to the defining modules; name bot_relay turn timeout/attempts as constants so the Desktop mirror test reads them instead of counting subprocess.run sites --- .../hermes-bots/relay-deliver-budget.test.ts | 15 ++++++++------- tests/docker/test_tui_prebuilt_bundle.py | 2 +- tests/hermes_cli/test_desktop_exe_integrity.py | 10 +++++----- tests/tools/test_windows_native_support.py | 2 +- tui_gateway/methods_bot_relay.py | 9 ++++++++- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/desktop/src/plugins/hermes-bots/relay-deliver-budget.test.ts b/apps/desktop/src/plugins/hermes-bots/relay-deliver-budget.test.ts index d7e933f5d1..78827f97bb 100644 --- a/apps/desktop/src/plugins/hermes-bots/relay-deliver-budget.test.ts +++ b/apps/desktop/src/plugins/hermes-bots/relay-deliver-budget.test.ts @@ -31,14 +31,15 @@ describe('bot_relay.deliver budget mirrors', () => { }) it('mirrors the backend per-attempt turn timeout', () => { - const attemptTimeouts = [...relayHandler.matchAll(/timeout=(\d+)/g)].map(m => Number(m[1])) + // The backend names both numbers explicitly (methods_bot_relay.py) so the mirror is a + // constant-to-constant check, not a count of textual subprocess.run(...) call sites. + const attemptTimeout = relayHandler.match(/^TURN_ATTEMPT_TIMEOUT_SECONDS\s*=\s*(\d+)/m) + const maxAttempts = relayHandler.match(/^TURN_MAX_ATTEMPTS\s*=\s*(\d+)/m) - expect(attemptTimeouts.length, 'expected the attempt and its policy-gated retry').toBeGreaterThanOrEqual(2) - // Every attempt shares one bound; if they ever diverge, the mirror below is - // no longer a faithful ceiling and this must be revisited deliberately. - expect(new Set(attemptTimeouts).size, `attempt timeouts diverged: ${attemptTimeouts}`).toBe(1) - expect(tsConstant('RELAY_TURN_ATTEMPT_MS')).toBe(attemptTimeouts[0] * 1000) - expect(tsConstant('RELAY_TURN_MAX_ATTEMPTS')).toBe(attemptTimeouts.length) + expect(attemptTimeout, 'TURN_ATTEMPT_TIMEOUT_SECONDS must exist in methods_bot_relay.py').toBeTruthy() + expect(maxAttempts, 'TURN_MAX_ATTEMPTS must exist in methods_bot_relay.py').toBeTruthy() + expect(tsConstant('RELAY_TURN_ATTEMPT_MS')).toBe(Number(attemptTimeout![1]) * 1000) + expect(tsConstant('RELAY_TURN_MAX_ATTEMPTS')).toBe(Number(maxAttempts![1])) }) it('keeps the client deadline strictly greater than the backend ceiling', () => { diff --git a/tests/docker/test_tui_prebuilt_bundle.py b/tests/docker/test_tui_prebuilt_bundle.py index 4cdf992920..93e778cf40 100644 --- a/tests/docker/test_tui_prebuilt_bundle.py +++ b/tests/docker/test_tui_prebuilt_bundle.py @@ -58,7 +58,7 @@ def test_prebuilt_bundle_present_and_no_runtime_install(built_image: str) -> Non py = ( "import json\n" "from pathlib import Path\n" - "from hermes_cli.main import _tui_need_npm_install, _find_bundled_tui, _make_tui_argv\n" + "from hermes_cli.main_tui_launch import _tui_need_npm_install, _find_bundled_tui, _make_tui_argv\n" "ui = Path('/opt/hermes/ui-tui')\n" "argv, cwd = _make_tui_argv(ui, tui_dev=False)\n" "out = {\n" diff --git a/tests/hermes_cli/test_desktop_exe_integrity.py b/tests/hermes_cli/test_desktop_exe_integrity.py index 0f151c33da..55e0e9f8d7 100644 --- a/tests/hermes_cli/test_desktop_exe_integrity.py +++ b/tests/hermes_cli/test_desktop_exe_integrity.py @@ -310,16 +310,16 @@ def test_build_only_fails_when_pack_produces_corrupt_exe(tmp_path, monkeypatch, make_pe(staging / "win-unpacked" / "Hermes.exe", PE_AMD64, truncate_to=0x300) return subprocess.CompletedProcess(list(cmd), 0) - with patch("hermes_cli.main.shutil.which", return_value="/usr/bin/npm"), \ - patch("hermes_cli.main._resolve_node_runtime_npm", return_value="npm.cmd"), \ - patch("hermes_cli.main._run_npm_install_deterministic", return_value=install_ok), \ - patch("hermes_cli.main._desktop_build_needed", return_value=True), \ + with patch("hermes_cli.main_desktop.shutil.which", return_value="/usr/bin/npm"), \ + patch("hermes_cli.main_install_repair._resolve_node_runtime_npm", return_value="npm.cmd"), \ + patch("hermes_cli.main_web_build._run_npm_install_deterministic", return_value=install_ok), \ + patch("hermes_cli.main_desktop._desktop_build_needed", return_value=True), \ patch("hermes_cli.main_desktop._stop_desktop_processes_locking_build", return_value=[]), \ patch("hermes_cli.main_desktop._purge_electron_build_cache", return_value=[]), \ patch("hermes_cli.main_desktop._desktop_stamp_path", return_value=tmp_path / "stamp.json"), \ patch("hermes_cli.main_desktop._write_desktop_build_stamp") as mock_stamp, \ patch("hermes_cli.main_desktop._windows_native_machine", return_value="AMD64"), \ - patch("hermes_cli.main.subprocess.run", side_effect=pack_into_staging), \ + patch("hermes_cli.main_desktop.subprocess.run", side_effect=pack_into_staging), \ pytest.raises(SystemExit) as exc: cli_main.cmd_gui(_ns()) diff --git a/tests/tools/test_windows_native_support.py b/tests/tools/test_windows_native_support.py index 7e65985243..b41a462764 100644 --- a/tests/tools/test_windows_native_support.py +++ b/tests/tools/test_windows_native_support.py @@ -764,7 +764,7 @@ class TestGitBashPathNormalization: ``windows_only``: the function's whole job is producing native Windows paths, which is only meaningful where ``os.sep`` is ``\\``. """ - import cli as cli_mod + from hermes_cli import worktree_ops as cli_mod assert cli_mod._normalize_git_bash_path("/c/Users/foo") == r"C:\Users\foo" assert cli_mod._normalize_git_bash_path("/C/Users/foo") == r"C:\Users\foo" assert cli_mod._normalize_git_bash_path("/cygdrive/d/data") == r"D:\data" diff --git a/tui_gateway/methods_bot_relay.py b/tui_gateway/methods_bot_relay.py index 7571c33e6c..df11a0db72 100644 --- a/tui_gateway/methods_bot_relay.py +++ b/tui_gateway/methods_bot_relay.py @@ -22,11 +22,18 @@ def _relay_root() -> Path: return home.parent.parent if home.parent.name == "profiles" else home +# Per-attempt turn timeout and attempt ceiling for bot_relay.deliver. The Desktop client mirrors +# both (apps/desktop/src/plugins/hermes-bots/relay.ts: RELAY_TURN_ATTEMPT_MS / RELAY_TURN_MAX_ATTEMPTS) +# and its relay-deliver-budget test reads these two lines, so a change here must be deliberate (#93911). +TURN_ATTEMPT_TIMEOUT_SECONDS = 600 +TURN_MAX_ATTEMPTS = 2 # first attempt + the policy-gated re-run + + def _run_delivery(profile: str, tmp: str) -> subprocess.CompletedProcess: from tools.bot_relay import local_delivery_command return subprocess.run( local_delivery_command(profile, tmp), capture_output=True, text=True, encoding="utf-8", - errors="replace", timeout=600) + errors="replace", timeout=TURN_ATTEMPT_TIMEOUT_SECONDS) @method("bot_relay.roster.sync")