autoFixable: transformei 30 min de bate-e-volta em revisão de código em 47 segundos
O comentário chegou às 15h47 de uma terça-feira. “nitpick: import não usado no arquivo user-service.ts”. O autor do PR estava em reunião. Voltou às 16h12, viu o comentário, tirou o import, subiu novo commit. O CI rodou de novo por 8 minutos. O revisor (eu) só notou às 16h34, aprovou, mergeu.
Da abertura do comentário ao merge: 47 minutos. O trabalho de fato: apagar uma linha.
Eu já sabia que isso era ridículo faz uns dois anos. Todo mundo sabe. Mas a gente sempre trata como um problema de disciplina — “revisor, seja mais rápido”, “autor, verifique antes de abrir PR” — quando na verdade é um problema de classificação. Existem coisas em código review que não deveriam ter comentário nenhum. Elas deveriam ter um commit.
O padrão que peguei do Capítulo 12 do meu book de code review chama isso de autoFixable. Depois de aplicar por dois meses no time, o mesmo tipo de correção que levava 30-47 minutos agora leva 47 segundos. Só que aí apareceu um problema novo que eu não tinha previsto. Vou contar essa parte também.
O que é autoFixable, na prática
A ideia é simples e chata: separar as coisas que uma máquina pode arrumar sem consultar ninguém, das coisas que precisam de julgamento humano. Em vez de comentar “tira esse import”, você deixa o pipeline aplicar eslint --fix e commitar.

A tabela que uso no time, resumida:
| autoFixable (a máquina resolve) | non-autoFixable (humano decide) |
|---|---|
| Formatação (Prettier / Biome) | Desenho de arquitetura |
Lint auto-corrigível (eslint --fix) | Correção de N+1 |
| Ordenação de imports | Nome de variável ou função |
| Remoção de imports não usados | Bug de lógica |
| Cast redundante que TypeScript infere | Regra de negócio |
O critério é meio brutal: se existe uma resposta única e mecânica, não é um comentário, é um commit. Se existe mais de uma resposta razoável, aí sim precisa de humano.
O workflow que eu subi (e que quase quebrou)
Meu primeiro workflow foi ingênuo. Um GitHub Action que rodava a cada PR aberto, aplicava Prettier + ESLint —fix, e commitava direto no branch do PR.
# .github/workflows/auto-fix.yml
name: Auto Fix
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: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- name: Format
run: npx 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: auto-fix format and lint issues"
)
Rodou lindo por três dias. No quarto dia, um dev do time abriu um PR de refatoração grande, o Action commitou 400 linhas de reformatação em cima, e a diff dele virou uma sopa. Quando ele foi rebasear, teve conflito com o próprio commit dele. Ficou puto (com razão).
A lição foi que autoFixable precisa acontecer ANTES do PR, não depois. Movi o mesmo lint para um pre-commit hook local + uma checagem gate no CI. O CI não fixa mais, ele só bloqueia o merge se algo autoFixable ainda passar. Isso muda todo o equilíbrio: o autor conserta na hora localmente, o revisor nunca vê o problema, o histórico do PR fica limpo.
Se você já leu documentação sobre Claude Code hooks, esse é exatamente o padrão que a Anthropic recomenda para PostToolUse — deixar biome check --write rodar depois de cada Edit do agente. Junto com um pre-commit hook local, dá para nunca gerar um commit sujo pra começar.
O que mudou nos números do time
Peguei 40 PRs antes de subir o padrão e 40 depois. Contei só os comentários puramente autoFixable (formatação, import não usado, ordenação, e afins). Ignorei bugs, decisões de nome, etc.
| Métrica | Antes | Depois |
|---|---|---|
| Comentários autoFixable por PR (mediana) | 4 | 0 |
| Tempo de fluxo autoFixable (mediana) | 32 min | 47 seg |
| Rodadas de CI por PR (mediana) | 3 | 2 |
| PRs bloqueados > 24h por nitpick | 6 / 40 | 0 / 40 |
O número que me impressionou não foi o tempo. Foi o 6 PRs bloqueados por mais de 24 horas por causa de nitpick. Um sexto do backlog do time estava esperando um humano tirar um import { useState } que ninguém usava. Multiplique isso por 12 devs e você tem sua estimativa de trimestre queimada em bikeshedding.

O problema novo que apareceu
Aqui vem a parte que ninguém conta.
Quando você tira todo o nitpick da revisão, sobra só o que exige julgamento. E aí acontece uma coisa engraçada: os revisores começam a se sentir inseguros. Um revisor experiente do meu time, que revisava 8 PRs por dia sem suar, veio me falar depois de duas semanas: “eu acho que estou revisando pior. Antes eu sempre tinha algo pra apontar. Agora eu leio o PR, não vejo nada, e me sinto mal aprovando”.
O que ele estava sentindo era o fim do teatro de revisão. Metade dos comentários de “nitpick” que a gente escreve não é sobre o código. É sobre provar que a gente leu. Quando o autoFixable tira 4 dos 5 comentários possíveis, sobra 1 comentário real por PR, ou zero. E aí “aprovar sem comentar” começa a parecer displicência, mesmo quando é a resposta correta.
Resolvi com dois combinados no time:
- Ficou combinado escrever “revisei, sem observações” em vez de só clicar em Approve. Textualmente. Faz diferença cultural.
- Nas 1 da retrospectiva, o “comentário-métrica” foi aposentado. Ninguém mais é medido por quantidade de comentários por PR. Só por defeitos que apareceram em produção depois de aprovado.
O segundo item foi mais difícil que o primeiro. Empresas gostam de contar coisas. Contar comentários de revisão é fácil. Contar julgamento é difícil.
CodeRabbit e o batch apply do GitHub
Se você usa CodeRabbit, tem um plus interessante. O CodeRabbit gera as sugestões como blocos aplicáveis nativos do GitHub, então o revisor (ou o autor) clica em “Apply suggestion” e vira commit sem tocar em nada.
Em março de 2026 o GitHub liberou o batch apply de Code Quality suggestions, e em abril fez o mesmo para alertas de code scanning. Isso mudou a economia do padrão: em vez de aplicar 15 sugestões uma por uma, você seleciona todas e vira um único commit. É o mesmo padrão autoFixable, só que com o humano puxando o gatilho em vez do CI.
Eu ainda prefiro o pre-commit hook, porque prevenir é mais barato que remediar. Mas para times que já operam com CodeRabbit no fluxo, batch apply é uma boa evolução incremental — você não precisa mexer no pipeline de CI, só ativa e pronto.
A linha que eu não cruzo
Vale falar o contrário também. Não é que “tudo que dá pra automatizar, deve ser automatizado”. Duas coisas eu deixei explicitamente fora do autoFixable, mesmo que ferramentas modernas consigam fazer:
Rename automático. Ferramentas como TypeScript LSP fazem rename com segurança em cima do grafo de símbolos. Mas rename é uma decisão. Se um campo se chama user_id e o linter sugere userId, isso pode estar certo tecnicamente e errado semanticamente — se aquele campo veio de uma API externa que devolve snake_case, o rename cria um bug sutil. Deixei rename como sugestão manual, nunca no CI.
Remover código morto. Analisadores estáticos (dead-code-elimination do Rollup, ts-prune, etc.) apontam código não referenciado. Mas “não referenciado no grafo de imports” não é o mesmo que “não usado”. Um export pode ser consumido por um pacote externo, por reflexão, ou por um build tool específico. Deixei código morto na categoria non-autoFixable também.
O critério na dúvida: se o pior caso do fix errado é um bug em produção, não é autoFixable. Fim.
Resumo do que sobrou
- Formatação, lint, ordenação de imports, remoção de imports não usados: pre-commit hook local + gate no CI. Zero comentário de revisão sobre isso.
- Decisões de nome, arquitetura, N+1, regra de negócio: revisor humano, como antes.
- Rename e remoção de código morto: manual, sob julgamento.
O impacto no time foi menos “economizamos tempo” e mais “paramos de discutir coisas que ninguém queria discutir”. O número que mais importa não é o 47 segundos. É o fato de que ninguém no time mais reclama de code review sendo lento por causa de bobagem. Sobrou só a discussão que valia a pena.
E, honestamente, o problema secundário — revisor se sentindo inseguro quando não tem o que comentar — vale meses de debate cultural. Se você adotar o padrão, prepare a retro seguinte pra falar sobre isso. Não tira nem coloca linha de código, mas ajuda o time a não recuar por reflexo.
ken imoto · WebRTC & Voice AI engineer · kenimoto.dev · TabNews
Este artigo foi útil?