diff --git a/Bot-Lifecycle-RU.md b/Bot-Lifecycle-RU.md index dfa8c54..f22b8d5 100644 --- a/Bot-Lifecycle-RU.md +++ b/Bot-Lifecycle-RU.md @@ -42,6 +42,8 @@ English version: [[Bot-Lifecycle]] - `SetStrictPayloadType(...)` - `SetDraftProvider(...)` +Явную модель фаз конфигурации и фиксации смотри в [[Configuration-Freeze-Model-RU]]. + Это важно, потому что механизм выполнения не рассчитан на модель “запустили, а потом продолжаем собирать конфигурацию на лету”. ## Почему `AddPlugins(...)` так важен @@ -53,6 +55,8 @@ English version: [[Bot-Lifecycle]] - потом регистрируй его; - не рассчитывай, что дальнейшая мутация исходного `*Plugin` будет официально поддерживаемой частью API. +На уровне самого `Bot` конфигурация фиксируется ещё сильнее после начала первого запуска. После этого поздние bot-level конфигурационные вызовы игнорируются. Подробности: [[Configuration-Freeze-Model-RU]]. + ## `Run()` и `RunWithContext(...)` `Run()` — это короткая форма для простых случаев. diff --git a/Bot-Lifecycle.md b/Bot-Lifecycle.md index 2bcd9b5..e9d1fa3 100644 --- a/Bot-Lifecycle.md +++ b/Bot-Lifecycle.md @@ -43,6 +43,7 @@ The normal pattern is to finish all structural configuration before starting the - `ErrorTemplate(...)` and `Debug(...)` adjust runtime behavior and logging. For an overview of handlers and plugins, see [[Commands-and-Plugins]]. For context helpers available inside handlers, see [[MsgContext]]. +For the explicit configuration-phase and freeze-phase rules, see [[Configuration-Freeze-Model]]. ## `AddPlugins` is a configuration commit point @@ -59,6 +60,8 @@ This is especially important for: - custom plugin loggers; - plugin shutdown hooks. +At the bot level, configuration freezes even further once the first run begins. After that point, late bot-level configuration calls are ignored. See [[Configuration-Freeze-Model]]. + ## Minimal startup pattern ```go diff --git a/Configuration-Freeze-Model-RU.md b/Configuration-Freeze-Model-RU.md new file mode 100644 index 0000000..97ef2dd --- /dev/null +++ b/Configuration-Freeze-Model-RU.md @@ -0,0 +1,136 @@ +# Configuration Freeze Model RU + +English version: [[Configuration-Freeze-Model]] + +Эта страница объясняет, когда конфигурацию бота в Laniakea ещё можно менять, когда она считается зафиксированной и почему поздние конфигурационные вызовы намеренно игнорируются. + +Коротко: +- конфигурацию плагина нужно считать завершённой до `AddPlugins(...)`; +- конфигурацию бота нужно считать завершённой до первого `Run()` или `RunWithContext(...)`; +- после старта runtime поздние bot-level конфигурационные вызовы игнорируются, а не применяются частично. + +## Зачем нужна такая модель + +Laniakea разводит: +- фазу построения и настройки; +- фазу регистрации и снимка состояния плагинов; +- фазу выполнения и обработки обновлений. + +Это делает поведение фреймворка предсказуемым. Без такой границы running bot мог бы увидеть наполовину применённые изменения prefixes, middleware, политики данных callback, локализации или общих зависимостей уже во время обработки update. + +Цель здесь не в том, чтобы сделать из `Bot` живую control surface. Цель в том, чтобы сделать startup и runtime-семантику явной и стабильной. + +## Три практические фазы + +### 1. Фаза построения + +Она начинается в `NewBot[T](opts)` и продолжается, пока ты настраиваешь экземпляр бота. + +Типичные операции этой фазы: +- `DatabaseContext(...)` +- `AddPrefixes(...)` +- `SetPayloadType(...)` +- `SetStrictPayloadType(...)` +- `UpdateTypes(...)` +- `AddUpdateType(...)` +- `AddPlugins(...)` +- `AddMiddleware(...)` +- `AddRunner(...)` +- `AddL10n(...)` +- `SetDraftProvider(...)` +- `SetSessionStore(...)` +- `SetSceneScopePriority(...)` +- `ErrorTemplate(...)` + +Именно здесь и должна происходить вся структурная настройка. + +### 2. Фаза снимка конфигурации плагина + +`AddPlugins(...)` — это точка фиксации конфигурации плагинов. + +Когда плагин добавляется в `Bot`, бот клонирует конфигурацию плагина во внутреннее состояние. После этого исходный `*Plugin` уже не стоит считать авторитетным источником конфигурации именно для этого экземпляра бота. + +До `AddPlugins(...)` нужно закончить: +- commands; +- обработчики данных callback; +- обработчики обновлений; +- middleware плагина; +- logger плагина; +- регистрацию сцен; +- `OnClose` callbacks. + +Если потом изменить исходный плагин, бот не обязан увидеть эти изменения. + +### 3. Фаза фиксации конфигурации бота + +Первый вызов `Run()` или `RunWithContext(...)` фиксирует bot-level конфигурацию. + +С этого момента бот считает структурную конфигурацию закрытой. Поздние вызовы конфигурационных методов игнорируются вместо того, чтобы применяться в тот момент, когда runtime уже активен или уже однажды был запущен. + +Сейчас это относится к таким bot-level методам, как: +- `SetDraftProvider(...)` +- `SetSessionStore(...)` +- `SetSceneScopePriority(...)` +- `DatabaseContext(...)` +- `UpdateTypes(...)` +- `SetPayloadType(...)` +- `SetStrictPayloadType(...)` +- `AddUpdateType(...)` +- `AddPrefixes(...)` +- `ErrorTemplate(...)` +- `AddPlugins(...)` +- `AddMiddleware(...)` +- `AddRunner(...)` +- `AddL10n(...)` + +Практически это нужно читать так: +- создать бот; +- закончить конфигурацию; +- один раз запустить runtime; +- для другой runtime-конфигурации создать новый `Bot`. + +## Что значит «игнорируется» + +«Игнорируется» значит, что метод возвращается без изменения структурного runtime-состояния бота. + +Это намеренное решение. Фреймворк предпочитает предсказуемый no-op вместо частичной live-мутации running bot. Это помогает избежать: +- неясного порядка между конфигурационными изменениями и обработкой update; +- гонок вокруг общего состояния бота во время runtime; +- путаницы в том, влияет ли изменение только на будущие update или ещё и на уже поставленную в очередь работу; +- несовместимого поведения между snapshot-моделью плагинов и живым состоянием бота. + +## Чего эта модель не означает + +Она не означает, что после старта каждый метод `Bot` становится бессмысленным. + +Она относится именно к структурным конфигурационным методам. Runtime-операции вроде: +- `RunWithContext(...)`; +- `Close()`; +- `CloseRemote(...)`; +- операций `MsgContext` внутри хендлеров; + +сохраняют обычную семантику. + +Важно и то, что не каждый нефункциональный флаг обязан быть частью freeze contract. Ключевой вопрос здесь такой: меняет ли метод структурную runtime-модель бота. + +## Рекомендуемая ментальная модель + +Удобно думать о `Bot` как о builder плюс одной runtime-сессии: + +1. создать бот; +2. полностью его настроить; +3. зарегистрировать законченные плагины; +4. один раз запустить runtime; +5. остановить его; +6. закрыть локальные ресурсы; +7. для следующего запуска с другой конфигурацией создать новый `Bot`. + +Именно эта модель сейчас лучше всего соответствует реализации и является самым безопасным контрактом для `1.0`. + +## Связанные страницы + +- [[Bot-Lifecycle-RU]] +- [[Commands-and-Plugins-RU]] +- [[Update-Routing-Model-RU]] +- [[Scenes-RU]] +- [[FAQ-RU]] diff --git a/Configuration-Freeze-Model.md b/Configuration-Freeze-Model.md new file mode 100644 index 0000000..8d50d91 --- /dev/null +++ b/Configuration-Freeze-Model.md @@ -0,0 +1,136 @@ +# Configuration Freeze Model + +Russian version: [[Configuration-Freeze-Model-RU]] + +This page explains when Laniakea bot configuration is still mutable, when it becomes fixed, and what kinds of late changes are intentionally ignored. + +The short version: +- plugin configuration should be treated as finished before `AddPlugins(...)`; +- bot configuration should be treated as finished before the first `Run()` or `RunWithContext(...)`; +- after runtime starts, late bot-level configuration calls are ignored rather than partially applied. + +## Why this model exists + +Laniakea separates: +- construction-time configuration; +- plugin registration and snapshotting; +- runtime update processing. + +That separation keeps the framework predictable. Without it, a running bot could observe half-applied changes to prefixes, middleware, payload policy, localization, or shared dependencies while updates are already being processed. + +The goal is not to create a live control surface. The goal is to make startup and runtime semantics explicit and stable. + +## The three practical phases + +### 1. Construction phase + +This begins at `NewBot[T](opts)` and continues while you configure the bot instance. + +Typical operations in this phase: +- `DatabaseContext(...)` +- `AddPrefixes(...)` +- `SetPayloadType(...)` +- `SetStrictPayloadType(...)` +- `UpdateTypes(...)` +- `AddUpdateType(...)` +- `AddPlugins(...)` +- `AddMiddleware(...)` +- `AddRunner(...)` +- `AddL10n(...)` +- `SetDraftProvider(...)` +- `SetSessionStore(...)` +- `SetSceneScopePriority(...)` +- `ErrorTemplate(...)` + +This is the intended place for all structural configuration. + +### 2. Plugin snapshot phase + +`AddPlugins(...)` is a configuration commit point for plugins. + +When a plugin is added to a bot, the bot clones the plugin configuration into its own internal state. After that, the original `*Plugin` should be treated as no longer authoritative for that bot instance. + +Configure these before `AddPlugins(...)`: +- commands; +- payload handlers; +- update handlers; +- plugin middleware; +- plugin logger; +- scene registrations; +- `OnClose` callbacks. + +If you mutate the original plugin later, the bot is not expected to observe those edits. + +## 3. Bot runtime freeze phase + +The first call to `Run()` or `RunWithContext(...)` freezes bot-level configuration. + +From that point on, the bot treats structural configuration as closed. Late calls to configuration mutators are ignored instead of being applied while runtime is already active or already initialized. + +This currently applies to bot-level methods such as: +- `SetDraftProvider(...)` +- `SetSessionStore(...)` +- `SetSceneScopePriority(...)` +- `DatabaseContext(...)` +- `UpdateTypes(...)` +- `SetPayloadType(...)` +- `SetStrictPayloadType(...)` +- `AddUpdateType(...)` +- `AddPrefixes(...)` +- `ErrorTemplate(...)` +- `AddPlugins(...)` +- `AddMiddleware(...)` +- `AddRunner(...)` +- `AddL10n(...)` + +In practice, you should read this as: +- build a bot; +- finish configuration; +- run it once; +- create a new bot if you need a different runtime configuration. + +## What “ignored” means + +Ignored means the method returns without changing the bot's structural runtime state. + +This behavior is intentional. The framework prefers a predictable no-op over partial live mutation of a running bot. That avoids: +- unclear ordering between configuration edits and update handling; +- runtime races around shared bot state; +- confusion about whether a change affects only future updates or also already queued work; +- inconsistent behavior between plugin-level snapshots and bot-level live state. + +## What this model does not mean + +This model does not mean every method on `Bot` becomes unusable after startup. + +It applies specifically to structural configuration methods. Runtime operations such as: +- `RunWithContext(...)`; +- `Close()`; +- `CloseRemote(...)`; +- handler-time `MsgContext` operations; + +still have their normal meaning. + +Also note that not every non-structural flag is part of the freeze contract. The important rule is whether the method changes the bot's runtime configuration model, not whether it is simply callable on `Bot`. + +## Recommended mental model + +Treat `Bot` as a builder plus one runtime session: + +1. construct a bot; +2. fully configure it; +3. register finished plugins; +4. start runtime once; +5. stop it; +6. close it; +7. create a new bot for the next differently configured run. + +That mental model matches the current implementation and is the safest contract to rely on for `1.0`. + +## Related pages + +- [[Bot-Lifecycle]] +- [[Commands-and-Plugins]] +- [[Update-Routing-Model]] +- [[Scenes]] +- [[FAQ]] diff --git a/FAQ-RU.md b/FAQ-RU.md index d8af86a..19dbf03 100644 --- a/FAQ-RU.md +++ b/FAQ-RU.md @@ -90,6 +90,24 @@ English version: [[FAQ]] - выбор логгера - `OnClose` +Подробную модель snapshot/freeze границ смотри в [[Configuration-Freeze-Model-RU]]. + +## Почему поздние bot-level конфигурационные вызовы игнорируются после старта runtime? + +Потому что Laniakea воспринимает конфигурацию бота как до-runtime фазу, а не как живую control surface во время работы. + +Как только начинается первый запуск, bot-level конфигурация считается frozen. Поздние вызовы вроде добавления middleware, смены payload defaults, изменения prefixes или подмены database context игнорируются вместо частичного применения. + +Это помогает избежать: +- неожиданной live-мутации running bot; +- неясного порядка между конфигурационными изменениями и обработкой update; +- runtime-изменений конфигурации с риском гонок; +- путаницы между snapshotted state и всё ещё изменяемым состоянием. + +Если нужна другая конфигурация, для следующего запуска нужно создать новый экземпляр `Bot`. + +Полную модель фаз и фиксации смотри в [[Configuration-Freeze-Model-RU]]. + ## Почему async middleware игнорирует `false`? Потому что async middleware задуман как путь для побочных действий, а не как механизм управления потоком. diff --git a/FAQ.md b/FAQ.md index 17924ed..99bcb09 100644 --- a/FAQ.md +++ b/FAQ.md @@ -134,6 +134,24 @@ Configure these before registration: - logger choice; - `OnClose` callback. +See [[Configuration-Freeze-Model]] for the broader lifecycle model around plugin snapshotting and bot-level configuration freeze. + +## Why are late bot configuration calls ignored after runtime starts? + +Because Laniakea treats bot configuration as a pre-runtime phase, not a live control surface. + +Once the first run begins, bot-level configuration is considered frozen. Late calls such as adding middleware, swapping payload defaults, changing prefixes, or injecting a new database context are ignored instead of being partially applied. + +That avoids: +- surprising live mutation of a running bot; +- unclear ordering between config changes and update processing; +- race-prone runtime configuration changes; +- confusion about which state is snapshotted and which state is still mutable. + +If you need a different configuration, create a new bot instance for the next run. + +See [[Configuration-Freeze-Model]] for the full phase model. + ## Why does async middleware ignore `false`? Because async middleware is designed for side effects, not flow control. diff --git a/Home-RU.md b/Home-RU.md index 07c81b5..8136432 100644 --- a/Home-RU.md +++ b/Home-RU.md @@ -20,6 +20,7 @@ English version: [[Home]] - [[Error-Handling-RU]] - [[Logging-RU]] - [[Update-Routing-Model-RU]] +- [[Configuration-Freeze-Model-RU]] - [[Scenes-RU]] ## Telegram API и взаимодействие @@ -42,37 +43,25 @@ English version: [[Home]] Но если смотреть именно на концептуальные дыры, а не просто на наличие страниц, то все еще выделяются такие темы: -1. `Update-Routing-Model` -Почему это важно: -Сейчас маршрутизация объяснена кусками в `Commands-and-Plugins`, `Bot-Lifecycle` и `Middleware`, но нет одной страницы, которая последовательно показывает, как обновление проходит через систему. -Что туда войдет: -`prepareUpdateCtx`, middleware бота, поток команд, поток данных callback, обработчики обновлений, клонированный контекст для обновлений вне командного потока и поведение первого совпадения. - -2. `Context-and-State-Model` +1. `Context-and-State-Model` Почему это важно: Страница про `MsgContext` уже есть, но нет отдельной концептуальной страницы про разделяемое состояние, копируемое состояние, поведение `DatabaseContext(T)` и про то, почему pointer types чаще всего являются правильным выбором по умолчанию. Что туда войдет: Разделяемые зависимости, копируемые значения context, ожидания во время выполнения и места, где легко ошибиться с предположениями о гонках. -3. `Plugin-Boundaries-and-Composition` +2. `Plugin-Boundaries-and-Composition` Почему это важно: Wiki уже объясняет, как использовать плагины на практике, но почти не говорит о том, как о них думать архитектурно. Что туда войдет: Как делить бот на плагины, что должно жить в middleware плагина, когда выделять новый плагин и как не прийти к дизайну одного гигантского плагина. -4. `Handler-Design-Guidelines` +3. `Handler-Design-Guidelines` Почему это важно: Это будет страница не столько про API, сколько про стиль и идиоматичное использование фреймворка. Что туда войдет: Когда возвращать `error`, когда отвечать вручную, как держать обработчики тонкими, когда выносить логику в сервисный слой и как не смешивать `tgapi` и высокоуровневые вспомогательные методы без необходимости. -5. `Update-Types-and-Coverage` -Почему это важно: -Сейчас обработчики обновлений уже задокументированы, но нет одной карты того, какие типы обновлений идут через команды и данные callback, какие через `AddUpdateHandler(...)`, и какие поля `MsgContext` разумно ожидать в каждом потоке. -Что туда войдет: -Категории маршрутизации, гарантии context для конкретных видов обновлений и влияние формы обновления на дизайн обработчика. - -6. `Telegram-Limits-and-Validation` +4. `Telegram-Limits-and-Validation` Почему это важно: Часть этой информации уже разбросана по страницам про ограничение частоты, данные callback и ошибки, но нет одной общей страницы с целостной моделью. Что туда войдет: @@ -84,10 +73,10 @@ Wiki уже объясняет, как использовать плагины - `Public-API-Stability` Если приоритизировать, то самый полезный порядок сейчас такой: -1. `Update-Routing-Model` -2. `Context-and-State-Model` -3. `Plugin-Boundaries-and-Composition` -4. `Handler-Design-Guidelines` +1. `Context-and-State-Model` +2. `Plugin-Boundaries-and-Composition` +3. `Handler-Design-Guidelines` +4. `Telegram-Limits-and-Validation` ## Миграция и сопровождение diff --git a/Home.md b/Home.md index ccc5ed6..1c388f3 100644 --- a/Home.md +++ b/Home.md @@ -24,6 +24,7 @@ Use this wiki as the structured companion to the README: start with setup, then - [[Error-Handling]] - [[Logging]] - [[Update-Routing-Model]] +- [[Configuration-Freeze-Model]] - [[Scenes]] ## Telegram API and Interaction @@ -44,37 +45,25 @@ The current wiki already covers most of the main framework surface: `Bot`, `BotO If we focus specifically on conceptual gaps rather than simple page presence, these topics still stand out: -1. `Update-Routing-Model` -Why it matters: -This behavior is currently explained in pieces across `Commands-and-Plugins`, `Bot-Lifecycle`, and `Middleware`, but there is no single page that explains how an update actually flows through the system. -What it would cover: -`prepareUpdateCtx`, bot middleware, command flow, payload flow, update handlers, cloned contexts for non-command updates, and first-match behavior. - -2. `Context-and-State-Model` +1. `Context-and-State-Model` Why it matters: `MsgContext` exists, but there is no dedicated conceptual page about what is shared state, what is copied state, how `DatabaseContext(T)` behaves, and why pointer types are usually the right default. What it would cover: Shared dependencies, copied context values, runtime expectations, and where race assumptions can go wrong. -3. `Plugin-Boundaries-and-Composition` +2. `Plugin-Boundaries-and-Composition` Why it matters: The wiki explains how plugins work in practice, but not yet how to think architecturally about plugin boundaries. What it would cover: How to split a bot into plugins, what belongs in plugin middleware, when to extract a new plugin, and how to avoid the giant-plugin anti-pattern. -4. `Handler-Design-Guidelines` +3. `Handler-Design-Guidelines` Why it matters: This would explain framework style rather than raw API surface. What it would cover: When to return `error`, when to answer manually, how to keep handlers thin, when to push logic into services, and how to avoid mixing `tgapi` with high-level helpers unnecessarily. -5. `Update-Types-and-Coverage` -Why it matters: -The wiki has update handlers, but not a single map of which update types go through commands and payloads, which go through `AddUpdateHandler(...)`, and which `MsgContext` fields are safe to expect in each flow. -What it would cover: -Routing categories, update-specific context guarantees, and how update shapes affect handler design. - -6. `Telegram-Limits-and-Validation` +4. `Telegram-Limits-and-Validation` Why it matters: Some of this exists in rate limiting, payload, and error docs, but not as one mental-model page. What it would cover: @@ -86,10 +75,10 @@ Less urgent, but still useful later: - `Public-API-Stability` If these are prioritized, the most useful order is: -1. `Update-Routing-Model` -2. `Context-and-State-Model` -3. `Plugin-Boundaries-and-Composition` -4. `Handler-Design-Guidelines` +1. `Context-and-State-Model` +2. `Plugin-Boundaries-and-Composition` +3. `Handler-Design-Guidelines` +4. `Telegram-Limits-and-Validation` ## Migration and Maintenance - [[Migration]]