mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-21 16:18:55 +00:00
fix(cron): resolve the no-override store fallback lazily so late env repoints can't write the real jobs file
Complements ec0227b43 (context-scoped cron store): the ContextVar override
is the right tool for deliberate cross-profile scoping, but with no
override active, _current_cron_store() returned the import-time constants —
so a HERMES_HOME set AFTER cron.jobs import (the filed incident: test
fixtures patching the env too late) still read/wrote the user's real
jobs.json. The fallback now resolves the active profile home fresh via
get_hermes_home() (context-local override, then env) and scopes the store
to it; when the home is unchanged since import, the exact module-level
constants are returned as before (zero change in the common path, and they
remain the documented compatibility surface). use_cron_store() still wins.
Three tests: late env repoint scopes the store; unchanged home returns the
import-time constants identically; an active use_cron_store() override
beats the env.
This commit is contained in:
parent
0f102fa4dc
commit
5c121f157f
2 changed files with 51 additions and 2 deletions
20
cron/jobs.py
20
cron/jobs.py
|
|
@ -116,11 +116,27 @@ _cron_store_override: ContextVar[Optional[_CronStorePaths]] = ContextVar(
|
|||
|
||||
|
||||
def _current_cron_store() -> _CronStorePaths:
|
||||
"""Return paths pinned to this execution context's profile."""
|
||||
"""Return paths pinned to this execution context's profile.
|
||||
|
||||
With no use_cron_store() override active, the active profile home is
|
||||
resolved FRESH via get_hermes_home() (context-local override, then the
|
||||
HERMES_HOME env var) instead of trusting the import-time capture. A test
|
||||
or embedder that re-points HERMES_HOME after this module was imported
|
||||
therefore reads/writes ITS OWN store — not whatever jobs.json the import
|
||||
happened to freeze (the filed incident: fixtures that patched the env too
|
||||
late silently rewrote the user's real jobs file). The module-level
|
||||
constants keep their import-time values as the documented compatibility
|
||||
surface, and the common path (home unchanged since import) still returns
|
||||
them unchanged.
|
||||
"""
|
||||
override = _cron_store_override.get()
|
||||
if override is not None:
|
||||
return override
|
||||
return _CronStorePaths(CRON_DIR, JOBS_FILE, OUTPUT_DIR)
|
||||
home = get_hermes_home().resolve()
|
||||
if home == HERMES_DIR:
|
||||
return _CronStorePaths(CRON_DIR, JOBS_FILE, OUTPUT_DIR)
|
||||
cron_dir = home / "cron"
|
||||
return _CronStorePaths(cron_dir, cron_dir / "jobs.json", cron_dir / "output")
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
|
|
|
|||
|
|
@ -1945,3 +1945,36 @@ class TestClaimDispatch:
|
|||
# At minimum, the good job's record is still intact (no corruption from the bad neighbor)
|
||||
loaded = {j["id"]: j for j in load_jobs()}
|
||||
assert "good" in loaded
|
||||
|
||||
|
||||
class TestLateEnvRepointScopesStore:
|
||||
"""A HERMES_HOME set AFTER cron.jobs import must scope the store even
|
||||
without use_cron_store(): fixtures that patch the environment too late
|
||||
previously read/wrote the import-time jobs.json — the user's real file."""
|
||||
|
||||
def test_late_env_repoint_scopes_store(self, tmp_path, monkeypatch):
|
||||
import cron.jobs as jobs
|
||||
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
||||
store = jobs._current_cron_store()
|
||||
expected = tmp_path.resolve() / "cron"
|
||||
assert store.cron_dir == expected
|
||||
assert store.jobs_file == expected / "jobs.json"
|
||||
assert store.output_dir == expected / "output"
|
||||
# the import-time compatibility constants are untouched
|
||||
assert jobs.JOBS_FILE != store.jobs_file
|
||||
|
||||
def test_unchanged_home_returns_import_time_constants(self, monkeypatch):
|
||||
import cron.jobs as jobs
|
||||
|
||||
monkeypatch.setenv("HERMES_HOME", str(jobs.HERMES_DIR))
|
||||
store = jobs._current_cron_store()
|
||||
assert store.jobs_file is jobs.JOBS_FILE
|
||||
|
||||
def test_use_cron_store_override_still_wins(self, tmp_path, monkeypatch):
|
||||
import cron.jobs as jobs
|
||||
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path / "env-home"))
|
||||
with jobs.use_cron_store(tmp_path / "override-home"):
|
||||
store = jobs._current_cron_store()
|
||||
assert store.jobs_file == (tmp_path / "override-home").resolve() / "cron" / "jobs.json"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue