fix(update): the purge keeps hermes_constants; it is refreshed in place instead

hermes_constants owns the _HERMES_HOME_OVERRIDE ContextVar. Evicting it hands later
imports a fresh var: a reset token taken through the old module raises, and an
override set before the purge silently disappears. _reload_updated_runtime_modules
already re-executes it in place before every purge, so new symbols still arrive.
Caught by tests/hermes_cli/test_update_config_reload_tools_config.py on the stack.
This commit is contained in:
kshitijk4poor
2026-09-15 21:50:30 +05:30
committed by kshitij
parent d6ea7aa002
commit 5341f135a5
2 changed files with 9 additions and 7 deletions
+6 -4
View File
@@ -27,10 +27,12 @@ _UPDATE_RUNTIME_RELOAD_MODULES = "hermes_constants", "tools.environments.local",
#: Modules EXECUTING the update survive the purge: evicting them buys nothing (running frames
#: keep them alive) and reloading them mid-flight is the one genuinely unsafe move.
#: ``hermes_logging`` is protected for a different reason: its queue listener, handler list and
#: ``_logging_initialized`` flag are module globals, so a fresh copy starts a SECOND
#: QueueListener over the same log files while the first one keeps running.
_STALE_PURGE_PROTECTED = frozenset({"hermes_cli", "hermes_cli.main", "hermes_logging"})
#: Two root modules carry process-wide identity state and are refreshed in place by
#: ``_reload_updated_runtime_modules`` instead: ``hermes_logging`` (a fresh copy starts a SECOND
#: QueueListener over the same log files while the first keeps running) and ``hermes_constants``
#: (its ``_HERMES_HOME_OVERRIDE`` ContextVar — a token taken through the old module cannot reset a
#: fresh module's var, and an override set before the purge would silently vanish).
_STALE_PURGE_PROTECTED = frozenset({"hermes_cli", "hermes_cli.main", "hermes_logging", "hermes_constants"})
#: The updater's own module family (``update_cmd*``, ``update_receipt``, ``update_inventory``,
#: ``update_lock``, ...) is protected as a prefix: these hold per-run state — the open receipt
@@ -70,9 +70,9 @@ def test_update_migration_survives_stale_module_missing_call_time_symbol(tmp_pat
def test_update_migration_import_failure_after_purge_prints_fallback(tmp_path, monkeypatch, capsys):
"""The purge evicts ``hermes_cli.*`` but not root modules (``hermes_constants``, ...), so the
post-purge ``from hermes_cli.config import ...`` re-executes NEW config.py against OLD root
modules and can raise ImportError. That must print the 'run hermes config migrate' fallback and
"""The purge protects ``hermes_constants`` (identity-bearing ContextVar state), so the
post-purge ``from hermes_cli.config import ...`` re-executes NEW config.py against that OLD
root module and can raise ImportError. That must print the 'run hermes config migrate' fallback and
return — not escape and abort the rest of post-update maintenance (fleet restart)."""
home = tmp_path / "flat-home"
home.mkdir()