Skip to content

fix(tui_gateway): the change watcher also probes served sibling profiles for cron/platform edits - #114210

Open
EloquentBrush0x wants to merge 1 commit into
NousResearch:mainfrom
EloquentBrush0x:fix/change-watcher-served-profile-homes
Open

EloquentBrush0x wants to merge 1 commit into
NousResearch:mainfrom
EloquentBrush0x:fix/change-watcher-served-profile-homes

Conversation

@EloquentBrush0x

Copy link
Copy Markdown

Summary

change_watcher.py::_sessions_sig() already probes every served sibling profile home (_served_profile_homes) alongside the launch home, per its own comment: "a backend serving several profiles owns one store per profile, so every served sibling home is [probed]" — otherwise a routed profile's Bot Chat never refreshes (#99333).

cron.changed and platforms.changed never got the same treatment, even though the files they watch are just as much per-profile-home artifacts as state.db:

  • cron/jobs.py's own docstring: a named profile's jobs live at ~/.hermes/profiles/<name>/cron/jobs.json.
  • hermes_cli/container_boot.py:212 writes gateway_state.json per profile_dir.

In a desktop backend hosting 2+ named profiles, a secondary profile's cron edit or platform connect/disconnect never broadcast a .changed event — only the launch profile's own file moves were ever seen.

Changes

  • Added _home_and_siblings_mtime_ns(*parts), mirroring _sessions_sig()'s pattern of joining the same relative path under _watcher_home() and every entry of _served_profile_homes.
  • cron.changed and platforms.changed now use it instead of the launch-home-only _home_mtime_ns.

Scope note — two watches deliberately left untouched

  • pet.changed: its payload function (_pet_changed_payload) reads only the launch profile's own active pet. Extending just the signature function to notice a served profile's pet change would broadcast an event to every client, but the payload would still describe the launch profile's pet — a data-correctness problem, not something a signature-only fix should paper over. Left out of scope.
  • bot_relay.outbox.pending: verified this does not have the same gap before touching it. get_profile_dir() always resolves named profiles under <default home>/profiles/<name> (hermes_cli/profiles.py), and _bot_relay_outbox_sig()'s own root-collapsing logic (home.parent.parent if home.parent.name == "profiles" else home) already folds every such profile home back to the shared launch root that _watcher_home() covers. Adding _served_profile_homes there would only re-probe the same directory. Confirmed by tracing _get_profiles_root() rather than assuming the pattern generalizes.

Test plan

  • Added test_served_profile_cron_jobs_move_broadcasts_cron_changed and test_served_profile_gateway_state_move_broadcasts_platforms_changed, mirroring the existing test_served_profile_store_move_broadcasts_sessions_changed harness (real server._profile_home() call, not a hand-inserted set entry).
  • Mutation-verify: reverted the production file only, confirmed both new tests fail (assert (...) in []); restored the fix, all 18 tests in test_change_watcher.py pass.
  • ruff check clean on both touched files.

🤖 Generated with Claude Code

…les for cron/platform edits

_sessions_sig() already probes every served sibling profile home
(_served_profile_homes) so a routed profile's Bot Chat refreshes on a
state.db move, per its own comment: "a backend serving several
profiles owns one store per profile, so every served sibling home is
[probed]". cron.changed and platforms.changed never got the same
treatment even though cron/jobs.json and gateway_state.json are just
as much per-profile-home files (cron/jobs.py's own docstring: a named
profile's jobs live at profiles/<name>/cron/jobs.json; gateway_state.json
is written per profile_dir in hermes_cli/container_boot.py). In a
desktop backend hosting 2+ named profiles, a secondary profile's cron
edit or platform connect/disconnect never broadcast a change, only the
launch profile's did.

pet.changed and bot_relay.outbox.pending were left out of this pass:
pet's payload function reads only the launch profile's own active pet
(broadcasting a served profile's pet change would still hand every
client the launch profile's pet, a data-correctness issue beyond a
signature fix), and bot_relay's outbox root already collapses every
named-profile home back to the shared launch root before probing it
(get_profile_dir() always resolves under <default home>/profiles/,
so _served_profile_homes entries fold to the same root _watcher_home()
already covers there) — verified empirically before ruling it out
rather than extending it redundantly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/tui Terminal UI (ui-tui/ + tui_gateway/) comp/cron Cron scheduler and job management area/profiles Multi-profile isolation, HERMES_HOME scoping labels Sep 17, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/profiles Multi-profile isolation, HERMES_HOME scoping comp/cron Cron scheduler and job management comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants