Превью — это ещё не продукт
Посмотрите демо любого ИИ-конструктора приложений — нашего в том числе — и вы увидите один и тот же сюжет: промпт, лента прогресса, а потом iframe с работающим приложением внутри. Аплодисменты. Iframe настоящий, код настоящий, и самая, казалось бы, сложная часть — ИИ написал полноценное full-stack приложение — действительно произошла.
Но iframe — это превью, а превью почти ничего не обещает. Оно не обещает, что будет на месте завтра. Оно не обещает, что следующая итерация не сотрёт его данные. Оно вообще ничего не обещает второму пользователю, потому что второго пользователя обычно просто нет. Генерация стала простой; демо — это лёгкие 80%. Продукт — это та, другая часть, которая начинается ровно в тот момент, когда незнакомый человек вбивает URL и доверяет вашему приложению строку своих данных.
Этот пост — инвентаризация той самой пропасти. И заодно проектная позиция, на которой держится вся платформа, сформулированная однажды и прямо:
Агенту разрешено ошибаться. Платформе — нет.
Каждый механизм ниже существует ради того, чтобы любой сбой агента — или инфраструктуры под ним — был переживаем в силу системного инварианта, а не особенности поведения модели.
Чего на самом деле требует «продакшен»
Данные, которые переживают следующий деплой
База превью — это черновик; база продакшена — это обещание. В тот момент, когда реальные пользователи записывают строки, «деплой» перестаёт означать заменить всё и начинает означать поменять код, применить миграции, не трогать больше ничего. На этой платформе так устроено структурно: у прода есть собственный таймлайн данных с самого первого релиза, деплои применяют к нему накопившиеся миграции, а перезапись данных прода данными дева — это отдельное, явное действие со снимком. Нет ни одного пути в коде, где это происходило бы как побочный эффект.
Откат, который затрагивает и данные
Релиз, который что-то сломал, не откатывается полностью одним лишь возвратом кода — миграция-то уже отработала. Каждый релиз здесь ставит pre-deploy чекпойнт на таймлайне продакшена, прежде чем что-либо тронуть, так что откат может восстановить код и данные на один и тот же согласованный момент по явным правилам о том, что ему позволено удалять.
Проверка, которую не уговорить
Превью достаточно один раз выглядеть правильно. Продукт должен быть правильным после каждой итерации — включая итерацию номер сорок, сделанную месяцами позже агентом, у которого нет ни единого воспоминания об итерации номер один. Именно поэтому «готово» решают компиляторы, живые контрактные пробы и собственные тесты приложения, а вовсе не самооценка модели. Интересное свойство: контракт — это декларация архитектора, поэтому фича, которую исполнитель тихо пропустил, проваливает проверку, даже если весь код, который он всё-таки написал, в полном порядке.
Секреты, которые никто не вставлял
Превью может подделать креды; продакшен — нет. Каждый секрет здесь — URL баз данных, пароли сервисов, API-ключи — генерируется на этапе провижининга, хранится в Vault и инжектится в namespace в виде Kubernetes Secrets по одному обязательному пути. Агент пишет код против переменных окружения, значений которых он никогда не видит. Утекать в промпт нечему, потому что в промпте этого никогда и не было.
Нулевая стоимость простоя
Платформа, на которой живёт каждая идея выходного дня, работает только если простаивающая идея ничего не стоит. Замороженные контейнеры и Postgres compute, который масштабируется до нуля и просыпается прямо посреди подключения делают «пусть себе крутится, мало ли» поведением по умолчанию вместо ежемесячного счёта. Обратная ситуация — приложение, чьи пользователи не потерпят холодного старта, — это осознанный, оплаченный выбор (keep-warm), а не случайность архитектуры.
Выживание собственной постройки
Самое недооценённое требование продакшена: сама фабрика падает. Сборки длинные; поды вытесняются; процессы получают OOM-kill посреди записи. Сверка состояния относится к «сборка умерла» как к нормальному входному сигналу — каждый прерванный прогон обнаруживается, и каждый кусочек состояния, который он держал, возвращается к согласованной, возобновляемой картине. Платформа, которая не умеет восстанавливать собственную недоделанную работу, рано или поздно оставила бы проект клиента в состоянии, которое не чинится никакой кнопкой.
Почему это проблема платформы, а не модели
У каждого пункта выше одна и та же форма: он должен держаться для каждого проекта, на каждой итерации, независимо от того, что выдаёт модель. Это и есть определение инварианта, а инварианты не живут в промптах. Они живут в namespace'ах, топологиях веток, append-only-журналах, проверочных гейтах и циклах сверки — в тех самых блоках из поста про анатомию.
Модели становятся лучше, и мы подключаем их в тот же день, когда они выходят, — движок относится к моделям как к конфигурации. Что не меняется вместе с моделью, так это вопрос, на который отвечает платформа: что должно оставаться истинным, что бы агент ни сделал? Превью — это то, что сделал агент. Продукт — это всё то, что остаётся истинным вокруг него.
Остальная часть этого блога проходит по этим инвариантам по одной системе за раз — база данных, построенная для агентов, деплой, который не двигает ни байта, кнопка отмены для данных, модель namespace'ов. А галерея показывает результат: по одному реальному приложению в день, с промптом, из которого оно родилось, и с тем, во что обошлась его сборка.