Files
openclaw/extensions/telegram
Dallin Romney 8209426867 fix(telegram): transient Telegram pairing prompts (#85555)
* fix: avoid false telegram pairing prompts

* docs: add telegram pairing changelog

* refactor(telegram): share pairing-store gating and align isGroup check

Extract loadTelegramPairingStoreIfNeeded so the text-fragment flush path
and resolveTelegramGroupAllowFromContext share one implementation, and
align the isGroup derivation in the flush path with the
'group || supergroup' form used elsewhere in bot-handlers.runtime.ts.

Note on transient-vs-known errors: readChannelAllowFromStore already
translates missing-file (ENOENT) and JSON parse failures to an empty
allowlist internally, so the only errors that escape into the new
silent-drop path are unexpected I/O failures (EMFILE/EACCES/EIO/...) —
unpaired senders still get a pairing challenge as expected.

* fix(telegram): skip pairing-store read when commands.allowFrom already authorizes the sender

Native command auth resolves group/dm allow context (which may read the
pairing store) before checking commands.allowFrom. On DMs with
dmPolicy: "pairing", a transient pairing-store I/O failure was therefore
dropping commands from senders explicitly authorized by
commands.allowFrom.telegram.

Add a skipPairingStoreRead hint on resolveTelegramGroupAllowFromContext /
loadTelegramPairingStoreIfNeeded, precompute the command authorization
once at chat scope before the context call, and pass the hint when that
pre-check already authorizes the sender. The post-context command auth
check still owns the topic-scoped decision.

Regression covers a DM /status from a sender allowed by
commands.allowFrom.telegram with dmPolicy: "pairing" and a rejecting
readChannelAllowFromStore mock.

* fix(telegram): satisfy test-types on harness readChannelAllowFromStore

CI check-test-types failed because the harness now stores a loose
AnyAsyncMock for readChannelAllowFromStore but TelegramNativeCommandDeps
requires the precise typeof readChannelAllowFromStore signature. Cast at
the telegramDeps assignment so harness callers can keep passing any
vi.fn(...) (including ones that reject) without type pollution at the
call site.

* feat(telegram): reply with a retry hint when pairing-store read fails transiently

Wrap unexpected pairing-store I/O errors (EACCES, EMFILE, ...) in a
typed TelegramPairingStoreReadError and surface them through
handleInboundMessageLike with a friendly "please try again" reply that
matches the media-failure precedent at bot-handlers.runtime.ts:1893.
Beats silent drop: paired senders see why their message wasn't
processed, and unpaired senders who happen to send a DM during a
transient store outage retry naturally and get the correct pairing
prompt once the store recovers.

Verified live against @paxicoto_bot with chmod 000 on
~/.openclaw/credentials/telegram-default-allowFrom.json after touching
mtime to bypass the stat-pinned cache.
2026-05-24 15:12:30 -07:00
..
2026-05-24 02:40:16 +01:00