A IA acertou as regras. O bug era nosso.
Pedimos ao Claude Code um serviço de cupom sem dar nenhuma regra de negócio. Ele acertou as oito, passou em 30 testes — e um cupom de uso único foi usado duas vezes. O bug nasceu na nossa especificação.
O vídeo acima mostra o experimento do começo ao fim, com as saídas reais do terminal. Aqui está a versão em texto — e, no final, o passo a passo para montar o mesmo harness no seu projeto.
Trinta testes passando, tudo verde. E mesmo assim um cupom de desconto que cada cliente só podia usar uma vez foi usado duas vezes pelo mesmo cliente. Bastou aplicar o cupom duas vezes no mesmo instante.
O código foi escrito por uma IA. O bug não nasceu nela: nasceu numa regra que nós mesmos escrevemos. E quem avisou do problema foi a própria IA.
O experimento
Um serviço de cupom de desconto, em Java. O projeto já tinha as classes do pedido e do cupom, uma interface que registra quem já usou cada cupom e um método vazio para a IA implementar.
Entregamos isso ao Claude Code, com o modelo Opus, sem a minha configuração pessoal — sem as minhas instruções e sem os meus plugins. O prompt tinha duas frases:
Implemente o método aplicar da classe CupomService. Ele aplica um cupom de desconto a um pedido e devolve o desconto e o total.
Nenhuma regra de negócio. Antes do experimento, tínhamos escrito oito regras para esse serviço, e a IA não viu nenhuma delas.
Em pouco mais de um minuto, ela devolveu o método e doze testes escritos por ela mesma. No fim da resposta, uma frase que vale mais que o código:
O pedido não definia várias regras, então eu escolhi. Vale você revisar cada uma.
Vieram sete escolhas. O desconto vale sobre o frete? Ela decidiu que não. O valor mínimo do pedido inclui o frete? Também não. O cupom vale no último dia da validade? Vale.
Na sua empresa, quem decide se o cupom dá desconto no frete? Não é o modelo. É o time de produto, é o financeiro. Ela decidiu sozinha — e pelo menos avisou.
A aposta perdida
As oito regras, convencionais de propósito, viraram dezoito testes de aceite que a IA nunca viu. Rodando tudo junto, os doze dela e os dezoito nossos: trinta de trinta.
Ela não errou nenhuma das oito. Montamos o experimento apostando que ela ia errar, e quem perdeu a aposta fomos nós. Meu palpite é que essas regras são o senso comum de qualquer loja virtual, e que uma regra fora do comum ela provavelmente não adivinharia.
Mas o placar importa menos do que parece. Só sabemos que ela acertou porque a regra estava escrita e havia um teste para conferir. Sem isso, "a IA acertou" é só uma opinião.
O parágrafo que ninguém lê
Trinta testes verdes. Você aprovaria esse código?
Antes de responder, volte ao último parágrafo da resposta — daqueles que dá
vontade de pular. Ela avisou que verificar se o cliente já usou o cupom
(jaUsou) e registrar o uso (registrar) são duas chamadas separadas. Se duas
requisições do mesmo cliente chegarem ao mesmo tempo, as duas podem passar pela
verificação, e o cupom é usado duas vezes.
Isso tem nome: condição de corrida. Verificar e depois agir, em dois passos, sem nada que impeça outra requisição de entrar no meio. A primeira pergunta "já usou?" e ouve não. A segunda pergunta a mesma coisa antes de a primeira registrar, e também ouve não. As duas aplicam o desconto.
Escrevemos um teste para isso: duas requisições do mesmo cliente, com o mesmo cupom, soltas ao mesmo tempo, com um registro que simula a demora de um banco de dados. Uso duplo em cinquenta de cinquenta tentativas.
Para ser justo, esse cinquenta de cinquenta vem de como o teste foi montado. Sem a demora simulada, deu uso duplo em 611 de 2000 tentativas — cerca de 30%. O bug é real.
A reviravolta
A regra sete, escrita por nós antes do experimento, dizia: se o cliente já usou, recusa; se aplicou, registra. Verificar, e depois registrar. O bug estava na nossa especificação. Tanto que o gabarito que preparamos seguindo essa regra tem exatamente o mesmo bug.
A IA nunca viu esse gabarito. Mas a interface que entregamos tinha o mesmo desenho: uma chamada para verificar, outra para registrar. Ela implementou o contrato que recebeu e avisou que ele tinha um problema. O teste de concorrência só existe porque alguém leu aquele último parágrafo.
Por que ela não corrigiu
Se ela viu o problema, por que não corrigiu? Porque corrigir de verdade muda o contrato — a interface de registro, que outras partes do sistema podem usar. Ela sugeriu um caminho, registrar só se ainda não existir, numa operação única, e parou ali.
Parou no lugar certo. Mudar contrato é decisão de engenharia, e essa decisão é sua.
Cuidado com a tentação de colocar uma trava no método. Passa no teste e quebra no dia em que a aplicação rodar em duas instâncias, cada uma com a sua trava. A garantia fica onde o dado mora: no banco, com uma restrição de unicidade, que recusa a segunda linha igual.
O harness
Segunda rodada, mesmo prompt, palavra por palavra. O que mudou foi o ambiente em volta dela — o harness. Quatro peças:
- Contexto: um
CLAUDE.mdexplicando o que é o sistema e que, aqui, erro é dinheiro perdido ou cliente cobrado errado. - Regras: as oito, com a regra sete corrigida. E uma instrução: se faltar regra, pergunte em vez de decidir sozinha.
- Verificação: os dezoito testes de aceite e o de concorrência. Não termine com teste vermelho e não mexa nesses testes.
- Limites: altere só o
CupomService, sem tocar nas interfaces. Se precisar de mais, pare e explique.
Para não enganar ninguém: o contrato novo, registrar só se ainda não existir, foi decisão nossa e já estava pronto no projeto. O zero de uso duplo vem dele, não da IA. O trabalho dela era usar o contrato direito, registrando o uso por último, depois de todas as outras regras passarem.
Resultado: dezenove testes passando. Uso duplo em zero de cinquenta, e em zero de duas mil sem demora nenhuma. Conferimos por fora que nenhum outro arquivo foi tocado.
O que importa não é o verde
O resultado que mais me interessa é outro. Onde as regras não cobriam, ela seguiu a instrução: não escolheu sozinha, perguntou. O que fazer com valores nulos? E com subtotal negativo?
Numa execução anterior, com uma primeira versão do harness que tinha menos testes, ela fez uma pergunta melhor ainda: se o uso é registrado quando o desconto é aplicado e o cliente desiste da compra, o cupom fica queimado. Não deveria registrar só quando o pagamento é confirmado? Isso é pergunta de produto, e nenhum teste pegaria.
As duas execuções perguntaram coisas diferentes. Não dá para contar com a IA lembrar da pergunta certa toda vez — por isso o certo precisa estar escrito e testado. E enquanto ninguém responde, o código da segunda rodada aceita frete negativo e quebra quando falta um campo. Não decidir também é uma decisão.
O que sobra para você
Antes, o caminho era engenheiro → código. Agora é engenheiro → harness → agente → código.
O que sobra é escrever a regra — e às vezes errar nela, como nós erramos. É ler o que a IA avisa. É decidir o contrato. E é provar que está certo.
Código ficou barato. Julgamento ficou caro. É a mesma conclusão de Inteligência ficou abundante. Julgamento não., agora com saída de terminal para provar.
Passo a passo: um harness mínimo em meia hora
- Escreva as regras que a IA não tem como saber. Antes de pedir, crie um
REGRAS.mdcom as regras de negócio da tarefa. Pronto quando cada regra cabe em uma frase. - Transforme cada regra em teste de aceite, incluindo os limites: último dia, valor igual ao mínimo, zero, cem por cento. Pronto quando os testes existem e falham antes da implementação.
- Dê ao agente contexto, verificação e limites. No
CLAUDE.md, ou no arquivo equivalente da sua ferramenta: o que é o sistema e quanto custa um erro; onde estão as regras, e "se faltar regra, pergunte"; o comando de teste, "não termine com teste vermelho" e "não altere estes testes"; o que ele pode alterar, e "se precisar de mais, pare e explique". - Leia a resposta inteira. Cada "eu escolhi" vira pergunta para quem decide ou vira teste. Cada aviso vira teste. Pronto quando nenhuma escolha da IA ficou sem dono.
- Para tudo que verifica e depois grava, pergunte: e se rodar duas vezes ao mesmo tempo? Escreva um teste com duas chamadas simultâneas e coloque a garantia no banco, com restrição de unicidade. Pronto quando existe um teste de concorrência verde que falharia sem a garantia.
Um detalhe que tem tudo a ver com isso: desde a versão 2.1.277, o Claude Code
lê um AGENTS.md quando o projeto não tem CLAUDE.md. O harness não pertence
a uma ferramenta. O que importa é que ele esteja escrito e versionado junto com
o código.
Pegue o último código que você aceitou de uma IA e liste cada decisão que ela tomou sem ninguém pedir. Escolha uma e transforme em teste. Depois faça a pergunta que derrubou o nosso cupom: e se isso rodar duas vezes ao mesmo tempo?
- claude code
- harness
- testes
- concorrência