hermes-agent/tests/gateway/relay
Ben Barclay f4df260f26
fix(relay): attach metadata.user_id on guild replies for egress fallback (#68320)
The relay adapter re-attaches an egress discriminator on outbound replies
so the connector can resolve the owning tenant. It captured scope_id for
scoped (guild) messages and user_id for DMs, but as MUTUALLY EXCLUSIVE:
a scoped inbound hit an early return, so the author's user_id was never
recorded, and _with_scope only attached user_id when there was no
scope_id. Guild replies therefore went out with scope_id only.

That's fine while the guild has a provision-time route row. But a MANAGED
Discord agent joins guilds dynamically (the shared bot is added to /
removed from servers at runtime), and GATEWAY_RELAY_ROUTE_KEYS — the only
thing that writes guild route rows — is a self-hosted, static field never
stamped for managed agents. So their guild has no route row, the
connector's guild-route lookup misses, and with no user_id on the frame
there's nothing to fall back to → every guild reply is declined
"discord egress declined: target not routed to an onboarded tenant"
even though INBOUND resolved the same guild fine (via the author-first
SharedSocketRouter.targets() fallback).

Fix: capture the authentic author user_id for EVERY inbound (DM and
scoped alike) and re-attach it on the outbound reply alongside scope_id.
The connector consults it only on a route/scope miss, so carrying both
never overrides routing-table resolution. This is the gateway half of the
paired gateway-gateway change (makeDiscordTenantOf guild-route-miss
author-binding fallback); together they make guild replies resolve the
same observed-author way inbound already does.

Tests (tests/gateway/relay/test_relay_adapter.py): a guild reply now
carries both scope_id AND user_id; a scoped inbound with no author still
yields scope_id only (never invents one). Verified fail-without /
pass-with.
2026-07-21 17:04:34 +10:00
..
__init__.py
stub_connector.py feat(relay): multi-platform-per-agent — list identity, provision-loop, N-hello, per-frame egress (Phase 1.5) (#52830) 2026-06-26 17:32:46 +10:00
test_auth.py feat(relay): connector⇄gateway channel auth + signed-HTTP inbound receiver + enroll CLI (#48147) 2026-06-18 12:01:54 +10:00
test_channel_context_consume.py feat(relay): consume channel context from the connector (#64649) 2026-07-15 09:31:34 +10:00
test_contract_doc_conformance.py test(gateway): enforce relay contract-doc ⟷ Python conformance 2026-06-17 16:37:45 -07:00
test_descriptor.py fix(relay): normalize a 0/negative max_message_length at the descriptor boundary 2026-07-16 07:21:23 -07:00
test_descriptor_from_entry.py feat(relay): derive descriptor from PlatformEntry 2026-06-17 16:37:45 -07:00
test_identity_token_resolver.py feat(gateway): generic OIDC client-credentials relay provisioning (NAS-free) (#60730) 2026-07-08 16:55:32 +10:00
test_no_stub_leak.py test(relay): assert connector stub never leaks into production paths 2026-06-17 16:37:45 -07:00
test_relay_adapter.py fix(relay): attach metadata.user_id on guild replies for egress fallback (#68320) 2026-07-21 17:04:34 +10:00
test_relay_follow_up.py feat(gateway): token-less follow_up outbound op (A2 capability action) 2026-06-17 16:37:45 -07:00
test_relay_going_idle.py fix(telegram): preserve Bot API update queue on watcher reconnect 2026-06-25 21:29:57 -07:00
test_relay_interrupt.py feat(relay): WS-only inbound on the gateway adapter (Phase 3) (#48294) 2026-06-19 09:33:15 +10:00
test_relay_multiplatform.py refactor(relay): purge platform-specific scope terminology from the relay adapter (D-Q2.5c) (#56016) 2026-07-01 12:30:59 +10:00
test_relay_passthrough.py refactor(relay): purge platform-specific scope terminology from the relay adapter (D-Q2.5c) (#56016) 2026-07-01 12:30:59 +10:00
test_relay_policy_send.py feat(relay): multi-platform-per-agent — list identity, provision-loop, N-hello, per-frame egress (Phase 1.5) (#52830) 2026-06-26 17:32:46 +10:00
test_relay_registration.py test(gateway): live ws-transport round-trip + config-driven registration 2026-06-17 16:37:45 -07:00
test_relay_roundtrip.py refactor(relay): purge platform-specific scope terminology from the relay adapter (D-Q2.5c) (#56016) 2026-07-01 12:30:59 +10:00
test_relay_roundtrip_telegram.py refactor(relay): purge platform-specific scope terminology from the relay adapter (D-Q2.5c) (#56016) 2026-07-01 12:30:59 +10:00
test_relay_sheds_crypto.py feat(relay): WS-only inbound on the gateway adapter (Phase 3) (#48294) 2026-06-19 09:33:15 +10:00
test_self_provision.py feat(relay): Phase 5 Unit C — wake primitive (gateway side) (#51595) 2026-06-24 11:00:11 +10:00
test_ws_transport.py refactor(relay): purge platform-specific scope terminology from the relay adapter (D-Q2.5c) (#56016) 2026-07-01 12:30:59 +10:00