Files
hermes-agent/tests/gateway/test_profile_serve_signature.py
teknium1 a1e7f74e64 fix: stat signatures cover inode + ctime everywhere config identity is cached
The cherry-picked commit extends the config/profile/MCP/managed-scope/completer/
OAuth/skills-manifest signatures. This commit finishes the class and trims it:

- `file_signature()` lives in `utils.py` next to the other stat/metadata helpers
  instead of `hermes_cli.managed_scope` (gateway/ and agent/ callers no longer
  reach into the managed-scope module for a generic stat helper).
- `hermes_cli/config_effective.py` was left comparing 2-/4-wide prefixes against
  the widened `_RAW_CONFIG_CACHE` / `_load_config_cache_sig` records, so
  `load_user_config_effective()` re-parsed on every call (3 parses for 3 calls on
  an unchanged file, 1 before); index by the new widths.
- Sibling caches keyed on the same (mtime, size) shape and reading the SAME files
  now use the helper: `load_env()` memo, `agent/skill_utils` raw-config and
  external-dirs caches, `hermes_cli/model_switch` alias identity, `agent/moa_loop`
  preset stamp, `hermes_cli/auth` global auth-store memo.
- Tests trimmed to one invariant each (pinned-mtime replacement invalidates; an
  unchanged file still hits), both red on origin/main.

Left alone on purpose: `tools/registry.py`, `tools/skills_tool_dedup.py`,
`gateway/status.py`, `hermes_cli/banner.py`, `hermes_cli/main.py`,
`hermes_cli/session_recovery.py` — those fingerprint source files, PID/lock files
or write to persisted on-disk caches shared across processes, where an inode/ctime
key would churn on every checkout/copy rather than catch a replaced config.
2026-09-15 06:29:50 -07:00

21 lines
893 B
Python

"""#111105: the profile re-scan watcher must rebuild adapters after a config.yaml replacement
that keeps mtime and size (``cp -p``, ``rsync -t``, a timestamp-pinning writer)."""
import os
import shutil
from gateway.run_profile_reconcile import profile_serve_signature
def test_profile_serve_signature_changes_on_replacement_with_pinned_mtime(tmp_path):
cfg = tmp_path / "config.yaml"
cfg.write_text("x" * 64, encoding="utf-8")
before = profile_serve_signature(tmp_path)
assert profile_serve_signature(tmp_path) == before # unchanged file: stable
st = cfg.stat()
other = tmp_path / "other"
other.write_text("y" * 64, encoding="utf-8")
shutil.copy2(other, cfg)
os.utime(cfg, ns=(st.st_atime_ns, st.st_mtime_ns))
assert (cfg.stat().st_mtime_ns, cfg.stat().st_size) == (st.st_mtime_ns, st.st_size)
assert profile_serve_signature(tmp_path) != before