fix(update): consolidate pre-update backups into one gated mechanism (#65754)

hermes update ran TWO separate pre-update backup mechanisms: the
config-gated full zip (updates.pre_update_backup, default off) and an
unconditional quick state snapshot added for #15733 that ignored the
user's setting entirely. On a large state.db (observed: 24 GB) the
'cheap' snapshot silently added ~60s to every update and ate 24 GB of
disk in state-snapshots/.

Now there is ONE mechanism, gated by updates.pre_update_backup with
three modes:

- quick (new default): state snapshot of critical small files (pairing
  JSONs, cron jobs, config, auth, per-profile DBs). Files over 1 GiB
  are skipped with a warning so a bloated state.db can never stall the
  update again.
- full: the quick snapshot plus the HERMES_HOME zip (old 'true'
  behavior; --backup forces it for one run).
- off: nothing runs — an explicit opt-out now disables the quick
  snapshot too (--no-backup does the same per-run).

Legacy booleans are honored: true -> full, false -> off.

_run_pre_update_backup() now returns the quick-snapshot id so the
post-update cron-jobs restore safety net (#34600) keeps working; the
snapshot moved from the post-fetch site to the pre-mutation site,
which also covers the zip-fallback update path it previously missed.
This commit is contained in:
Teknium 2026-07-16 08:47:25 -07:00 committed by GitHub
parent 8462764367
commit d0dcb9a5fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 343 additions and 161 deletions

View file

@ -3110,21 +3110,29 @@ DEFAULT_CONFIG = {
# ``hermes update`` behaviour.
"updates": {
# Run a full ``hermes backup``-style zip of HERMES_HOME before every
# ``hermes update``. Backups land in ``<HERMES_HOME>/backups/`` and
# can be restored with ``hermes import <path>``. Off by default:
# zipping a large HERMES_HOME (sessions DB, caches, skills) can add
# minutes to every update. The #48200 incident — a ``hermes update
# --yes`` run that computed a wrong path and silently wiped the
# user's ``.env``, ``MEMORY.md``, ``kanban.db``, custom skills, and
# scripts — is the reason this knob exists; enable it (here, or via
# ``--backup`` for a single run) if you want that safety net.
"pre_update_backup": False,
# How many pre-update backup zips to retain. Older ones are pruned
# automatically after each successful backup. Values below 1 are
# floored to 1 — the backup just created is always preserved. To
# disable backups entirely, set ``pre_update_backup: false`` above
# rather than ``backup_keep: 0``.
# Pre-update safety backup — ONE consolidated mechanism, three modes:
#
# quick (default) — snapshot critical small state files (pairing
# JSONs, cron jobs, config.yaml, .env, auth.json, per-profile
# DBs) into <HERMES_HOME>/state-snapshots/ before the update.
# Files over 1 GiB (e.g. a bloated state.db) are skipped with a
# warning so the snapshot stays fast. Restore via ``/snapshot``.
# This is the #15733 (lost pairing data) / #34600 (emptied cron
# jobs) safety net.
# full — the quick snapshot PLUS a full ``hermes backup``-style zip
# of HERMES_HOME into <HERMES_HOME>/backups/, restorable with
# ``hermes import``. Can add minutes on large homes. This is the
# #48200 (wrong-path wipe) safety net. ``--backup`` forces this
# for a single run.
# off — no pre-update backup of any kind. ``--no-backup`` forces
# this for a single run.
#
# Legacy boolean values are honored: true -> full, false -> off.
"pre_update_backup": "quick",
# How many full pre-update backup zips to retain (mode ``full``).
# Older ones are pruned automatically after each successful backup.
# Values below 1 are floored to 1 — the backup just created is
# always preserved. The quick snapshot always keeps exactly 1.
"backup_keep": 5,
# What `hermes update` does with uncommitted local changes to the
# source tree when it runs NON-interactively — i.e. triggered from