Padrão autoFixable: 0 revisões humanas de lint em 3 meses
Sobre os números deste texto. O padrão autoFixable vem do capítulo 12 do meu livro sobre code review com harness. Os cenários, as porcentagens e os tempos aqui são um exemplo trabalhado para mostrar o mecanismo, e não medição de um time em produção. Meça no seu repositório antes de adotar qualquer número daqui.
Vou começar pelo alvo: em um time que aplica o padrão por alguns meses, o número de comentários de revisão humana sobre lint, formatação, import não usado, ordem de imports, semicolon esquecido tende a zero.
Zero na contagem absoluta, não na média. Dá para conferir isso no seu repositório puxando o export de comentários do GitHub via API e filtrando por regex (no-unused-vars|prefer-const|@typescript-eslint/|prettier/|semi|import/order).
Esse tipo de comentário costuma responder por um terço do total de revisões humanas em PRs. Ele some, e não porque a revisão parou. Ele some porque o harness corrige antes do humano ver.
Este post é sobre como cheguei nesse número, o que quebrei no caminho, e uma opinião que vai contra o discurso da bolha: revisão humana ainda serve. Só serve para uma coisa diferente do que você acha.
O padrão em 3 linhas
O harness roda em três etapas antes de qualquer humano encostar no PR:
- pre-commit local: Biome (ou ESLint —fix + Prettier) aplica todas as correções
safeFixno arquivo antes do commit sair da máquina do dev - GitHub Actions no
pull_request: mesma coisa roda de novo em CI, commita direto no branch do PR se ainda restou algo, e roda testes só depois - CodeRabbit no PR: sugere correções
unsafeFixcomo suggestion blocks que o autor aplica com 1 clique
Se o comentário conseguiu chegar a um humano, é porque a máquina já disse “isso aqui eu não sei arrumar sozinha”. E aí a decisão volta a ter valor.

