🎯 Os 3 testes de aceitação
Até aqui você construiu acervo, wiki, regras, agente, skills e portão. Falta responder a única pergunta que interessa: o mentor funciona? "Parece bom" não é resposta. O kit responde com três tarefas fixas, rodadas numa sessão nova, cada uma com uma condição de aprovação que dá para conferir por comando ou por arquivo.
Novo aqui? Três termos deste módulo
- Teste de aceitação é uma tarefa que o usuário real faria, com um critério claro de "passou". Não testa uma função isolada; testa o mentor inteiro trabalhando.
- Congelado quer dizer que a tarefa e o critério foram escritos antes e não mudam durante o piloto. Se você ajusta o teste para o mentor passar, o teste deixou de medir.
- Transcript (ou log da sessão) é o arquivo .jsonl com tudo o que aconteceu na sessão do Claude Code, linha por linha: cada texto escrito e cada comando rodado, na ordem. É a testemunha que não tem interesse no resultado.
Como ler: cada cartão traz a tarefa e o critério de aprovação. O do meio brilha porque é o único que não passou inteiro. Repare no critério dele: não basta acertar, tem que prever antes de rodar. É esse detalhe que vai ocupar os tópicos 3, 4 e 5.
| Teste | O que prova | Hábito ruim que ele caça |
|---|---|---|
| 1 · Construir e ensinar | O mentor segue o loop (pronto, previsão, saída real, versão quebrada, relatório) e ensina algo de verdade. | Explicar demais e não rodar nada. |
| 2 · Revisar "que funciona" | O mentor desconfia do que parece certo, prevê onde quebra e prova a correção. | Parecer certo sem estar. |
| 3 · Ingerir fonte nova | O mentor cresce sem edição manual, mantendo links e citações válidos. | Conhecimento genérico e parado no tempo. |
💡 Por que três e não trinta
Cada teste mira um dos maus hábitos da trilha 1. Três tarefas que você roda de verdade valem mais do que uma bateria que ninguém roda. O roteiro do piloto ainda define a decisão de antemão: 5/5 com nota ≥ 7 valida o kit; 3–4/5 manda corrigir numa versão nova e repetir só o que falhou; ≤ 2/5 manda rever o desenho.
✅ Teste 1 passou: o hook que travava a sessão
O pedido foi algo que o Nei ainda não dominava: um hook Stop que impede o Claude Code de encerrar o turno enquanto o TODO.md tiver itens abertos (- [ ]). O mentor levou 0,9 min mais um subagente e seguiu o loop inteiro. O validador, lendo o transcript, contou 14 chamadas Bash e devolveu exit 0.
Novo aqui? Hook Stop
Um hook é um script que o Claude Code roda sozinho num momento fixo. O evento Stop acontece quando o Claude vai encerrar o turno. Se o script responder {"decision":"block","reason":"…"}, o turno não termina e o reason volta para o Claude como instrução.
O caminho que o mentor percorreu
Pronto (R2)
3 critérios verificáveis e um critério de aborto: no máximo 3 bloqueios seguidos por sessão.
Menor versão (R4, R7)
Uma v0 em Python só com a biblioteca padrão, sem LLM e sem gastar tokens por checagem.
Previsão → saída real (R3, R1)
"Caso 1 bloqueia e lista 2 itens; casos 2 e 3, exit 0 sem saída." Rodou. Bateu nos três.
Versão quebrada
Um item que o agente não fecha sozinho ("aguardar aprovação do cliente"). 6 Stops seguidos → 6 bloqueios. Loop infinito.
Correção + prova real
Contador por sessão com teto de 3. Numa sessão real com claude -p "diga apenas oi", o hook obrigou o Claude a criar o ok.txt e marcar os itens.
Sua vez (R6) + relatório
Um exercício no projeto do aluno e uma tabela passo a passo com a regra que guiou cada um.
A saída real da versão quebrada e da corrigida, como ficou registrada na resposta:
✗ v0 (sem teto)
tentativa 1 active=false -> "decision": "block" tentativa 2 active=true -> "decision": "block" tentativa 3 active=true -> "decision": "block" tentativa 4 active=true -> "decision": "block" tentativa 5 active=true -> "decision": "block" tentativa 6 active=true -> "decision": "block"
✓ versão com teto de 3
tentativa 1 -> bloqueio 1/3 tentativa 2 -> bloqueio 2/3 tentativa 3 -> bloqueio 3/3 tentativa 4 -> liberado após 3 bloqueios tentativa 5 -> bloqueio 1/3
💡 O que o Nei aprendeu (o critério "aprendi algo")
Um bloqueio sem teto prende a sessão para sempre quando o item não depende do agente. E um medo foi descartado por medição, não por suposição: o TODO.md com quebra de linha do Windows (CRLF) não quebrou o hook — a contagem de \r na saída deu 0.
🧪 Faça agora — rodar o teste 1 no seu mentor, com log
Objetivo: executar o teste 1 numa sessão nova e guardar o transcript para o validador conferir por fora.
cd ~/mentores/mentor-<slug> mkdir -p logs claude -p "/<slug>-ensina <algo pequeno e real do domínio que você não domina>" \ --output-format stream-json --verbose > logs/teste1.jsonl ls testes/respostas/ # a resposta salva pela skill python3 tools/validar_resposta.py testes/respostas/<arquivo>.md \ --transcript logs/teste1.jsonl; echo "exit=$?"
Como verificar: exit=0 no fim. Se sair 1, a mensagem diz o que faltou (seção, regra inexistente, nenhuma execução real ou previsão depois da execução). Depois, escreva em duas linhas o que você aprendeu. Se não aprendeu nada, o teste não passou, mesmo com exit 0.
⚠️ Teste 2, rodada 1: acertou tudo, menos a ordem
O script_emoji.py é uma armadilha de propósito: lê comentários de um JSON, imprime as perguntas com emojis e grava um relatório. No terminal comum, funciona. Num terminal sem UTF-8, quebra. A pergunta do teste não é "você conserta?", é "você desconfia antes de rodar?".
Novo aqui? cp1252 e md5
- cp1252 é uma codificação de texto antiga do Windows, que não tem emoji. Quando a saída vai para arquivo, pipe ou agendador, o Python pode usá-la, e um print("🔎") vira UnicodeEncodeError. A variável PYTHONIOENCODING=cp1252 simula isso no Linux.
- md5 é uma "impressão digital" de um arquivo: se dois arquivos têm o mesmo md5, o conteúdo é igual byte a byte. Serve para provar que a versão corrigida produz a mesma saída útil.
Rodada 1, ainda com o kit 1.1: 1,8 min, um subagente. O placar dessa rodada:
✓ O que deu certo
- ✓Reproduziu o UnicodeEncodeError com cp1252.
- ✓Achou um 2º ponto de quebra que o Nei não tinha previsto: o 🤔 dentro do JSON de entrada. Tirar emoji do código não basta.
- ✓Corrigiu na saída, com sys.stdout.reconfigure(errors="replace"), e enxugou de 38 para 25 linhas.
- ✓Provou lado a lado: md5 do relatório igual ao do original. Original intacto.
✗ O que faltou
- ✗Nenhuma previsão escrita antes da primeira execução em cp1252. O log mostra: leu com cat/grep e já rodou.
- ✗O passo "preveja" da skill existia no texto, mas nada o conferia.
- ✗Detalhes menores: arquivo salvo com nome confuso e temporários em /tmp, fora do projeto.
Por que a ordem importa tanto, se o resultado estava certo? Porque previsão escrita depois de rodar não é previsão: é narração. A regra R3 do Nei ("medir com e sem antes de acreditar") só tem valor se o número esperado estiver no papel antes do número real. Sem isso, você não sabe se o mentor entendeu o problema ou só reagiu ao erro que apareceu na tela.
🧪 Faça agora — veja a armadilha com os próprios olhos
Objetivo: reproduzir as duas quebras antes de pedir ao mentor. Escreva sua previsão numa linha antes de rodar cada comando.
cd ~/mentores/mentor-<slug>
python3 testes/aceitacao/script_emoji.py; echo "exit=$?"
PYTHONIOENCODING=cp1252 python3 testes/aceitacao/script_emoji.py; echo "exit=$?"
PYTHONIOENCODING=cp1252 python3 -c 'print("Onde baixo o arquivo de exemplo? 🤔?")'; echo "exit=$?"
Como verificar: o 1º sai com exit=0; o 2º com UnicodeEncodeError … '\U0001f50e' e exit=1; o 3º quebra em '\U0001f914', o emoji que vem do dado. Compare com o que você escreveu antes. Se errou, ótimo: agora você sabe o que o teste cobra.
🔁 As 4 rodadas do teste 2
Depois da rodada 1, o placar era 4/5 (e ficou 4/5 até o kit 1.3). Pelo roteiro, 4/5 manda corrigir o kit e repetir só o que falhou. O kit 1.2 saiu com a correção: revisão em 5 seções (Previsão → Reprodução → Correção → Lado a lado → Relatório), perfil --perfil revisao no validador e, com --transcript, a checagem de que a previsão veio antes da primeira execução. Então o teste 2 rodou de novo. Duas vezes.
Como ler: em rosa, o que o mentor fez; em ciano, o que o kit mudou entre as rodadas. Repare que a correção do 1.2 (ciano) ficou em cima e as rodadas seguintes continuaram embaixo, no mesmo lugar. Mudar o texto não mudou o comportamento. O cartão brilhante à direita é a decisão humana de parar de insistir. O desfecho (rodada 4, já com o mecanismo) está logo abaixo da tabela.
| Rodada | O que mudou antes | O que o mentor fez | Validador de fora |
|---|---|---|---|
| 1 (kit 1.1) | — | Reproduziu, achou o 🤔 no dado, corrigiu, provou com md5. Previsão: não escrita antes. | O passo não era verificado. |
| 2 (kit 1.2) | 5 seções, perfil revisão, checagem de ordem no transcript. | "Vou ler… sem executar nada" → executa em cp1252 → "A previsão se confirmou". | Reprovado. |
| 3 (kit 1.2) | Pedido explícito: "escreva uma linha Previsão: antes do primeiro comando que executa código". | Prevê no raciocínio, executa, escreve "a previsão bateu" depois. | Reprovado. |
| 4 (kit 1.3) | Portão de previsão: hook PreToolUse em Bash nega o comando que executa código se ainda não há "Previsão: …" no turno. | Tentou executar antes de prever → negado. Escreveu a previsão, depois rodou. | Aprovado (9 execuções, OK). |
🚨 O detalhe que mais assusta
Na rodada 2, a sessão principal declarou que "o validador passa". E passava mesmo — porque ela o rodou sem o log. Sem --transcript, o validador só confere se as seções existem; não tem como saber a ordem dos fatos. A própria skill de revisão manda rodar o validador assim, só com a resposta.
Na rodada 3, a resposta salva diz, com todas as letras, que a previsão foi "escrita na conversa antes do primeiro comando que executou código". O log diz que não. O texto do mentor sobre o próprio processo não é evidência do processo.
💡 Saber parar também é método
Depois de duas tentativas sem avanço, o piloto parou em vez de tentar uma terceira formulação da mesma instrução. É o critério de aborto (R2) aplicado ao próprio operador: se reescrever o pedido não mudou nada duas vezes, o problema não está na redação.
✅ Rodada 4 (kit 1.3) — o desfecho
- 17:55 · tentou rodar primeiro. O mentor fez o de sempre: quis executar o script antes de prever. Desta vez o portão de previsão negou o comando ("antes de executar código, escreva 'Previsão: …'").
- Escreveu a previsão. Na conversa, antes de rodar: Previsão: UnicodeEncodeError com '\U0001f50e' na linha 28, exit 1 e nenhum relatorio.txt criado.
- Só então rodou, reproduziu, corrigiu e provou lado a lado, como nas outras rodadas.
- Verificação de fora: validar_resposta --perfil revisao --transcript → 9 execuções, OK. O validador do 1.3 ignora o comando negado pelo hook (a tentativa bloqueada não rodou).
Placar final: 5/5, nota 8. O caminho do teste 2 é a lição inteira em três passos: instrução (rodadas 2 e 3 falharam) → mecanismo (portão de previsão) → verificação de fora (o validador lendo o log provou que resolveu).
🧱 A lição central: instrução não basta
Se você levar uma coisa só deste curso, leve esta. Pedir ao modelo um comportamento — por mais claro, repetido e em negrito que seja o pedido — não garante o comportamento. O que garante são duas camadas que não dependem da boa vontade da sessão.
Como ler: de cima para baixo, cada camada é mais difícil de contornar. A instrução tem borda tracejada porque falhou no piloto. À direita, em ciano, os exemplos reais de cada camada: o portão de execução (trilha 5) é um mecanismo que já bloqueou certo no piloto; o portão de previsão (kit 1.3) é o mecanismo que resolveu o teste 2 na rodada 4. Ele fica na faixa da instrução porque transforma aquele pedido em regra que o ambiente cumpre.
Novo aqui? PreToolUse
PreToolUse é o evento de hook que roda antes de uma ferramenta ser usada — por exemplo, antes de cada comando Bash. Um hook nesse ponto pode recusar o comando. É assim que o portão de previsão do kit 1.3 funciona: se o comando executa código e o assistente ainda não escreveu Previsão: … no turno, o comando não roda.
🔍 Veja como o kit 1.3 faz — o portão de previsão
O registro fica em template/.claude/settings.json: o mesmo script do portão de execução, agora também no evento PreToolUse, só para Bash.
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/portao-execucao.py\"",
"timeout": 10
}
]
}
]
E o trecho que decide, em template/.claude/hooks/portao-execucao.py:
if nome_evento == "PreToolUse" and ferramenta == "Bash":
if not cfg.get("previsao", True) or not executa_codigo(entrada.get("command", "")):
return 0
tr = transcricao_de(evento)
if tr is None or previu_no_turno(tr) is not False:
return 0
print(json.dumps({"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": ("Portão de previsão: antes de executar código, escreva na conversa uma linha "
"'Previsão: …' com o que você espera ver (valor, saída ou erro). Depois rode "
"e compare. Ler/listar arquivos não precisa de previsão."),
}}))
return 0
- • executa_codigo: só barra o que executa código (python, node, bash, pytest…). Ler/listar (cat, ls, grep), os scripts do kit (tools/stats.py, tools/validar_*.py, tools/coletar_*.py) e --version passam.
- • previu_no_turno: lê a transcrição desde a última mensagem humana e procura "previs…" nos textos do assistente. Num subagente, lê a transcrição dele: <sessão>/subagents/agent-<id>.jsonl.
- • Sem transcrição legível, deixa passar: o portão nunca trava a sessão por falta de dado.
Para desligar (por exemplo, num mentor que não revisa código): em mentor.config.json, "portao": {"previsao": false}. Para ganhar o portão num mentor que já existe: ~/caminho/do/kit/mentor-especialista/novo-mentor.py --atualizar ~/mentores/mentor-<slug> (módulo 6.2).
Instrução
Necessária: diz o que se espera. Insuficiente: o modelo pode cumprir "no raciocínio" e escrever depois, como no piloto.
Mecanismo
Muda o ambiente para que o caminho errado não exista. No piloto, o portão de execução bloqueou na hora certa, uma vez por turno, sem bloqueio indevido.
Verificação de fora
Um programa que não participou da sessão lê o log e decide. Foi o que separou "a sessão disse que passou" de "passou".
🧪 Faça agora — a mesma resposta, duas verificações
Objetivo: ver com seus olhos a diferença entre conferir o relato e conferir o log. Rode o teste 2 com transcript e valide das duas formas.
cd ~/mentores/mentor-<slug> claude -p "/<slug>-revisa testes/aceitacao/script_emoji.py" \ --output-format stream-json --verbose > logs/teste2.jsonl R=$(ls -t testes/respostas/*revisao* | head -1) # 1) só o relato (o que a sessão costuma rodar) python3 tools/validar_resposta.py "$R" --perfil revisao; echo "exit=$?" # 2) relato + log (a verificação de fora) python3 tools/validar_resposta.py "$R" --perfil revisao \ --transcript logs/teste2.jsonl; echo "exit=$?"
Como verificar: se as duas saírem com exit=0, seu mentor previu antes de rodar. Se a 1ª passar e a 2ª reprovar com "a primeira execução veio ANTES de qualquer previsão escrita — preveja, depois rode", você reproduziu o achado do piloto. Anote no seu diário: era a limitação conhecida do kit 1.2. No kit 1.3, com o portão de previsão ligado, o normal é ver no log um comando negado pelo hook, a linha Previsão: e só então a execução — e as duas saindo com exit=0 (o validador ignora a tentativa negada).
📊 Teste 3 e o placar final
O teste 3 deu ao mentor um guia que não estava no acervo. Em 2,4 min, o /nei-ingere criou a página da fonte, dois métodos novos, as regras R9 e R10 já como ativas, reforçou R1, R2 e R6, atualizou index, hot e log, e os três validadores saíram com exit 0. O módulo 6.2 abre esse caso em detalhe. Aqui, o que importa é o placar.
| Critério | Resultado |
|---|---|
| Fases 1–3 com exit 0 | ✅ (fase 1 depois de calibrar a meta de guias e acrescentar uma fonte) |
| Portão: bloqueou certo, sem bloqueio indevido | ✅ |
| Teste 1 passou e o Nei aprendeu algo | ✅ teto de bloqueio por sessão em hook Stop |
| Teste 2 previu, reproduziu e provou | ✅ na rodada 4 (kit 1.3, portão de previsão); nas rodadas 1–3 reproduziu e provou, mas sem previsão escrita antes de rodar |
| Teste 3 atualizou a wiki sozinho | ✅ |
| Nota "reconheço a pessoa nas regras" (0–10) | 8 |
| Placar | 5/5 (era 4/5 até o kit 1.3) |
| Tempo total (humano / máquina) | ~1h20 operando / ~20 min de sessões + 7,7 min de transcrição |
22
fontes no fim (14 lives + 8 guias)
~189 mil
palavras no acervo
10 / 40
regras / citações validadas
8
correções viraram o kit 1.2
🛠️ O que o piloto devolveu ao kit
O diário registrou cada problema sem consertar durante o piloto. Depois, as correções viraram a versão 1.2:
- • alta — transcrição salva como transcript.txt sobrescrevia a anterior → nome por título + ID.
- • média — manifesto sem trava perdia itens em paralelo → trava de arquivo + escrita atômica.
- • média — legenda picada em linhas com [hh:mm:ss] → parágrafos de ~30 s.
- • média — seções do agente fixas → seções vindas das regras do especialista.
- • média — revisão sem previsão verificada → perfil revisão + checagem pelo transcript.
- • baixa — metas, aviso "Stop hook error occurred", idioma, extensão do revisado, temporários no projeto.
O 1.2 saiu com uma limitação declarada, não escondida: a previsão antes de rodar dependia de mecanismo. O kit 1.3 fechou isso e o resto do piloto:
- • portão de previsão (PreToolUse em Bash) → resolveu o teste 2 na rodada 4; desligável em "portao": {"previsao": false}.
- • validar_resposta ignora comandos negados por hook (a tentativa bloqueada não rodou).
- • validar_links exige ida e volta fonte ↔ conceito → achou as 3 ligações de mão única do mentor do Nei, que foram fechadas.
- • docs/ADAPTAR.md: aviso de caminho relativo para montar um conselho de mentores.
- • 81 testes no kit.
🧪 Faça agora — o seu placar
Objetivo: registrar os três testes do seu mentor com evidência, no formato do piloto.
Abra testes/aceitacao/RESULTADOS.md e acrescente uma linha por teste: | data | teste | passou? | evidência (arquivo/saída) | observação | |---|---|---|---|---| | <AAAA-MM-DD> | 1 Construir e ensinar | <sim/parcial/não> | testes/respostas/<arq>.md; validar_resposta --transcript logs/teste1.jsonl → exit <n> | <o que você aprendeu> | | <AAAA-MM-DD> | 2 Revisar script | ... | logs/teste2.jsonl; --perfil revisao --transcript → exit <n> | previu antes? | | <AAAA-MM-DD> | 3 Ingerir fonte nova | ... | wiki/log.md; 3 validadores → exit <n> | regras promovidas |
Como verificar: cada linha "sim" aponta para um arquivo ou saída que outra pessoa consegue reabrir. Linha sem evidência vira "não", por mais que você lembre que funcionou. Commit: git add -A && git commit -m "testes de aceitação".
Checagem rápida: seu mentor escreveu na resposta "Previsão escrita antes de executar" e o validador, rodado só com a resposta, deu exit 0. Você pode marcar o teste 2 como "sim"?
📌 Resumo do módulo
Próximo Módulo:
6.2 - Ingestão contínua, promoção de regras, atualização do kit, reuso e o projeto final.