Skip to content

fix(gateway): fail-closed session destination ownership + isolated workers#66703

Open
bogagyn wants to merge 2 commits into
NousResearch:mainfrom
bogagyn:fix/session-ownership-20260717
Open

fix(gateway): fail-closed session destination ownership + isolated workers#66703
bogagyn wants to merge 2 commits into
NousResearch:mainfrom
bogagyn:fix/session-ownership-20260717

Conversation

@bogagyn

@bogagyn bogagyn commented Jul 18, 2026

Copy link
Copy Markdown

Summary

Two commits hardening Telegram (and general platform) session destination ownership and gateway restart/footer behavior, derived from operational soak on a VPS gateway:

  1. d509ad10e — fix(gateway): harden restart notice and runtime footer

    • Await adapter send-ready before restart notification (closes a send_path_degraded race where the post-boot "restarted" notice could fire before Telegram was connected).
    • Runtime footer base fields: total_tokens, cost, profile, session_id.
  2. 2b110b438 — fix(gateway): fail-closed session destination ownership and isolated workers

    • SessionOwnershipConflict raised on a second unthreaded DM destination owner (prevents split-owner routing).
    • Handoff requires a distinct thread/topic (_require_isolated_handoff_thread).
    • Kanban creator wake is opt-in (kanban.wake_creator_session: false default); even when enabled, it refuses root-chat wake.
    • Footer fields: role / title / thread.

No behavior change for correctly-configured single-owner setups; these only add fail-closed guards and fix a startup-notify race. Upstream origin/main has no equivalent of these contracts.

Test plan

  • Targeted (pre-commit): 69 passed — tests/gateway/test_session_destination_ownership.py, test_handoff_thread_isolation.py, test_kanban_creator_wake_policy.py, test_runtime_footer_ownership.py, tests/hermes_cli/test_kanban_creator_wake_default.py, test_runtime_footer.py, test_restart_notification.py
  • Broader related: 119 passed (session race guard, restart drain, kanban gates)
  • git status clean; branch is 2 commits ahead / 0 behind origin/main.

Notes

  • This is an operational hardening carry; no schema/config redesign, no unrelated cleanup.
  • Authorship preserved as-is from the soak branch.

🤖 Generated with Claude Code

root and others added 2 commits July 18, 2026 01:19
…workers

One physical unthreaded Telegram DM may have a single foreground owner.
Background workers and handoffs must opt into a distinct thread/topic;
kanban creator wake is off by default and still refuses root-chat wake.
Runtime footer exposes role/thread/title for ownership visibility.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery comp/cron Cron scheduler and job management comp/cli CLI entry point, hermes_cli/, setup wizard sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades needs-decision Awaiting maintainer decision before any implementation labels Jul 18, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Comment

+582/-9 gateway fix for fail-closed session destination ownership and isolated workers. Moves kanban watch subscription cleanup into the session lifecycle. Security-sensitive change (process ownership). The delta is substantial but scoped to two files. No obvious issues spotted.

Reviewed by Hermes Agent

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for targeting a real session-ownership hazard: current main constructs every Kanban creator wake as chat_type="group" despite documenting that the real type is unavailable (gateway/kanban_watchers.py:517-548).

Problems

  • gateway/run.py:7824 makes every no-thread handoff fail. That regresses the existing, intentional fallback documented in gateway/run.py:7779-7784 and gateway/platforms/base.py:2984-3000; /handoff is still documented for WhatsApp, Signal, and Matrix (website/docs/reference/slash-commands.md:63). This is a behavior change even for a single-owner destination.
  • The footer title lookup added near gateway/run.py:12350 occurs before checking whether the footer is enabled. display.runtime_footer.enabled defaults to false (hermes_cli/config.py:1978-1981), so this adds a SessionDB query to normal gateway replies that will not render a footer.

Suggested changes

  • Preserve the no-thread single-owner handoff path, or redesign it around a verified destination-owner check; cover adapters returning None from create_handoff_thread.
  • Resolve footer configuration before fetching the title, and fetch it only for an enabled footer requesting title.

Automated hermes-sweeper review.

Comment thread gateway/run.py
# chat: a handoff is a new conversational owner and must be isolated.
effective_thread_id = new_thread_id or (
str(home.thread_id) if home.thread_id else None
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: this turns every adapter without thread support, and every thread-creation failure, into a failed /handoff. Current main deliberately falls back to the home channel in this case (gateway/run.py:7779-7784; BasePlatformAdapter.create_handoff_thread documents it at gateway/platforms/base.py:2984-3000). Preserve a verified single-owner fallback or update the design and supported-platform contract together.

Comment thread gateway/run.py
@@ -12322,13 +12349,32 @@ async def _handle_message_with_agent(self, event, source, _quick_key: str, run_g
_footer_line = ""
try:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The runtime footer is disabled by default, but this title lookup runs before footer enablement and field selection. Resolve the footer config first and query SessionDB only when an enabled footer requests title.

@teknium1 teknium1 added sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform area/sessions Session lifecycle, resume, persistence, history labels Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/sessions Session lifecycle, resume, persistence, history comp/cli CLI entry point, hermes_cli/, setup wizard comp/cron Cron scheduler and job management comp/gateway Gateway runner, session dispatch, delivery needs-decision Awaiting maintainer decision before any implementation P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants