Перейти к основному содержимому

ADR 0061 — Тип сессии — это данные создания, а выполнение остаётся событием

  • Статус: принят
  • Дата: 2026-08-09
  • Предыдущий контекст: ADR 0045 (состояние dev agent выводится из события — то же семейство решений), ADR 0046 (новый default
    • направленный backfill — формат миграции, переиспользованный здесь)

Контекст​

Каждая сессия рождалась одинаковой. Чтобы добраться до Criativo — агента, который ведёт идеацию и является входной дверью производящей цепочки, — нужно было сначала открыть сессию и потом обнаружить кнопку в верхней панели. Пользователь сообщил ровно об этом: "o processo de ter que selecionar o botão acima para iniciar o criativo não ficou claro o suficiente; faça com que exista diferença entre o tipo de sessão apenas consultiva e uma para iniciar de fato o criativo". Вместе с этим пришли две просьбы из той же навигации: возможность назвать сессию, не теряя хештега, по которому на неё ссылаются, и иметь путь назад на дашборд — SessionPage не импортировал ни Link, ни useNavigate, и вход в сессию был тупиком.

Первая просьба несёт архитектурный риск, и дело не в новом поле, а в том, что продукт уже умел отличать выполняющую сессию. Умел через выведение — findActiveExecutionSession ищет сессию active, несущую событие execution.activated, и именно это заставляет повторную активацию попадать в сессию, где dev agents уже находятся, вместо открытия сиротской при каждом клике (находка #11 первого dogfooding). Запись типа в таблицу создаёт второй источник для похожего вопроса. Два источника об одном и том же в итоге расходятся, а расхождение здесь не было бы косметическим: оно решает, куда пишут dev agents.

Был выход ничего не записывать и продолжать выводить всё из журнала. Он не годится, и причина временна́я: намерение существует до любого события — в клике, открывающем сессию, — и это как раз тот момент, когда продукту нужно было спросить. У творческой сессии, которую ещё никто не активировал, нет ни одного события для выведения, и именно её описывает просьба пользователя.

Решение​

Оба источника существуют и отвечают на разные вопросы.

sessions.kind (consultiva | criativa) классифицирует намерение при создании. Он выбирается в теле POST /projects/:projectId/sessions, который до сих пор не принимал никакого тела, и он неизменяем — нет маршрута, который бы его менял. Событие execution.activated продолжает классифицировать состояние выполнения, а findActiveExecutionSession не стал смотреть на kind: творческая сессия, которая никогда не активировала выполнение, не является текущей сессией выполнения.

То, что не даёт им писать друг поверх друга, — одно правило, и оно и есть настоящее решение: execution.activated в сессии consultiva — это ошибка (409), а не тихое преобразование. Позволить событию повысить тип значило бы ровно то, что два источника борются за одну строку. Запрет живёт в воронке — AppendSessionEventUseCase, — а не в ActivateExecutionUseCase: оба пути, записывающие событие (маршрут пользователя и /internal/* engine), проходят через неё, а запрет в use case оставил бы другой открытым. Он выполняется до incrementSeq, чтобы отклонённая попытка не расходовала seq.

Тип обязателен во всех точках создания, включая внутренние: метод репозитория и use case требуют поле. Необязательный параметр заставил бы пять вызывающих молча наследовать default, что является исходным дефектом под другим именем. Четыре внутренних пути (provisionar, adotar, ativar execução, seed) объявляют criativa, потому что следующее, что эти сессии получают, — это execution.activated.

Default колонки — consultiva, тип, который может меньше всего. Он существует не для удобства: он существует, чтобы строка, пришедшая путём, не проходящим через маршрут, не получала права выполнять. Backfill миграции идёт в противоположном направлении и является направленным: в момент её выполнения каждая сессия предшествует различию, а некоторые — это сессии, в которых dev agents работают сейчас; проснувшись consultiva, они отклоняли бы повторную активацию идущего проекта, хотя никто ничего не решал. Это формат ADR 0046, приходящий к тому же выводу тем же аргументом.

Имя — это метка, а не факт. sessions.name необязательно и меняется через PATCH /projects/:projectId/sessions/:sessionId (роль developer, та же, что открывает сессию). Переименование не становится событием: журнал — это то, что сессия прожила, а N переименований вытолкнули бы из хвоста в 200 ровно то, что важно. Метка составная — имя и хештег, — потому что хештег — это то, что вставляют в URL, а имя, выбранное человеком, не уникально; без имени она деградирует до одного хештега. Пустое считается отсутствием, а null в теле — это путь отмены.

Последствия​

Что улучшается. Выбор происходит там, где он делается, с обоими объяснениями на виду, и консультативная сессия перестаёт предлагать то, чего не делает, — кнопка "Iniciar ideação" есть только в творческой. Сессия получает имя и выход. А Disclosure дизайн-системы получил своё первое реальное место вызова: сворачивание "Log de eventos", которое было button с текстовыми −/+, без aria-controls и без именованной области.

Что становится хуже, и это принято. На вопрос "выполняет ли эта сессия?" теперь есть два места для поиска, и никакой комментарий не заменяет этой памяти: кто изменит findActiveExecutionSession, чтобы он смотрел на kind, заставит продукт отправлять dev agents в сессии, которые никто не активировал. Тест, который падает в этом случае, явный и написан, чтобы падать именно по этой причине.

Тип неизменяем, и это будет мешать. Кто открыл консультативную и передумал, открывает другую сессию. Это намеренно: changeKind превратил бы намерение в состояние и разом вернул бы проблему, которую этот ADR существует, чтобы не создавать. Если неудобство окажется реальным, выход — не разблокировать поле, а явное действие "promover", которое копирует контекст в новую сессию и оставляет след того, что было повышение.

Предел имени и никакой уникальности. Имя ограничено 80 символами, потому что метка делит полосу фиксированной ширины с хештегом. Нет unique: две сессии могут называться одинаково, и их различает хештег — требование уникальности было бы просьбой к пользователю администрировать пространство имён, о котором он не просил.

Вне области, объявлено. Творческая сессия не активирует Criativo сама: это по-прежнему клик, теперь только там, где он имеет смысл. Активация по собственной инициативе была бы эффектом при открытии экрана, а продукт так не делает. Вкладки Chat и Criativo, которые FASE 24 построит на kind, тоже сюда не входят.