ADR 0192 — План тестирования рождается после сдачи dev, а gate implementavel начинает судить по истории и module_map
Статус
Accepted. 2026-10-01 (AT-269, история HS-069, эпик EP-030, раунд 35;
решение владельца от 01.10: «QA только после сдачи dev» — выход (b) из
задачи, выбранный с пониманием, что он противоречит ADR 0090). Пересматривает
часть ADR 0090, не
редактируя его: QA-стратегия по-прежнему — это qa-lead во втором МОМЕНТЕ, без
нового агента, но момент меняет место — уходит из проектирования (PRE-DEV) в
начало цикла ревью сдачи. Appsec, другая половина 0090, НЕ меняется.
Контекст
Симптом
Реальное использование 29.09 (анализ analise-uso-real.md, пункт A23): два
раунда toolloop.limit_reached 8/8, за которыми следует agent.error
источника modelo, "limite de iterações atingido sem emit_plano_de_teste"
(сессия be70, seq 373/374 и 463/464). Цикл потратил восемь итераций на
чтение документов, пустой RAG и папки (seq 375–463), а seq 454 называет
причину текстом: "O código ainda não existe". Dev Lead так и не получил
заключения.
Что делал код (измерено в dev, 2026-10-01)
- Кто открывает gate.
implementavel(docs/gates.yml) принадлежитdev-lead,fluxo: pre-dev,severidade: warn,aprovacao_humana: true, доказательство в event log (proposed_action.*, отфильтрованный поactionType: assess_implementability). Открывает его инструментassess_implementability(Engine.Agents.DevLeadTools.run_assessment/2), который kickoff Dev Lead представляет как НЕОБЯЗАТЕЛЬНЫЙ ("use o julgamento"). - Что он судил.
run_assessment/2читал хвост сессии; безartifact.plano_de_testeистории вызывалDispatcher.run_qa_estrategia/3→QaLeadServer.run_design/3→QaEstrategiaAgent.run/4и возвращал{:error, "chame de novo em instantes"}; с планом предлагал заключение (implementavel/inviavel+ обоснование) сplanoDeTesteиcriteriosExecutaveis, встроенными в payload. Входом был план; СУЖДЕНИЕ уже принадлежало Dev Lead. - Контекст QA-стратегии.
QaEstrategiaContext.fetch/3давал story +module_map, без worktree;ReadFile/SearchWorkspaceпопадали в общий checkout проекта.EmitPlanoDeTesteпринимает только после чтения — поэтому без кода для чтения модель ищет до потолка. - Потолок.
"qa-estrategia"сводится к значению по умолчанию:conversacional(8) изEngine.Harness.Iteracoes, намеренно (ADR 0090: безtoken_budget_microsпод ним подъём потолка умножил бы худший случай). - Кто зависит от вердикта. Никто в коде. Ни один use case api и ни один
модуль engine не читает решение
assess_implementability: активация исполнения его не запрашивает, ни у одного другого gate он не являетсяentrada, а единственный потребитель — экран (фраза вapps/web/src/lib/aprovacoes.ts). Gate —warn: прохождение — это доказательство, а не замок. - Последующий gate.
qa-verificada(block, владелецarea-qa) выполняется вQaLeadServer.run/2над worktree dev:ContextBuilder.fetch/3, делегирования (Automação всегда, Performance/Segurança по нефункциональным требованиям) и ОДИН консолидированныйqa_verdict. Automação собираетcoverageMatrixпо правилам story (RF + RNF) и одобряет только при зелёной suite и покрытии каждого правила.
Решение
-
План тестирования — первый шаг цикла
qa-verificada.QaLeadServer.run_area/3послеContextBuilder.fetch/3и до делегирований получает план СДАЧИ:- находит в хвосте сессии (потолок регидрации, RN-580)
artifact.plano_de_testeТОЙ ЖЕtaskId— раунд исправления (RN-015) не платит за ещё один цикл; - если его нет, запускает
QaEstrategiaAgent.run/6синхронно, в том же процессе (агент никогда не приостанавливается), сdev_state/dev_context, которые получают подспециализации:workspace_root= worktree dev, единицы бизнес-правил и список файлов, затронутых сдачей (Engine.Gates.Diff,git diff dev...HEAD, до 40 имён), в первом сообщении. Diff, который падает, становится текстом ("não consegui listar: motivo"), никогда пустым списком.
План входит в
dev_contextкак:plano_de_teste, и Automação получает его В КОНЦЕ своего сообщения, как вход для шага 2 («какой тест покрывает каждое правило»). Мерка вердикта не меняется: одна строкаcoverageMatrixна правило story,approvedтолько при зелёной suite и покрытии каждого правила. Внешний контракт по-прежнему — ОДИНqa_verdictна цикл. - находит в хвосте сессии (потолок регидрации, RN-580)
-
Неудавшийся план не задерживает ревью. QA-стратегия уже записывает
agent.errorс источником (RN-059); Lead продолжает без плана, а сообщение Automação — прежнее, байт в байт. Если бы отказ плана блокировал task, это был бы новый замок в gateblockиз-за нового входа — этого не решали, а решение владельца касается того, КОГДА рождается план, а не того, чтобы он проваливал сдачу. -
implementavelсудит по истории иmodule_map.assess_implementabilityне читает и не запускает план: входом становится то, что у Dev Lead УЖЕ есть в контексте хода, — его kickoff перечисляет модули действующегоmodule_mapи истории backlog (RF, RNF, DoD), — а суждение идёт вjustificativa. Заключение выходит при ПЕРВОМ вызове; payload теряетplanoDeTeste/criteriosExecutaveis. Gate продолжает существовать, с тем же владельцем, серьёзностью, человеческим одобрением и доказательством — меняется толькоentrada([story-ready, module_map]). Никакого нового gate. -
Что уходит.
QaLeadServer.run_design/3,Dispatcher.run_qa_estrategia/3(и callback) иQaEstrategiaContext— без вызывающего после пункта 3 они оставались бы доступными для момента, который решение владельца отправило в отставку. -
Артефакт меняет форму.
artifact.plano_de_testeначинает требоватьtaskId(Engine.Harness.ArtifactSchemas): это план ОДНОЙ сдачи, и по нему Lead его находит. -
Потолок ОСТАЁТСЯ 8.
"qa-estrategia"не получает клаузы вIteracoes.tipo/1. Не хватало входных данных, а не запаса: когда код существует, а файлы сдачи есть в сообщении, двух-трёх чтений достаточно. Со стороны расходов изменилось то, что теперь есть task, и агент начинает работать подtask_budget_micros, который делят подспециализации (RN-036), — критерий RN-085 даже позволил бы потолок gate при таком бюджете под ним, и решение — НЕ использовать эту дверь, чтобы план прошёл. -
docs/gates.ymlиdocs/fluxo.ymlменяются, потому что изменилось, кто что кому передаёт:qa-verificadaполучаетplano-de-testeвentrada;implementavelменяетplano-de-testeнаmodule_map; вfluxo.ymlqa-estrategiaначинает получать сдачу отdevи передаватьarea-qa, сgate_saidaqa-verificada(вход, а не собственный вердикт), аdev-leadперестаёт получать план тестирования.
Последствия
За
- У симптома реального использования больше нет причины: план больше не запрашивается у агента в момент, когда нет того, что ему нужно читать.
- Dev Lead получает заключение при первом вызове, без асинхронного окна без callback, которое ADR 0090 объявил ценой (оно зависело от того, решит ли МОДЕЛЬ вызвать снова).
- План начинает писаться по реальному коду, с worktree и diff, и потребляется
тем, кто проверяет, —
qa-verificada, — в том же процессе и том же цикле. Ноль маршрутов, ноль таблиц, ноль новых GenServer; на три детали меньше. - У плана появляется бюджет под ним (бюджет task).
Против
implementavelстановится мельче. Раньше был второй взгляд (QA) на story до того, как тратить токены на написание кода; теперь заключение — только Dev Lead, по истории иmodule_map. Это прямая цена решения владельца, и gate былwarnи необязательным — но «shift-left» QA, который купил ADR 0090, перестаёт существовать для QA (appsec остаётся в проектировании).- Ещё один цикл LLM на каждую СДАЧУ, на критическом пути ревью: Automação
начинает только после плана. На task, а не на раунд (переиспользование по
taskId); в длинной сессии план мог выпасть из окна в 200 событий и будет написан заново — это цена, никогда не неверные данные. - План конкурирует за тот же бюджет task, что и ревью: дорогая сдача может дойти до Automação с меньшим запасом.
- План — вход, а не мерка. Должны ли исполняемые критерии плана стать
обязательными строками
coverageMatrix(и, значит, проваливать сдачу) — продуктовое решение, которое этот ADR НЕ принимает. - Потолок 8 по-прежнему может быть превышен на большой сдаче; тогда исход
— озвученный
agent.error, и ревью продолжается без плана. Измерение этого при следующем реальном использовании скажет, хватает ли 8. - Переведённый pt-BR
docs/fluxo.yml(website/i18n/…) уже отставал от оригинала до этого изменения и продолжает отставать (AT-209).
Рассмотренные альтернативы
Выход (a): оставить план в проектировании, на основе истории, правил и
module_map, без исследования кода, с ранним требованием
emit_plano_de_teste. Не противоречил 0090 и был самым дешёвым исправлением
симптома. Отвергнут владельцем (01.10) в пользу (b).
Поднять потолок qa-estrategia до 60. Отвергнуто задачей и этим ADR: это
означало бы проталкивать план, тратя больше, в момент, когда читать нечего.
Новый gate для плана (plano-de-teste-pronto) после сдачи. Отвергнуто:
новый gate — продуктовое решение с собственным ADR, изменил бы внешний
контракт (лишний вердикт на PR), а плану нечего ветировать в одиночку —
вердикт покрытия уже принадлежит qa-verificada.
Запускать QA-стратегию асинхронно при сдаче (cast из DevAgentServer),
параллельно с ревью. Отвергнуто: Automação начала бы до появления плана,
а это та гонка, которую этот дизайн существует, чтобы избежать; и результат
снова зависел бы от события, которого никто не ждёт.
Отправить implementavel в отставку. Отвергнуто: никто не просил; gate
по-прежнему имеет что судить (историю и module_map) и остаётся измеримой
записью того, что кто-то подумал о story до кода.
Ссылки
- ADR 0090 — второй момент
qa-leadи secops; этот ADR меняет момент первого - ADR 0054 — внешний контракт gates
- ADR 0085 —
docs/fluxo.yml - RN-674 (
docs/business-rules.md), RN-340/341 (пересмотренные ею), RN-085, RN-036, RN-163, RN-580 apps/engine/lib/engine/gates/qa_lead_server.ex,qa_estrategia_agent.ex,qa_automacao_agent.ex,dispatcher.ex;apps/engine/lib/engine/agents/dev_lead_tools.ex;apps/engine/lib/engine/harness/artifact_schemas.ex