fix(formatter+telegram): drop tel: inline button, mark all 4xx as permanent
Pilot on washanyanya.ru exposed that Telegram Bot API rejects tel: URLs in inline_keyboard with HTTP 400 "Wrong port number specified in the URL". Queue was stuck on 5 items retrying the same failure 4 times each. - MessageFormatter: always returns reply_markup = null. The phone number is already rendered in the '📱 ...' line, and mobile Telegram clients linkify it automatically. - TelegramClient::is_permanent: treat all 4xx except 429 as permanent client-side errors, so future payload-shape bugs surface in the dashboard widget immediately instead of burning five retry cycles. - MessageFormatterTest updated: the old test asserting tel: in reply_markup is replaced with one asserting reply_markup is null and the phone still appears in the text body. - Spec §9 + §19 updated, §19's open question closed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -71,16 +71,11 @@ final class MessageFormatter
|
||||
$text = implode("\n", $lines);
|
||||
$text = self::truncate($text);
|
||||
|
||||
$markup = null;
|
||||
if ($phone !== null) {
|
||||
$markup = [
|
||||
'inline_keyboard' => [[
|
||||
['text' => '📞 Позвонить: ' . $phone['pretty'], 'url' => 'tel:' . $phone['e164']],
|
||||
]],
|
||||
];
|
||||
}
|
||||
|
||||
return ['text' => $text, 'reply_markup' => $markup];
|
||||
// Telegram Bot API rejects tel: URLs in inline_keyboard with HTTP 400
|
||||
// ("Wrong port number specified"), so no inline button is emitted.
|
||||
// The phone number is already shown in the message body (line '📱 ...')
|
||||
// and mobile Telegram clients make such numbers tappable automatically.
|
||||
return ['text' => $text, 'reply_markup' => null];
|
||||
}
|
||||
|
||||
private static function pick(array $fields, array $keys): string
|
||||
|
||||
@@ -64,13 +64,11 @@ final class TelegramClient
|
||||
|
||||
private static function is_permanent(int $code, string $desc): bool
|
||||
{
|
||||
if ($code === 401 || $code === 403) return true;
|
||||
if ($code === 400) {
|
||||
$d = strtolower($desc);
|
||||
if (strpos($d, 'chat not found') !== false) return true;
|
||||
if (strpos($d, 'bot was blocked') !== false) return true;
|
||||
if (strpos($d, 'user is deactivated') !== false) return true;
|
||||
}
|
||||
// 4xx (except 429 rate-limit) are client-side errors: bad request,
|
||||
// invalid chat, revoked token, malformed payload — retrying will not
|
||||
// help. Mark as permanent so the queue gives up immediately and the
|
||||
// admin is notified via the dashboard widget.
|
||||
if ($code >= 400 && $code < 500 && $code !== 429) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user