Validando no Disco o Benchmark Que Escrevi de Madrugada
Por Brenner Cruvinel • 6 minutos de leitura
abri uma sessão nova, sem contexto nenhum, e perguntei como se eu fosse alguém que acabou de clonar o repo: como usa o nest, ele tem interface? o primeiro comando que a resposta sugeriu devolveu command not found na minha própria máquina. o segundo mostrou um modelo padrão que eu tinha certeza de ter trocado semanas atrás. dois furos que nenhum teste pega, achados em cinco minutos, e foi aí que percebi que o assunto da semana não era compressão.
o benchmark era só o lugar onde deu pra ver. então antes de publicar qualquer número da série, rodei um dia inteiro de validate: cada número contra o arquivo em disco.
o que estava errado
a primeira coisa que não bateu nem era número. rodei um strings no arquivo de release e apareceu "Spellbook MTG corpus". o arquivo se chama mtgdataset. o rename de uma semana atrás, que trocou o nome do app do felipe pelo nome genérico em todos os arquivos de texto, nunca entrou no binário. o lock ao lado do release descrevia um arquivo com o nome novo enquanto o arquivo tinha o nome velho dentro, e nenhuma ferramenta acusou, porque a validação confere o arquivo consigo mesmo. refiz os dois releases com o nome certo dentro, e os bytes da mídia saíram idênticos, o que pelo menos provou que o encode é reproduzível.
os tamanhos dos três builds mais agressivos estavam em mebibyte com rótulo de gigabyte. o du fala em MiB e eu colei como GB. a diferença é de cinco por cento por linha, mas o ratio herda o erro: o build de busca que eu tinha anunciado como 7,8 vezes menor que a fonte é 7,5. o avif que eu disse ser 20% menor que o recomendado é 13%. nada muda de conclusão, e mesmo assim me deu vergonha, porque é o tipo de erro que eu apontaria num relatório dos outros.
o mais estranho foi o manifest do build em avif, que registra uma fonte de 21 GB. a fonte tem 4. fiquei sem entender até dividir pelo número de cartas: dá o peso de uma imagem descomprimida, que é o que o encoder recebe no meio do caminho. o backend contou o intermediário em vez do jpeg. uma linha pra corrigir, um teste pra escrever, e até lá o ratio daquele manifest era invenção.
e tem o que não dá mais pra verificar. o primeiro build completo eu apaguei quando o disco encheu, então a frase "os três builds compartilham o mesmo hash" hoje tem dois terços conferíveis. o experimento do capcut e a matriz de reprints não deixaram artefato, só texto. eu mesmo mandei apagar, pra liberar espaço. espaço em disco é mais barato que confiança e eu devia saber disso.
as outras vezes que eu li o resumo e não o arquivo
o resumo das 200 cartas. pedi o dataset inteiro, recebi um resumo que falava do corpus como se fosse o corpus, e era um piloto. percebi com reunião marcada. o agente não mentiu, ele resumiu o escopo sem avisar, e eu li o resumo em vez do disco. desde então toda entrega de build vem com a validação do arquivo real, e este post existe pelo mesmo motivo.
os paths da minha máquina. dias depois do benchmark achei o caminho da minha home em dezenas de arquivos que iam pro github, dentro de manifest, lock, spec. o fix foi uma variável de ambiente e um script que reescreve os sidecars antes de commitar. e antes disso o agente tinha querido guardar preferências minhas num arquivo local de memória. pedi pra apagar. se o fluxo depende do que ele lembra da minha máquina, não roda no próximo repo, e não roda na máquina de quem clonar.
o repo de cinco giga. em algum momento perguntei como engenheiro de ml lida com isso, porque o github não aceita. a resposta que eu adotei: nenhum byte de imagem entra no git. cada amostra é uma lista de ids com a regra que gerou ela, e quem tem o sqlite reconstrói a amostra exata. os .nest vão pro hugging face com hash do lado, e o repo guarda o lock, o manifest limpo e o hash. o relatório inteiro é gerado dos json de cada experimento, e um check no ci falha se o markdown estiver diferente do json. eu não consigo mais colar número errado num relatório sem o ci reclamar, o que é o tipo de proteção que eu precisava contra mim mesmo.
os commits. o agente prefere um commit gordo no fim do dia. eu pedi dezesseis, separados, com descrição, porque a história tem que ser legível pra quem chega depois. e os planos: rejeitei três seguidos porque tratavam a comparação de modelos como rodapé de um build já decidido. a lista de modelos que hoje existe no nest só existe porque eu insisti que pesquisa vira feature, nunca rodapé.
o que esses episódios têm em comum é um só: em todos eu aceitei uma camada entre mim e o arquivo. resumo, manifest, memória, commit gordo. e a camada tava errada e não avisou.
o que eu vou tentar da próxima vez
uma coisa que me deixou mais de boa, no meio do validate, foi descobrir que os dois achados que eu mais gostei já tinham nome. a redundância entre imagens de uma coleção, que o inter explora, se chama set redundancy desde uma tese de 1996, e o truque de enfileirar as imagens como pseudo-vídeo tem uma década de literatura. e a distinção entre qualidade visual, estabilidade do vetor e utilidade da busca, que eu achei que tinha inventado, é a área que os padrões chamam de coding for machines, onde "distância no espaço de features não prevê acurácia da tarefa" é resultado conhecido. eu não descobri nada. confirmei duas coisas num corpus onde ninguém tinha olhado, e isso me deixa mais tranquilo pra publicar do que se fosse novidade.
o arquivo de 1,3 GB já está no repo do pasta.cards esperando a tela que vai usar ele. o que falta do benchmark cabe num parágrafo: medir a busca com o wemm, buildar o corpus de reprints inteiro, decidir se o avif vira padrão. nenhuma dessas três tem data marcada.
o que eu vou tentar é o mais barato de tudo: abrir uma sessão limpa como usuário antes de cada release e digitar o primeiro comando do readme. cinco minutos, e achou dois furos que uma semana de agente não achou. não sei se vou lembrar de fazer. mas agora está escrito, e eu confiro mais o que está escrito do que o que eu lembro.