O problema da revisão

O conselho padrão para código gerado por AI é “revise com cuidado”.

Esse conselho está correto e é inútil em escala.

Um desenvolvedor revisando saída de AI encontra problemas quando está alerta, familiarizado com o domínio e sem pressão de tempo. Em qualquer outra condição — que é a maior parte das condições — coisas passam batido.

Um revisor com AI detectando problemas gerados por AI é ainda menos confiável. Você está pedindo a um sistema probabilístico que verifique a saída de outro sistema probabilístico. Os modos de falha se correlacionam.

O único padrão que escala é enforcement determinístico. Regras verificadas em todo commit, que não podem ser anuladas por fadiga ou otimismo e que falham o build quando são violadas.

O que determinístico significa

Determinístico significa que a checagem produz o mesmo resultado toda vez, independentemente de quem a execute ou de quando ela rode.

  • Uma regra de linter é determinística.
  • Uma checagem de tipos é determinística.
  • Uma restrição de imports entre fronteiras é determinística.
  • Um contract test é determinístico.
  • A capacidade de atenção de um revisor humano não é.
  • A avaliação de um LLM não é.

Essa distinção importa ainda mais em codebases geradas por AI porque o volume de código gerado excede o que qualquer equipe consegue revisar manualmente. Você não consegue escalar revisão de forma linear com a velocidade de geração. Checagens determinísticas escalam trivialmente.

A stack de guardrails

Para codebases geradas por AI, a stack de guardrails tem quatro camadas:

Camada 1: sistema de tipos

O sistema de tipos é o primeiro guardrail. Tipos estritos capturam uma classe de erros que nenhum processo de revisão — humano ou com AI — captura com consistência:

  • Violações de null
  • Incompatibilidades de interface
  • Tratamento de casos ausentes
  • Tipos de argumentos incorretos

Se o projeto usa TypeScript, strict: true é inegociável. Se usa uma linguagem sem um sistema de tipos forte, adicione um por meio de ferramental ou escolha outra linguagem.

Camada 2: regras de arquitetura

Regras de arquitetura fazem enforcement da disciplina de fronteiras:

  • Nenhuma tela importa detalhes internos de outra tela.
  • Nenhuma lógica de domínio importa infraestrutura diretamente.
  • Nenhum module contorna a composition root para acessar dependências.
  • Nenhum SDK de fornecedor aparece fora do seu module adaptador.

Ferramentas como Semgrep, ArchUnit, dependency-cruiser ou regras customizadas de ESLint podem fazer esse enforcement estaticamente. A chave é que elas rodem em CI e falhem o build. Um aviso que desenvolvedores podem ignorar não é um guardrail.

Camada 3: contract tests

Contract tests verificam se modules satisfazem suas interfaces sem rodar o sistema inteiro:

  • O adaptador de auth satisfaz a interface de auth.
  • O adaptador de analytics satisfaz a interface de analytics.
  • O adaptador de storage satisfaz a interface de storage.

Eles rodam rápido, testam fronteiras de integração e pegam o modo de falha específico em que código gerado por AI satisfaz a assinatura de tipo, mas viola o contract comportamental.

Camada 4: checagens determinísticas de integração

No nível de integração, as checagens verificam propriedades do sistema como um todo:

  • A composition root resolve todas as dependências sem erros em runtime.
  • O grafo de dependências não contém ciclos.
  • Todas as variáveis de ambiente obrigatórias estão declaradas.
  • A configuração é válida em build time, não apenas em runtime.

Semgrep para código gerado por AI

Semgrep merece menção específica porque é excelente para expressar regras de arquitetura como código:

  • Pattern matching na estrutura da AST, não string matching.
  • Regras customizadas por projeto, não apenas linting genérico.
  • Rápido o suficiente para rodar em todo commit.
  • Expressivo o suficiente para codificar violações de fronteira.

