#4749: fix: handle string thread IDs in queue drain for Slack
Cluster:
Slack Thread Management Fixes
## Problem
When multiple messages arrive while the agent is busy (queued messages), replies to Slack threads were incorrectly being sent to the main channel instead of the thread.
## Root Cause
The code in `src/auto-reply/reply/queue/drain.ts` checks for thread IDs using:
```typescript
typeof threadId === "number"
```
However, Slack thread timestamps are **strings** (e.g., `"1769015989.090599"`), not numbers. This caused:
1. Thread IDs to be filtered out when checking for cross-channel routing
2. `originatingThreadId` to be `undefined` when collecting queued messages
3. Replies going to the main channel instead of the originating thread
## Fix
Changed type checks from `typeof threadId === "number"` to `threadId != null` which correctly handles both string (Slack) and number thread IDs across different providers.
## Testing
Tested locally by:
1. Sending multiple messages in a Slack thread while agent was busy
2. Verified replies now correctly go to the thread instead of main channel
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR fixes followup queue drain routing when draining queued messages for Slack threads. The prior logic treated `originatingThreadId` as numeric-only (`typeof ... === "number"`), but Slack thread timestamps are strings, so the thread component was dropped during cross-channel key generation and while selecting an `originatingThreadId` for collect mode.
The change switches thread detection to null checks (`threadId != null`) so both string and number thread IDs are preserved in the routing key and in the collected followup run, keeping replies routed to the original thread instead of the main channel.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge with low risk; it’s a narrow fix to thread ID handling in queue drain routing.
- The change is small and localized (replacing numeric-only thread checks with null checks) and aligns with Slack’s thread timestamp format. Primary remaining risk is limited test coverage for string thread IDs in collect routing, since the existing routing test helper constrains thread IDs to `number` and doesn’t exercise the Slack case.
- src/auto-reply/reply/queue/drain.ts; consider extending src/auto-reply/reply/queue.collect-routing.test.ts to cover string thread IDs
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#11194: fix(slack): queue drain drops string thread_ts — replies leak to ma...
by Lukavyi · 2026-02-07
92.7%
#20406: fix(slack): respect replyToMode when computing statusThreadTs in DMs
by QuinnYates · 2026-02-18
86.3%
#23804: fix(slack): preserve string thread context in queue + DM route
by vincentkoc · 2026-02-22
85.6%
#19083: Slack: preserve per-thread context and consistent thread replies
by jkimbo · 2026-02-17
83.7%
#22485: fix(slack): use threadId from delivery context as threadTs fallback...
by dorukardahan · 2026-02-21
83.6%
#14720: fix(slack): pass threadId in plugin read action (#14706)
by lailoo · 2026-02-12
83.0%
#2917: Slack: fix thread context + prevent reply spillover
by SocialNerd42069 · 2026-01-27
82.2%
#23320: fix(slack): respect replyToMode when incomingThreadTs is auto-created
by dorukardahan · 2026-02-22
82.2%
#12244: fix(slack): preserve thread context for DM thread replies
by junhoyeo · 2026-02-09
81.5%
#4878: fix: string/type handling and API fixes (#4537, #4380, #4373, #4547...
by lailoo · 2026-01-30
81.3%