From 832f77939a91f553b98bc8ab3d21129dfcb2ca90 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Wed, 2 Sep 2026 16:57:00 -0700 Subject: [PATCH] refactor(update): lift snapshot safety nets out of _check_and_apply_config_migration (192 -> 130 LOC) --- hermes_cli/update_cmd_config.py | 132 +++++++++++++++++--------------- 1 file changed, 69 insertions(+), 63 deletions(-) diff --git a/hermes_cli/update_cmd_config.py b/hermes_cli/update_cmd_config.py index df9437ae7c..d4f5bb3273 100644 --- a/hermes_cli/update_cmd_config.py +++ b/hermes_cli/update_cmd_config.py @@ -110,6 +110,74 @@ def _migrate_sibling_profile_configs() -> list[tuple[str, int, int]]: return migrated +def _restore_snapshot_safety_nets(pre_update_snapshot_id) -> None: + """Post-migration safety nets: restore cron jobs / protected model settings lost during the update, + for the active profile (from *pre_update_snapshot_id*) and every sibling profile (own snapshot).""" + # Safety net: migrations/desktop scheduler have emptied or truncated cron/jobs.json; + # restore from the pre-update snapshot if jobs went missing. + try: + from hermes_cli.backup import restore_cron_jobs_if_emptied + + cron_restore = restore_cron_jobs_if_emptied(pre_update_snapshot_id) + if cron_restore: + print() + print( + " ⚠️ cron/jobs.json lost jobs during this update — " + f"restored {cron_restore['job_count']} job(s) from " + f"pre-update snapshot {cron_restore['snapshot_id']}." + ) + except Exception as exc: + # Never let the cron safety net break an otherwise-good update. + logger.debug("Cron jobs auto-restore check failed: %s", exc) + + # Desktop update/repair cycles have rewritten model.provider/model.default and dropped + # moa:; restore only those protected keys from the same pre-update snapshot. + try: + from hermes_cli.backup import restore_config_model_settings_if_rewritten + + cfg_restore = restore_config_model_settings_if_rewritten(pre_update_snapshot_id) + if cfg_restore: + print() + print( + " ⚠️ config.yaml user model settings were rewritten during " + f"this update — restored {', '.join(cfg_restore['keys'])} " + f"from pre-update snapshot {cfg_restore['snapshot_id']}." + ) + except Exception as exc: + # Never let the config safety net break an otherwise-good update. + logger.debug("Config model-settings auto-restore check failed: %s", exc) + + # Same cron-jobs safety net per sibling profile against ITS OWN pre-update snapshot. + with _best_effort('Sibling cron auto-restore check failed: %s'): + from hermes_cli.backup import restore_cron_jobs_all_profiles + + for _restored in restore_cron_jobs_all_profiles( + _LAST_SIBLING_SNAPSHOTS + ): + print() + print( + f" ⚠️ Profile '{_restored['profile']}': cron/jobs.json " + f"lost jobs during this update — restored " + f"{_restored['job_count']} job(s) from pre-update " + f"snapshot {_restored['snapshot_id']}." + ) + + # Same config model-settings safety net for sibling profiles. + with _best_effort('Sibling config auto-restore check failed: %s'): + from hermes_cli.backup import restore_config_model_settings_all_profiles + + for _cfg_restored in restore_config_model_settings_all_profiles( + _LAST_SIBLING_SNAPSHOTS + ): + print() + print( + f" ⚠️ Profile '{_cfg_restored['profile']}': config.yaml " + f"user model settings were rewritten during this update — " + f"restored {', '.join(_cfg_restored['keys'])} from " + f"pre-update snapshot {_cfg_restored['snapshot_id']}." + ) + + def _check_and_apply_config_migration( *, assume_yes: bool = False, @@ -239,69 +307,7 @@ def _check_and_apply_config_migration( for _name, _from_ver, _to_ver in _migrated_siblings: print(f" ✓ Profile '{_name}': config format updated " f"(v{_from_ver} → v{_to_ver})") - # Safety net: migrations/desktop scheduler have emptied or truncated cron/jobs.json; - # restore from the pre-update snapshot if jobs went missing. - try: - from hermes_cli.backup import restore_cron_jobs_if_emptied - - cron_restore = restore_cron_jobs_if_emptied(pre_update_snapshot_id) - if cron_restore: - print() - print( - " ⚠️ cron/jobs.json lost jobs during this update — " - f"restored {cron_restore['job_count']} job(s) from " - f"pre-update snapshot {cron_restore['snapshot_id']}." - ) - except Exception as exc: - # Never let the cron safety net break an otherwise-good update. - logger.debug("Cron jobs auto-restore check failed: %s", exc) - - # Desktop update/repair cycles have rewritten model.provider/model.default and dropped - # moa:; restore only those protected keys from the same pre-update snapshot. - try: - from hermes_cli.backup import restore_config_model_settings_if_rewritten - - cfg_restore = restore_config_model_settings_if_rewritten(pre_update_snapshot_id) - if cfg_restore: - print() - print( - " ⚠️ config.yaml user model settings were rewritten during " - f"this update — restored {', '.join(cfg_restore['keys'])} " - f"from pre-update snapshot {cfg_restore['snapshot_id']}." - ) - except Exception as exc: - # Never let the config safety net break an otherwise-good update. - logger.debug("Config model-settings auto-restore check failed: %s", exc) - - # Same cron-jobs safety net per sibling profile against ITS OWN pre-update snapshot. - with _best_effort('Sibling cron auto-restore check failed: %s'): - from hermes_cli.backup import restore_cron_jobs_all_profiles - - for _restored in restore_cron_jobs_all_profiles( - _LAST_SIBLING_SNAPSHOTS - ): - print() - print( - f" ⚠️ Profile '{_restored['profile']}': cron/jobs.json " - f"lost jobs during this update — restored " - f"{_restored['job_count']} job(s) from pre-update " - f"snapshot {_restored['snapshot_id']}." - ) - - # Same config model-settings safety net for sibling profiles. - with _best_effort('Sibling config auto-restore check failed: %s'): - from hermes_cli.backup import restore_config_model_settings_all_profiles - - for _cfg_restored in restore_config_model_settings_all_profiles( - _LAST_SIBLING_SNAPSHOTS - ): - print() - print( - f" ⚠️ Profile '{_cfg_restored['profile']}': config.yaml " - f"user model settings were rewritten during this update — " - f"restored {', '.join(_cfg_restored['keys'])} from " - f"pre-update snapshot {_cfg_restored['snapshot_id']}." - ) + _restore_snapshot_safety_nets(pre_update_snapshot_id) # {profile: snapshot_id} from this run's pre-update backup, consumed by the per-profile