#19190: Signal: preserve group ID casing in session keys
gateway
size: M
Cluster:
Signal Reaction Fixes
## Summary
- preserve case for `signal:group:<groupId>` session keys instead of lowercasing the base64 group ID
- route explicit `SessionKey` and gateway `sessionKey` inputs through a signal-aware normalizer
- keep non-Signal providers on the existing lowercase normalization path
## Testing
- pnpm test src/routing/session-key.test.ts src/config/sessions.test.ts src/infra/outbound/outbound.test.ts src/gateway/server-methods/send.test.ts src/gateway/session-utils.test.ts
- pnpm lint -- src/routing/session-key.ts src/routing/session-key.test.ts src/config/sessions/session-key.ts src/config/sessions.test.ts src/gateway/server-methods/send.ts src/gateway/server-methods/send.test.ts src/gateway/session-utils.ts src/gateway/session-utils.test.ts src/infra/outbound/outbound-policy.ts src/infra/outbound/outbound.test.ts
Fixes #19139
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR fixes a bug where Signal group IDs (which are base64-encoded and case-sensitive) were being lowercased during session key normalization, causing session key mismatches.
- Introduces `normalizeSessionKeyForStorage()` in `src/routing/session-key.ts` that selectively preserves case for Signal group IDs (the `signal:group:<base64Id>` segment) while lowercasing all other components (agent IDs, channel names, other provider IDs)
- Adds `normalizePeerIdForSessionKey()` to handle case preservation at the peer ID level in `buildAgentPeerSessionKey` and `buildGroupHistoryKey`
- Updates `normalizeTarget()` in outbound policy to preserve Signal target casing for cross-context comparison
- Replaces all direct `.toLowerCase()` calls on session keys with `normalizeSessionKeyForStorage()` across 5 call sites: explicit `SessionKey` resolution, gateway send handler, session store key resolution, session key canonicalization, and spawned-by canonicalization
- Comprehensive test coverage added across all affected modules
- One potential follow-up: `src/auto-reply/reply/dispatch-from-config.ts:70` still uses `sessionKey.toLowerCase()` for store lookups, which could miss Signal group sessions stored with preserved casing (mitigated by fallback to original key)
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge with minimal risk; the normalization logic is well-structured and comprehensively tested.
- Score of 4 reflects that the core changes are correct, well-tested, and narrowly scoped. One minor concern is that a pre-existing session store lookup in dispatch-from-config.ts still uses .toLowerCase() which could theoretically miss Signal group sessions, though this is mitigated by its fallback to the original key. All changed paths are covered by tests.
- No files in the PR require special attention. Outside the PR, `src/auto-reply/reply/dispatch-from-config.ts` has a pre-existing `sessionKey.toLowerCase()` store lookup that may warrant a follow-up.
<sub>Last reviewed commit: ade6f06</sub>
<!-- greptile_other_comments_section -->
<sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#16562: fix(signal): preserve case for group and username targets
by akalypse · 2026-02-14
82.0%
#12793: fix(signal): preserve case-sensitivity for group IDs, UUIDs, and us...
by wilmerdooley1-star · 2026-02-09
75.3%
#15176: fix(sessions): allow channel-routed session IDs and cross-agent paths
by cathrynlavery · 2026-02-13
73.9%
#4878: fix: string/type handling and API fixes (#4537, #4380, #4373, #4547...
by lailoo · 2026-01-30
73.4%
#20078: feat(session): Add channelGroups config(optional config) for shared...
by demarlik01 · 2026-02-18
73.2%
#18511: fix(signal): signal:-prefixed phone numbers fail target resolution ...
by yinghaosang · 2026-02-16
72.8%
#22469: fix(gateway): avoid stale whatsapp labels on direct sessions
by loganprit · 2026-02-21
72.6%
#22098: fix: isolate agent sessions by explicit --session-id
by AIflow-Labs · 2026-02-20
72.4%
#17453: fix(signal): make group reactions deterministic from inbound sender...
by akalypse · 2026-02-15
72.3%
#16061: fix(sessions): tolerate invalid sessionFile metadata
by haoyifan · 2026-02-14
72.1%