fix(alerter): escape all dynamic numeric fields in Telegram MarkdownV2 (#106)
Telegram's MarkdownV2 parser treats `.` as a special character and rejects
the message with `Bad Request: can't parse entities` if any unescaped `.`
appears outside a code or pre block. The current formatter only escapes
the static `Market:` title and the `$` in the USDC amount, while leaving
three numeric runs unescaped:
*Risk Score:* 0.82 (HIGH) ← `.` in the score literal
*Trade:* BUY Yes @ $0.075 | $15,000.00
↑ ↑
price USDC amount
In production this means well-formed alerts silently fail to reach
Telegram users — the dispatcher reports a 400 from the Bot API and the
event is dropped.
This change routes every dynamic value through `_escape_telegram_markdown`
before interpolation:
- `assessment.weighted_score` (risk score)
- `trade.price` (price string)
- `format_usdc(trade.notional_value)` (USDC amount, including its `.`)
- `trade.side` and `trade.outcome` (defensive — upstream values may
contain `-` or `.` in future schema changes)
The test that previously asserted `"0.82" in result.telegram_markdown` is
updated to require the escaped form `"0\.82"`, and a new test pins down
that none of `0.82` / `0.075` / `15,000.00` appear in unescaped form.
Co-authored-by: schrodinger01 <schrodinger01@users.noreply.github.com>
This commit is contained in:
co-authored by
schrodinger01
parent
b962bdaee2
commit
5afbb35ee9
@@ -409,12 +409,27 @@ class TestTelegramMarkdown:
|
||||
assert "`0x1234...5678`" in result.telegram_markdown
|
||||
|
||||
def test_telegram_includes_risk_score(self, high_risk_assessment: RiskAssessment) -> None:
|
||||
"""Test that Telegram message includes risk score."""
|
||||
"""Test that Telegram message includes risk score, MarkdownV2-escaped."""
|
||||
formatter = AlertFormatter()
|
||||
result = formatter.format(high_risk_assessment)
|
||||
assert "0.82" in result.telegram_markdown
|
||||
# MarkdownV2 requires `.` to be escaped, so 0.82 becomes 0\.82.
|
||||
assert "0\\.82" in result.telegram_markdown
|
||||
assert "HIGH" in result.telegram_markdown
|
||||
|
||||
def test_telegram_escapes_all_decimals(self, high_risk_assessment: RiskAssessment) -> None:
|
||||
"""Telegram MarkdownV2 rejects unescaped `.` in dynamic numeric
|
||||
fields (risk score, price, USDC amount). All must be present in
|
||||
their escaped form."""
|
||||
formatter = AlertFormatter()
|
||||
result = formatter.format(high_risk_assessment)
|
||||
md = result.telegram_markdown
|
||||
for unescaped in ("0.82", "0.075", "15,000.00"):
|
||||
assert unescaped not in md, (
|
||||
f"unescaped {unescaped!r} would be rejected by Telegram MarkdownV2: {md!r}"
|
||||
)
|
||||
for escaped in ("0\\.82", "0\\.075", "15,000\\.00"):
|
||||
assert escaped in md, f"missing escaped {escaped!r} in {md!r}"
|
||||
|
||||
def test_telegram_includes_links(self, high_risk_assessment: RiskAssessment) -> None:
|
||||
"""Test that Telegram message includes links."""
|
||||
formatter = AlertFormatter()
|
||||
|
||||
Reference in New Issue
Block a user