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.jsonRelease 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_URLapi никогда не вызывает работающий 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, который тоже не поднимается, — измеренная смежность, не исправленная здесь, потому что установщик принадлежит другому параллельному направлению.