ADR 0093 — Роль dbre становится двумя скриптами: линтер миграций и отчёт о резервном копировании
- Статус: Принят
- Дата: 2026-08-17
- Контекст: решение владельца продукта предвосхитить часть роли
dbre, объявленной вdocs/fluxo.yml(ADR 0085), не дожидаясь срабатывания триггера ("реальный объём данных") - Пересматривает:
docs/fluxo.yml, блокid: dbre
Контекст
docs/fluxo.yml (ADR 0085) уже объявлял dbre как proposto, поглощённую
dev-lead (ревью миграций) и platform (tuning, когда активируется),
с критерием разделения: "volume real de dados no projeto gerenciado
(hoje o risco é de SCHEMA, não de carga)".
Эта фраза уже содержала ответ, который оставалось исполнить. Из четырёх
целевых результатов роли — parecer-de-migracao, plano-de-capacidade,
backup-restore-testado, tuning — лишь два действительно зависят от
реального объёма данных:
plano-de-capacidadeиtuningтребуют реальной нагрузки, чтобы что-то значить. Имитировать их без неё значило бы выдумать число — тот же класс ошибки, который ADR 0042 уже отвергает для оценки модели, а ADR 0077 отвергает для рейтинга возможностей.parecer-de-migracao— это СТАТИЧЕСКИЙ анализ текста SQL: шаблон риска (DROP COLUMN,ALTER COLUMN ... TYPE,ADD COLUMN ... NOT NULLбезDEFAULT) рискован независимо от того, десять или десять миллионов строк в управляемой базе.backup-restore-testadoуже реален и протестирован СЕГОДНЯ — CronJob резервного копирования работает с Фазы 5, пишет вbackup_runs, а процедура восстановления была действительно ВЫПОЛНЕНА (docs/runbook.md#restore, реальный RTO ~40 с для базы ~108 KB). Не хватало лишь способа ПРОЧИТАТЬ это состояние по требованию, оформленного как отчёт.
Ни один из двух не требует LLM-агента (нет суждения на естественном языке —
это распознавание шаблонов в тексте SQL и чтение таблицы)
и GenServer engine (нет долгоживущего состояния и цикла —
каждое выполнение — точечное чтение, запускаемое человеком или CI). Решением
было трактовать их как то, чем они являются: два механических скрипта того же
рода, что scripts/ci/pr-police.ts и apps/api/scripts/medir-execucao.ts.
Решение
apps/api/scripts/lint-migracao.tsпросматривает ВСЕapps/api/src/db/migrations/*.sql(без--projeto— это анализ репозитория, а не выполнения) и отмечает пять шаблонов риска построчно:DROP TABLE,TRUNCATE,DROP COLUMN,ALTER COLUMN ... TYPE/SET DATA TYPEиADD COLUMN ... NOT NULLбезDEFAULT. Логика ЧИСТАЯ (lintarConteudo, получает имя + текст SQL, возвращает находки), отделённая от адаптера ввода-вывода (lintarDiretorio/principal), та же конструкция, что уpr-police.ts(avaliarPr). Строка-комментарий игнорируется, потому что комментарии этого репозитория цитируют сами шаблоны в прозе, объясняя, почему их ИЗБЕГАЛИ (реальный случай:0042_tough_captain_midlands.sql, строка 3). Завершается с!= 0, если находит хотя бы одно вхождение.apps/api/scripts/relatorio-backup.tsчитаетbackup_runsс ТОЙ ЖЕ логикой, чтоDomainGaugesCollector.collectBackup()(последний УСПЕХ — возраст, размер — и как завершилось ПОСЛЕДНЕЕ выполнение), оформленной как отчёт по требованию — не gauge Prometheus, а точечное чтение для того, кто хочет ответ сейчас. Ссылается на уже протестированную процедуру восстановления вместо её повторного выполнения. Логика классификации (avaliarBackup) чистая, тестируемая с подменённымbackup_runs.- Ни один из двух пока не входит в CI — см. Последствия.
docs/fluxo.yml:dbreпереходит изstatus: propostoвstatus: active.entregaveis_alvo(плоский список) становитсяentregaveis(список объектов соstatus):parecer-de-migracaoиbackup-restore-testadoотмеченыreal, с доказывающим их механизмом;plano-de-capacidadeиtuningсохранены какlacuna, с явной причиной.hoje_absorvido_por/criterio_de_separacaoостаются в блоке, теперь описывая лишь то, что осталось, — правило ОДНОЙ миграции на волну (meta/_journal.json) больше НЕ называется "механизированной версией роли": оно предотвращает КОНФЛИКТ snapshot между параллельными агентами, забота, ортогональная "в этом SQL есть рискованный шаблон", у которой теперь есть собственный механизм.
Последствия
- Линтер просматривает ВЕСЬ репозиторий, а не diff PR. Его запуск
против сегодняшних реальных миграций НАХОДИТ три вхождения в уже
смёрженных и принятых миграциях —
0006_whole_princess_powerful.sql:22и0034_quick_saracen.sql:33(DROP COLUMN),0007_groovy_bullseye.sql:2(ALTER COLUMN ... SET DATA TYPE). Это не дефект для исправления: это уже принятые решения, и их исправление мимоходом стёрло бы свидетельство того, почему они существовали (то же правило CLAUDE.md для находок Z/AD/AE). Именно поэтому скрипт не вошёл как шаг CI: gate, просматривающий весь репозиторий, отклонял бы каждый PR навсегда из-за находок, которые ему не принадлежат. Сделать его настоящим gate требует той же техники, что уpr-police.ts, — ограничить diff относительно базы PR, — оставленной на тот случай, когдаdbreдействительно понадобится БЛОКИРОВАТЬ merge; сегодня это заключение, а не вердикт, и он запускается вручную (pnpm --filter api lint:migracao). - Отчёт о резервном копировании не перезапускает восстановление. Он переиспользует
исключительно чтение, которое уже делает
collectBackup(); сама процедура восстановления уже протестирована и задокументирована (docs/runbook.md#restore). Смешение двух раздуло бы область скрипта до переписывания того, что уже существует и уже работает. - Порог "резервная копия опаздывает" (26 ч) дублирован, а не импортирован, из
оповещения
brabo-backup-atrasado(deploy/k8s/observability/alerts/brabo-alerts.yaml) — YAML Grafana не читается процессом Node скрипта. Два числа могут разойтись, если кто-то изменит одну сторону и забудет другую; это принято сознательно, с той же ценой, которую имел бы любой дублированный порог в коде. plano-de-capacidadeиtuningостаются ПРОБЕЛОМ, объявленным вdocs/fluxo.yml, без срока. Триггером для их выделения остаётся реальный объём данных в УПРАВЛЯЕМОМ проекте — не объёмtoken_usage/session_eventsсамого Brabo, который уже велик, а объём продукта, который строят агенты.