Por que o Biome mudou a matemática
Quando comecei a testar, em fevereiro, ainda estava rodando ESLint + Prettier separados via Husky. Funcionava. Mas cada commit levava uns 4-6 segundos só para o hook rodar em ~200 arquivos TypeScript, e cerca de 15% dos erros do ESLint eram --fix incompatíveis (regras que dizem “arruma X” mas não sabem como escrever X sem quebrar Y).
Em março troquei para Biome v2. Três coisas importantes mudaram:
Autofix reliability. Biome tem hoje ~500 regras e distingue explicitamente safeFix (mudança semanticamente equivalente) de unsafeFix (pode mudar comportamento). No pre-commit rodo só as safe. As unsafe entram via CodeRabbit suggestion, o autor decide.
Velocidade. O pre-commit hook baixou de 4-6s para uns 300-400ms no mesmo repositório. Isso importa: quando o hook demora mais que 2 segundos, o dev começa a rodar git commit --no-verify “só uma vez, é urgente”. Aí o padrão morre.
Cobertura. Biome cobre ~80% das configs comuns de ESLint, com gaps conhecidos em jsx-a11y, alguns edge cases de import/order e regras que dependem de type information do TypeScript. Para lint puro de estilo e correção mecânica, os 80% que ele cobre são exatamente o que estava gerando comentário humano.
Se você está em Python ou Rust, a mesma lógica vale com Ruff e Clippy. O ponto não é a ferramenta específica. É a garantia de que o autofix não vai produzir código quebrado. Sem essa garantia, o time perde confiança e volta a comentar manualmente por medo.
O biome.json que eu uso hoje
Direto do repositório principal, sem invenção:
{
"$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noExplicitAny": "error"
},
"correctness": {
"noUnusedImports": "error",
"noUnusedVariables": "warn"
}
}
},
"organizeImports": { "enabled": true }
}
Roda tudo com um comando:
biome check --write .
--write aplica só safe fixes. Para incluir as unsafe, --write --unsafe, mas isso eu NUNCA rodo em CI. Só localmente quando quero fazer um sweep manual.
O hook pre-commit (lefthook)
Trocamos Husky por lefthook porque paraleliza. Em repositórios com 300+ arquivos alterados num rebase, faz diferença.
# lefthook.yml
pre-commit:
parallel: true
commands:
biome:
glob: "*.{js,ts,jsx,tsx,json}"
run: npx biome check --write --no-errors-on-unmatched {staged_files}
stage_fixed: true
biome-format:
glob: "*.{js,ts,jsx,tsx,json,md}"
run: npx biome format --write {staged_files}
stage_fixed: true
O detalhe importante é stage_fixed: true. Sem isso, o hook corrige o arquivo mas não faz git add do resultado, aí o commit sai com a versão errada e o dev pensa que o hook está bugado. Perdi 2 horas descobrindo isso.
O GitHub Actions que fecha o loop
O hook local não é suficiente. Sempre tem o dev que instala Husky/lefthook mas por algum motivo pulou uma configuração. Ou o hook falhou silenciosamente. Ou o --no-verify aconteceu. O CI é a rede de segurança:
# .github/workflows/autofix.yml
name: autofix
on:
pull_request:
types: [opened, synchronize]
jobs:
autofix:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
token: ${{ secrets.GITHUB_TOKEN }}
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- name: Biome check --write
run: bunx biome check --write .
- name: Commit if changed
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git diff --quiet || (
git add -A &&
git commit -m "chore: autofix via biome" &&
git push
)
E o mais importante: os testes rodam num job separado que depende deste. Se autofix commitou algo, os testes rodam contra o código já corrigido. Se não commitou, roda contra o commit original. Nunca acontece de o teste passar num código pré-fix e falhar depois no main.
O 34% que sumiu, distribuído
Antes do padrão entrar, os 34% de comentários humanos de lint se distribuíam mais ou menos assim:
| Categoria | % dos comentários humanos | Onde vai agora |
|---|---|---|
| Formatação (espaço, quebra) | 12% | Biome formatter safeFix |
| Imports não usados | 8% | Biome noUnusedImports safeFix |
| Ordem de imports | 5% | Biome organizeImports |
prefer-const, no-var | 4% | Biome safeFix |
| Semicolon / trailing comma | 3% | Biome formatter |
any explícito | 2% | Biome noExplicitAny (error, quebra CI) |
Nada disso justifica tempo de humano. Nada disso justifica esperar o autor voltar da reunião. Cada um destes casos hoje ou é corrigido antes do commit sair, ou é bloqueado no CI antes do PR ser considerado revisável.
O efeito colateral: revisão humana ficou mais difícil
Aqui é onde o discurso “automatize tudo” quebra na prática. Quando você elimina os 34% de comentários fáceis, os 66% que sobram ficam concentrados em decisões de design, contratos de API, nomes de coisas, tratamento de erro em bordas do sistema.
Todo comentário humano agora é caro. Todo comentário exige que eu leia o código de verdade, não só o diff. Todo comentário custa uma pergunta genuína ao autor, e ele custa uma resposta que não cabe em uma linha.
Meu tempo médio revisando um PR subiu de 8 minutos para 22 minutos. E isso é ótimo. Antes eu estava gastando 8 minutos para deixar 4 comentários de estilo. Agora gasto 22 minutos para deixar 1 comentário de design que muda como duas classes conversam entre si.
A revisão humana não morreu. Ela ficou com o trabalho que sempre foi dela e nunca deveria ter sido misturado com o resto.
Contrarian: pare de dizer “revisão humana é obsoleta”
Vejo isso o tempo todo em thread de X e no TabNews: “IA vai substituir code review”. Não vai. IA (via CodeRabbit ou similar) substitui o subconjunto mecânico que a gente sempre soube que era mecânico. O que sobra é o pedaço que exige entender o problema de negócio, o histórico do sistema, e o que o próximo dev que ler esse arquivo em 6 meses vai pensar.
Nada disso está resolvido nem com Claude Opus 4.7 nem com GPT-5. Os dois são bons em detectar bug óbvio e ruins em explicar por que a escolha de arquitetura X está incoerente com uma decisão registrada num ADR de 2024 que ninguém indexou. Isso continua sendo humano, e é para onde o tempo de revisão deveria ir.
Se você quer o pipeline completo (o Capítulo 12 tem toda a matriz autoFixable / non-autoFixable e as regras para timing de merge), escrevi um book sobre isso — está no Kindle BR. Mas o padrão em si você pode aplicar amanhã com um biome.json, um lefthook.yml e o Actions acima. É basicamente o que fiz, e o resto veio pelo hábito.
Se quiser um passo anterior (revisar código com IA sem passar por IA no primeiro filtro), escrevi antes sobre revisão de código com Tree-sitter antes do LLM — o padrão autoFixable encaixa na saída dele. E se você quer o compartimento adjacente (o mesmo padrão, mas medindo tempo em vez de contagem de comentários), já contei essa história em autoFixable: 30 min em 47 segundos.
Zero revisão humana de lint, e o tempo de PR concentrado na parte que exige julgamento. Se o seu time ainda comenta manualmente remove esse import, você está pagando salário sênior por trabalho de máquina.
ken imoto · WebRTC & Voice AI engineer · kenimoto.dev · TabNews
Livro relacionado Revisão de Código com Harness Engineering Revisão de código em três camadas | hooks + IA + humano · AGENTS.md · CodeRabbit · GitHub Actions Ver a página do livro → Este artigo foi útil?