Skip to content

fix(gateway): handoffs fail closed and load secrets off-loop; Discord slash commands honor profile_routes (#97693 #100014 #69178 #91633, salvage #97694 #100049) - #101247

Merged
teknium1 merged 4 commits into
mainfrom
salvage/mux-handoff-discord-slash
Sep 2, 2026
Merged

teknium1 merged 4 commits into
mainfrom
salvage/mux-handoff-discord-slash

Conversation

@teknium1

@teknium1 teknium1 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Three multiplex-gateway bugs in one branch: a secondary-profile handoff whose config failed to load silently delivered through the primary's home channel; the handoff watcher (and per-message handlers) entered the profile secret scope synchronously on the event loop, stalling every adapter during slow secret reads; and native Discord slash commands built their SessionSource without guild_id/parent_chat_id, so guild/channel profile_routes never matched and /new, /reset, /model, /status ran against the default profile.

Changes

  • _process_handoff: config-load failure → error + raise (row marked failed) instead of falling back to self.config (fix(gateway): fail closed when a secondary profile handoff cannot load its config #97694, @Adolanium, cherry-picked).
  • _load_profile_secret_scope + _async_profile_runtime_scope: secret scope loaded via asyncio.to_thread, then the existing sync scope is entered with prepared_secret_scope=; watcher reclaim/tick use it (fix(gateway): keep multiplex handoffs responsive during slow secret reads #100049, @fangliquanflq, cherry-picked).
  • Class widening: the three async per-message scope entries (_make_profile_message_handler, _make_default_profile_message_handler, _prepare_inbound_message_text_scoped) now use the async scope too.
  • Discord _build_slash_event / _dispatch_thread_session pass guild_id (new _interaction_guild_id, mirrors on_message) and parent_chat_id to build_source.
  • Tests: 1 fail-closed handoff test, 1 loop-responsiveness test, 1 slash-routing parity test (+ existing watcher tests adapted to the async scope).

Validation

Scenario origin/main this branch
Secondary handoff, profile config unloadable create_handoff_thread on PRIMARY home '111', row completed RuntimeError, no adapter call, row failed
Watcher tick with 600ms secret hydration loop stalled 601 ms 21 ms
Discord /new in guild-routed channel profile=None, reset key agent:main:… profile='work', key agent:work:… (idle + busy)
/status in thread guild_id/parent_chat_id None → no route guild_id='1', parent_chat_id='100' → routed
Sabotage: each regression test fails with its fix reverted. Targeted suites: 70 passed; 34-file seam sweep: 586 passed.

Credits

@Adolanium (#97694 merged as-is), @fangliquanflq (#100049, first submitter), @Tranquil-Flow (#100076, same mechanism, co-author), @Sora-bluesky (#69242, first fix for #69178, co-author), @jondgilbert (#91634 / #91633, co-author), @tensorbit89-netizen (#31102, first report), @vKongv (#85355 diagnosis; its residual /new symptom is the guild_id gap fixed here).


Probes kept at /tmp/mux_sweep/hds/ (probe_failclosed.py, probe_watcher.py, probe_discord_slash.py, probe_reset_key.py, probe_85355.py). Baseline worktree /tmp/salv-hds-base (detached origin/main) also left in place.

Fixes #97693
Fixes #100014
Fixes #69178
Fixes #91633

## Infographic

![mux-handoff-discord-slash](https://v3b.fal.media/files/b/0aa8cde9/NJuZa3RsvwDHXZIDrBnou_BOEjghDB.png)

@github-actions

github-actions Bot commented Sep 2, 2026 •

Copy link
Copy Markdown

૮ >ﻌ< ა ci review

ran on 8c1ca9b — fix(discord): native slash commands honor guild/channel prof

⚠️ Warnings

OSV vulnerability scan · View job

13 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.


debug info

CI timings

CI timings · View report · View job

Wall time 6m10s vs 5m15s (+17.5%). 8 job(s) slower, 3 faster, 3 unchanged.

  • Detect affected areas: -47.0s
  • Python tests / Run tests: +22.0s
  • OS-specific tests / Windows-only tests: +13.0s
  • OS-specific tests / macOS-only tests: +12.0s
  • Python lints / Windows footguns (blocking): +8.0s

@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/plugins Plugin system and bundled plugins platform/discord Discord bot adapter area/auth Authentication, OAuth, credential pools area/profiles Multi-profile isolation, HERMES_HOME scoping sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data labels Sep 2, 2026
@teknium1
teknium1 force-pushed the salvage/mux-handoff-discord-slash branch from 06cddef to 496bfb5 Compare September 2, 2026 12:44
Adolanium and others added 4 commits September 2, 2026 05:44
…g cannot load

_process_handoff caught a config load failure for a secondary profile,
logged a warning, and kept going with self.config, which is the primary
profile's config. The handoff then went out through the right bot to the
primary's home channel and the row was reported completed. That is the
exact wrong delivery the multi-profile handoff work exists to prevent,
and the same fail closed posture the no-live-adapters branch already
takes.

A load failure now logs an error and raises, which marks the row failed
so the CLI can report and retry it. The default profile path is
untouched, it never reloaded config.
The handoff watcher entered _profile_runtime_scope synchronously on the
event loop each tick; hydrate_profile_secret_sources + build_profile_secret_scope
do blocking file/secret-source IO, so a slow profile secret read stalled every
adapter (#100014). Load the secret scope via asyncio.to_thread, then enter
the existing sync scope with prepared_secret_scope=.

Fixes #100014
Co-authored-by: Tranquil-Flow <66773372+Tranquil-Flow@users.noreply.github.com>
Same class as the handoff watcher (#100014): the secondary/primary message
handlers and the scoped inbound-preprocess hop entered
_profile_runtime_scope synchronously on the loop thread, so a slow
profile .env read or external secret-source hydration stalled every other
adapter's traffic. Route those three async sites through
_async_profile_runtime_scope (asyncio.to_thread load, then the existing
sync scope with prepared_secret_scope=). _format_session_info_scoped is
already called via asyncio.to_thread and stays sync.
_build_slash_event and _dispatch_thread_session built their SessionSource
without guild_id/parent_chat_id, while on_message passes both. Route
matching in build_source keys off exactly those fields, so under
gateway.multiplex_profiles a guild- or channel-routed profile never matched
a native slash command: /new, /reset, /model, /profile, /status ... all ran
against the default profile and reset the wrong session (#69178, #91633).

Pass guild_id (interaction.guild_id, falling back to channel.guild like the
message path) and the thread's parent channel id into build_source at both
sites. One test pins channel + thread routing parity with messages.

Fixes #69178
Fixes #91633
Co-authored-by: Sora-bluesky <179361977+Sora-bluesky@users.noreply.github.com>
Co-authored-by: jondgilbert <42873618+jondgilbert@users.noreply.github.com>
Co-authored-by: tensorbit89-netizen <257030052+tensorbit89-netizen@users.noreply.github.com>
@teknium1
teknium1 force-pushed the salvage/mux-handoff-discord-slash branch from 496bfb5 to 8c1ca9b Compare September 2, 2026 12:45
@teknium1
teknium1 merged commit 0437fe6 into main Sep 2, 2026
37 checks passed
@teknium1
teknium1 deleted the salvage/mux-handoff-discord-slash branch September 2, 2026 12:55
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 6, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 6, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 6, 2026
cursor Bot pushed a commit to pebble-tech/hermes-agent that referenced this pull request Sep 21, 2026
cursor Bot pushed a commit to pebble-tech/hermes-agent that referenced this pull request Sep 22, 2026
cursor Bot pushed a commit to pebble-tech/hermes-agent that referenced this pull request Sep 23, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 24, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 24, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 24, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 24, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 24, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 24, 2026
cursor Bot pushed a commit to pebble-tech/hermes-agent that referenced this pull request Sep 27, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 28, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 28, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 28, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 28, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 28, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 28, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 29, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 29, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 29, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 29, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 29, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 29, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 30, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 30, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 30, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 30, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 30, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Sep 30, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Oct 1, 2026
vKongv added a commit to pebble-tech/hermes-agent that referenced this pull request Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools area/profiles Multi-profile isolation, HERMES_HOME scoping comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P2 Medium — degraded but workaround exists platform/discord Discord bot adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants