Prompt Server ADR

Table of Contents

1. Статус и назначение документа

Статус: planned capability, runtime implementation на April 16, 2026 отсутствует.

Назначение: зафиксировать архитектурную границу будущего Prompt Server, чтобы по мере развития проекта:

  • не смешать delivery runtime с authoring system;

  • не превратить сервер в удалённый редактор;

  • не свести сервер только к "ещё одному API над storage";

  • зафиксировать его как будущий published prompt registry + deterministic render API.

2. Контекст

В текущем состоянии TextFoundry уже умеет:

  • хранить блоки и композиции с версиями;

  • публиковать их как canonical assets;

  • детерминированно рендерить композиции;

  • использовать GUI и TUI как authoring surfaces;

  • поверх authoring-ядра вызывать optional AI workflows.

При этом у продукта есть естественная следующая потребность:

  • дать внешним или внутренним клиентам runtime-доступ к опубликованным prompt assets без подключения к полному authoring workflow;

  • дать backend- и Python-клиентам способ использовать published prompts без desktop UI;

  • вынести published prompt consumption в отдельную серверную boundary;

  • дать продукту возможность расти из workbench в prompt delivery platform.

Именно здесь возникает Prompt Server как planned capability.

Ключевая опасность на этом этапе: если не зафиксировать границу заранее, сервер может начать:

  • читать draft-состояние;

  • вызывать publish/update методы;

  • наследовать UI-специфичную semantics;

  • становиться удалённым обходным путём в authoring system;

  • или, наоборот, быть спроектирован слишком узко и оказаться лишь thin file API, а не настоящим prompt registry/render layer.

3. Проблема, которую нужно было решить

Нужно было определить, каким должен быть серверный delivery boundary для TextFoundry, чтобы он:

  • отдавал только опубликованные артефакты;

  • сохранял deterministic render contract;

  • адресовал prompt assets как versioned registry entities;

  • не получал полномочий редактора;

  • не ломал текущую модель разделения Draft / Published;

  • не тянул в runtime AI-authoring semantics из GUI;

  • давал устойчивый server contract для downstream clients;

  • и в продуктовой перспективе мог закрывать часть сценариев, для которых сейчас команды используют Langfuse-like prompt storage.

Иначе проект легко скатывается в смешанную систему, где один и тот же runtime одновременно:

  • редактирует assets;

  • рендерит assets;

  • читает незафиксированные изменения;

  • отдаёт их клиентам как будто это production truth.

Нужно было отдельно решить, чем именно должен быть будущий сервер:

  • generic LLM gateway;

  • remote authoring API;

  • thin asset download endpoint;

  • или published prompt registry с deterministic render contract.

4. Рассмотренные варианты

Вариант A. Дать клиентам прямой доступ к authoring engine

Идея: не делать отдельный серверный boundary, а просто открыть текущий engine наружу.

Плюсы:

  • быстро начать;

  • меньше нового кода на первом этапе;

  • можно переиспользовать существующие методы.

Минусы:

  • наружу утекает authoring surface;

  • становится трудно гарантировать published-only access;

  • возрастает риск несанкционированных мутаций;

  • клиенты начинают зависеть от внутренних authoring API.

Вердикт:

  • отклонено.

Вариант B. Построить generic LLM gateway с prompt storage рядом

Идея: сделать сервер прежде всего прокси или orchestration layer для вызова моделей, а prompt storage/render рассматривать как один из дополнительных сценариев.

Плюсы:

  • кажется универсальнее;

  • звучит ближе к "AI platform";

  • можно в одном месте собирать model access и prompts.

Минусы:

  • смещает центр тяжести с prompt assets на live model execution;

  • делает deterministic render вторичным;

  • смешивает prompt registry с provider gateway;

  • усложняет security, latency и compatibility story;

  • уводит продукт в другую категорию, чем исходный asset-centric workbench.

Вердикт:

  • отклонено.

Вариант C. Разрешить серверу видеть и draft, и published данные

Идея: сервер может обслуживать "предпросмотр" и production из одного и того же runtime, выбирая нужный режим флагами.

Плюсы:

  • гибкость;

  • один runtime для разных сценариев.

Минусы:

  • размывается trust boundary;

  • draft accidentally becomes externally visible;

  • операционная модель усложняется сильнее, чем выигрывает;

  • аудит доступа и инцидентов становится хуже.

Вердикт:

  • отклонено.

Вариант D. Сделать Prompt Server отдельным published-only registry and render runtime

Идея: серверный слой читает только published assets, выполняет deterministic resolve и render, и не предоставляет authoring mutation endpoints.

При этом сервер рассматривается не как "хранилище файлов", а как version-aware prompt registry:

  • published blocks and compositions являются адресуемыми сущностями;

  • клиенты могут получать metadata, versions и deterministic render;

  • API становится единым runtime boundary для backend-, Python- и agent-клиентов.

Плюсы:

  • чистая граница между authoring и delivery;

  • проще безопасность и access model;

  • runtime contract понятнее для клиентов;

  • меньше риск, что сервер станет "скрытым редактором";

  • появляется естественная основа для Python clients и service integrations;

  • продукт получает шанс выйти в класс prompt registry/render systems.

Минусы:

  • появляется отдельная эксплуатационная поверхность;

  • нужно продумать authn/authz, compatibility policy и release discipline;

  • часть удобных authoring-возможностей сознательно недоступна через сервер;

  • observability story уровня full Langfuse остаётся вне базового scope.

Вердикт:

  • выбранный вариант.

5. Принятое решение

Принято решение рассматривать Prompt Server как отдельную delivery boundary и future server product layer со следующими базовыми правилами:

  • сервер работает только с Published сущностями;

  • сервер не читает и не отдает Draft-состояние;

  • сервер не предоставляет authoring operations;

  • основной контракт сервера - version-aware resolve/render published assets;

  • сервер выполняет роль published prompt registry;

  • сервер не должен наследовать GUI-specific preview semantics.

Это означает, что в целевой архитектуре продукт будет состоять из трёх разных поверхностей:

  • workbench для authoring;

  • core engine для deterministic assembly;

  • prompt server для published delivery.

Важно: это решение зафиксировано архитектурно уже сейчас, хотя самого runtime пока нет.

6. Детализация принятого решения

6.1. Prompt Server не является authoring surface

Причина: в проекте уже есть явные authoring surfaces:

  • Qt GUI;

  • TUI;

  • локальный engine в составе workbench.

Сервер нужен для доставки и исполнения опубликованных assets, а не для редактирования библиотеки.

Следствие:

  • сервер не должен иметь publish, update, delete, deprecate endpoints;

  • draft editing и AI-assistance остаются вне server boundary.

6.2. Published-only access является основным trust boundary

Причина: в TextFoundry опубликованные сущности и рабочие черновики имеют разный статус доверия.

Published assets:

  • прошли authoring workflow;

  • имеют versioned identity;

  • являются canonical source для доставки.

Draft data:

  • может быть неполным;

  • может содержать непроверенные изменения;

  • не должно утекать в delivery runtime.

Поэтому серверный слой обязан работать только с published storage view.

6.3. Базовый server contract должен оставаться deterministic

Причина: сервер нужен прежде всего как runtime-доставка артефактов, а не как AI-orchestration service.

Это означает:

  • основой сервера должен быть существующий deterministic render path;

  • structural style и parameter validation допустимы;

  • implicit AI rewrite не должен быть частью базового delivery contract.

Иначе клиент перестанет понимать, что именно является стабильным runtime output.

6.4. Сервер должен быть prompt registry, а не только render endpoint

Причина: клиентам нужен не только итоговый текст, но и адресуемый доступ к published prompt assets.

Если оставить сервер только как POST /render, продукт теряет часть своей сильной стороны:

  • blocks and compositions перестают быть first-class runtime entities;

  • version history и identity становятся внутренней деталью;

  • downstream clients не могут явно опираться на published asset model.

Поэтому базовый server layer должен уметь:

  • адресовать published blocks and compositions;

  • показывать доступные версии;

  • возвращать metadata resolved assets;

  • отдельно рендерить composition по стабильному contract.

6.5. Server boundary не должен наследовать UI-preview semantics

Причина: в GUI есть authoring-oriented представления вроде:

  • raw preview;

  • normalized preview;

  • stale-state markers;

  • form-specific editing context.

