db407dd078
Every Telegram health probe measures the transport. A getUpdates round-trip that returns 200 proves bytes are moving and nothing else: the stall watchdog (#92991), the pending-update probe (#42909/#55769), the get_me() heartbeat (#66377) and the polling-progress instrumentation all stay green while updates arrive and then die downstream. The adapter then publishes "connected", logs nothing at all, and is indistinguishable from a bot nobody has messaged. That is #102260: three weeks of telegram.state "connected" plus "polling confirmed healthy: getUpdates progressing (generation 1)" with zero inbound reaching the agent, surviving every restart. Two of the issue's three hypotheses do not hold on this code — _record_polling_progress fires on every round-trip (not only at start_polling), and _send_path_degraded is cleared on the first confirmed round-trip — and the reporter's own observation that fresh messages are received but not processed places the failure downstream of the transport, in the one stretch with no instrumentation at all. Add the missing delivered side of the accounting: - received: updates Telegram handed the process, read from the getUpdates envelope the adapter already parses (an empty result proves the transport, not arrival, so only non-empty results count). - dispatched: updates PTB's dispatcher carried through the whole handler chain, stamped in the existing group-99 catch-all before its early returns. - delivered: inbound events that reached the gateway's message handler, stamped in BasePlatformAdapter.handle_message for every platform. _check_ingress_delivery_gap runs on the existing heartbeat and, when updates arrived but nothing was delivered for 300s, names the broken hop: received > dispatched means the dispatcher is not draining, dispatched > delivered means Hermes is dropping what arrives. Diagnostic only — a received update legitimately reaches no gateway turn, and reconnecting a healthy transport cannot repair a dropped update, so this never drives recovery. Also make the silent discard on the shared funnel speak: handle_message returned with no log when no message handler was installed, so a mis-wired adapter discarded 100% of inbound while connected and able to send. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018pT5hFJBRfLj8KMqFhm3qz