Files
hermes-agent/apps/shared
Teknium 9caff74408 fix(desktop): key fan-out event consumption by (connectionId, profile)
Secondary-gateway events were tagged with connectionId (store/gateway
fan-out) but no consumer read it: working/attention tracking, the
pruneSecondaryGateways keep-set, and the profile-scoped event gates
(skin.changed / change-watcher broadcasts / approval-mode reconcile)
all keyed by session id + bare profile name. Every registered source
exposes a 'default' profile (the roster force-unshifts it), so two
connected gateways collided — gateway B's 'default' activity was
attributed to gateway A's 'default', keeping the wrong socket alive
and applying the wrong source's config/skin/cron changes.

Thread connectionId through consumption using the existing composite
backendScopeKey helper:

- session-states records each registry-tagged event's (connectionId,
  profile) scope per runtime session; liveSessionScopes() projects the
  busy/needs-input ones as composite keys for the gateway keep-set.
- recomputeKeptGateways (use-gateway-boot) seeds the keep-set with
  those scopes; pruneSecondaryGateways matches registry-scoped entries
  ONLY on their composite key, while local entries keep matching bare
  profile names (single-source path unchanged).
- gateway-event's 'from the active profile' gates now compare the
  event's composite scope against the active gateway's connection via
  the new activeGatewayConnectionId(); untagged local/primary events
  behave byte-identically.

Display-only surfaces that already use roster handles are untouched.
2026-08-16 10:11:47 -07:00
..