fix(config): order ghost-home guard after ambient short-circuit (#4516 Codex gate)

Codex SILENT finding: the new 'if not target.exists(): return {}' guard ran
BEFORE the ambient-resolver short-circuit, so a matching ambient profile home
whose directory does not physically exist (fresh install / monkeypatched cfg)
returned {} instead of deferring to get_config() — breaking in-memory overrides
and changing the default-profile missing-home path. Move the guard below the
ambient short-circuit; add a regression test (matching-but-nonexistent ambient
home still defers to get_config()).
This commit is contained in:
nesquena-hermes
2026-06-20 03:57:56 +00:00
parent acd2c186ef
commit e1e2bbc7ef
2 changed files with 22 additions and 3 deletions
+6 -3
View File
@@ -510,15 +510,18 @@ def get_config_for_profile_home(profile_home: "Path | str | None") -> dict:
target = Path(profile_home).expanduser()
except Exception:
return get_config()
if not target.exists():
return {}
# If the ambient resolver already points at this profile home, defer to
# get_config() so in-memory overrides (monkeypatched cfg) are honored.
# get_config() so in-memory overrides (monkeypatched cfg) are honored. This
# MUST run before the nonexistent-home guard below: a matching ambient home
# whose directory doesn't physically exist yet (fresh install, monkeypatched
# cfg) must still resolve through get_config(), not return {} (#4516 gate).
try:
if _get_config_path().parent == target:
return get_config()
except Exception:
pass
if not target.exists():
return {}
# Read the profile file directly and apply documented defaults locally so the
# returned dict matches ambient get_config() shape (including built-in
# personalities) without mutating any global cache state.
@@ -108,6 +108,22 @@ def test_matching_home_defers_to_get_config(_two_profiles):
]
def test_matching_ambient_home_that_does_not_exist_still_defers_to_get_config(_two_profiles, monkeypatch, tmp_path):
"""Regression (#4516 gate): the nonexistent-home guard must run AFTER the
ambient-resolver short-circuit. A home that matches the ambient config path
but whose directory doesn't physically exist (fresh install / monkeypatched
cfg with no dir on disk) must still defer to get_config() — NOT return {}."""
cfg, default_home, profile_b_home = _two_profiles
ghost_ambient = tmp_path / "ghost-ambient"
monkeypatch.setenv("HERMES_CONFIG_PATH", str(ghost_ambient / "config.yaml"))
cfg.reload_config()
assert not ghost_ambient.exists()
# The requested home matches the (nonexistent) ambient home → must defer to
# get_config(), honoring the in-memory cfg, not short-circuit to {}.
result = cfg.get_config_for_profile_home(ghost_ambient)
assert result == cfg.get_config()
def test_empty_or_none_home_falls_back_to_get_config(_two_profiles):
"""A missing/empty profile home (ImportError fallback path in the worker)
must not crash — it falls back to the ambient get_config()."""