The pre_update_version co_varnames check added in af26acab73 rejected the
current updater's entrypoints, but it also rejected historical updaters
from 2026-07-26..08-16, whose _cmd_update_impl/cmd_update never declared
that local — their in-process dependency installs would have continued on
the old interpreter instead of handing off to the takeover child.
Invert the gate: the CURRENT updater declares the
_hermes_current_updater_frame sentinel local in both entrypoints; no
historical on-disk version can contain it. in_historical_update() now
hands off on entrypoint match unless the sentinel is present, restoring
the handoff for every historical window while still refusing current
frames. Verified live for all four frame classes; mutation check: with
the sentinel check removed, the current-updater refusal test fails.
26 lines
1018 B
Python
26 lines
1018 B
Python
"""Retired runtime installers must not turn agent construction into an update."""
|
|
from unittest.mock import Mock
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.mark.parametrize("module,name,locals_", [
|
|
("community_plugin", "cmd_update", ""),
|
|
("hermes_cli.main", "serve", ""),
|
|
# current updater entrypoints carry the sentinel local
|
|
("hermes_cli.update_cmd", "_cmd_update_impl",
|
|
" _hermes_current_updater_frame = True\n"),
|
|
])
|
|
def test_runtime_lookalikes_do_not_start_updates(module, name, locals_, monkeypatch):
|
|
from hermes_cli import _old_updater
|
|
from tools.lazy_deps import install_specs
|
|
|
|
child = Mock(return_value=(0, {}))
|
|
monkeypatch.setattr(_old_updater, "_run_child", child)
|
|
monkeypatch.setattr(_old_updater, "_result", None)
|
|
namespace = {"__name__": module, "install_specs": install_specs}
|
|
exec(f"def {name}():\n{locals_} install_specs(['hindsight-all'])\n", namespace)
|
|
with pytest.raises(ImportError, match="retired"):
|
|
namespace[name]()
|
|
child.assert_not_called()
|