Um code review confiável trata a origem do patch como detalhe e exige intenção explícita, evidência executável e uma resposta para quando a suposição falhar.
A PR foi aprovada, o deploy passou e ninguém consegue responder uma pergunta simples: o que impede esse novo caminho de duplicar uma cobrança quando o provedor remoto responde tarde? O diff parece bem escrito, os testes estão verdes e o autor usou IA para acelerar parte do patch. Só que o comportamento relevante não está explicado.
Para um Tech Lead, esse é o sintoma que importa. A pergunta não é se a IA pode escrever código; é se o time consegue explicar a mudança, verificar suas alegações e operar o sistema quando uma suposição embutida falha.
Um bom code review não deveria classificar a origem das linhas. Deveria deixar claro qual comportamento o patch promete, que evidência sustenta a promessa e qual limite existe caso ela falhe em produção.
O sintoma que o diff não resolve
Patches gerados costumam ser convincentes em escala local. Cada função parece razoável, cada if trata um caso reconhecível e cada chamada reaproveita uma abstração já existente. O problema aparece quando essas escolhas se combinam sem uma intenção explícita para governá-las.
O diff mostra implementação, não intenção. Ele revela que uma requisição será repetida, que um campo entrou no payload ou que um erro ganhou tratamento. Não diz se repetir é seguro, se o campo preserva o contrato, se a ordem dos efeitos importa nem se o fallback muda a experiência do cliente.
Em mudanças pequenas, o risco pode ser baixo. Alterar um texto de log ou renomear uma variável local não exige uma tese extensa. Só que “pequena” não quer dizer “poucas linhas”: uma linha que muda retry, autorização, cache, schema ou persistência é consequente mesmo cabendo em uma tela.
O custo de pedir explicação existe. O autor precisa pensar antes de abrir a PR, e talvez o merge espere mais um ciclo. Em troca, o revisor deixa de fazer arqueologia sozinho e quem está de on-call recebe um modelo de falha, não hipóteses improvisadas. A mudança precisa ser pequena o bastante para que seu autor consiga explicá-la com precisão.
Uma aprovação sem modelo de comportamento transfere o trabalho de entendimento para o próximo incidente.
O mecanismo entre intenção e efeito
Código gerado não é suspeito por definição; código humano também pode juntar decisões plausíveis sem declarar as invariantes que as conectam. A diferença é de velocidade: uma ferramenta propõe bastante código coerente na superfície antes que alguém formule o contrato que deveria restringi-lo.
Uma invariante é o que precisa continuar verdadeiro apesar dos detalhes da implementação. Em um pagamento, por exemplo: “a mesma chave de operação produz no máximo um efeito externo”. Essa frase orienta retry, timeout, estado persistido, logs e rollback. Não é comentário decorativo.
Sem essa condição, o reviewer tenta inferir intenção a partir de um catch, de uma chave de cache, de uma transação ou da ordem entre duas chamadas. Pode encontrar um bug, mas a leitura é frágil: o patch pode estar correto por acidente no cenário feliz e errado exatamente no caso que ninguém nomeou.
Uma mudança consequente precisa ligar intenção, implementação, prova e resposta operacional:
flowchart LR
A[Nota de intenção e invariante] --> B[Diff da implementação]
B --> C[Teste focado ou comando reproduzível]
C --> D[Contrato: API, schema ou regra de domínio]
D --> E[Sinal observável em produção]
E --> F[Contenção ou rollback seguro]
A -. limita .-> B
A -. define o que observar .-> E
F -. reduz o custo de errar .-> A
O diagrama não é uma burocracia em sequência. São superfícies que se corrigem. A nota pode ser vaga; o diff pode omitir contexto; o teste pode provar só o cenário preparado; um sinal pode mostrar efeito sem causa; e rollback de código pode não desfazer dados enviados a outro sistema. Cruzar essas evidências reduz o ponto cego.
| Superfície de evidência | O que prova | Ponto cego |
|---|---|---|
| Nota de intenção ou invariante | Qual comportamento deve permanecer verdadeiro | Pode declarar desejo sem cobrir a implementação real |
| Diff | O que mudou concretamente | Não revela intenção nem todos os efeitos indiretos |
| Teste focado ou comando reproduzível | Que um cenário observável funciona | Pode deixar de fora timeout, concorrência ou dados reais |
| Contrato de API, schema ou domínio | O que consumidores podem esperar | Não prova que integração e migração o respeitam |
| Sinal em produção | Que o sistema apresenta um efeito | Pode chegar tarde e não explicar a causa |
| Contenção ou rollback | Como limitar a falha após deploy | Pode não reverter efeitos externos ou dados derivados |
Você não precisa exigir todas as superfícies com o mesmo peso. Uma alteração visual pode pedir intenção, diff e teste. Uma escrita remota pede também contrato, sinal observável e uma forma concreta de conter o estrago.
Esse é o passo seguinte de decidir quais workflows de IA vale adotar de forma deliberada: o workflow não acaba quando a ferramenta entrega código. Ele acaba quando o time sabe avaliar o que aceitou e como reagir ao que pode dar errado.
Onde o retry atravessa a fronteira errada
Considere uma mudança útil à primeira vista: após timeout de um provedor remoto, o serviço reenvia a mesma operação. O patch adiciona uma política de retry, registra a exceção e preserva a resposta ao cliente. Tudo parece defensável até você separar “não recebi resposta” de “a operação não aconteceu”.
O provedor pode ter executado a primeira solicitação e perdido a resposta no caminho de volta. Se a nova tentativa atravessa a fronteira sem uma chave de idempotência que ele respeite, surgem dois efeitos externos. Localmente, a resposta pode indicar um sucesso; fora do processo, a cobrança pode ocorrer duas vezes.
sequenceDiagram
participant S as Serviço
participant P as Provedor remoto
participant R as Reviewer
S->>P: operação com chave de idempotência
P-->>P: efeito externo é aplicado
P--xS: resposta perdida ou timeout
S->>S: política decide repetir
Note over S,P: Fronteira de idempotência
alt chave é persistida e reconhecida
S->>P: mesma chave, nova tentativa
P-->>S: resultado original, sem novo efeito
else chave ausente ou variável
S->>P: nova operação efetiva
P-->>S: segundo efeito externo
R->>R: review exige teste, contrato e sinal de duplicidade
end
O review não precisa adivinhar o comportamento interno do fornecedor. Precisa expor as alegações escondidas no patch: onde a chave nasce, se ela sobrevive a tentativas e reinícios, o que o contrato remoto faz com a mesma chave e como o teste reproduz uma resposta perdida depois do efeito externo. Timeout antes de qualquer efeito é o caso fácil; timeout ambíguo é o que decide se retry é seguro.
Também falta a pergunta operacional: qual sinal revelará uma repetição inesperada e qual ação vem depois? Uma contagem por chave, a correlação entre tentativa e efeito ou um conflito de estado podem tornar o problema visível. Desativar retry por feature flag, reduzir o rollout, interromper uma fila ou bloquear uma integração são respostas diferentes de simplesmente “fazer rollback”.
A arquitetura fica difícil de sustentar quando uma decisão de confiabilidade se esconde em um helper genérico. É a mesma pressão descrita em arquitetura simples vence quando o sistema fica difícil de entender: antes de o sistema ficar maior, ele pode ficar opaco.
O diagnóstico que cabe na PR
Antes de aprovar uma mudança consequente, peça uma nota curta na descrição da PR. Não precisa virar documento separado nem template pesado; precisa dar ao reviewer uma hipótese verificável.
- Intenção e invariante: que comportamento a mudança cria ou preserva?
- Caminho alterado: onde ele aparece no diff e que fronteiras do sistema cruza?
- Evidência executável: que teste focado, comando ou cenário reproduzível verifica a alegação?
- Observação: que sinal confirma em produção que o comportamento está saudável ou falhando?
- Contenção: que ação reduz o impacto se a hipótese estiver errada e o que ela não desfaz?
A nota orienta a leitura; ela não substitui o review. Se o autor não consegue respondê-la, isso não demonstra que o patch está errado. Demonstra que ele ainda não está pronto para ser aprovado com confiança. O reviewer pode entender o código sozinho, mas o time continua dependente de uma pessoa que fez arqueologia para validar a mudança.
Explicar também não é fingir certeza absoluta. Uma nota útil pode dizer: “não sabemos se o provedor deduplica depois de trinta dias; por isso o rollout começa restrito e o retry fica atrás de flag”. Essa incerteza nomeada é melhor que uma PR limpa na superfície e investigável apenas durante um incidente.
O objetivo do review é tornar as suposições discutíveis antes que elas se tornem comportamento em produção.
A resposta do time antes do merge
Para times que estão formando esse hábito, treinamento prático de IA para engenharia pode começar pelo ritual de revisão, não por uma lista de prompts. A ferramenta acelera autoria; o time precisa preservar a capacidade de avaliar comportamento, limites e consequências.
A regra vale igualmente para código digitado por uma pessoa, copiado de uma resposta ou produzido por IA. A origem muda a velocidade e talvez a quantidade de opções, mas não muda a obrigação de declarar o que o patch afirma fazer. Tratar IA como exceção cria uma política fácil de contornar e deixa intactos os mesmos riscos nos demais diffs.
Faça a nota proporcional ao risco. Para algo local e reversível, uma frase e um teste podem bastar. Ao cruzar autorização, persistência, contrato público, retry ou efeito externo, aumente a evidência em vez de alongar a discussão. O trade-off é tempo de revisão agora contra tempo de diagnóstico quando a falha já atingiu usuários; quem fica de on-call paga pela escolha de pular a explicação.
Perguntas frequentes
Mudanças triviais também precisam dessa nota?
Nem sempre. Se o efeito é local e óbvio no diff, basta registrar o essencial e apontar o teste. O critério é consequência, não número de linhas: uma mudança curta que cruza dados, contrato, autorização, retry ou efeito externo ainda merece explicação.
O reviewer não pode explicar no lugar do autor?
Pode, mas isso transforma a revisão em arqueologia e concentra o entendimento em quem revisou. Peça que o autor reduza o escopo, investigue a intenção ou escreva o modelo de falha; recuperar essa explicação faz parte da autoria.
Testes verdes não provam que a intenção está correta?
Eles provam que cenários definidos passaram. A invariante explica por que esses cenários importam e revela os que ainda faltam, como concorrência, timeout ambíguo ou dados persistidos. Um teste pode validar com perfeição uma regra que ninguém pretendia ter criado.
Isso também se aplica a código humano ou copiado?
Sim. Qualquer patch pode ocultar uma suposição não declarada, independentemente de ter sido escrito linha a linha, copiado de um snippet ou aceito de uma ferramenta. A origem não elimina a necessidade de evidência e contenção.
Na próxima PR consequente, registre a invariante antes do patch, combine a prova, o sinal e a primeira ação de contenção; só então mantenha o escopo até essa explicação caber na própria revisão.


