Skip to content

M3: Routing bootstrap and rejection visibility#6212

Merged
noanflaherty merged 2 commits into
feature/telegram-msg-gap-closurefrom
swarm/tg-msg-gap/task-3
Feb 21, 2026
Merged

M3: Routing bootstrap and rejection visibility#6212
noanflaherty merged 2 commits into
feature/telegram-msg-gap-closurefrom
swarm/tg-msg-gap/task-3

Conversation

@noanflaherty
Copy link
Copy Markdown
Contributor

@noanflaherty noanflaherty commented Feb 21, 2026

Auto-configure GATEWAY_UNMAPPED_POLICY=default and GATEWAY_DEFAULT_ASSISTANT_ID in local gateway startup for single-assistant deployments. Add operator-visible Telegram notice and logging when routing is rejected instead of silent drop. Part of #6200.


Open with Devin

…d rejection visibility

Co-Authored-By: Claude <noreply@anthropic.com>
@noanflaherty noanflaherty self-assigned this Feb 21, 2026
@noanflaherty noanflaherty merged commit 781c60a into feature/telegram-msg-gap-closure Feb 21, 2026
@noanflaherty noanflaherty deleted the swarm/tg-msg-gap/task-3 branch February 21, 2026 20:19
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +32 to +41
const rejectionNoticeTimestamps = new Map<string, number>();

function shouldSendRejectionNotice(chatId: string): boolean {
const now = Date.now();
const lastSent = rejectionNoticeTimestamps.get(chatId);
if (lastSent !== undefined && now - lastSent < REJECTION_NOTICE_COOLDOWN_MS) {
return false;
}
rejectionNoticeTimestamps.set(chatId, now);
return true;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Unbounded memory growth in rejectionNoticeTimestamps map — no eviction of expired entries

The rejectionNoticeTimestamps module-level Map<string, number> grows without bound. Every unique chat ID that triggers a routing rejection adds an entry, but entries are never removed — even after the 5-minute cooldown expires.

Root Cause and Impact

Unlike the DedupCache (at gateway/src/dedup-cache.ts:18-23) which has a maxSize cap and TTL-based eviction, the rejectionNoticeTimestamps map has no eviction mechanism. The shouldSendRejectionNotice function only reads and writes entries but never deletes stale ones:

const rejectionNoticeTimestamps = new Map<string, number>();

function shouldSendRejectionNotice(chatId: string): boolean {
  const now = Date.now();
  const lastSent = rejectionNoticeTimestamps.get(chatId);
  if (lastSent !== undefined && now - lastSent < REJECTION_NOTICE_COOLDOWN_MS) {
    return false;
  }
  rejectionNoticeTimestamps.set(chatId, now);
  return true;
}

In a scenario where the gateway is misconfigured (routing rejects all messages) and the bot is added to many Telegram groups or receives messages from many unique users, each distinct chatId permanently consumes memory. Over a long-running gateway lifetime, this leads to unbounded memory growth proportional to the total number of unique rejected chat IDs ever seen.

Impact: Slow memory leak in long-running gateway processes. Severity depends on traffic volume — a bot in many groups with misconfigured routing could accumulate thousands of entries that are never cleaned up.

Prompt for agents
In gateway/src/http/routes/telegram-webhook.ts, the rejectionNoticeTimestamps Map (line 32) grows without bound. Add periodic eviction of entries older than REJECTION_NOTICE_COOLDOWN_MS. Two approaches:

1. (Simple) In shouldSendRejectionNotice (lines 34-41), after the cooldown check, periodically sweep the map to delete entries where (now - timestamp) >= REJECTION_NOTICE_COOLDOWN_MS. For example, run the sweep every N calls or every M minutes using a counter or last-sweep timestamp.

2. (Better) Add a maxSize cap similar to DedupCache. When the map exceeds the cap, evict all expired entries. If still over cap, delete the oldest entries. This bounds memory usage regardless of traffic patterns.

Either approach prevents unbounded memory growth from accumulating stale chat ID entries.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bd30fbd007

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +36 to +40
const lastSent = rejectionNoticeTimestamps.get(chatId);
if (lastSent !== undefined && now - lastSent < REJECTION_NOTICE_COOLDOWN_MS) {
return false;
}
rejectionNoticeTimestamps.set(chatId, now);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bound rejection notice cache growth

rejectionNoticeTimestamps is updated for every new chat ID but never evicted, so a long-lived gateway handling many distinct Telegram chats will retain stale IDs forever and grow memory usage over time. This is especially likely for public bots/groups where unique chat IDs can accumulate continuously; adding TTL-based cleanup or a max-size eviction policy would prevent unbounded growth.

Useful? React with 👍 / 👎.

@noanflaherty noanflaherty mentioned this pull request Feb 21, 2026
6 tasks
noanflaherty added a commit that referenced this pull request Feb 21, 2026
* fix: remove assistantId dependency from Telegram attachment delivery (#6210)

Co-authored-by: Claude <noreply@anthropic.com>

* feat: add Telegram webhook lifecycle reconciliation (#6211)

Co-authored-by: Claude <noreply@anthropic.com>

* feat: auto-configure gateway routing for single-assistant mode and add rejection visibility (#6212)

Co-authored-by: Claude <noreply@anthropic.com>

* feat: add Telegram Bot messaging provider for proactive outbound sends (#6222)

Co-authored-by: Claude <noreply@anthropic.com>

* feat: harden /deliver/telegram auth and align docs with Telegram capabilities (#6238)

Co-authored-by: Claude <noreply@anthropic.com>

* fix: correct misleading comment in Telegram attachment download path (#6241)

Co-authored-by: Claude <noreply@anthropic.com>

* fix: bound rejection notice cache with periodic eviction (#6242)

Co-authored-by: Claude <noreply@anthropic.com>

* fix: support tokenless providers in withProviderToken and fix testConnection error handling (#6244)

Co-authored-by: Claude <noreply@anthropic.com>

* fix: always reconcile webhook and normalize ingress URL (#6245)

Co-authored-by: Claude <noreply@anthropic.com>

* fix: resolve gateway lint error and credential security allowlist for Telegram adapter (#6257)

Co-authored-by: Claude <noreply@anthropic.com>

* fix: require webhook_secret in Telegram isConnected check (#6259)

Co-authored-by: Claude <noreply@anthropic.com>

* fix: only default routing policy in single-assistant deployments (#6261)

Co-authored-by: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant