Marquei 96 PRs escritos com IA e contei quantos arquivos voltaram em 90 dias: 33,9% contra 20,8%
Provar que o time entrega mais rápido com IA é a parte fácil da conta. Lead time cai, PR fecha mais cedo, o gráfico fica bonito e a reunião termina em paz. A metade que quase ninguém mostra é a de depois: quantas vezes aquele mesmo arquivo volta para a mesa.
Um post com o título "Velocidade de entrega e custo de manutenção pós IA" juntou 86 reações no dev.to, e a discussão em volta dele anda quase toda em impressão. Resolvi tirar o número de um repositório real. Recebi acesso de leitura a um monolito em TypeScript, uns 130 mil linhas, cinco devs, nove meses de histórico. Segue o método inteiro para você rodar no seu.
A definição operacional
Retrabalho no board é ruim de medir porque depende de alguém abrir o card certo. Fui no git, que ninguém preenche a mão. Um arquivo "voltou" quando ele recebe commit em um PR diferente dentro de 90 dias corridos depois do merge do PR original.
Duas exclusões, porque sem elas o número infla:
- commits de merge e commits cujo diff some com
git show -w, ou seja, formatação e lint que passou por cima do arquivo. - commits do próprio PR que originou a contagem, filtrados pelo(#numero)no assunto do commit de squash.
A marcação de "escrito com IA" veio de uma label que o time já usava desde o piloto de assistente. Onde a label faltava, olhei o trailer Assisted-by: no commit. Isso é autodeclarado, e eu vou voltar nesse ponto no fim.
O script
Primeiro, os PRs mergeados na janela, virando uma linha por par PR/arquivo:
gh pr list --state merged --limit 1000 \
--search "merged:2025-09-01..2026-05-31" \
--json number,mergedAt,labels,files \
> prs.json
jq -r '
.[]
| {n: .number,
d: .mergedAt,
ia: ([.labels[].name] | index("ia-assistida") != null),
f: [.files[].path]}
| .n as $n | .d as $d | .ia as $ia
| .f[] | "\($n)\t\($d)\t\($ia)\t\(.)"
' prs.json > pr_arquivos.tsv
Depois, a contagem de retornos por arquivo dentro da janela de 90 dias:
while IFS=$'\t' read -r pr data ia arq; do
fim=$(date -u -d "$data +90 days" +%Y-%m-%dT%H:%M:%SZ)
voltas=$(git log --no-merges --format=%H \
--since="$data" --until="$fim" -- "$arq" \
| while read -r sha; do
git show -w --format= --stat "$sha" -- "$arq" | grep -q '|' || continue
git log -1 --format=%s "$sha" | grep -q "(#$pr)" && continue
echo "$sha"
done | wc -l)
printf '%s\t%s\t%s\t%s\n' "$ia" "$pr" "$arq" "$voltas"
done < pr_arquivos.tsv > reincidencia.tsv
E a agregação, que é onde a discussão começa de verdade:
$ awk -F'\t' '{g[$1]++; if($4>0) r[$1]++}
END{for(k in g) printf "%s\t%d\t%d\t%.1f%%\n", k, g[k], r[k], 100*r[k]/g[k]}' \
reincidencia.tsv
true 271 92 33.9%
false 308 64 20.8%
214 PRs mergeados na janela, 96 deles marcados. 271 pares PR/arquivo do lado da IA, 308 do lado sem marcação. Perto de um terço dos arquivos tocados por PR assistido recebeu mudança de novo em até 90 dias, contra uns 21% do outro grupo.
O segundo número me interessou mais que o primeiro. A mediana de dias até a primeira volta foi 11 no grupo com IA e 27 no grupo sem. O arquivo não volta um trimestre depois com uma feature nova, ele volta na quinzena seguinte.
O que esse número não prova
Aqui a honestidade custa barato e vale a leitura.
O time não sorteou onde usar o assistente. Ele usou onde parecia mais rápido usar, e isso quer dizer arquivo movimentado, controller grande, serviço que todo mundo já mexe toda semana. Arquivo quente volta mais, com IA ou sem. Rodei de novo restringindo aos 137 arquivos que aparecem nos dois grupos, e a diferença caiu para perto de 7 pontos em vez de 13. Continua existindo, ficou bem menor.
A marcação também é frouxa. Ninguém abre PR dizendo "aqui eu colei o que o modelo escreveu e não reli". Se a subnotificação for grande, parte do grupo false está no lugar errado, e o efeito real fica maior do que o medido, não menor. Não tenho como separar isso com o dado que eu tinha.
E a janela de 90 dias mistura correção com evolução. Tentei separar por título de PR começando com fix, e desisti: no repositório, fix e chore são escolhidos por hábito de cada dev, não por critério. Se você tiver convenção de commit levada a sério, esse recorte melhora bastante a medição, e é o que eu faria primeiro no seu lugar.
O que mudou na prática
Tirei uma coisa só desse trabalho, e é chata de defender em reunião: velocidade de escrita virou métrica sem par. Ela só quer dizer alguma coisa ao lado da taxa de retorno do arquivo em 90 dias.
O time passou a rodar o script uma vez por mês e a olhar uma lista curta, os arquivos que voltaram duas vezes ou mais na janela. Esses saíram do fluxo normal de review. Ninguém aprova por leitura de diff ali, o revisor abre o arquivo inteiro e roda o caso de uso na mão. É o mesmo princípio da solda que volta para ensaio uma segunda vez: a terceira você não confia mais no relatório, você vai olhar.
O custo total foi de uns dois fins de semana montando isso, e a maior parte foi entender por que o git show -w estava deixando passar commit de lint. O script acima já está com essa correção.
Se você tem repositório com marcação de PR assistido, roda aí e comenta o par de números. Quero saber principalmente de quem mediu e achou o contrário, porque uma amostra de 214 PRs em um repositório só não decide nada. E se você separou correção de evolução com convenção de commit, me conta como ficou o recorte.
Fonte do raciocínio de fundo sobre o que medir quando o volume de código sobe e a entrega fica parada: https://revin.com.br/pt/blog/mais-codigo-menos-produto-ia-o-que-medir