Engenharia

Reporte dois números ou você não está reportando nenhum

Um eval local rápido é um proxy e a superfície deployada é a verdade, colapse-os e você entrega o proxy.

ASR

Apollo Space Research

Apollo Space

· 10 min de leitura

Uma suíte de testes local fica verde em vinte e cinco segundos. Um engenheiro lê o verde, escreve “funciona” no pull request, e a mudança é mergeada. Três dias depois um cliente clica no exato botão que o teste verde deveria cobrir, e ele faz a coisa errada. O teste não estava mentindo. Estava respondendo uma pergunta diferente da que alguém se importava.

O verde significava que o proxy passou. Ninguém nunca checou a verdade.

Um eval local rápido é um proxy e a superfície deployada é a verdade, colapse-os e você entrega o proxy.

Este post é sobre uma única disciplina que fixamos no jeito como construímos agents na Apollo: nunca deixar um número valer por ambos. O número rápido te diz que a mudança é plausível. O número lento te diz que ela é real. Reporte um deles como “pronto” e você silenciosamente não reportou nenhum.

A versão ingênua: um número, e é o rápido

A forma óbvia de saber se uma mudança de agent funciona é rodar a checagem barata e confiar nela. Você tem um harness local, ele sobe o runtime in-process, replica um cenário, imprime um pass. Roda em segundos. Custa centavos. Você pode rodá-lo em cada commit, espalhá-lo por uma centena de cenários, fazer A/B de dois modelos antes do almoço. É, genuinamente, uma das melhores ferramentas da bancada.

Então é tentador deixar que ele seja a resposta inteira. Verde aqui, entrega ali.

Funciona lindamente até o momento em que não funciona, e a falha é específica. O harness local roda o agent numa sala limpa. O modelo é carregado do jeito que o teste o carregou. A memória é o que a fixture semeou. As tools retornam o que o harness as fiou para retornar. Cada variável que não é a mudança está pinada num valor amigável, que é exatamente o que torna o harness rápido, e exatamente o que torna seu verde indigno de confiança como resposta final.

Um pass em sala limpa te diz que a mudança é plausível. Não te diz que ela sobrevive ao contato com o mundo.

A superfície deployada não tem nenhum desses pinos. Auth real. Boundaries de org reais. A memória que o usuário de fato acumulou ao longo de quatro turns de conversa. A tool que dá timeout sob carga em vez de retornar uma fixture arrumadinha. Um pass na sala limpa e um pass na superfície deployada não são a mesma reivindicação, e no momento em que você trata o primeiro como se fosse o segundo, você entregou o proxy e o chamou de produto.

Essa é a armadilha, dita claramente. O eval rápido é tão bom que você para de perguntar o que ele não consegue ver. E o que ele não consegue ver é a única coisa que o cliente toca.

Dois números, e por que nenhum é opcional

A correção é quase constrangedoramente simples de dizer: toda reivindicação comportamental carrega dois números, não um.

O primeiro é o número inner, o eval local. Ele roda o runtime real in-process, replica o cenário, e reporta uma taxa de pass rápida e barata o suficiente para rodar em cada mudança. O segundo é o número outer, o mesmo comportamento exercitado na superfície deployada que um cliente de fato usaria, com auth real, memória real, tools reais, latência real. Inner é o proxy rápido. Outer é a verdade. Você reporta ambos, sempre, lado a lado, e nunca deixa um deles desaparecer dentro da palavra “pronto”.

Dois números rodam como um pipeline: um inner eval rápido replica o cenário numa sala limpa como um proxy barato, e uma checagem outer mais lenta exercita o mesmo comportamento na superfície deployada como a verdade; reportar apenas um número entrega o proxy.

A razão pela qual você não pode largar o número inner é velocidade. Se o único sinal em que você confia é o deployado, cada checagem custa um deploy, e uma disciplina que é cara em cada mudança é uma disciplina que é pulada na mudança que importa. O inner loop é o que te deixa pegar a quebra óbvia em segundos em vez de esperar um pipeline te dizer o que um run local teria gritado.

A razão pela qual você não pode largar o número outer é honestidade. O inner loop, por construção, não consegue ver o que pinou. Ele não pode falhar no boundary de auth que stubou, na memória que não acumulou, na tool que fingiu. Então um pass inner é um sinal real, útil, estrutural, e é também estruturalmente cego a uma classe inteira de falha. O número outer é o único conquistado nas mesmas condições em que o usuário vive.

Aqui está a regra que de fato seguimos: inner-green é “comportamentalmente verde, pendente a checagem deployada”, nunca “pronto”. O eval local rápido é um proxy e a superfície deployada é a verdade, dois números, reportados como dois números. No instante em que eles colapsam em um, você perdeu a única informação que te dizia qual tipo de verde você estava olhando.

Por que colapsá-los parece seguro e não é

Há uma versão mais suave desse erro que soa responsável, e é a que a maioria dos times recorre, então vale nomeá-la.

A versão suave é: rode o eval rápido, e confie nele, porque ele roda o runtime real, não mocks, o loop de agent de verdade. Isso parece rigoroso. É mais rigoroso que um unit test que afirma que um stub retornou um stub. Então o raciocínio segue: isto não é uma checagem de brinquedo, exercita o código real, portanto verde aqui é verde em todo lugar.

