Lição 8 de 13: Fechar o loop de verificação
- Um check rodável definido para a fatia 1 (o pass/fail da sua stack + 1 teste novo verde)
- Um prompt que exige o check e mostra evidência (output, não "feito")
- Um teste que FALHA reproduzindo um bug, depois fica verde (TDD com agente)
- O Stop hook
run-check-if-changed.shdo starter confirmado e entendido - Critério pessoal de quando subir um degrau (prompt → /goal → Stop hook → revisor)
O Claude para quando parece pronto
Na L06 você instalou um evento rastreado, um sinal de que alguém atravessou o produto. Esta lição é sobre o sinal análogo durante o desenvolvimento: como o Claude sabe que terminou a tarefa direito, e não só que ela parece terminada.
A documentação da Anthropic descreve o problema de forma exata:
"Parece pronto" é um juízo visual. Compila? Não dá pra saber só olhando. O teste novo passa? Também não. Quando você não dá um check, o trabalho de verificar recai inteiro sobre você: relendo cada diff, rodando a app na mão, conferindo se aquela função existe. Na L01 você aprendeu a revisar uma saída do Claude antes de aprovar, sem aceitar "parece certo" como prova. Esta lição é o passo seguinte: parar de ser você o loop e instalar um check que fecha o loop sem você.
O check é qualquer coisa que devolva um sinal que o Claude lê na conversa. Vale pra qualquer stack, não só JS: uma suíte de testes, o exit code de um build, um linter, um pytest que valida o schema de um scraper, um assert que confere que a soma das partes bate com o total, ou um screenshot de browser comparado com um design. Onde estiver escrito npm run build ou npm run check nesta lição, leia "o comando que devolve passou/falhou na sua stack": pytest, ruff check, tsc, o que for. O método é o mesmo; só o comando muda.
A escada de quatro degraus
Existe o check, e existe quão forte ele trava a parada. A documentação organiza isso em quatro degraus, do mais fraco ao mais forte. Conforme você sobe, cada degrau pede um pouco mais de configuração uma vez. Em troca, o check passa a rodar sem você precisar lembrar de pedir, até numa execução que você não está assistindo.
Degrau 1 — check no prompt
No mesmo pedido, você manda o Claude rodar o check e iterar até passar. Funciona em qualquer tarefa, hoje, sem configurar nada. Este é o degrau que resolve a maioria dos casos.
Implementa a validação do campo valor no form de recibo.
Só responda OK se `npm run build` passar E o teste novo que cobre
"valor negativo é rejeitado" ficar verde. Roda os dois, me mostra o
output de cada um, e itera até passarem. Não diga "feito" sem o output.Antes de colar, troque npm run build pelo comando da sua stack (pytest, ruff check, tsc, o que for o pass/fail do seu projeto). O "só responda OK se…" é o coração do degrau. Você está dizendo qual é o sinal de conclusão: o exit code, e não o seu julgamento de que parece pronto.
Degrau 2 — condição /goal
Em vez de repetir o check em cada mensagem, você declara a condição uma vez, no começo, como um /goal. Um avaliador separado re-checa a condição depois de cada turno, e o Claude continua trabalhando até ela valer. Útil quando a tarefa atravessa vários turnos.
Você declara o /goal digitando o comando seguido da condição que o avaliador vai re-checar:
/goal A suíte passa inteira (`npm run build` verde) e o teste de
"valor negativo é rejeitado" está verde. Não considere a tarefa pronta
enquanto qualquer teste estiver vermelho.De novo: troque npm run build pelo comando da sua stack antes de colar.
Degrau 3 — Stop hook
Um Stop hook roda seu check como script quando o Claude termina de responder, e bloqueia o fim do turno até passar. É determinístico: não depende de o Claude escolher rodar o check; o script roda sempre. O starter já trouxe um, e a próxima seção tem o passo pra confirmar que ele está no seu repo. Um detalhe operacional, pra não travar pra sempre: o Claude Code sobrepõe o hook e encerra o turno depois de 8 bloqueios consecutivos (Best practices for Claude Code, seção "Give Claude a way to verify its work").
Degrau 4 — revisor adversarial
Um subagente revisor num contexto limpo vê só o diff e os critérios, não o raciocínio que produziu a mudança. Um modelo fresco tenta refutar o resultado, então quem fez o trabalho não é quem dá a nota. O starter traz a skill /code-review pronta pra isso. Você roda ela depois que o Claude diz que terminou, e ela devolve as falhas que achou direto na sessão:
/code-reviewPara checar contra um plano em vez de só caçar bugs, escreva o prompt do revisor à mão, nomeando o que checar e o que conta como falha:
Use um subagente pra revisar o diff da validação do campo valor contra
o critério "valor negativo é rejeitado". Confirma que o caso tem teste e
que nada fora do escopo mudou. Reporta falhas de correção, não preferência
de estilo.O Stop hook que o starter já trouxe
Você não precisa escrever o degrau 3 do zero. O starter já instalou um Stop hook em .claude/settings.json.
Primeiro, confirme que ele está no seu repo. Abra .claude/settings.json e procure o bloco Stop. Você deve ver isto:
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/bin/hooks/run-check-if-changed.sh"
}
]
}
]Se o bloco Stop não estiver lá, ou o arquivo bin/hooks/run-check-if-changed.sh não existir, peça ao Claude pra criá-lo: "Cria um Stop hook em .claude/settings.json que roda bin/hooks/run-check-if-changed.sh, e cria esse script: se nada em src/ ou app/ mudou, sai com exit 0; senão roda o check da minha stack." Não dá pra auditar um hook que não está instalado, então confirme que existe antes de seguir.
Com o hook confirmado, abra bin/hooks/run-check-if-changed.sh. A lógica cabe em três linhas:
if git diff --quiet HEAD -- 'src/' 'app/' 2>/dev/null; then
exit 0
fi
npm run checkSe nada em src/ ou app/ mudou na sessão, o hook sai limpo (exit 0) e o Claude termina sem overhead. Se houve mudança em código, ele dispara o check, aqui npm run check (lint + typecheck + test), mas troque pelo comando da sua stack (pytest, ruff check, etc.). Se o check falhar, o turno não fecha limpo: o erro volta pro Claude, que vê o que quebrou e tem a chance de consertar antes de você sequer olhar.
Troque também os paths (src//app/) pelos do seu projeto. Se o seu código mora em pipelines/ ou scripts/ (um projeto Python, por exemplo) e o hook só olha src/ e app/, o git diff --quiet vai dar verde mesmo com código mudado: um falso-negativo silencioso que faz o check nunca disparar. O hook só protege as pastas que você listar.
Esse é o degrau 3 funcionando sem esforço extra, herdado do starter. Sem o hook, um check quebrado dorme no seu repo até você rodá-lo na mão. Com o hook, ele aparece no fim do turno em que entrou.
TDD com agente: o teste é a verificação, não seus olhos
O degrau 1 fica muito mais forte quando o check já existe e já está vermelho antes de o Claude tocar no código. É a inversão do TDD: você escreve um teste que falha reproduzindo o bug, depois deixa o agente consertar até ficar verde. Quem verifica é o teste, não a sua releitura do diff.
A própria documentação da Anthropic sugere esse gesto para correção de bug, mandando o agente "write a failing test that reproduces the issue, then fix it" (Best practices for Claude Code).
O fluxo, no seu projeto:
1. Escreva o teste vermelho primeiro. Descreva o bug como um teste que falha. Não deixe o Claude consertar nada ainda.
Bug: o form de recibo aceita valor negativo e cria o registro.
NÃO conserte ainda. Primeiro escreve um teste que reproduz isso:
ele submete valor -100 e espera erro de validação. Roda o teste e me
mostra ele FALHANDO (vermelho). Só quero ver o teste vermelho agora.Você quer ver o vermelho. Um teste que já passa não prova nada, porque pode estar testando a coisa errada. O vermelho confirma que o teste de fato pega o bug.
2. Agora solte o agente pra ficar verde. Com o teste vermelho na mesa, o critério de "pronto" está objetivo.
Agora conserta. Faz o teste do valor negativo ficar verde sem quebrar
os outros. Roda a suíte inteira e me mostra o output: todos verdes.
Trata a causa raiz (validação faltando), não suprime o sintoma.3. Exija a evidência, não o "feito". A documentação é direta: o Claude deve mostrar evidência (o output do teste, o comando que rodou e o que voltou, um screenshot) em vez de afirmar sucesso. Reler a evidência é mais rápido que rodar a verificação você mesmo. Se a resposta for só "pronto, ficou verde" sem o output colado, peça o output.
Por que isso conecta com a regra de assertions
Uma regra que vale pra qualquer cálculo: sempre adicione assertions / sanity checks onde um número precisa obedecer uma invariante. Um valor em centavos nunca é negativo; um total nunca é menor que a soma das partes; um percentual fica entre 0 e 100; uma data não cai fora do período esperado. Essas assertions são checks rodáveis embutidos no código: o degrau 1 morando dentro da própria função.
A ligação é direta, e o exemplo muda conforme o seu produto:
- Produto transacional (SaaS de recibo da fatia 1): o teste de "valor negativo é rejeitado" e uma assertion
assert valor_centavos >= 0são a mesma ideia em dois lugares. - Produto de dados públicos (scraper, dataviz): o teste de "a soma das despesas por deputado bate com o total declarado" e uma assertion
assert soma_partes == totalsão a mesma ideia em dois lugares. O check rodável de um scraper costuma ser exatamente isso: umpytestque valida o schema da resposta da API oficial contra um fixture, mais asserts de invariante sobre os números extraídos.
O teste fecha o loop na hora de desenvolver; a assertion fecha o loop em produção, quando um input estranho chega. Para qualquer tarefa que mexe em número que precisa bater, o check é o que transforma "parece certo" em uma confirmação de que está certo.
Você terminou quando
Você consegue, na sua própria sessão, nomear a escada de quatro degraus (check no prompt → /goal → Stop hook → revisor) e usar o degrau certo sem pensar. Concretamente, você:
- definiu um check rodável para a fatia 1: o comando de pass/fail da sua stack mais 1 teste novo verde;
- escreveu pelo menos um teste que falhou reproduzindo um bug e o levou ao verde;
- exigiu o output como evidência em vez de aceitar "feito";
- confirmou o
run-check-if-changed.shdo starter no seu repo e entendeu quando ele dispara.
Auto-checagem: você consegue responder?
- Por que "parece pronto" é um sinal fraco, e o que o substitui?
- Qual a diferença entre o degrau 1 (check no prompt) e o degrau 3 (Stop hook), e em que situação só o Stop hook resolve?
- No TDD com agente, por que você quer ver o teste vermelho antes de deixar o Claude consertar?
- Como a regra de assertions é o mesmo princípio do degrau 1?