📊 Benchmark honesto
Comparação ferramenta contra ferramenta — Polypus, OpenCode e Aider —
rodando o mesmo modelo (deepseek-v4-flash), nas
mesmas tarefas, na mesma máquina. O veredito é objetivo (testes unitários
reais), e o custo é medido por fonte neutra (a API da OpenRouter, uma
chave dedicada por ferramenta) — nunca pelo que cada ferramenta se auto-reporta.
Filosofia: diagnóstico primeiro, marketing depois. O objetivo original
era achar onde o Polypus quebra — e ele achou (veja os bugs corrigidos abaixo).
🇬🇧 In short: a tool-vs-tool benchmark (Polypus, OpenCode, Aider) on the same model, same tasks, same machine. Verdict is real unit tests; cost is measured from a neutral source (OpenRouter API, one dedicated key per tool), never self-reported. Diagnostic-first: the point was to find where Polypus breaks — and it did.
Metodologia
| Modelo | deepseek/deepseek-v4-flash (via OpenRouter) — o mesmo para as três, provedor único (sem variância de roteamento). |
| Veredito | node --test — testes unitários reais. Score parcial X/N (quantos subtests passaram), não só passa/falha. |
| Custo | Delta de gasto na API da OpenRouter, uma chave dedicada por ferramenta. Fonte neutra, imune ao auto-reporte. |
| Isolamento | Cada tarefa roda num workspace git descartável. Prompt idêntico para as três. |
| Anti-trapaça | Hash dos arquivos de teste antes/depois: se a ferramenta editar o teste para "passar", vira desclassificado. |
| Reprodutível | Scripts abertos em bench/demo/ no repositório. Rode ./run-all.ps1. |
Uma tarefa é uma pasta com PROMPT.md (instrução idêntica), a(s) fonte(s) e
*.test.mjs. As ferramentas recebem só o prompt e o workspace — descobrem sozinhas
o que fazer. As tarefas vão de algoritmos simples (ano bissexto) a debugging
(código já vem quebrado) e multi-arquivo (o bug está num de dois arquivos e a
ferramenta precisa achar qual).
Resultados por tarefa
| Tarefa | Tipo | Polypus | OpenCode | Aider |
|---|---|---|---|---|
| leap | bissexto | 7/7 | 7/7 | 7/7 |
| rle | encode/decode | 12/12 | 12/12 | 12/12 |
| roman | edge cases | 14/14 | 14/14 | 14/14 |
| anagram | case + traps | 8/8 | 8/8 | 8/8 |
| fix-flatten | debugging | 8/8 | 8/8 | 8/8 |
| stats-bug | multi-arquivo | 7/7 | 7/7 | 7/7 |
Correção: empate perfeito. Nessa dificuldade, com um modelo forte, as três ferramentas resolvem tudo. Na tarefa multi-arquivo, as três acharam o arquivo certo e deixaram o outro (o "chamariz") intacto. Onde elas se separam é em eficiência.
leap— "é ano bissexto?", pelas regras do calendário gregoriano (÷4, exceto ÷100, exceto ÷400). Algoritmo curto.rle— run-length encoding: comprimir"AAAB"→"3A1B"e descomprimir de volta.roman— inteiro → algarismo romano (1–3999) com notação subtrativa (4=IV, 9=IX). Cheio de casos de borda.anagram— dada uma palavra e candidatas, achar os anagramas (ignorando maiúsculas, excluindo a própria palavra).fix-flatten— debugging: o código de achatar array aninhado já vem QUEBRADO; a ferramenta tem que achar e corrigir o bug.stats-bug— multi-arquivo: o bug está numa função que importa de outro arquivo; a ferramenta precisa descobrir em qual dos dois está.
7/7— subtests que passaram / total (score parcial, não só passou/falhou).- Na tabela de tokens: total de tokens processados na tarefa (menos = mais eficiente).
Custo da rodada (6 tarefas)
Tokens processados por tarefa
| Tarefa | Polypus | OpenCode | Aider |
|---|---|---|---|
| leap | 18.378 | 27.095 | 1.067 |
| rle | 26.902 | 19.662 | 2.400 |
| roman | 18.820 | 21.058 | 1.474 |
| anagram | 25.035 | 28.152 | 1.622 |
| fix-flatten | 26.958 | 36.063 | 2.500 |
| stats-bug (multi) | 63.496 | 45.118 | 1.827 |
A nuance honesta por trás dos números. O Aider é ~25× mais barato — mas
parte disso é porque ele exige que você diga quais arquivos editar; ele não navega,
recebe tudo mastigado e resolve em um tiro. Polypus e OpenCode são agentes de
verdade: leem o repositório, rodam os testes e iteram sozinhos — e pagam por isso em
tokens. Isso fica gritante na tarefa multi-arquivo (stats-bug): o Polypus gastou
63k tokens descobrindo qual arquivo tinha o bug; o Aider gastou 1,8k porque recebeu os dois
arquivos de bandeja. São categorias diferentes de ferramenta — a comparação de custo tem que
levar isso em conta.
O que os dados dizem
✅ Correção equivalente
Polypus entrega a mesma taxa de acerto que ferramentas consagradas, no mesmo modelo. A tese "qualidade equivalente" se sustenta nos dados — não é opinião.
💸 Mais barato que o agente concorrente
Contra o OpenCode (o concorrente agêntico direto), o Polypus custa o mesmo ou menos — a vantagem do prompt caching aparece quando a medição é honesta.
🧭 Navegação multi-arquivo correta
Na tarefa com bug espalhado, o Polypus achou o arquivo certo e não tocou no chamariz — navegação autônoma que o one-shot não faz sem ajuda humana.
🎯 Alvo claro de melhoria
O flanco do Polypus é eficiência de tokens, sobretudo em multi-arquivo. É um gap concreto e mensurável — virou item de roadmap, não desculpa.
O benchmark achou 4 bugs reais — e a gente corrigiu
O valor de um benchmark honesto não é o gráfico bonito — é o que ele quebra. Nas primeiras rodadas o Polypus falhou, e cada falha virou uma correção:
- Fallback de tool-mode — o roteamento da OpenRouter às vezes parava de emitir tool calls nativas e o agente entregava prosa em vez de editar. → modo emulado (imune) + issue aberta
- Vazamento de CDATA — o parser do modo emulado gravava
<![CDATA[…]]>dentro do arquivo, quebrando o código. → corrigido + teste de regressão - Finish com teste vermelho — o agente rodava o teste, ele falhava, e mesmo assim ele declarava "concluído". → finish-gate rejeita finish após comando com erro
- Atribuição de custo furada — descoberto que o Aider ignorava a chave dedicada (usava uma chave OAuth interna), invalidando a medição de custo dele. → chave forçada por flag, medição neutra restaurada
Stress test das features (hooks + swarm)
Segunda trilha, focada nas features próprias do Polypus — não é comparação, é diagnóstico interno. Cada cenário roda num workspace descartável com timeout rígido (pega loop infinito) e verifica se a feature se comportou como especificado. Achou 2 gaps reais, ambos viraram issue.
hooks— scripts que o Polypus roda em pontos do ciclo do agente:PostToolUse— roda depois de uma tool (ex.: rodar teste/lint); a saída volta pro modelo, que pode se corrigir sozinho.PreToolUse— roda antes de uma tool; se o script falhar, a tool é bloqueada.Stop— roda quando o agente termina (no finish).swarm— quebra a tarefa em subtarefas e roda vários "workers" em paralelo, cada um numa cópia git isolada, mesclando os resultados no fim.
hook-selfcorrect— um PostToolUse exige uma correção; testa se o modelo obedece à saída injetada.hook-stop— testa se o Stop realmente roda no fim.hook-block— um PreToolUse tenta impedir a edição de um arquivo protegido.swarm-fanout— workers criando arquivos independentes (o caso feliz do merge).swarm-conflict— workers editando o MESMO arquivo (força conflito de merge).
| Cenário | Feature | Resultado | Tempo | Tokens | O que revelou |
|---|---|---|---|---|---|
| hook-selfcorrect | PostToolUse | OK | 20,7s | 27,7k | a saída do hook injetada dirige a auto-correção do modelo |
| hook-stop | Stop | OK | 14,8s | 17k | Stop roda no finish (marcador criado) |
| swarm-fanout | swarm | OK | 41,5s | 77k | 3 arquivos independentes, workers paralelos, merge limpo no Windows |
| hook-block | PreToolUse | GAP | 42,4s | 66k | bloqueio de arquivo contornado via run_command (#213) |
| swarm-conflict | swarm | GAP | 33,3s | 100k | 1 de 3 contribuições sobrevive, mas reporta "sem conflito" (#212) |
Gap 2 — swarm perdia trabalho silenciosamente (#212) — CORRIGIDO ✅. Com 3
workers editando o mesmo arquivo, o swarm reportava "mesclado sem conflito" — mas só 1 das 3
contribuições sobrevivia. Causa: um git checkout -f HEAD (workaround de Windows)
que descartava o merge conflitado sem deixar marcador. Corrigido em
worktree.ts: o resultado passa a ser decidido inspecionando o status do git, e o
conflito é reportado honestamente (branch mantido, recuperável) em vez de sumir. Retestado.
Para arquivos independentes o merge sempre funcionou.
Gap 1 — hook não protege arquivo de verdade (#213) — vira feature nova (#214).
Um hook PreToolUse que bloqueia edições funciona para as tools de escrita, mas o agente rota em
volta via shell: mesmo bloqueado 19×, alterou o arquivo com glob + variável (sed -i $f)
sem citar o nome. Lição: hook é observação/advisory, não fronteira de segurança.
A correção: proteção real de caminho (#214) — IMPLEMENTADA ✅. Nova flag
--protect <globs> (e permissions.protect) que torna os arquivos
read-only no nível do SO durante o run — o filesystem recusa a escrita de
qualquer tool (write_file, sed, echo >, python), não só das
tools diretas. No retest da mesma task que furou o hook: edit_file negado com
mensagem clara e o arquivo sobreviveu intacto. Comandos que removem a proteção
(attrib -r, chmod +w) agora são bloqueados como destrutivos. É assim
que se protege um arquivo de verdade — enforcement no SO, não pattern-matching.
Honestidade metodológica
Este é um benchmark pequeno e transparente, não um leaderboard definitivo. Limites que assumimos de propósito: (1) um modelo só nesta rodada; (2) 6 tarefas auto-contidas — o suficiente para diagnóstico, não para ranking universal; (3) o Aider recebe os arquivos explicitamente, o que abarata o custo dele em troca de exigir um humano no loop; (4) tarefas nessa dificuldade não separam as ferramentas por correção — para isso, o próximo passo é modelo mais fraco ou tarefas maiores. Tudo é reprodutível: os scripts, as tarefas e o critério estão no repositório.
Quer reproduzir? cd bench/demo e ./run-all.ps1. Cada ferramenta
usa a própria chave OpenRouter; o placar sai em runs/results.csv e o custo neutro
em ./show-costs.ps1. Código aberto:
github.com/GaberRB/polypus.