Mas “roda o runtime real” e “roda nas condições reais” são reivindicações diferentes, e o gap entre elas é precisamente onde as coisas quebram. Um simulador de voo roda o software de aviônica real. Ele não roda o tempo real, o gelo real na asa, o pássaro real. Você não certificaria um piloto só com horas de simulador e o chamaria de testado-na-estrada, não porque o simulador é falso, mas porque ele pina as variáveis que mais mordem no ar. O eval local é o simulador. Não é falso. Só não é o céu.

Então o perigo não é um eval ruim. É um bom eval confiado além de sua evidência. Quanto melhor seu inner loop fica, mais convincente seu verde se torna, e mais forte o puxão para deixá-lo ser o único número. Um proxy fraco é checado duas vezes por suspeita. Um proxy forte é acreditado, e um proxy acreditado é como o pass de sala limpa vira a surpresa de produção.

A disciplina não é “desconfie do número rápido”. O número rápido é excelente. A disciplina é recusar deixá-lo responder uma pergunta que ele estruturalmente não consegue ver. Ele pode te dizer que a mudança é plausível. Não pode te dizer que o botão do cliente faz a coisa certa. Essas são duas perguntas, e você deve duas respostas.

O que os dois números de fato te dizem

Uma vez que você se compromete a reportar ambos, os dois números param de ser redundantes e começam a ser um diagnóstico. A informação interessante está em como eles discordam.

Um dois-por-dois de resultados inner e outer: ambos verdes significa entregar, ambos vermelhos significa um bug localizado, inner-verde com outer-vermelho expõe a condição que a sala limpa pinou, e inner-vermelho com outer-verde significa que o próprio eval está errado e deve ser corrigido.

Quando ambos estão verdes, você tem algo perto de confiança conquistada, a mudança é plausível e sobrevive à superfície deployada. Esse é o único estado que conta como pronto, e vale notar quão raramente um único número poderia ter te dito isso.

Quando ambos estão vermelhos, você tem um diagnóstico limpo: um gap real, reproduzível, localizado. Esse é o caso fácil. O proxy e a verdade concordam, e você vai consertar a coisa que eles concordam que está quebrada.

Os dois estados interessantes são as divergências.

Inner-verde, outer-vermelho é a razão inteira pela qual a disciplina existe. A sala limpa passou e o mundo falhou, o que significa que a falha vive exatamente na coisa que o inner loop pinou, o boundary de auth, a memória acumulada, a tool sob carga real. A discordância não só te diz que algo quebrou. Ela te diz onde: no gap entre o simulador e o céu. Esse é um bug encontrado com um endereço, não uma sensação vaga de que “a versão deployada parece estranha”.

Inner-vermelho, outer-verde é o que as pessoas esquecem, e é uma descoberta também. Se a superfície deployada faz a coisa certa enquanto o eval local insiste que está quebrado, o eval está errado, uma fixture velha, um cenário que se desviou do comportamento real, um pino que não combina mais com a realidade. Um número inner vermelho nem sempre é um bug de código. Às vezes é um bug no próprio proxy, e a única forma de você jamais pegá-lo é tendo um segundo número para discordar. Um time rodando um número “consertaria” código que funciona para satisfazer um teste quebrado.

Um número pode ser verde ou vermelho. Dois números podem te dizer qual tipo, e qual tipo é a pergunta inteira.

A virada: um número é uma promessa sobre uma pergunta

O que uma pessoa de fato está fazendo quando cola um checkmark verde num pull request e escreve “funciona”?

Ela está fazendo uma promessa, ao revisor, ao próximo engenheiro, ao cliente lá na frente que nunca vai ler o teste. A promessa é: eu chequei a coisa com que você se importa, e está boa. E a tragédia silenciosa do único número rápido é que ele deixa um engenheiro sincero e cuidadoso fazer essa promessa sobre uma pergunta que ninguém fez. A sala limpa passou. O botão nunca foi tocado. A promessa foi cumprida à letra e quebrada em espírito, e a única pessoa que descobre é o cliente.

Dois números é, por baixo do ferramental, só honestidade intelectual transformada em hábito. É o engenheiro que, perguntado “funciona?”, se recusa a responder com o verde barato sozinho, que diz, “passa localmente, e aqui está o que a superfície deployada fez”, porque ele sabe que essas são duas coisas diferentes e te respeita demais para borrá-las. Essa recusa não é algo que você consegue instalar. É uma postura: uma desconfiança operante das próprias boas notícias, forte o bastante para sobreviver a um deadline apertado e a uma tela verde às 18h.

O número rápido vai continuar ficando mais rápido. Os proxies vão continuar ficando melhores, mais perto da verdade, mais convincentes no seu verde. Nada disso aposenta o segundo número. Quanto melhor o simulador, mais disciplinado você tem que ser sobre ainda voar o avião, porque as falhas que alcançam um cliente são, por definição, as que o simulador não conseguiu te mostrar.

Um eval local rápido é um proxy e a superfície deployada é a verdade. Colapse-os, e o verde que você entrega é uma promessa sobre uma pergunta que ninguém fez.


Essa é a disciplina que construímos na Apollo Space, agents cujo cada “funciona” carrega a prova rápida e a real, porque a superfície que um cliente toca é a única que tem voto. Se você já entregou um verde que virou vermelho no momento em que uma pessoa real clicou, você já sabe qual dos dois números você esqueceu de ler.

A Apollo cuida da operação repetitiva da sua empresa pro seu time não precisar.

Entre na lista de espera: acesso antecipado, preço de usuário fundador e um lugar na primeira fila enquanto a gente constrói.

Entrar na lista de espera