Skip to content

fix(banner): invalidate update-check cache when local git HEAD moves - #40985

Closed
luyao618 wants to merge 1 commit into
NousResearch:mainfrom
luyao618:fix/40944-update-check-cache-head-invalidation
Closed

fix(banner): invalidate update-check cache when local git HEAD moves#40985
luyao618 wants to merge 1 commit into
NousResearch:mainfrom
luyao618:fix/40944-update-check-cache-head-invalidation

Conversation

@luyao618

@luyao618 luyao618 commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Summary

For git-source installs, the version banner reported a stale N commits behind count for up to 6 hours after the user manually ran git pull --ff-only to update — the documented update path for source installs.

Root cause: check_for_updates() in hermes_cli/banner.py cached its result at ~/.hermes/.update_check and invalidated only on TTL expiry, change of HERMES_REVISION (nix-only; None for git installs), or change of VERSION. When a git pull brought in upstream commits that did not bump __version__ (common: backports, security patches, non-versioned batches), the predicate stayed satisfied and the stale count survived the full 6h TTL.

Fix: track the local git HEAD SHA in the cache and add a fourth condition to the cache-validity predicate. Once HEAD moves the cache is invalidated immediately and the next banner check shows the correct count.

This implements Option A from the issue body, which the reporter explicitly preferred. The cost is a single local git rev-parse HEAD per banner check (no network) — the same cost profile already paid by _check_via_local_git.

Test plan

source ~/.hermes/hermes-agent/venv/bin/activate
pytest tests/hermes_cli/test_update_check.py tests/hermes_cli/test_banner.py -q
# 21 passed

New tests in tests/hermes_cli/test_update_check.py:

  • test_check_for_updates_invalidates_on_head_change — primary regression: a cache stamped at the old HEAD is invalidated when git rev-parse HEAD returns a new SHA, the fresh check runs, and the cache is rewritten with the new SHA + behind=0.
  • test_check_for_updates_cache_hit_includes_head — a cache stamped with the current HEAD is honored without a git fetch (a non-rev-parse subprocess call would fail the test).
  • test_check_for_updates_legacy_cache_without_head_invalidates_on_git_install — old cache files (no "head" key) on git installs trigger a refresh, and the new file includes "head".

Updated tests in the same file account for the new head field and the extra git rev-parse HEAD subprocess call.

Backward compatibility verified:

  • Legacy cache files (no "head" key): cached.get("head") is None.
  • On pip / Docker installs local_head is also None — predicate matches, no spurious refresh.
  • On git installs local_head is non-None — predicate mismatches, fresh check runs (intended).

Manual repro (matches issue body)

# Before this fix, on a source install with a stale cache:
$ cat ~/.hermes/.update_check
{"ts": 1780798639.18, "behind": 81, "rev": null, "ver": "0.16.0"}

$ cd ~/.hermes/hermes-agent && git pull --ff-only && pip install -e .
# HEAD now matches origin/main.

$ hermes --version
# Old behavior: still says "81 commits behind" for up to 6h.
# New behavior: refreshes immediately, shows "up-to-date".

Risks / out of scope

  • Touches one production helper (check_for_updates) plus one tiny new helper (_local_head_sha); no other call sites changed.
  • The other cache-invalidation paths (_invalidate_update_cache() from the CLI update command, the docker short-circuit, the version guard from check_for_updates() cache not invalidated after pip upgrade, showing stale "1 commit behind" #34491) remain untouched.
  • Does not address Option B/C from the issue (cache self-heal on transition to 0, post-merge git hook) — Option A is the smallest correct fix and the reporter stated preference.

Fixes #40944.

For git-source installs, the version banner reported a stale
"N commits behind" count for up to 6 hours after the user manually
ran `git pull --ff-only` to update — the documented update path
for source installs.

Root cause: `check_for_updates()` cached the result at
`~/.hermes/.update_check` and invalidated only on TTL expiry, change
of `HERMES_REVISION` (nix-only, None for git installs), or change of
`VERSION`. When a git pull brought in upstream commits that didn't
bump `__version__` (common: backports, security patches, non-versioned
batches), the predicate stayed satisfied and the stale count survived
the full 6h TTL.

Fix: track the local git HEAD SHA in the cache and add a fourth
condition to the validity predicate. Once HEAD moves, the cache is
invalidated immediately and the next banner check shows the correct
count.

- Add `_local_head_sha()` helper around the existing
  `_check_via_local_git()` (reuses the same subprocess pattern,
  5s timeout, broad exception handling).
- Compute `local_head` once via `_resolve_repo_dir()` (the helper
  already used by other banner code paths) before the cache read,
  reuse the same `repo_dir` in the git-path branch.
- Add `"head": local_head` to both the predicate and the cache
  write.

Backward compatibility:
- Legacy cache files (no "head" key): `cached.get("head")` is None.
- On pip/docker installs `local_head` is also None — predicate matches,
  no spurious refresh.
- On git installs `local_head` is non-None — predicate mismatches,
  fresh check runs (intended).

Per-call cost: one extra local `git rev-parse HEAD` (no network),
identical to the cost profile already paid by `_check_via_local_git`.

Tests:
- New: `test_check_for_updates_invalidates_on_head_change` —
  HEAD-moved cache is invalidated and rewritten.
- New: `test_check_for_updates_cache_hit_includes_head` —
  matching HEAD is honored without a git fetch.
- New: `test_check_for_updates_legacy_cache_without_head_invalidates_on_git_install`
  — old cache shape on a git install triggers a refresh.
- Updated: two existing tests for the new HEAD probe + cache field.

Fixes NousResearch#40944
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard labels Jun 7, 2026
@luyao618 luyao618 closed this Jun 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Banner shows stale "commits behind" count after manual git pull in source installs

2 participants