Uma equipe que usa geração com AI de forma intensiva deveria manter um ruleset de Semgrep que codifique suas fronteiras arquiteturais. Quando a AI gera código que viola uma fronteira, o build falha antes do merge. Sem exigir atenção humana.

O ponto aqui não é pegar bugs na saída da AI. É tornar violações estruturais impossíveis de fazer merge independentemente de como foram produzidas.

O que a revisão de código com AI realmente pega

Ferramentas de revisão de código com AI são úteis para:

  • Consistência de estilo
  • Lacunas de documentação
  • Erros lógicos óbvios
  • Sugerir abordagens alternativas

Ferramentas de revisão de código com AI não são confiáveis para:

  • Violações de fronteira arquitetural
  • Acoplamento sutil introduzido entre modules
  • Violações de contract comportamental
  • Propriedades de segurança que exigem raciocínio sobre o sistema inteiro

O modo de falha não é que a revisão com AI deixa passar coisas ocasionalmente. O modo de falha é que ela deixa passar coisas de forma imprevisível, e você não consegue saber quando isso aconteceu. É por isso que ela não pode substituir enforcement determinístico — apenas complementá-lo.

A economia

Guardrails determinísticos são baratos de rodar e caros de construir no início.

Escrever as regras de arquitetura leva alguns dias. Manter a configuração do Semgrep exige atenção contínua. Configurar contract tests exige definir interfaces primeiro.

Mas, uma vez que existem, eles rodam em todo commit a um custo marginal quase zero. Não se cansam. Não pulam checagens na sexta-feira à tarde. Não cedem à senioridade nem à pressão social.

Para codebases geradas por AI, em que o volume de código é alto e a velocidade de geração é grande, esse perfil econômico é decisivo. A alternativa — escalar revisão humana para acompanhar a velocidade de geração de AI — não é viável.

A conexão com a arquitetura AI-native

Escrevi sobre esse padrão mais amplo em Stanford CS146S está certo sobre AI coding. A disciplina que falta é arquitetura. Guardrails determinísticos são o mecanismo de enforcement que torna real uma arquitetura substituível.

Sem guardrails, fronteiras arquiteturais são aspiracionais. Com eles, as fronteiras são estruturais. A diferença entre “tentamos manter modules isolados” e “o build falha se o isolamento entre modules for violado” é a diferença entre uma arquitetura que sobrevive à iteração em velocidade de AI e uma arquitetura que colapsa sob esse peso.

O desenvolvedor de software moderno não precisa apenas de fluência com ferramentas de AI. Precisa de uma stack de guardrails que torne código gerado por AI estruturalmente seguro para lançar com velocidade.

Perguntas frequentes

Qual é a melhor ferramenta para fazer enforcement de regras de arquitetura em código gerado por AI?

Semgrep é a opção mais flexível para regras arquiteturais customizadas. Ele suporta pattern matching contra a estrutura da AST, roda rápido em CI e permite que equipes codifiquem fronteiras específicas do projeto. Para projetos JavaScript/TypeScript, dependency-cruiser e regras customizadas de ESLint também são eficazes.

A revisão de código com AI pode substituir a revisão humana?

Não. A revisão de código com AI complementa a revisão humana para estilo e documentação, mas não é confiável para enforcement de fronteiras arquiteturais e propriedades de segurança. Checagens determinísticas (sistema de tipos, linters, regras de arquitetura, contract tests) são o único substituto escalável para revisão dependente de atenção.

Como você configura guardrails sem desacelerar o time?

Comece pelo sistema de tipos (strict mode, sem exceções). Adicione regras de arquitetura para as três fronteiras de maior risco. Adicione contract tests para integrações externas. Cada camada leva um dia para configurar e roda em segundos. A desaceleração vem das violações, não das checagens em si.

Qual é a diferença entre um guardrail e um linter?

Um linter sugere melhorias. Um guardrail falha o build. A distinção está no enforcement. Em codebases geradas por AI, sugestões são ignoradas em escala porque o volume é alto demais para atenção manual consistente. Só falhas de build garantem conformidade.