Inbound transport gates: pinned sender, flood bound, hash-only drop log.
Proposal V1 §4 and §10.4. The poller is the only thing that turns a Telegram
update into a stored message, and it refuses far more than it accepts:
* **Pinned sender only.** The account id *and* the chat id must both match the
destination pinned at setup, and the sender must not be a bot. Everything
else is dropped, hash-logged, and never written to the inbox. Dropped
updates still advance the cursor: re-reading a hostile sender's message on
every poll would be a self-inflicted flood.
* **Text only.** A v1 message without text is dropped the same way. Widening
to attachments is new attack surface and needs its own ruling.
* **Flood bound.** At most :data:`FLOOD_LIMIT` accepted messages per
:data:`FLOOD_WINDOW_SECONDS`. Updates are processed oldest-first, and once
the window is full the poller *stops* and leaves the cursor where it is, so
the overflow is deferred rather than discarded and arrives in order on a
later poll. The overflow itself is logged.
* **Taps are bound twice (plan 236).** A ``callback_query`` update is
admitted only when its sender passes the same pinned check as a message
AND its callback data names a SENT question whose transport message is the
one the button sits under. Each failed binding is refused by name
(:data:`CALLBACK_REFUSALS`), hash-logged, never stored, and never
acknowledged. An admitted tap is stored as a structured reply, counts
against the flood window like a message, and is acknowledged afterwards;
a failed acknowledgement is logged and never loses the tap.
The transport is always injected. There is no code path in this module that
constructs an HTTP client, which is what keeps the suite free of live calls.
Dependencies
------------
- oc_connect.audit (AuditStore, AuditRecord, content_hash, timestamp, utc_now - hash-only received, dropped, overflow and tap-acknowledgement records)
- oc_connect.comms (CommsBus, new_ulid - the poll cursor path and inbound message ids)
- oc_connect.connectors.telegram.destinations (TelegramDestination - the pinned account and chat a sender must match)
- oc_connect.inbound.classify (classify - mechanical classification of each admitted message)
- oc_connect.inbound.inbox (InboxStore - stores admitted messages and counts the flood window)
- oc_connect.outbox (Outbox, OutboxItem - correlates replies and taps to the sent question)
- oc_diagnostics (_dbg structured logger)
- option_c_connector_contracts (InboundMessage, InboundCorrelation, REPLY_VOCABULARY, lane - message model, correlation and lane risk)