refactor(cli): decompose _cmd_update_impl into phase helpers, unify duplicated update helpers, compact comments

hermes_cli/update_cmd.py 11217 -> 10204 LOC; _cmd_update_impl 2797 -> 521 LOC.

Decomposition (behavior-neutral, AST free-name verified) — _cmd_update_impl is
now a thin orchestrator calling, in order:
  _clear_windows_venv_holders_or_exit -> _prepare_checkout_for_update
  (-> _CheckoutPlan) -> _repair_current_checkout | _pull_updates ->
  _sync_python_dependencies_after_pull -> _run_post_update_maintenance ->
  _restart_gateway_fleet_after_update (-> _GatewayRestartOutcome;
  _restart_systemd_gateway_units) -> _resume_windows_gateways_and_merge_outcome
  -> _verify_fleet_after_update. _resolve_manage_cmd hoisted to module level.

Unified helpers: _git_run (49 captured git subprocess.run sites),
_systemctl / _systemctl_reset_and_restart (17 sites + 2 pairs),
_sweep_bytecode_after_update (3x), _print_bundled_skills_sync_report (ZIP+git),
_ensure_venv_pip (ZIP+git), _self_and_non_gateway_ancestor_pids (2x),
_record_update_step (4x), _write_gateway_update_exit_code for the 3 inline
".update_exit_code" writes. Dropped duplicate nested copies of
_wait_for_service_active/_service_restart_sec/_print_items, dead
upstream_exists, a dead if/pass branch and unused imports.

Comments/docstrings hand-compacted (236 blocks, AST-identical with docstrings
normalized); rationale/invariant sentences kept.

Tests: source-inspection guards repointed to the helper that now owns the code
(test_update_self_lock, test_update_fleet_check_fail_closed,
test_update_apply_shallow_count); new regression test drives the real Windows
resume/merge helper.
This commit is contained in:
Teknium
2026-09-02 12:27:35 -07:00
parent a3d33fe22f
commit 401efb0b2b
5 changed files with 3217 additions and 4189 deletions
+3171 -4184
View File
File diff suppressed because it is too large Load Diff
@@ -82,10 +82,13 @@ def test_source_matches_exercised_logic():
"""
import inspect
src = inspect.getsource(update_cmd._cmd_update_impl)
src = inspect.getsource(update_cmd._prepare_checkout_for_update)
assert "apply_is_shallow" in src
assert "_github_compare_behind" in src
assert "commit count unknown on this shallow checkout" in src
# The "count unknown" print stays in _cmd_update_impl, which consumes the plan.
assert "commit count unknown on this shallow checkout" in inspect.getsource(
update_cmd._cmd_update_impl
)
def test_full_clone_keeps_exact_count():
@@ -130,7 +130,9 @@ class TestCallSiteWiring:
def _impl_source(self):
from hermes_cli import update_cmd
return inspect.getsource(update_cmd._cmd_update_impl)
# The fleet-version probe lives in the post-restart verifier that
# _cmd_update_impl calls; guard the wiring there.
return inspect.getsource(update_cmd._verify_fleet_after_update)
def test_settle_sleep_gated_on_expected_runtimes(self):
src = self._impl_source()
+5 -2
View File
@@ -249,9 +249,12 @@ def test_pre_fetch_flow_has_no_self_lock_preflight():
pre_fetch = src[:fetch_idx]
assert "_detect_self_loaded_native_modules()" not in pre_fetch
assert "_m()._abort_dependency_sync_if_self_locked" not in pre_fetch
# ... and it must still guard the dependency sync after the code swap.
# ... and it must still guard the dependency sync after the code swap
# (the sync itself lives in _sync_python_dependencies_after_pull).
post_fetch = src[fetch_idx:]
assert "_m()._abort_dependency_sync_if_self_locked" in post_fetch
assert "_sync_python_dependencies_after_pull(" in post_fetch
sync_src = inspect.getsource(update_cmd._sync_python_dependencies_after_pull)
assert "_m()._abort_dependency_sync_if_self_locked" in sync_src
def test_zip_update_guards_dependency_sync():
@@ -165,3 +165,36 @@ def test_resume_with_no_relaunched_profiles_key_does_not_crash_the_merge():
for profile in token.get("relaunched_profiles") or []:
relaunched_profiles.append(profile)
assert relaunched_profiles == []
def test_merge_helper_reads_token_keys_into_restart_outcome(monkeypatch):
"""Drive the real merge helper (not a mirror): the Windows resume token's
``relaunched_profiles`` / ``restarted_services`` / ``service_profiles`` /
``services`` keys must land in the shared restart bookkeeping."""
from hermes_cli import update_cmd
monkeypatch.setattr(hm, "_resume_windows_gateways_after_update", lambda token: None)
outcome = update_cmd._GatewayRestartOutcome(
incomplete=False,
phase_errors=[],
pre_restart_gateway_pids=[],
restarted_services=["hermes-gateway"],
failed_or_stale_units=[],
relaunched_profiles=[],
externally_supervised_profiles=[],
killed_pids=set(),
)
token = {
"resume_needed": False,
"relaunched_profiles": ["p1"],
"restarted_services": ["svc"],
"service_profiles": {"svc": "p2", "pending": "p3"},
"services": ["pending"],
}
with patch("hermes_cli.update_receipt.record_gateway_restart", lambda **kw: None):
update_cmd._resume_windows_gateways_and_merge_outcome(outcome, token, False)
assert outcome.relaunched_profiles == ["p1", "p2"]
assert outcome.restarted_services == ["hermes-gateway", "svc"]
assert outcome.failed_or_stale_units == ["p3"]
assert outcome.incomplete is False