fix(telegram): escape MarkdownV2 reserved parens in chunk indicators (#74004) - #74040
fix(telegram): escape MarkdownV2 reserved parens in chunk indicators (#74004)#74040Tranquil-Flow wants to merge 1 commit into
Conversation
Related: #74028 escapes the same standalone MarkdownV2 chunk-indicator parentheses. This PR also applies the existing fence-separation helper for the distinct case where a generated indicator shares a closing code-fence line; reviewers should compare the broader coverage before choosing a consolidation path. |
|
Thanks for adding standalone-path parity and regression coverage. Current main still sends raw Automated hermes-sweeper review. |
What
When
_send_telegram()(the standalone send path used by cron delivery whenthe gateway is down) chunks a long MarkdownV2 message,
truncate_message()appends a raw
(1/N)indicator afterformat_message()has alreadyescaped all MarkdownV2 special characters. The unescaped
(and)causeTelegram to reject the parse and silently fall back to plain text, stripping
all formatting.
The live gateway adapter (
plugins/platforms/telegram/adapter.py) alreadyapplies this exact transformation; the standalone path was missing it — a
classic code-duplication gap.
How
After
truncate_message(), whensend_parse_mode == ParseMode.MARKDOWN_V2and the message spans multiple chunks, apply both transformations the live
adapter uses:
re.sub(r" \((\d+)/(\d+)\)$", r" \\\(\1/\2\\\)", chunk)— escape theindicator parens.
_separate_chunk_indicator_from_fence(chunk)— move the indicator off atrailing code-fence line so Telegram treats the fence as a clean close.
This reuses the existing
_separate_chunk_indicator_from_fencehelper (alreadyused in 3 other call sites in the adapter) rather than duplicating the logic.
HTML mode is exempt: the guard is scoped to
MARKDOWN_V2, so parens stayunescaped when
parse_mode='HTML'.Why layer 2 matters
When
truncate_message()splits inside a fenced code block, it closes thefence and appends
(1/N)on the same line as the closing fence. Telegramdoes not treat that as a clean fence close and again falls back to plain text.
Tests
4 new production-path regression tests (RED on upstream/main, GREEN with fix):
test_chunk_indicators_have_escaped_parens— multi-chunk MDv2 message has escaped(N/M)indicators (RED proof: raw(1/3)parens reached unescaped)test_single_chunk_no_indicator— short message gets no indicatortest_html_mode_chunked_no_paren_escaping— HTML mode does NOT backslash-escape parenstest_chunked_code_fence_indicator_separated— indicator not glued to closing fenceResults: 4/4 new tests pass; 8/8 nearby
test_telegram_send_message_*pass.git rev-list --left-right --count upstream/main...HEAD=0 1.Competitor
PR #74028 (kyssta-exe) addresses the same root cause but is incomplete: no
committed regression test, missing the code-fence-separation layer (Layer 2),
and uses a redundant inline
import re as _rewhenreis already imported atmodule level.
Fixes #74004.
Auto-published by Moonsong via Path B automated pipeline.