REPOSITORY / ScuroNeko/Laniakea

Wiki

KNOWLEDGE REPOSITORY
4
Update Routing Model
ScuroNeko edited this page 2026-05-20 13:28:29 +03:00

Update Routing Model

Russian version: Update-Routing-Model-RU

This page defines the current update-routing contract in Laniakea: which Telegram update kinds go through command routing, which go through payload routing, which go through generic update handlers, and what MessageContext guarantees exist in each path.

This is a model of current framework behavior, not a second API surface. The goal is to make the existing routing and MessageContext normalization explicit and testable.

Top-level routing

Laniakea currently routes updates like this:

Update type Routing path
message command flow
channel_post command flow
callback_query payload flow
everything else AddUpdateHandler(...)

Important:

  • message, channel_post, and callback_query are reserved from AddUpdateHandler(...).
  • scenes are checked before normal routing, but the current scene model is still fundamentally message-driven.

What prepareUpdateCtx(...) does

Before handler routing, Laniakea normalizes a MessageContext from the incoming Telegram update.

That normalization is intentionally broader than command and payload routing:

  • some update kinds populate ctx.Msg
  • some populate ctx.From and ctx.FromID
  • callback queries may populate callback-target fields
  • ctx.Text, ctx.Args, and ctx.Prefix are not populated by this stage

This is an important distinction:

  • prepareUpdateCtx(...) defines the raw normalized context shape
  • routing then decides which handler path receives that context

Command flow contract

Command flow applies only to:

  • message
  • channel_post

When a command matches, these guarantees apply:

  • ctx.Update is always present
  • ctx.Msg is present
  • ctx.Prefix contains the matched command prefix
  • ctx.Text contains the parsed tail after the command name
  • ctx.Args contains strings.Fields(ctx.Text)
  • ctx.Logger switches to the matched plugin logger when one exists

Not guaranteed:

  • ctx.From
  • ctx.FromID

Example edge case:

  • a channel_post sent via sender_chat still has ctx.Msg
  • but ctx.From may be nil
  • and ctx.FromID may stay 0

Payload flow contract

Payload flow applies only to:

  • callback_query

Base guarantees:

  • ctx.Update is always present
  • ctx.CallbackQueryID is populated
  • ctx.From and ctx.FromID are populated when Telegram includes a user
  • ctx.Args is populated from decoded payload args
  • ctx.Logger switches to the matched plugin logger when one exists

Not guaranteed:

  • ctx.Text
  • ctx.Prefix

There are two payload target shapes.

Callback query targeting a chat message

Guarantees:

  • ctx.Msg is present
  • ctx.CallbackMsgID is populated
  • ctx.InlineMsgID == ""

Callback query targeting an inline message

Guarantees:

  • ctx.Msg == nil
  • ctx.CallbackMsgID == 0
  • ctx.InlineMsgID is populated

Generic update handler contract

Generic update handlers are registered through Plugin.AddUpdateHandler(...).

They apply to all update kinds outside the reserved command/payload flow.

General guarantees:

  • ctx.Update is always present
  • ctx.Text is not normalized
  • ctx.Args is not normalized
  • ctx.Prefix is not normalized
  • each plugin update handler receives its own copied MessageContext struct

Important limitation:

  • the copied context is an isolated struct copy, not a deep copy of all nested Telegram payload objects

Normalized MessageContext fields by update kind

Message-backed update kinds

Update type ctx.Msg ctx.From / ctx.FromID
message yes yes, when Msg.From exists
edited_message yes yes, when Msg.From exists
channel_post yes only when Msg.From exists
edited_channel_post yes only when Msg.From exists
business_message yes yes, when Msg.From exists
edited_business_message yes yes, when Msg.From exists

Important:

  • message-backed does not mean command-routed
  • edited_message, edited_channel_post, business_message, and edited_business_message currently do not enter command flow automatically

User-backed but not message-backed update kinds

Update type ctx.Msg ctx.From / ctx.FromID
inline_query no yes
chosen_inline_result no yes
shipping_query no yes
pre_checkout_query no yes
purchased_paid_media no yes
my_chat_member no yes
chat_member no yes
chat_join_request no yes
business_connection no yes
poll_answer no yes
message_reaction no yes, when Telegram includes User
chat_boost no yes
removed_chat_boost no yes

Callback-specific update kind

Update type ctx.Msg ctx.From / ctx.FromID Special fields
callback_query with Message yes yes CallbackQueryID, CallbackMsgID
callback_query with InlineMessageID no yes CallbackQueryID, InlineMsgID

Update kinds without normalized user/message guarantees

Update type ctx.Msg ctx.From / ctx.FromID
poll no no
message_reaction_count no no
deleted_business_messages no no
unknown no no

What is already stable enough to rely on

  • message and channel_post stay on command flow
  • callback_query stays on payload flow
  • prepareUpdateCtx(...) itself does not populate Text, Args, or Prefix
  • command parsing populates Text, Args, and Prefix
  • payload decoding populates Args, not Text
  • callback target shape is split between chat-message callbacks and inline-message callbacks
  • edited_message and edited_channel_post stay out of command routing

What is still intentionally open

  • whether scenes should remain message-driven only or grow a broader update model
  • whether message-backed edited/business updates should ever gain command-style routing
  • whether “message-backed update” should become an explicit documented framework concept