401efb0b2b
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.