ADR 0192 — O plano de teste nasce depois da entrega do dev, e o gate implementavel passa a se julgar sobre a história e o module_map
Status
Accepted. 2026-10-01 (AT-269, história HS-069, épico EP-030, rodada 35;
decisão do dono em 01/10: "QA só depois da entrega do dev" — a saída (b) da
atividade, escolhida sabendo que contradiz o ADR 0090). Revisa parte do
ADR 0090 sem editá-lo: a
QA-estratégia continua sendo o qa-lead num segundo MOMENTO, sem agente novo,
mas o momento muda de lugar — sai do design (PRE-DEV) e vai para o começo do
ciclo de revisão da entrega. O appsec, a outra metade do 0090, NÃO muda.
Context
O sintoma
Uso real de 29/09 (análise analise-uso-real.md, item A23): duas rodadas de
toolloop.limit_reached 8/8 seguidas de agent.error origem modelo,
"limite de iterações atingido sem emit_plano_de_teste" (sessão be70,
seq 373/374 e 463/464). O laço gastou as oito iterações lendo docs, um RAG
vazio e pastas (seq 375–463), e a seq 454 diz o motivo em texto: "O código
ainda não existe". O Dev Lead nunca teve parecer.
O que o código fazia (medido em dev, 2026-10-01)
- Quem abre o gate. O
implementavel(docs/gates.yml) é dodev-lead,fluxo: pre-dev,severidade: warn,aprovacao_humana: true, evidência no event log (proposed_action.*filtrado poractionType: assess_implementability). Quem o abre é a ferramentaassess_implementability(Engine.Agents.DevLeadTools.run_assessment/2), que o kickoff do Dev Lead apresenta como OPCIONAL ("use o julgamento"). - O que ele julgava.
run_assessment/2lia a cauda da sessão; semartifact.plano_de_testeda story, chamavaDispatcher.run_qa_estrategia/3→QaLeadServer.run_design/3→QaEstrategiaAgent.run/4e devolvia{:error, "chame de novo em instantes"}; com plano, propunha o parecer (implementavel/inviavel+ justificativa) complanoDeTesteecriteriosExecutaveisembutidos no payload. O insumo era o plano; o JULGAMENTO já era do Dev Lead. - O contexto da QA-estratégia.
QaEstrategiaContext.fetch/3dava story +module_map, sem worktree;ReadFile/SearchWorkspacecaíam no checkout compartilhado do projeto.EmitPlanoDeTestesó aceita depois de uma leitura — então, sem código para ler, o modelo procura até o teto. - O teto.
"qa-estrategia"cai no default:conversacional(8) deEngine.Harness.Iteracoes, de propósito (ADR 0090: semtoken_budget_microspor baixo, subir o teto multiplicaria o pior caso). - Quem depende do veredito. Ninguém no código. Nenhum caso de uso da api
nem módulo do engine lê a decisão de
assess_implementability: a ativação da execução não a consulta, nenhum outro gate a tem comoentrada, e o único consumidor é a tela (a frase emapps/web/src/lib/aprovacoes.ts). O gate éwarn: a passagem é evidência, não trava. - O gate de depois.
qa-verificada(block, donoarea-qa) roda emQaLeadServer.run/2sobre o worktree do dev:ContextBuilder.fetch/3, delegações (Automação sempre, Performance/Segurança por RNF) e UMqa_verdictconsolidado. A Automação monta acoverageMatrixpelas regras da story (RF + RNF) e só aprova com suite verde e toda regra coberta.
Decision
-
O plano de teste é o primeiro passo do ciclo do
qa-verificada.QaLeadServer.run_area/3, depois deContextBuilder.fetch/3e antes das delegações, obtém o plano da ENTREGA:- reencontra na cauda da sessão (teto da reidratação, RN-580) o
artifact.plano_de_testeda MESMAtaskId— a rodada de correção (RN-015) não paga outro laço; - não havendo, roda
QaEstrategiaAgent.run/6síncrono, no próprio processo (o agente nunca suspende), com odev_state/dev_contextque as subespecialidades recebem:workspace_root= worktree do dev, as unidades de regra de negócio, e a lista de arquivos que a entrega tocou (Engine.Gates.Diff,git diff dev...HEAD, até 40 nomes) na primeira mensagem. Diff que falha vira texto ("não consegui listar: motivo"), nunca lista vazia.
O plano entra no
dev_contextcomo:plano_de_teste, e a Automação o recebe NO FIM da mensagem dela, como insumo do passo 2 ("qual teste cobre cada regra"). A régua do veredito não muda: uma linha decoverageMatrixpor regra da story,approvedsó com suite verde e toda regra coberta. O contrato externo continua sendo UMqa_verdictpor ciclo. - reencontra na cauda da sessão (teto da reidratação, RN-580) o
-
Plano que falha não segura a revisão. A QA-estratégia já grava
agent.errorcom origem (RN-059); o Lead segue sem plano, e a mensagem da Automação é a de antes, byte a byte. Fazer a falha do plano bloquear a task seria trava nova num gateblockpor causa de um insumo novo — isso não foi decidido, e a decisão do dono é sobre QUANDO o plano nasce, não sobre ele reprovar entrega. -
O
implementavelse julga sobre a história e omodule_map.assess_implementabilitynão lê nem dispara plano: o insumo passa a ser o que o Dev Lead JÁ tem no contexto do turno — o kickoff dele lista os módulos domodule_mapvigente e as histórias do backlog (RF, RNF, DoD) —, e o julgamento vai najustificativa. O parecer sai na PRIMEIRA chamada; o payload perdeplanoDeTeste/criteriosExecutaveis. O gate continua existindo, com o mesmo dono, severidade, aprovação humana e evidência — muda só aentrada([story-ready, module_map]). Nenhum gate novo. -
O que sai.
QaLeadServer.run_design/3,Dispatcher.run_qa_estrategia/3(e o callback) eQaEstrategiaContext— sem chamador depois do item 3, ficariam acionáveis para um momento que a decisão do dono aposentou. -
O artefato muda de forma.
artifact.plano_de_testepassa a exigirtaskId(Engine.Harness.ArtifactSchemas): é o plano de UMA entrega, e é por ele que o Lead o reencontra. -
O teto CONTINUA 8.
"qa-estrategia"não ganha cláusula emIteracoes.tipo/1. O que faltava era insumo, não folga: com o código existindo e os arquivos da entrega na mensagem, duas ou três leituras bastam. O que mudou do lado do gasto é que existe task agora, e o agente passa a rodar sob otask_budget_microsque as subespecialidades compartilham (RN-036) — o critério da RN-085 até permitiria o teto de gate com esse orçamento por baixo, e a decisão é NÃO usar essa porta para o plano passar. -
docs/gates.ymledocs/fluxo.ymlmudam porque mudou quem entrega o quê a quem:qa-verificadaganhaplano-de-testenaentrada;implementaveltrocaplano-de-testepormodule_map; emfluxo.yml, aqa-estrategiapassa a receber a entrega dodeve a entregar àarea-qa, comgate_saidaqa-verificada(insumo, não veredito próprio), e odev-leaddeixa de receber plano de teste.
Consequences
A favor
- O sintoma do uso real deixa de ter causa: o plano não é mais pedido a um agente num momento em que não existe o que ele precisa ler.
- O Dev Lead tem o parecer na primeira chamada, sem a janela assíncrona sem callback que o ADR 0090 declarou como preço (ele dependia de o MODELO decidir chamar de novo).
- O plano passa a ser escrito sobre o código real, com worktree e diff, e é
consumido por quem verifica — o
qa-verificada—, no mesmo processo e no mesmo ciclo. Zero rota, zero tabela, zero GenServer novo; três peças a menos. - O plano passa a ter orçamento por baixo (o da task).
Contra
- O
implementavelfica mais raso. Antes havia um segundo olhar (QA) sobre a story antes de gastar tokens escrevendo código; agora o parecer é só do Dev Lead, sobre a história e omodule_map. É o preço direto da decisão do dono, e o gate erawarne opcional — mas o "shift-left" do QA que o ADR 0090 comprou deixa de existir para o QA (o appsec continua no design). - Um laço de LLM a mais por ENTREGA, no caminho crítico da revisão: a
Automação só começa depois do plano. Por task, não por rodada (o reuso por
taskId); numa sessão longa o plano pode ter saído da janela de 200 eventos e é escrito de novo — custo, nunca dado errado. - O plano compete pelo mesmo orçamento da task que a revisão usa: uma entrega cara pode chegar à Automação com menos folga.
- O plano é insumo, não régua. Se os critérios executáveis do plano
deveriam virar linhas obrigatórias da
coverageMatrix(e portanto reprovar entrega) é decisão de produto que este ADR NÃO toma. - O teto 8 continua podendo estourar numa entrega grande; aí o desfecho é
o
agent.errornarrado e a revisão segue sem plano. Medir isso no próximo uso real é o que diria se 8 basta. - O pt-BR traduzido de
docs/fluxo.yml(website/i18n/…) já estava atrás do original antes desta mudança, e segue atrás (AT-209).
Alternatives considered
Saída (a): manter o plano no design, a partir de história, regras e
module_map, sem explorar código, com emit_plano_de_teste exigido cedo.
Não contradizia o 0090 e era a correção mais barata do sintoma. Recusada pelo
dono (01/10) a favor da (b).
Subir o teto do qa-estrategia para 60. Recusada pela atividade e por
este ADR: seria fazer o plano passar gastando mais, sobre um momento em que
não há o que ler.
Gate novo para o plano (plano-de-teste-pronto) depois da entrega.
Recusada: gate novo é decisão de produto com ADR próprio, mudaria o contrato
externo (um veredito a mais por PR) e o plano não tem o que vetar sozinho — o
veredito de cobertura já é do qa-verificada.
Disparar a QA-estratégia de forma assíncrona na entrega (cast do
DevAgentServer), em paralelo à revisão. Recusada: a Automação começaria
antes do plano existir, que é a corrida que este desenho existe para evitar;
e o resultado voltaria a depender de um evento que ninguém espera.
Aposentar o implementavel. Recusada: ninguém pediu; o gate continua
tendo o que julgar (a história e o module_map) e continua sendo o registro
mensurável de que alguém pensou na story antes do código.
References
- ADR 0090 — o segundo
momento do
qa-leade do secops; este ADR muda o momento do primeiro - ADR 0054 — o contrato externo dos gates
- ADR 0085 —
docs/fluxo.yml - RN-674 (
docs/business-rules.md), RN-340/341 (revistas por ela), 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