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

ADR 0087 — UX Designer входит как разговорный агент

  • Статус: Принят
  • Дата: 2026-08-17
  • Контекст: явное решение владельца продукта, опережающее триггер разделения, который docs/fluxo.yml уже объявлял для этой роли

Контекст​

docs/fluxo.yml (ADR 0085) уже фиксировал ux-designer как роль целевой модели команды, со status: proposto, hoje_absorvido_por: criativo (discovery) + design/ (design system como dado) и объективным критерием разделения:

Когда у УПРАВЛЯЕМОГО проекта будет собственный интерфейс для проектирования — сегодня design system является статическим входом. Разделяется, когда прототип станет повторяющимся артефактом.

Этот триггер не сработал. Brabo пока не строит в продакшене проекты с действительно собственным UI; design system (design/tokens.css, design/COMPONENTS.md) остаётся статическим входом, к которому обращаются Arquiteto и dev agents, а не живым проектом, нуждающимся в повторяющихся решениях UX.

Владелец продукта всё же решил построить агента сейчас — СОЗНАТЕЛЬНОЕ решение опередить, зафиксированное здесь, чтобы его не путали с ошибкой прочтения критерия. История того, что вбирала роль, остаётся в docs/fluxo.yml, как комментарий: прежний текст не стирается, лишь перестаёт быть действующим состоянием.

Решение​

UX Designer входит как пятый разговорный агент — Criativo, PO, Arquiteto, Dev Lead и теперь UX Designer, — ОДИНОЧНЫЙ (без области, без субагентов), зеркаля дизайн Engine.Agents.DevLeadServer.

Детали​

  1. Engine.Agents.UxDesignerServer (apps/engine/lib/engine/agents/ux_designer_server.ex) — GenServer на сессию, регидрация из event log, streaming, ограниченный цикл tool use с потолком 14 (того же калибра, что Arquiteto/Dev Lead: агент РАССУЖДЕНИЯ, а не лёгкого разговора, как Criativo/PO, у которых потолок 12). Активируется handoff accepted, адресованным "ux-designer", — механизм ОБЩИЙ (ActivateAgentUseCase/canActivateAgent в api уже принимают любого агента с принятым handoff; там не изменилось ни строки), — а kickoff выполняется только при СВЕЖЕМ старте (перезапуск не регенерирует прототип).
  2. Kickoff читает artifact.product_brief, ту же «бизнес-потребность», которую производит Criativo, — без нового артефакта, тот же образец чтения, что уже делает ArquitetoServer.build_kickoff/1.
  3. Система дизайна ОПИСАНА в идентичности (Engine.Harness.Agents, запись "ux-designer"), статический текст с токенами из design/tokens.css (семантические цвета, типографика, отступы, радиус) и соглашениями из design/COMPONENTS.md (варианты кнопок, стиль значков). У разговорных агентов НЕТ инструмента чтения файлов репозитория — переиспользовать было нечего, — а идентичность — единственный слой промпта, присутствующий в КАЖДОМ ходе, а не только в kickoff.
  4. propose_prototype (Engine.Agents.UxDesignerTools, apps/engine/lib/engine/agents/ux_designer_tools.ex) — ЕДИНСТВЕННЫЙ инструмент: personas, jornadas, prototipo (telas + anotacoes) и resumo. Записывает artifact.prototipo_navegavel и предлагает handoff "po" и "dev-lead" по ТОМУ ЖЕ артефакту.
  5. Engine.Agents.UxDesignerSupervisor — точная копия образца DevLeadSupervisor; зарегистрирован в Engine.Application рядом с ним. EngineWeb.AgentCommandController получил три клаузы (start, message, via_for), которые уже есть у четырёх других разговорных.
  6. apps/web/src/lib/agents.ts: 'ux-designer' в AgentKey, запись с color: 'var(--accent)'. Ни один из пяти семантических токенов design/tokens.css не был свободен от другого агента — --accent переиспользован меньше всех (только Arquiteto), а правило design system запрещает новый hex. icon: PencilIcon — единственный значок каталога, семантически связанный с дизайном/редактированием и ещё не имеющий владельца.

artifact.prototipo_navegavel: без таблицы и без выделенного use case в api​

Это решение, которому понадобилось исследование до написания кода, потому что два прецедента «артефакта без таблицы» (artifact.project_image, ADR 0065; artifact.c4_diagram, RN-149) используют ДРУГОЙ путь, чем artifact.business_rule/artifact.product_brief, и два пути кажутся взаимозаменяемыми, пока не посмотришь, ПОЧЕМУ.

У choose_project_image/create_c4_diagram есть СОБСТВЕННЫЙ use case в api (DecidirImagemDoProjetoUseCase, CreateC4DiagramUseCase), потому что у каждого есть структурная причина:

  • уровень Container у C4 ВЫВОДИТСЯ из действующего module_map — содержимое, которое модель не может перепечатать, не рискуя разойтись с реальным источником;
  • у решения об образе есть доменный отказ (явный тег, потолок ресурсов), который более одного потребителя должны соблюдать одинаково.

