polish(mem): readonly config read, debug-level trim logs, loud frame test

Simplify-pass follow-up on the #66355 salvage:

1. _config_settings runs on EVERY trim attempt (before the cooldown
   check) and only reads — swap load_config for load_config_readonly.
   Deep-copying the whole config per attempt generates exactly the
   allocator garbage this module exists to release. Tests re-seamed.

2. Trim-failure logs demoted warning->debug at all 3 periodic sites
   (gateway housekeeping, idle reaper, slash worker): sibling failure
   branches in the same loops log at debug, and a persistent failure
   (e.g. broken import after a partial update) would otherwise warn
   every 60s forever.

3. The frame-inspection test now asserts the expected locals exist
   before reading them — a rename in _run_prompt_submit fails the test
   loudly instead of vacuously passing on None.
This commit is contained in:
kshitij
2026-08-02 22:20:25 +05:30
parent da43a8527b
commit 3fad8fdc45
6 changed files with 27 additions and 8 deletions
+5 -1
View File
@@ -25436,7 +25436,11 @@ def _start_gateway_housekeeping(stop_event: threading.Event, adapters=None, loop
trim_memory(reason="messaging gateway housekeeping")
except Exception as exc:
logger.warning(
# debug, not warning: sibling housekeeping branches all log
# failures at debug, and a persistent failure (e.g. broken
# import after a partial update) would otherwise warn every
# 60s forever.
logger.debug(
"gateway housekeeping memory trim failed: %s: %s",
type(exc).__name__,
exc,
+7 -2
View File
@@ -37,9 +37,14 @@ def _config_settings() -> tuple[bool, float, int, float]:
log_every_n: Any = _DEFAULT_LOG_EVERY_N
info_log_min_delta_mb: Any = _DEFAULT_INFO_LOG_MIN_DELTA_MB
try:
from hermes_cli.config import load_config
# Read-only access: settings are only .get()ed and coerced, never
# mutated — use the no-deepcopy variant. This runs on EVERY trim
# attempt (before the cooldown check), and generating a full-config
# deepcopy per attempt is exactly the allocator garbage this module
# exists to release.
from hermes_cli.config import load_config_readonly
config = load_config() or {}
config = load_config_readonly() or {}
context = config.get("context") if isinstance(config, dict) else None
settings = context.get("memory_trim") if isinstance(context, dict) else None
if isinstance(settings, dict):
+2 -2
View File
@@ -144,7 +144,7 @@ def test_config_cooldown_controls_rate_limit(monkeypatch):
monkeypatch.setattr(mem_trim, "_last_trim_monotonic", 1.0)
monkeypatch.setattr(mem_trim.time, "monotonic", lambda: 100.0)
monkeypatch.setattr(
"hermes_cli.config.load_config",
"hermes_cli.config.load_config_readonly",
lambda: {
"context": {
"memory_trim": {"enabled": True, "cooldown_seconds": 120.0}
@@ -161,7 +161,7 @@ def test_legacy_environment_switch_does_not_control_behavior(monkeypatch):
monkeypatch.setattr(mem_trim, "_malloc_trim", trim)
monkeypatch.setenv("HERMES_DISABLE_MEMORY_TRIM", "1")
monkeypatch.setattr(
"hermes_cli.config.load_config",
"hermes_cli.config.load_config_readonly",
lambda: {"context": {"memory_trim": {"enabled": True}}},
)
+7 -1
View File
@@ -14186,7 +14186,7 @@ def test_reap_idle_sessions_logs_trim_failure(monkeypatch, caplog):
monkeypatch.setattr(mem_trim, "trim_memory", lambda **_kw: (_ for _ in ()).throw(RuntimeError("boom")))
server._sessions.clear()
try:
with caplog.at_level("WARNING", logger="tui_gateway.server"):
with caplog.at_level("DEBUG", logger="tui_gateway.server"):
server._reap_idle_sessions()
assert "idle reaper memory trim failed: RuntimeError: boom" in caplog.text
finally:
@@ -15610,6 +15610,12 @@ def test_prompt_submit_releases_old_history_before_heap_trim(monkeypatch):
frame = inspect.currentframe()
assert frame is not None and frame.f_back is not None
caller_locals = frame.f_back.f_locals
# Loud, not vacuous: if the production locals are ever renamed, fail
# the test instead of silently reading None and "passing".
assert "history" in caller_locals and "run_kwargs" in caller_locals, (
"expected locals not found in _run_prompt_submit's finally frame — "
"renamed? update this test"
)
observed["history"] = caller_locals.get("history")
observed["run_kwargs"] = caller_locals.get("run_kwargs")
+3 -1
View File
@@ -1064,7 +1064,9 @@ def _reap_idle_sessions() -> None:
trim_memory(reason="idle reaper periodic trim")
except Exception as exc:
logger.warning(
# debug, not warning — persistent failure would repeat every reaper
# scan (300s) forever; sibling failure branches log at debug.
logger.debug(
"idle reaper memory trim failed: %s: %s", type(exc).__name__, exc
)
+3 -1
View File
@@ -183,7 +183,9 @@ def main():
trim_memory(reason="slash worker command completion")
except Exception as exc:
logger.warning(
# debug, not warning — a persistent failure would repeat on
# every slash command forever.
logger.debug(
"slash worker memory trim failed: %s: %s",
type(exc).__name__,
exc,