Quase todas as 1.562 linhas de testes do TopicReview foram escritas pelo Claude. Eu só faço a review — já passou de duas semanas em produção, todos os commits posteriores adicionam testes, nenhum os reescreve. Este post trata do porquê os testes são o alvo ideal para delegar, o que olhar e o que ignorar na review (incluindo um edge case real ausente no spec), e a configuração padrão desse reparto.
O post anterior fechou com "119 specs no verde" para TopicReview. A pergunta real que vem a seguir: quem escreveu esses testes?
Resposta: Claude escreveu quase as 1.562 linhas de código de teste. Eu só reviso. Depois de mais de duas semanas em produção, o padrão de manutenção dessas 1.562 linhas tem sido só adicionar novos testes, nunca reescrever os antigos.
Este post trata de por que os testes são o melhor candidato para delegar ao Claude, o que olhar e o que ignorar na review, e até onde esse reparto aguenta na prática.
Os testes do TopicReview estão em 7 arquivos:
spec/services/topic_review_service_spec.rb 760 linhas (88 testes)
spec/requests/topic_reviews_spec.rb 281 linhas (32 testes)
spec/requests/review_appeals_spec.rb 152 linhas (16 testes)
spec/requests/review_votes_spec.rb 127 linhas
spec/policies/topic_review_policy_spec.rb 109 linhas
spec/jobs/close_topic_review_job_spec.rb 71 linhas (7 testes)
spec/models/topic_review_spec.rb 62 linhas
───────────────────────────────────────────
1.562 linhas
Cobre quatro tipos de teste: service (lógica de negócio), request (controller + integração), policy (autorização com Pundit), job (tarefas agendadas).
O commit inicial d162f1e traz Co-Authored-By: Claude Sonnet 4.6 e aterrissa 1.100+ dessas linhas de uma só vez. Todos os commits de spec subsequentes são "Add test for..."—nenhum é refactor ou rewrite:
00393fc Add test for finalize! with zero votes (expired review)
3f53304 Add test for finalize! with legacy votes missing reasoning
3b185da Update specs to use PROVISIONAL_PENALTY constant
Tapando lacunas, não refazendo. Este detalhe volta a importar depois.
Quatro razões sólidas:
1. Entradas e saídas explícitas. Um teste é "dado este estado → esperar este comportamento". É o ponto forte do Claude: traduzir uma especificação para uma asserção. Código de negócio às vezes exige equilibrar trade-offs; testes, quase nunca.
2. Mecânico × alto volume. Um único describe .open! tem que cobrir "com jurados elegíveis / sem jurados / sem topic / review já ativo"—quatro contexts, 2–5 it cada. O humano começa a cortar no terceiro context. O Claude escreve o it número 88 com o mesmo cuidado do primeiro.
3. Ciclo de feedback curtíssimo. Escreve um teste, roda rspec, em segundos sabe se passa. Código de negócio leva dias de uso real para expor problemas. Ciclo curto = qualquer erro do Claude é pego pelo rspec na hora—você não precisa vigiar.
4. Naturalmente paralelo. Os blocos it são independentes, sem acoplamento oculto, escalam trivialmente. Gerar dezenas de testes isolados de uma vez é exatamente o forte do Claude.
Aqui está o pivô do reparto.
Ignorar:
Olhar:
O último item é o valor real da review. O Claude cobre os testes "que ele consegue imaginar", mas os que ele não imagina não se escrevem sozinhos. É exatamente aí que a review humana encaixa—caminhar de trás para frente, das regras de negócio para a cobertura faltante.
Abrir o início do describe ".open!" de spec/services/topic_review_service_spec.rb:
describe ".open!" do
context "when there are eligible jurors" do
# status do review ok / post under_review / assignments criados / author notificado / jurors notificados / não abre duas vezes
end
context "when there are no eligible jurors" do
# review é criado mas assignments não
end
context "when post has no topic" do
# retorna nil
end
end
Parece abrangente. Mas a regra real de eligible_jurors no model exclui três grupos:
def eligible_jurors
excluded_ids = [ post.user_id ] + post.reports.pluck(:user_id) + review_votes.where(stage: :initial).pluck(:user_id)
User.jurors_and_judges.where.not(id: excluded_ids.uniq)
end
Agora olhe os testes—qual teste afirma que "o autor do post nunca é selecionado como jurado"?
Vasculha service_spec.rb e model_spec.rb: não existe. model_spec.rb só testa alguns casos do scope pending_vote_by; não cobre eligible_jurors diretamente. service_spec.rb tem só um comentário: # Jurors must NOT be the post author—é parte do setup, não uma asserção.
É isso que a review pega: três regras de exclusão (autor / denunciante / já-votou-na-fase-inicial), e nenhuma delas está protegida por um teste. Se alguém depois refatorar eligible_jurors e sem querer derrubar post.user_id da lista de exclusão, todos os testes existentes passam—e a produção silenciosamente deixa autores sentarem no próprio júri.
O Claude não errou—testou o que pediram. Só não perguntou por conta própria: "cada uma dessas três regras precisa de cobertura de teste?" Essa pergunta—de regras para cobertura, de trás para frente—é o que a review faz.
(Honestidade: eu mesmo deixei isso passar na review original. Só pesquei numa segunda auditoria enquanto escrevia este post. Então a review também não é one-shot—mas continua sendo 10× melhor do que não revisar.)
Se "Claude escreve + humano revisa" fosse perfeito, não haveria commits de teste novos depois do inicial. O que aconteceu é mais interessante—tapando lacunas sem reescrituras:
00393fc Add test for finalize! with zero votes (expired review)
3f53304 Add test for finalize! with legacy votes missing reasoning
O primeiro é regression test pós-bug—e8cb2db Default to keep verdict when review expires with zero votes foi o fix, 00393fc foi o teste emparelhado. Mesmo padrão para o segundo, seguindo abaa22e Fix CloseTopicReviewJob failing due to reasoning validation on old votes.
Esses dois commits provam duas coisas ao mesmo tempo:
"Bom o suficiente + dá para seguir remendando" é uma régua muito mais realista do que "perfeito". Perseguir review perfeita é o que te impede de delegar testes ao Claude. Aceitar "bom o suficiente" é o que faz o reparto começar a girar.
Nem todo teste serve para handoff total:
Nesses casos, humano lidera e o Claude auxilia.
Para transformar esse reparto em um default executável:
Programadores têm menos energia mental para ler testes do que para ler código. Testes são repetitivos, mecânicos, desgastantes, necessários. Tudo isso descreve o sweet spot do Claude—ele não enjoa, não cansa, não corta caminho no it número 50.
Seu trabalho não é "escrever testes"—é "garantir que toda regra de negócio esteja coberta por um teste". Um é implementação, o outro é julgamento. O julgamento fica com você; a implementação vai para o Claude.
119 specs / 1.562 linhas entregues num commit e sobrevivendo mais de duas semanas sem rework—não aconteceu porque eu escreva melhor testes, mas porque eu não escrevi nenhum. Só faço uma coisa a mais que o Claude: decido quais regras de negócio merecem proteção.