Por que o inventário do código não pode ser escrito por um LLM

Mesmo código, três contagens diferentes. O que muda quando o denominador vem de Git e parser, e não de um modelo.

Antes de planejar qualquer teste, um sistema de QA precisa saber o que existe no alvo: quais rotas, quais funções, quais arquivos. Se essa lista muda a cada execução, tudo o que vem depois (plano, cobertura, decisão de release) é construído em areia. No QAOS, a lista é chamada de inventário, e ele não pode ser escrito por um modelo de linguagem.

Mesmo repositório, três respostas

Numa medição interna de 20 de setembro de 2026, o QAOS leu três vezes o mesmo repositório de exemplo (o petclinic, um projeto Java open source) com a enumeração feita pelo Code Reader. O modelo listou 33, 39 e 17 funções. Mesmo código, mesmo prompt, três denominadores diferentes.

O problema não era só o número. Com a lista variando, o Test Planner chegou a enviar controllers que não eram isoláveis para o teste unitário. Cobertura calculada sobre uma lista instável não é cobertura: é opinião com casas decimais.

Regra: o que o modelo escolhe listar não fixa o denominador. Quem fixa é o código.

O universo vem do Git, não do modelo

O inventário parte de git ls-files: todo arquivo versionado entra na conta. Cada um termina de duas formas, lido ou não lido com caminho e motivo fechado. O texto enviado ao modelo e o inventário saem do mesmo clone, então não há como divergirem.

Parser lê o código, modelo interpreta

Para Python, a extração usa ast. Para Java, tree-sitter-java. Em nenhum dos casos o QAOS importa ou executa o código do alvo dentro da API; ele só o analisa.

O Code Reader continua existindo, mas com outro papel: recebe referências numeradas e interpreta o que cada trecho faz. Uma guarda em código reconstrói método, caminho, assinatura, visibilidade e status a partir do parser. Se o modelo citar um endpoint ou uma função que o parser não encontrou, o item é descartado.

Antes

O modelo escolhia o que listar. A contagem variava entre execuções e o plano herdava a variação.

Agora

O parser fixa a lista. O modelo só acrescenta interpretação, e o que ele inventa é descartado.

Arquivo não lido tem motivo

Nem todo arquivo vale ser enviado ao modelo: lockfiles, licenças, código gerado e arquivos enormes só gastam contexto. Mas “deixar de fora” não pode significar “esquecer”. Esses arquivos continuam no inventário, marcados como não lidos, com um motivo de uma lista fechada: por exemplo asset, lockfile, licenca, gerado ou acima-de-500kb. A decisão sai só do caminho no índice, sem abrir o arquivo.

O inventário também publica o commit e um digest do estado analisado. Dois inventários só são comparáveis se o formato for o mesmo, e o sistema versiona isso.

Quem confere o inventário

Um script verificador independente, fora do caminho principal, confere o JSON contra o Git, contra um segundo parser Python (tree-sitter-python), contra o bytecode Java (javap) e contra as rotas do framework quando há referências disponíveis. O bytecode ficou de fora do produto de propósito: obrigaria a API a compilar o alvo, com JDK, dependências e rede.

O mesmo critério vale para medir estabilidade. O comparador do portão de qualidade exige inventário disponível e igual nas três execuções; o que variar de interpretação aparece como dispersão, não como acordo.

Limites que o sistema declara

  • Autenticação e pureza de uma função continuam sendo interpretação do modelo, e são rotuladas assim onde aparecem.
  • O formato de resposta de um endpoint fica nulo nas stacks com parser: uma linha literal não prova a semântica do formato.
  • Stacks sem parser usam a origem modelo e declaram que a garantia de inventário determinístico não existe ali.

É a mesma regra do resto do produto: onde não há fato, o sistema diz que não há.

Quer ver o QAOS rodando no seu sistema? Conte o seu cenário e a gente mostra o fluxo completo.

Falar com a NoirCode ↗