> For the complete documentation index, see [llms.txt](https://docs.onerpa.ru/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.onerpa.ru/mcp-servery-1c/sistema-pluginov/pravila-hosta.md).

# Правила хоста

Хост — общая половина системы плагинов: обнаружение и загрузка файлов, передача аргументов, семантика возврата, изоляция сбоев, порядок, перезагрузка, эпохи, интроспекция, версии и dry-run. Это общий контракт семейства; реализации встроены в HelpSearchServer, SSLSearchServer, SyntaxCheckServer, TemplatesSearchServer, Graph Metadata Search и 1CCodeChecker. Различается только набор хуков — он в [справочнике по серверам](/mcp-servery-1c/sistema-pluginov/spravochnik-hukov.md).

## Загрузка файла

**Плагин — один файл, без церемоний.** Загрузка не требует базового класса, декоратора, регистрации, записи в манифесте и импорта. Файл, не объявивший ни хука, ни таблицы, загружается успешно и ничего не меняет.

**Имена хуков — закрытый набор.** Разрешены ровно те имена, которые объявил продукт. Имя верхнего уровня, похожее на хук, но отсутствующее в наборе, отклоняет загрузку **всего файла**, называя нарушителя и перечисляя допустимые имена. Сервер при этом стартует с остальными плагинами. Функция, чьё имя не похоже на имя хука, — ваш собственный помощник, её не трогают.

**Файлы читаются как UTF-8**, с BOM или без. Другая кодировка отклоняет файл с указанием имени и правила, а не угадывается.

**Порядок детерминирован и объявлен.** Файлы выполняются в отсортированном порядке имён, каждый хук применяется конвейером: выход одного файла — вход следующего. Действующий порядок показывает интроспекция.

## Аргументы и возврат

**Аргументы передаются по объявленным именам.** Хук получает ровно те аргументы, которые названы в его сигнатуре, выбранные по имени из предложенных для этого хука. `def on_result(result):` и `def on_result(result, request):` — оба корректны. Имя параметра, которое хост не может предоставить, отклоняет файл **при загрузке**, а не при первом вызове.

**Возврат — единственный канал.** Хук получает *копию* payload, применяется только возвращённое значение. Возврат `None` (или выход из функции без `return`) оставляет payload неизменным — это нормальный способ сказать «не мой случай». Изменение аргумента без возврата не даёт никакого эффекта.

**В хуки передаются данные, а не живые объекты.** Каждое значение — примитив, список или словарь. Из аргумента хука недостижимы ни хранилище, ни модель, ни соединение, ни поколение индекса, ни объект сервера.

## Изоляция сбоев

**Упавший плагин никогда не роняет сервер.** Исключение перехватывается, пишется в журнал с файлом, именем хука и трассировкой, и не распространяется дальше. Сервер продолжает так, как если бы хук вернул `None`.

* Упавший **call-scoped** хук отключается до следующей перезагрузки и показывается как отключённый со своей ошибкой и счётчиком сбоев.
* Упавший **derived-state** хук не оставляет отдельную единицу наполовину преобразованной: по умолчанию она берётся неизменённой, сбой считается и попадает в сводку. В строгом режиме (`PLUGIN_STRICT_DERIVED_STATE`, у Graph — `GRAPH_PLUGIN_STRICT_BUILD`) сборка падает целиком. Сохраняется ли прежнее поколение в обслуживании, зависит от механизма перестроения конкретного сервера — см. предупреждение ниже.
* Файл, который не загрузился вообще, не мешает старту: сервер поднимается и называет файл и причину.

{% hint style="warning" %}
Строгий режим — инструмент отладки. TemplatesSearchServer строит новое поколение рядом с обслуживающим, проверяет его и только затем атомарно переключает указатель; прежнее поколение остаётся rollback target. У SSLSearchServer это нельзя обобщать на любую инвалидизацию: обычное изменение plugin/normalization/chunking/extraction проходит через `recreate_collection`, а соседние поколения гарантируются отдельной операторской миграцией `MIGRATE_VECTOR_STORE`. Перед изменением derived-state хука конкретного продукта проверьте его раздел индексации.
{% endhint %}

## Границы производного состояния

**Derived-state хуки участвуют в отпечатке годности.** Там, где сервер решает, актуально ли сохранённое производное состояние, сравнивая отпечаток породивших его правил, исходник каждого derived-state хука входит в этот отпечаток. Правка такого файла делает сохранённое состояние устаревшим: следующий старт пересобирает его. Серверы с поколенческой схемой продолжают обслуживать прежнее поколение до проверки и promotion; для SSL обычная инвалидизация и операторская миграция имеют разную семантику, описанную выше. Манифест состояния перечисляет плагины, которые его сформировали, с отпечатком исходника каждого.

**Call-scoped хуки не инвалидируют производное состояние.** Их правка не входит ни в один отпечаток и не вызывает пересборки.

**Токены продолжения несут эпоху плагинов.** Там, где сервер выдаёт курсор для продолжения ответа, курсор привязан к действовавшему набору плагинов так же, как к поколению индекса и запросу. Курсор, предъявленный в другой эпохе, отклоняется как принадлежащий устаревшему состоянию (например, кодом `stale_cursor`), и это означает «искать заново», а не «продолжать». Пока эпоха держится, страницы не дублируются и ничего не теряется.

## Контракт ответа

Опубликованный контракт ответа применяется **после** хуков:

* объявленные пределы (`max_items`, `max_chars`, `top_k`, лимиты бюджета) измеряются после последнего хука;
* счётчики в ответе пересчитываются из фактически возвращённого — счёт никогда не принимается на веру;
* payload проверяется по схеме ответа продукта.

Результат плагина, нарушающий контракт, **отбрасывается в пользу неизменённого**, а нарушение пишется в журнал с именем файла и проблемной записью. Практическое следствие: хук может переупорядочивать и отбрасывать, но не может добавить запись, которой сервер не производил, продублировать её или расширить ответ за опубликованные границы.

**Изменённый запрос виден вызывающей стороне.** Если хук поменял аргументы вызова, ответ сообщает и то, что прислал клиент, и то, что было использовано, и файл плагина, который это сделал.

**Классификация приватности распространяется на плагины.** Поля, которые продукт считает чувствительными, остаются такими и внутри плагина, включая значения, произведённые плагином. Секреты не приходят в `on_startup` в открытом виде: часть серверов подменяет их на `<redacted>` / `***redacted***`, Graph Metadata Search передаёт булево «задано или нет».

## Версии и совместимость

| Константа в `plugin_api.py` | Что версионирует                                                                                                                     |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `HOST_CONTRACT_VERSION`     | Общий контракт хоста — правила этой страницы. Одинаков во всех серверах семейства                                                    |
| `PRODUCT`                   | Идентификатор продукта: `1c-help`, `ssl-search`, `bsl-syntax-check`, `template-search`, `graph-metadata-search`, `onec-code-checker` |
| `HOOKS_VERSION`             | Набор хуков и таблиц конкретного продукта; поднимается, когда payload меняет форму так, что плагин этого не переживёт                |

Плагин может закрепить любую из трёх через `REQUIRES`. Это необязательно, и единственная причина так делать — быть отклонённым рано и внятно:

```python
REQUIRES = {"host": 1, "product": "graph-metadata-search", "hooks": 1}
```

Плагин, написанный для другого продукта семейства, отклоняется с указанием обоих продуктов, а не сообщением о пяти неизвестных именах функций. Плагин, требующий версию набора хуков, которую продукт больше не предлагает, отклоняется с указанием обеих версий.

## Интроспекция и перезагрузка

**Перезагрузка без перезапуска.** Каталог перечитывается целиком, действующие хуки заменяются атомарно, начинается новая эпоха плагинов. Неудачная перезагрузка не меняет ничего: прежний набор остаётся в силе, ответ называет файл и причину. Derived-state хуки вступают в силу со следующего построения, а не задним числом.

**Загруженные плагины интроспектируемы.** Состояние подсистемы показывает: каждый файл, объявленные им хуки и таблицы, классификацию каждого хука, включён он или отключён, ошибку, которая его отключила, счётчик сбоев, накопленное в каждом хуке время, порядок файлов и текущую эпоху.

**Бюджет времени хука** — продуктовое дополнение: Graph Metadata Search ограничивает один hook значением `GRAPH_PLUGIN_HOOK_TIMEOUT_SECONDS` (`0` отключает контроль), CodeMetadataSearchServer — значением `PLUGIN_HOOK_TIMEOUT_SECONDS` (по умолчанию `5.0`; превысивший бюджет хук считается упавшим и call-scoped отключается до следующей перезагрузки каталога). Остальные серверы бюджета не навязывают, но накопленное время каждого хука показывают.

## Упаковка и dry-run

**`plugin_api.py` поставляется читаемым исходником** в runtime-образе и является полным справочником: форма payload и рабочий пример для каждого хука и таблицы продукта. Он не импортирует ничего вне стандартной библиотеки. Скомпилированные модули собраны без встроенных docstring — описания реализации в бинарниках нет.

**Каталог плагинов самоописывающийся.** В нём лежат инструкция для агента (`AGENTS.md`) и закомментированный пример (`example.py`), объявляющий все хуки и таблицы продукта.

**Плагин можно попробовать без данных и без сборки.** Каждый образ содержит команду, которая прогоняет хуки файла на зашитых в образ фикстурах и печатает payload до и после — без смонтированных данных, без построенного состояния и без запущенного сервера. Ошибку загрузки dry-run сообщает теми же словами, что и сервер. Команды по серверам — в [Как написать плагин](/mcp-servery-1c/sistema-pluginov/kak-napisat-plugin.md).

## Чего система не обещает

Хук — это Python внутри процесса сервера, поэтому плагин может прочитать всё, что может процесс. Компиляция модулей повышает стоимость чтения реализации, но не останавливает плагин. Система не защищает реализацию от автора плагина — она гарантирует, что плагин не испортит производное состояние, не нарушит опубликованный контракт ответа и не уронит сервер.