Это полезно в workbench, но не должно автоматически переноситься в delivery API.

Сервер не должен:

  • отдавать GUI-specific raw snapshot как production contract;

  • зависеть от логики review-mode;

  • повторять stateful authoring semantics клиента.

6.6. Runtime API должен быть уже и строже authoring engine API

Причина: наружу следует выносить только тот контракт, который действительно нужен потребителям published prompt assets.

Минимально разумный набор:

  • inspect published blocks/compositions and versions;

  • resolve published composition/block;

  • render composition с runtime params;

  • валидировать входные параметры;

  • возвращать deterministic result и понятные ошибки.

Не следует по умолчанию выносить:

  • генерацию блоков;

  • normalization;

  • composition rewrite;

  • draft lifecycle operations.

6.7. Python bindings не должны диктовать форму server boundary

Причина: Python integration выглядит полезной и, вероятно, действительно понадобится:

  • для evaluation scripts;

  • для backend use cases;

  • для orchestration frameworks;

  • для research-side integration.

Но это не должно вести к неправильной ставке, где сервер или engine shape определяются только удобством прямого binding слоя.

Правильный порядок:

  • сначала зафиксировать продуктовую и server boundary;

  • потом строить Python client или bindings как интеграционный слой поверх неё.

Следствие:

  • Python важен как клиентская поверхность;

  • но Prompt Server проектируется исходя из prompt delivery model, а не исходя из локального FFI-first мышления.

6.8. Planned status тоже является архитектурным решением

Причина: важно не документировать несуществующую реализацию как уже имеющуюся.

Поэтому в документации прямо фиксируется:

  • capability входит в целевую архитектуру;

  • runtime implementation пока отсутствует;

  • ADR описывает boundary и ограничения, а не текущий работающий сервис.

Это защищает документацию от ложных утверждений и преждевременных обещаний.

7. Последствия решения

Положительные:

  • разделение authoring и delivery остаётся чистым;

  • security model проще и яснее;

  • клиентам проще объяснить, что сервер работает только с canonical published assets;

  • deterministic render contract можно перенести в runtime без UI-зависимостей;

  • TextFoundry получает траекторию в сторону prompt registry/render platform;

  • появляется естественная основа для Python clients и backend consumption.

Компромиссы:

  • сервер не сможет удовлетворить все "удобные" authoring-сценарии;

  • часть пользователей может захотеть больше функций, чем разумно давать через delivery API;

  • появится отдельный operational surface;

  • observability story уровня full Langfuse остаётся за пределами базового server scope.

Отрицательные:

  • нужна отдельная работа по authn/authz, compatibility и release policy;

  • planned capability придётся удерживать в документации синхронно с кодом, пока реализация не появилась;

  • реализация будет больше, чем "тонкий HTTP wrapper".

8. Риски и меры снижения

Риск: сервер превратится в обходной путь вокруг authoring UI

Снижение:

  • published-only model;

  • отсутствие mutation endpoints;

  • отдельный ADR на server boundary.

Риск: delivery runtime начнёт зависеть от draft data

Снижение:

  • repository access только через published policy;

  • fail closed при недоступности published storage;

  • запрет на fallback к draft.

Риск: в сервер перенесут AI-authoring semantics "для удобства"

Снижение:

  • считать generate/normalize/rewrite вне базового server contract;

  • документировать server как deterministic delivery layer.

Риск: клиентская стратегия будет выбрана раньше, чем server model

Снижение:

  • сначала зафиксировать server boundary;

  • Python client и bindings рассматривать как downstream integration.

Риск: документация создаст ложное впечатление, что сервер уже реализован

Снижение:

  • явная пометка planned, not implemented;

  • отсутствие формулировок о runtime implementation в настоящем времени.

9. Что сознательно не покрывается

Данный ADR не фиксирует:

  • конкретный HTTP API shape;

  • модель деплоя и масштабирования;

  • multi-tenant policy в деталях;

  • кэширование и rate limiting;

  • способы аутентификации и авторизации;

  • схему remote observability;

  • окончательное решение по Python SDK или bindings.

Эти вопросы должны быть оформлены позже, когда начнётся реальная реализация сервера.

10. Связанные документы