У propose_prototype нет ни одной из двух. Персоны, путешествия, экраны и аннотации — САМОДОСТАТОЧНОЕ содержимое — пишет только сам UX Designer, читает обратно только он, ничто не выводится из другого артефакта, и нет второго общего доменного правила, ждущего переиспользования. Поэтому он идёт путём business_rule/product_brief: проверка ФОРМЫ в ENGINE (Engine.Harness.ArtifactSchemas, тип "prototipo_navegavel") и запись по ОБЩЕМУ пути, который api уже выставляет для любого session_event (EngineApiClient.append_event_returning/3, без нового маршрута). Открытие CreatePrototipoUseCase повторило бы форму CreateC4DiagramUseCase без обеих причин, которые её там оправдывают, — сложность без довода.

Один артефакт, два handoff — никогда два артефакта​

docs/fluxo.yml перечисляет два выхода роли: prototipo (для PO) и spec-visual (для Dev Lead). Очевидным соблазном был второй вызов инструмента или второй артефакт для «spec-visual». Решение — НЕ дублировать: прототип (экраны + аннотации поведения) И ЕСТЬ визуальная спецификация — PO читает resumo/prototipo, чтобы спроектировать backlog, Dev Lead читает ТЕ ЖЕ telas/anotacoes как эталон реализации. Две копии одного содержимого разошлись бы при первом пересмотре, сделанном с одной стороны, — тот же довод, что уже действует для C4, не перепечатывающего module_map.

Ход останавливается на первом успехе — урок Dev Lead, без его приостановки​

UxDesignerServer переиспользует ту половину дизайна DevLeadServer, которая выживает без ADR 0086: УСПЕШНЫЙ propose_prototype завершает ход, чтобы модель не предложила снова и не произвела два прототипа с одним итогом (реальный дефект, мотивировавший эту охрану у Dev Lead). ДРУГАЯ половина ADR 0086 — приостановка в ожидании proposed_action — здесь не применяется: у propose_prototype нет никакого внешнего эффекта (это содержимое, а не действие; нет параллели «расходу, за который взимает потолок RN-083»), поэтому он рождается простым событием, как рождался execution.plan_proposed до 0086.

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

За

  • Роль входит активной с ТЕМ ЖЕ строгим подходом, что у остальных четырёх разговорных, — потолок итераций, регидрация, озвученный отказ с источником (RN-059/163), — а не растёт как ad-hoc функциональность внутри Criativo.
  • Ноль новых маршрутов в api: механизма активации по handoff, общего append_event_returning и общего create_handoff уже хватало. Единственная новая поверхность в api — поле uxDesignerActive в составе (RN-287), симметричное тому, что уже делал infraActive.
  • docs/fluxo.yml перестаёт описывать роль, которой не было в коде, — status: active, реальные входы/выходы, без суффикса _alvo.

Против

  • Триггер опережён, по явному решению. Исходный критерий разделения (собственный интерфейс в управляемом проекте) сам по себе не выдерживает как обоснование — принят, потому что владелец продукта попросил, понимая это.
  • teste-de-usabilidade остаётся вне досягаемости. Требует реального человека, тестирующего интерфейс; ни один агент его не заменит. Не имитируется.
  • metricas-de-uso остаётся объявленным пробелом. Зависит от роли analytics (ПРОДУКТОВАЯ метрика), которую docs/fluxo.yml держит proposto, — без неё у соответствующего входа UX Designer нет реального источника.
  • Карточка дашборда и панель команды вычисляют uxDesignerActive раздельно (RN-090) — то же дублирование, что уже было у infraActive, принятое по той же причине: api отвечает ФАКТАМИ, представление — дело web.

Рассмотренные альтернативы​

Ждать срабатывания триггера разделения. Это было буквальное прочтение docs/fluxo.yml до этого изменения. Отвергнуто явным решением владельца продукта — см. Контекст.

artifact.prototipo_navegavel с выделенным use case в api, по образцу CreateC4DiagramUseCase. Отвергнуто: ни одна из двух причин, оправдывающих тот образец (выводимое содержимое, общий доменный отказ), здесь не применяется. Копирование формы без причины — сложность, которую следующему читающему код пришлось бы оправдывать самому.

Второй вызов инструмента/артефакт для «spec-visual». Отвергнуто: прототип уже является визуальной спецификацией. Две копии одного содержимого (одна для PO, другая для Dev Lead) рисковали бы разойтись при первом пересмотре, сделанном с одной стороны.

UX Designer как субагент новой области. Отвергнуто: ничто в роли не требует внутреннего делегирования или нескольких параллельных исполнителей — это рассуждение ОДНОГО человека на сессию, как уже Criativo/PO/Arquiteto/Dev Lead.

Ссылки​

  • docs/fluxo.yml — блок id: ux-designer, исходный триггер разделения
  • ADR 0085 — docs/fluxo.yml как декларативный реестр ролей
  • ADR 0053 — создаёт Dev Lead, шаблон, который повторяет этот ADR
  • ADR 0086 — почему propose_prototype НЕ приостанавливается (нет внешнего эффекта)
  • ADR 0065, RN-149 — образец артефакта без таблицы, которому следует artifact.prototipo_navegavel, и почему ему НЕ нужен выделенный use case, который есть у двух других
  • apps/engine/lib/engine/agents/ux_designer_server.ex, ux_designer_tools.ex, ux_designer_supervisor.ex
  • apps/engine/lib/engine/harness/agents.ex, artifact_schemas.ex
  • apps/web/src/lib/agents.ts, agent-status.ts