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

ADR 0161 — Экран предлагает только тот режим, который выполняет установка, а у установки через Release нет broker

Статус​

Accepted. Решено сопровождающим 2026-09-18 (AT-085) ответом «оба» на вопрос «установщик включает broker или экран перестаёт предлагать то, что не работает?». Пересматривает предвыбор RN-513 (ADR 0146, пункт 4) и добавляет локальную причину отказа к RN-521. Ни одна из них не редактируется; этот документ ссылается на них. Поставлена только ЭКРАННАЯ половина — половина установщика была измерена и остановлена по причине из раздела «Остановившаяся половина».

Контекст​

Реальная установка v6.1.0, выполненная однострочником 2026-09-14, создала через web проект в mounted. Это был предвыбранный режим: install.sh всегда записывает BRABO_PROJECTS_BASE (согласованная база, RN-531), а при известной базе RN-513 предвыбирает mounted. Что последовало в event log:

  • 6× dev.started → 6× dev.blocked_by_container;
  • 2× container.start_failed с «BROKER_URL não está definida — o broker de container não faz parte desta instalação…».

Никто не работает в этом проекте — навсегда. container и mounted поднимают контейнер только через BROKER (ADR 0144), а без running контейнера ни одна команда dev agent не выполняется (ADR 0143). От него не зависит только runner: контейнер поднимает локальный агент, на машине пользователя (ADR 0137). А страница /containers позволила одобрить два container_start, которые могли только провалиться.

Измерено, и отличается от описания задачи: compose установки не «унаследовал broker под выключенным profile». Сервиса broker не существует в docker/docker-compose.install.yml — его заголовок говорит это в пункте 3, — и отсутствие было решено письменно в решении 7 ADR 0150, который также объявил его «в выводе установщика». Дефект не в том, что установщик скрывает отсутствие: дело в том, что ЭКРАН не знает о нём и предлагает — даже предвыбирает — режим, который отсутствие делает бесполезным.

Остановившаяся половина: установщик не может получить образ broker​

У решения сопровождающего была часть (a): install.sh спрашивает, включать ли broker, с риском, высказанным текстом (сокет Docker, смонтированный в сервис, эквивалентен root на хосте). Прежде чем писать вопрос, было измерено, может ли установка иметь образ, который поднял бы ответ «да». Не может:

  • у docker-bake.hcl четыре цели (api, engine, web, backup); scripts/ci/images-manifest.ts не знает broker; а images.json Release v6.1.0 перечисляет ровно эти четыре;
  • docker manifest inspect ghcr.io/daneiel/brabo-broker:6.1.0 отвечает denied (репозитория не существует), тогда как ТА ЖЕ анонимная команда для ghcr.io/daneiel/brabo-api:6.1.0 разрешается — дело не в отсутствии учётных данных;
  • assets Release v6.1.0 не включают ни docker/broker/Dockerfile.prod, ни код apps/broker/packages/docker-port, поэтому установке через однострочник, работающей в папке без checkout (ADR 0160), даже нечего собирать.

Вопрос, чьё «да» не имеет образа для подъёма, хуже, чем никакого: человек соглашается с риском сокета и получает pull access denied. Только --source=local (чистый checkout, на теге) мог бы собрать broker — и даже там в compose установки нет сервиса. Исправление — то, которое ADR 0150 уже назвал небольшим и вне своего охвата: опубликовать broker как пятый образ (одна цель в bake, один id в манифесте, ещё одна подпись), и ТОЛЬКО ПОТОМ вопрос установщика. Это остаётся для отдельного направления, и именно оно снова откроет эту половину. install.sh этим ADR не затронут.

Решение​

1. api сообщает, есть ли у установки broker, в двух маршрутах, которые экран уже читает​

brokerConfigurado: boolean входит в два существующих ответа и ни в один новый маршрут:

  • GET workspaces/:workspaceId/projects-base — вопрос мастера создания уже был «какой режим эта УСТАНОВКА способна выполнить?», и база была лишь его половиной. Тот же минимум (maintainer), тот же вызывающий, тот же момент;
  • GET workspaces/:workspaceId/containers — по СТРОКЕ, с одним значением во всех. Ответ — список, и замена его конвертом сломала бы контракт ради поля, принадлежащего установке.

Источник — ContainerBrokerPort.configurado(), ТОТ ЖЕ, который решает, спрашивает ли чтение наблюдаемого состояния broker или объявляет отсутствие, — повторное чтение BROKER_URL было бы вторым источником, который однажды разойдётся. Поле говорит, что переменная СУЩЕСТВУЕТ, никогда — что broker ОТВЕЧАЕТ: об этом по-прежнему знает naoObservado (RN-486).

2. Мастер не предвыбирает mounted без broker и предлагает runner​

Три состояния, которые не сливаются:

  • broker подтверждён (true): поведение RN-513 не тронуто — при базе mounted предвыбран;
  • отсутствие подтверждено (false): container и mounted остаются НА ЭКРАНЕ (убрать карточку значило бы скрыть информацию — линейка «убирается элемент управления, никогда информация» из RN-102), но инертны, причина сказана ОДИН раз текстом под ними, а runner — предвыбранный. Человеческий выбор, сделанный до прихода ответа, в режиме, который ответ делает невыполнимым, падает на runner — то же правило, которое уже сбрасывало mounted, когда исчезала база;
  • не знаю (загрузка, сбойный запрос, отсутствующее поле): ни «есть», ни «нет». Не предвыбирает mounted — пересмотр RN-513, — но и не блокирует карточки и не утверждает текстом отсутствие, которого никто не подтвердил: остаётся выбранным container, как раньше.

3. /containers отказывает в подъёме до клика, с собственной причиной​

decidirSubida получает причину sem_broker_na_instalacao для container и mounted, когда brokerConfigurado !== true, — «не знаю» не становится «есть». Она идёт сразу после ja_esta_de_pe и ДО sem_imagem_decidida: в установке без того, кто поднимет контейнер, отправлять решать образ значило бы указывать не на ту дверь. runner в неё никогда не попадает. Ветвление — то же по НАЗНАЧЕНИЮ, что у acaoDeSubidaDoModo (от broker зависит тот, кто предлагает container_start), читаемое с другой стороны через usaBroker, а не вторая линейка.

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

  • В установке через Release режим, работающий от начала до конца, становится предлагаемым, а неработающий начинает говорить почему, прежде чем кто-то его выберет. Цена: runner требует работающего локального агента и Docker на машине пользователя — что установка через однострочник уже даёт (ADR 0155).
  • В compose РАЗРАБОТКИ broker поднимается по умолчанию (RN-512), но BROKER_URL остаётся пустой, пока кто-нибудь не пропишет её в .env (docker/docker-compose.yml, .env.example). Без неё мастер у того, кто разрабатывает, начинает показывать предупреждение — и это ПРАВИЛЬНО: без BROKER_URL api никогда не вызывает работающий broker, и container_start провалился бы так же.
  • RN-512 НЕ меняется: broker остаётся под profiles: ["container-broker"] в production compose, вне compose установки, и ни один из пяти слоёв сдерживания не затронут. Меняется то, что ЭКРАН перестаёт предполагать обратное.

Вне охвата, объявлено:

  • половина установщика (раздел выше) — зависит от публикации образа;
  • преобразование режима (ExecutionModeSection, ADR 0111) по-прежнему может преобразовывать в container/mounted в установке без broker; оно читает тот же маршрут и поле под рукой, но это другой экран, с другой линейкой предложения (RN-559);
  • остановка и удаление (container_stop/container_remove) не получили отказа: без broker нет контейнера container/mounted, зарегистрированного как работающий, чтобы его останавливать, и этот случай не измерялся;
  • Infra Lead не знает об отсутствующем broker — он отказывает по РЕЖИМУ (RN-566), а обогащение его контекста установкой — самое дорогое направление, которое RN-566 уже объявляет;
  • подсказка о параллелизации, игнорирующая агента, заблокированного контейнером;
  • завершающая фраза install.sh говорит, что без broker «projeto em modo Pasta montada não sobe container», и опускает режим container, который тоже не поднимается, — измеренная смежность, не исправленная здесь, потому что установщик принадлежит другому параллельному направлению.