ADR 0054 — Gates как декларативный реестр
Статус
Предложен
Контекст
Gates потока (QA, SecOps, ручное продвижение story, план принятия, ручной merge, конвейер proposed_actions) существуют и были проверены реальным выполнением (ADR 0020, 0044–0046), но они неявные: разбросаны по prompts агентов, коду engine, чистым правилам api и соглашениям CLAUDE.md.
Урок Фазы 10/13 — метрика извлекается скриптом, никогда не записывается вручную — нельзя применить к gate, который нельзя перечислить.
ADR 0048 решил нижнюю половину
этой проблемы: поместил решение о действии в event log с реальным актором и
заставил proposed_action.created нести status — то, что отличает "пользователь
кликнул" от "политика решила сама". Без этого измерение прохождения
gate было бы подсчётом несуществующих событий. Этот ADR — верхняя половина: сказать,
КАКИЕ gates существуют, чтобы то, что 0048 сделал наблюдаемым, стало и
перечислимым.
Решение
Декларативный реестр в docs/gates.yml, версионируемый, со схемой: id, поток,
владелец (агент/область/пользователь), входы, результат, verificacao (script |
humana), severidade (block | warn), aprovacao_humana, status (active |
planned).
Правила:
- Gate без скрипта проверки рождается
warn; повышение доblockтребует, чтобы скрипт существовал и измерил прохождения (та же философия, что staged rollout документации). aprovacao_humana: trueнеизменяем продуктовой конфигурацией в gates, которые конституция объявляет ручными (merge в защищённую, продвижение story в ручном режиме, план принятия, решение о действии), — гарантировано тестом, как ручной merge уже гарантирован.status: plannedобъявляет gate будущей роли, не активируя его.
evidencia: где живёт доказательство
Поле, которого исходная spec не предусматривала и которое первое чтение кода сделало обязательным: не у каждого gate может быть доказательство в event log.
merge-protegidaне выдаёт собственного события. Это предел, применяемый последним поверх уже вычисленного вердикта (decide.ts), который понижаетauto_approveдоrequire_approval; исход проявляется как ожидающийproposed_action.created, неотличимый от любой другой ожидающей позиции. Замок гарантирует тест.backmergeживёт полностью вне приложения: это обязательная проверка PR, с состоянием, версионируемым в.release/gate.jsonнаmain.
Без этого поля правило "gate active + block без свидетельства в журнале проваливается"
сделало бы оба красными навсегда — а они самые жёсткие замки
продукта. Поэтому каждый gate объявляет evidencia: event_log | teste | ci вместе с
локатором (типы событий и фильтр payload, путь spec или
workflow). Скрипт требует event log только от тех, кто его объявляет; для teste и ci
он подтверждает, что цель существует.
Альтернатива — понизить оба до warn — отвергнута, потому что лжёт о
реальной серьёзности, а покончить именно с этим и существует реестр.
Gates репозитория входят вместе
backmerge, pr-no-lugar-certo, aprovacoes-da-escada и promocao-conferida
(ADR 0030) являются gates по тому же критерию, что и остальные: у них есть владелец, вход,
результат, механическая проверка и серьёзность. И именно они чаще всего отклоняют PR в
повседневной работе. Включить только backmerge было бы произвольно — это одно и то же семейство
(чистый скрипт + workflow + spec).
aprovacoes-da-escada — единственный gate CI с aprovacao_humana: true: то, что
он измеряет, — люди, одобряющие по ролям. Реестр gates, опустивший бы
именно gate, считающий человеческие подписи, опустил бы самый очевидный.
Предел: реестр — индекс, а не политика. Над ветками по-прежнему властвует
docs/explanation/branching-policy.md; entrada и entregavel
— одна фраза, а onde указывает на скрипт. YAML никогда не воспроизводит правило —
если бы воспроизводил, стал бы вторым источником истины, избегать которого он существует.
Фильтр важен так же, как тип
qa-verificada и secops-segura — не два типа событий: оба
записывают pr.gate_changed, различаемые по payload.gate. И тот же тип
записывается при ОТКРЫТИИ gate, без veredito. Реестр, хранящий лишь
имя типа, считал бы открытие прохождением и измерял бы вдвое больше
случившегося. Поэтому evidencia несёт фильтр payload, а не только тип.
По той же причине суждение о PR инфраструктуры — это два gate
(infra-qa-verificada и infra-secops-segura): infra.gate_changed тоже
различает по payload.gate, и их объединение сообщало бы прохождение одного так, будто
это прохождение другого. Тест утверждает, что ни одна пара (event_types + filtro) не повторяется в
реестре, — именно эта уникальность делает измерение осмысленным.
Рассмотренные альтернативы
- Оставить неявным в prompts: отвергнуто — неизмеримо.
- Таблица в базе вместо YAML: пока отвергнуто — gates меняются ревьюируемым PR,
а не в runtime; следует прецеденту
.docmap.ymlи версионируемых rulesets (ADR 0030). Миграция в базу останется тривиальной с loader как границей.
Последствия
- Режим community в approval-ladder (backlog) становится изменением значений в
aprovacao_humana, а не переписыванием агентов. - Dev Lead (ADR 0053) и Platform/SRE получают контракт входа: когда они будут
реализованы, их gate уже специфицирован как
planned. - Реестр рождается, зная о gates, которые исходный список забыл, —
суждение QA/SecOps о PR инфраструктуры, у которого собственный путь
(
infra.gate_changed), потому что за ним нет task backlog. Перечисление находит то, что было вне учёта: это первый дивиденд реестра, ещё до того, как он что-либо измерит. - И находит пробел:
promocao-conferida— обязательная проверка без собственного spec, в отличие отpr-policeиapproval-ladder. Её свидетельство указывает на скрипт вместо теста, с записанным там пробелом. Он идёт в триаж 13c как пункт, а не исправляется здесь — фаза объявляет и измеряет, а не чинит.