ADR 0090 — QA-стратегия и AppSec как второй МОМЕНТ, а не новый агент
- Статус: Принят
- Дата: 2026-08-17
- Контекст: сознательное решение владельца продукта опередить триггер —
не «естественный триггер», который предусматривал
docs/fluxo.yml(hoje_absorvido_por+criterio_de_separacao), а сама работа по построению того, что включает gate - Активирует: gate
implementavel(docs/gates.yml,status: plannedначиная с ФАЗЫ 14d) - Пересматривает часть: ADR 0053
(который объявил gate
implementavelкакplanned) - Прямой прецедент: ADR 0038 (область
QA — Lead + подспециализации), ADR 0085
(
docs/fluxo.yml, который уже предусматривал обе роли какproposto)
Контекст
docs/fluxo.yml (ADR 0085) фиксирует две роли целевой модели как proposto,
каждую с критерием разделения, записанным в самом файле:
qa-estrategia — hoje_absorvido_por: area-qa (которая действует только ПОСЛЕ, на PR). criterio_de_separacao: Когда gate implementavel включится — план тестирования является его входом. Может быть сам qa-lead во втором МОМЕНТЕ, не обязательно новый агент: разделение — по результату.
appsec — hoje_absorvido_por: secops (который действует только на PR). criterio_de_separacao: Тот же образец, что у QA: два МОМЕНТА, а не два агента пока. Threat model в проектировании включается, когда появится gate implementavel. Отдельный агент только с реальным продакшеном.
Объявленный триггер («когда gate implementavel включится») никогда не
срабатывал органически — ничему в продукте он ещё не был нужен. Владелец
продукта решил опередить: триггер есть сама работа по построению
механизма, включающего gate, а не симптом использования, ждущий своего часа.
Эта поставка покрывает qa-estrategia полностью. appsec остаётся
proposto, в ТОЙ ЖЕ доктрине (два момента, а не два агента), с реализацией в
отдельном направлении — образец и решение одни, описаны здесь; код
appsec/threat-model остаётся на тот момент, когда это направление
запустится.
Решение
QA-стратегия — это qa-lead во втором МОМЕНТЕ — тот же процесс, отдельный
результат. Никакого нового агента, никакого нового GenServer с собственным
именем в составе. Engine.Gates.QaLeadServer получает ДОБАВОЧНУЮ точку
входа, run_design/3, рядом с привычным run/2 (ревью PR):
Детали
Engine.Gates.QaEstrategiaContext.fetch/3— ЛЁГКИЙ контекст: только story (изEngineApiClient.list_backlog/1, дерево, которое PO читает уже с RN-164) и действующийmodule_map(изEngineApiClient.get_infra_context/2, ТОТ ЖЕGetInfraContextUseCase, который потребляет Infra Lead, здесь только по полюmoduleMap) — БЕЗdev_state, БЕЗworktree_path. Никакого нового маршрута в api: обе функции уже существовали, а gateimplementavelвыполняется PRE-DEV — dev agent, worktree иtask_idещё нет.Engine.Gates.QaEstrategiaAgent— модуль БЕЗ СОСТОЯНИЯ (неGenServer), той же ФОРМЫ, чтоEngine.Gates.QaPerformanceSegurancaAgent: реестр инструментов БЕЗTerminal(ReadFile,SearchWorkspace,EmitPlanoDeTeste), выполняющий общийToolLoopharness. Ни один из трёх инструментов не проходит черезEngine.Harness.Hooks.ActionPipeline(проходят толькоterminal/write_file) — этот агент НИКОГДА не приостанавливается, аrun_design/3выполняется синхронно внутри собственногоhandle_cast. Выпускаетartifact.plano_de_teste(схема проверяется вEngine.Harness.ArtifactSchemas) в event log вызвавшей сессии.Engine.Gates.QaLeadServer.run_design/3—GenServer.cast, в том же стиле, чтоrun/2, БЕЗDevAgentState.find_by_task_id. Вызывается черезEngine.Gates.Dispatcher.run_qa_estrategia/3(ТУ ЖЕ заменяемую в тесте косвенность, что уже используютrun_qa/2/run_secops/2, — избегает подъёма настоящего GenServer в лёгком тесте).Engine.Agents.DevLeadTools.assess_implementability— новый инструмент Dev Lead. Читает самый свежийartifact.plano_de_testestory в истории СОБСТВЕННОЙ сессии Dev Lead:- плана ещё нет — запускает
Dispatcher.run_qa_estrategia/3и возвращает{:error, texto}с просьбой попробовать снова. Ошибка инструмента — это ВХОД цикла, а не конец пути (RN-163) — у Dev Lead есть 14 итераций, чтобы попробовать снова после появления плана; - план есть — собирает заключение (
implementavel/inviavel+ обоснование, с планом тестирования, встроенным в payload) и вызываетEngineApiClient.propose_action/5с"assess_implementability", ТОТ ЖЕ образец из трёх исходов, что уpropose_execution_plan(RN-284, ADR 0086).
- плана ещё нет — запускает
decide.tsполучаетassess_implementability, минимальная рольmaintainer, НАМЕРЕННО вне блока абсолютных потолков — то же рассуждение, что уpropose_execution_plan: это начальное решение сессии, а не превышение уже разрешённого потолка.docs/gates.yml,implementavel:status: planned→active, сevidencia, указывающим на event log (proposed_action.created, отфильтрованный поactionType: assess_implementability).severidadeостаётсяwarn— не тронута; реестр уже говорил «рождается warn, даже когда включится».
Почему потолок итераций НЕ получил новой клаузы
Engine.Harness.Iteracoes.tipo/1 классифицирует неизвестного агента как
:conversacional (потолок 8). "qa-estrategia" попадает в это значение по
умолчанию, и это ПРАВИЛЬНОЕ решение — не пробел. Критерий
RN-085 — не «кто много работает», а «что
удерживает расход сверх потолка итераций». Этот агент работает БЕЗ
token_budget_micros (нет task, PRE-DEV), та же ситуация, что у
infra-workflows, — который тоже остаётся на 8, хотя использует инструмент,
потому что подъём потолка без бюджета под ним умножил бы худший случай без
чего-либо, что его сдерживало бы.
Последствия
За
- Поведение начинает совпадать с тем, что уже объявлял
docs/fluxo.yml, — тот же класс исправления, что ADR 0086 (закрыть расхождение между объявленным fluxo и кодом), только здесь «кода» никогда не существовало. - Разделение по результату доказывается без цены новой инфраструктуры: ноль GenServer, ноль новых HTTP-маршрутов, ноль таблиц.
- Gate
implementavelполучает измеримое доказательство в event log, в том же духе, что ADR 0054, — зафиксированное решение и делает прохождение gate измеримым.
Против
- Окно ожидания между «запустил оценку» и «план существует» асинхронно и
без callback. Dev Lead узнаёт, что план готов, только когда МОДЕЛЬ решит
снова вызвать
assess_implementability, — автоматического возобновления нет (в отличие от приостановки на одобрении в ADR 0086, которая ЯВЛЯЕТСЯ событийно-ориентированной). Принято, потому чтоEngine.Gates.QaEstrategiaAgentработает в отдельном процессе (qa-lead), а Dev Lead не может блокировать синхронныйrun_turn/2, ожидая результата ДРУГОГО процесса, не сцепив их, — а потолок 14 итераций даёт достаточно запаса, чтобы модель попробовала снова в пределах ТОГО ЖЕ хода. appsecостаётсяproposto. Эта поставка не решает вторую роль, которую объявляет тот же фрагментdocs/fluxo.yml, — сознательное решение о рамках, зафиксированное здесь, чтобы следующее направление переиспользовало ТОТ ЖЕ образец, не открывая решение заново.
Рассмотренные альтернативы
Новый агент qa-estrategia, собственный GenServer. Отвергнуто: сам
docs/fluxo.yml уже возражал против этого — «не обязательно новый агент:
разделение — по результату». Новый GenServer продублировал бы проводку
Wake/Registry области QA без какого-либо выигрыша, поскольку этот путь
никогда не приостанавливается и не нуждается в машине возобновления,
оправдывающей собственный процесс.
assess_implementability блокируется в ожидании плана тестирования
(синхронный вызов от начала до конца). Отвергнуто — потребовало бы от Dev
Lead прямо вызывать QaEstrategiaAgent.run/4, в СОБСТВЕННОМ процессе, и
выполнять ToolLoop QA-стратегии ВНУТРИ хода Dev Lead. Технически возможно
(ни один из двух toolloop не приостанавливается), но сцепляет двух агентов —
ошибка чтения в QA-стратегии уронила бы весь ход Dev Lead, а потолок итераций
одного начал бы съедать потолок другого. Сохранение процессов раздельными, с
результатом, проходящим через event log, — ТОТ ЖЕ дизайн, что использует вся
коммуникация api↔engine.
Переиспользовать Engine.Dev.ContextBuilder.fetch/3 (builder, который уже
использует QaPerformanceSegurancaAgent) вместо нового builder.
Отвергнуто: тот builder — по task_id, он предполагает dev agent, worktree и
код, уже закоммиченный в ветку. Вынуждать фиктивный task_id для оценки
PRE-DEV перевернуло бы порядок, который gate существует, чтобы гарантировать
(оценить ДО того, как сжечь токены на написание кода).
Ссылки
docs/fluxo.yml— ролиqa-estrategia(теперьactive) иappsec(остаётсяproposto)docs/gates.yml— gateimplementavel(теперьactive)- ADR 0053 — объявил gate
implementavelкакplanned - ADR 0038 — область QA (Lead + подспециализации), структурный прецедент этого дизайна
- ADR 0086 — образец
proposed_actionиз трёх исходов, который повторяетassess_implementability apps/engine/lib/engine/gates/qa_estrategia_agent.ex,qa_estrategia_context.ex,qa_lead_server.ex,dispatcher.exapps/engine/lib/engine/agents/dev_lead_tools.ex,dev_lead_server.exapps/api/src/domain/actions/decide.ts