REPOSITORY / ScuroNeko/Laniakea

Wiki

KNOWLEDGE REPOSITORY

Add configuration freeze model pages

Link freeze model from lifecycle and FAQ
Refresh home navigation after routing docs landed
2026-03-30 00:52:12 +03:00
parent 443045d509
commit c1c9e62954
8 changed files with 333 additions and 40 deletions
+4
@@ -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()` — это короткая форма для простых случаев.
+3
@@ -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
+136
@@ -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]]
+136
@@ -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]]
+18
@@ -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 задуман как путь для побочных действий, а не как механизм управления потоком.
+18
@@ -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.
+9 -20
@@ -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`
## Миграция и сопровождение
+9 -20
@@ -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]]