O EXECUTE construiu uma unidade delimitada. Agora vem o passo que decide se o ciclo pode terminar: VERIFY. Você não pode apenas dizer que funciona — você precisa mostrar no boundary real. Esta lição trata dos três gates que um turno precisa atravessar antes de fechar: Scope, Proof e Course — e da única regra que mantém o método inteiro de pé: uma alegação não é evidência.
Cada turno do loop roda cinco passos — LEARN → ANALYZE → EXECUTE uma unidade delimitada → VERIFY no boundary real → DECIDE. Você já percorreu os três primeiros. Esta lição é o quarto, e é o que protege todos os outros: VERIFY.
Eis a falha que o VERIFY existe para evitar. Você faz uma mudança, ela parece certa, e você escreve "pronto — o endpoint agora retorna 200". Você acredita nisso. Você segue em frente. Mas você nunca de fato chamou o endpoint. A mudança tinha um erro de digitação, ou bateu numa config que você esqueceu, ou funcionou na sua máquina e em nenhuma outra. A palavra "pronto" era uma alegação, e uma alegação é só uma frase. Ela não carrega prova alguma por dentro.
O VERIFY troca a alegação por evidência. Evidência é o que você obtém quando vai ao boundary real e faz a coisa acontecer: você roda o programa e lê a saída; você bate no endpoint e olha o código de status e o corpo; você alimenta com a entrada mais difícil que conseguir imaginar e observa o que acontece. A diferença entre "deveria funcionar" e "eu rodei, aqui está a saída" é a diferença inteira entre uma esperança e um fato.
Para manter isso honesto, um turno do loop não pode fechar até passar por três gates, cada um exigindo evidência, não palavras:
Pense nisto como… uma feira de ciências. Não basta dizer que seu vulcão de bicarbonato entra em erupção — o jurado fica ali enquanto você despeja o vinagre e observa a espuma transbordar. Dizer "confia, funciona em casa" não te rende nada. A erupção, feita ao vivo, na frente do jurado, é a prova. Onde a analogia quebra: numa feira você demonstra uma vez; no loop você reexecuta a prova após cada mudança, porque a última mudança pode tê-la quebrado em silêncio.
O VERIFY reúne e julga evidências; o DECIDE age sobre esse julgamento. Depois do VERIFY você está segurando um veredito — passou ou falhou, por gate. O DECIDE é a ramificação que vem em seguida: todos os gates verdes → fecha o turno e ou escolhe a próxima unidade ou converge; um gate vermelho → loop de novo (re-LEARN com o novo estado e roda outra unidade delimitada), ou, se a falha for uma bifurcação genuinamente só do usuário, faz o handoff. Mantê-los separados evita que você racionalize um resultado falho como um "passou" só porque quer seguir em frente.
O boundary é onde quer que a verdade de fato resida para esta mudança: o exit code do processo e o stdout/stderr para um script; o status HTTP e o corpo da resposta para um endpoint; o DOM renderizado para uma UI; a linha que foi ou não escrita para uma mutação de banco de dados. Um test double, um mock, um stub ou um type-check estático modelam esse boundary — de forma útil — mas um modelo pode divergir da realidade (o mock retorna o que você mandou; o serviço real não). Então esses são complementos: rode-os, mantenha-os, mas o gate só está satisfeito quando a própria realidade foi observada.
Às vezes você genuinamente não consegue alcançar o boundary dentro do turno — sem credenciais para o serviço ao vivo, um dispositivo de hardware que não está conectado, uma ação destrutiva que precisa de aprovação humana. A regra é explícita e estrita: pare antes de alegar. Você não escreve "pronto" sobre uma mudança não verificada. Você expõe o bloqueio (um handoff pronto para decisão) e deixa o humano destravá-lo. Um honesto "bloqueado, é exatamente disto que eu preciso" vale muito mais do que um confiante "pronto" que é falso.
Os gates não são um menu do qual você escolhe — eles estão em série, como três portas trancadas em um mesmo corredor. O turno só pode sair quando as três estão abertas. Se qualquer uma estiver BLOQUEADO, o turno fica lá dentro: você loop de novo, corrige a lacuna e reverifica. Abaixo, observe um turno tentar passar. A primeira tentativa tropeça no Proof; após uma reexecução, os três viram PASSOU.
A ordem é deliberada. Scope primeiro: não adianta provar uma mudança no boundary se ela nem sequer atende o done-when combinado — você estaria provando a coisa errada. Proof em segundo: uma vez que o scope diz "este é o alvo certo", você confirma que a realidade concorda. Course por último: é o entregável de empacotamento/observabilidade que acompanha cada turno neste método, então é verificado no fim, quando a substância já está resolvida. Um gate vermelho curto-circuita o resto exatamente como as guard clauses que você viu no fluxo de auth — não há razão para avaliar a porta três se a porta dois está trancada.
Um gate bloqueado não é um estado de erro do qual se envergonhar; é o sistema funcionando. Significa que o turno está reportando honestamente "ainda não" em vez de mentir com "pronto". O passo DECIDE lê o bloqueio e roteia: loop de novo para algo que o agente pode corrigir, ou handoff para uma bifurcação genuinamente só do usuário. O custo de um BLOQUEADO honesto é mais uma passada; o custo de um PASSOU falso pode ser um bug entregue, um build quebrado, ou uma mentira no log em que a próxima pessoa confia.
Eis o VERIFY inteiro em uma só tela. A unidade delimitada sai do EXECUTE. Ela é verificada contra o escopo, provada no boundary real e empacotada no curso. A saída é um único veredito sobre o qual o DECIDE então age. Repare na seta tracejada: qualquer mudança feita para corrigir um gate te manda de volta para reprovar — verificação não é um checkbox que você marca uma vez só.
Lá na lição 2 você escreveu um contrato de escopo: uma lista de condições "done-when" mensuráveis. O Scope Gate é onde essa lista é cobrada. Você percorre linha por linha e, para cada condição, responde uma pergunta: está atendida — e qual é a evidência?
A palavra mensurável é o que faz todo o trabalho. "O login está melhor" não passa por um gate — não há nada para apontar. "Fazer login com uma senha errada retorna HTTP 401 e a mensagem bad_credentials" passa: você ou vê essa resposta ou não vê. O Scope Gate transforma o contrato num checklist onde cada linha é ou um tique verde com prova anexada, ou ainda não está pronta.
Pense nisto como… um checklist de pré-voo. O piloto não "se sente pronto" — ele lê cada linha em voz alta e a confirma fisicamente: flaps acionados, quantidade de combustível confirmada, portas armadas. Uma linha que você não consegue confirmar é uma linha que não está pronta, e o avião não sai do portão. Aqui é igual: um done-when ao qual você não consegue apontar evidência não está atendido.
Corta dos dois lados. Um turno falha no Scope se um done-when está não atendido — mas você também não ganha crédito por coisas fora do contrato. Se você "melhorou" outros cinco arquivos que ninguém pediu, isso não é um pass; na melhor das hipóteses é ruído, na pior é risco não verificado que você contrabandeou. O gate mede o turno contra a lista combinada, nem mais nem menos. É isso que mantém uma unidade delimitada delimitada.
Cada done-when carrega sua própria evidência: a saída de um comando, um screenshot do estado renderizado, a troca HTTP exata, uma contagem de linhas do banco. "Tudo funciona" é uma alegação sobre o todo; o gate quer uma prova sobre cada parte. Quando a evidência está anexada linha por linha, o próximo leitor pode reverificar qualquer linha isolada sem reexecutar o mundo inteiro.
O Proof Gate é aquele ao qual este curso inteiro sempre volta. Ele tem uma única exigência: a mudança foi provada no boundary real. Não argumentada. Não presumida. Não "os tipos passam, então deve estar tudo bem." Você foi até onde a verdade mora e fez a coisa acontecer, com seu próprio comando, e leu o que voltou.
Abaixo há um mergulho focado no Proof Gate — o que conta como boundary real, como mocks e type-checks se encaixam (eles complementam, nunca substituem), o que fazer quando o boundary está fora de alcance, e as perguntas que as pessoas de fato fazem. Há um medidor de evidência ao vivo: cada tipo de prova que você coleta o enche, e você pode ver uma esperança virar um fato.
Mergulho no gate · O Proof Gate — provando uma mudança no boundary real
Uma alegação é uma frase; prova é uma observação. O Proof Gate só abre quando você observou o boundary real. O boundary é onde quer que a verdade desta mudança de fato resida: para um script é o exit code e o texto que ele imprime; para um endpoint é o status HTTP e o corpo; para uma página é o que de fato renderiza; para uma escrita no banco é se a linha realmente está lá.
Você coleta prova fazendo a coisa real — e a prova mais forte é alimentá-la com a entrada mais difícil que você conseguir conceber, não o caminho feliz fácil. Um type-check e um mock são bem-vindos, mas ficam abaixo da prova no boundary real: eles pegam erros baratos cedo e te deixam ir rápido, mas um type-check verde nunca, nem uma vez, retornou um 200 de um endpoint ao vivo. Eles complementam; não substituem.
Pense nisto como… provar que uma ponte aguenta. Um projeto que fecha no papel (o type-check) e um modelo em escala num túnel de vento (o mock) são trabalho real e útil — mas ninguém abre a ponte até um caminhão carregado ter atravessado o vão de verdade. O caminhão na ponte real é o Proof Gate.
Classifique o que você pode coletar, do mais fraco ao mais forte: (1) "deveria funcionar" — uma alegação, zero evidência; (2) um type-check / lint estático — prova a forma, não o comportamento; (3) um teste de unidade contra um mock — prova sua lógica dadas as suposições que você escreveu; (4) o boundary real, caminho feliz — você de fato rodou uma vez e funcionou; (5) o boundary real, entrada mais difícil — você rodou contra o caso mais cruel e ele aguentou. O Proof Gate está satisfeito no nível 4 e convincente no nível 5. Os níveis 2–3 são complementos que tornam o 4–5 mais rápido de alcançar, nunca substitutos deles.
Boa prova é reproduzível: o mesmo comando no mesmo boundary gera a mesma observação. É por isso que "cliquei por aí e pareceu bem" é fraco — ninguém consegue repetir. Um comando capturado + sua saída é prova que qualquer um pode reexecutar, o que também é o que torna barato obedecer à regra de reexecutar-após-mudança (mais adiante nesta lição).
Comece numa alegação pura. Adicione cada tipo de evidência e veja o medidor subir. O gate permanece BLOQUEADO até o próprio boundary real ser atingido — type-checks e mocks sozinhos nunca conseguem empurrá-lo para PROVADO.
Três visões do mesmo gate: a verificação que bate no boundary e se recusa a mentir, a política que você configura, e como o loop a usa antes de fechar um turno.
def proof_gate(change, boundary): # supplements first — cheap, fast, but NOT the gate if not typecheck(change): return blocked("types fail") if not unit_tests(change): return blocked("unit tests fail") # the gate itself: hit the REAL boundary if boundary.unreachable: return halt("cannot reach boundary — ask, do not claim") observed = boundary.run(change, inputs=hardest_cases()) if observed == expected: return proven(evidence=observed) # real output captured return blocked("boundary disagreed", evidence=observed)
# what the Proof Gate accepts as real-boundary evidence proof: require_real_boundary: true # mocks never satisfy on their own supplements: - typecheck # run, but not sufficient - unit_tests_with_mocks # run, but not sufficient on_unreachable: "halt_and_handoff" # stop before claiming rerun_after_change: true # any edit re-proves prefer_inputs: hardest_first # nastiest case, not happy path
def verify(unit): if not scope_gate(unit): return Verdict.LOOP if not proof_gate(unit, real_boundary): return Verdict.LOOP # or HANDOFF if halted if not course_gate(unit): return Verdict.LOOP return Verdict.CLOSE # all three green # the human never runs this — they READ the verdict + evidence
Encontre você mesmo: grep -rn "def proof_gate" loop/
WebSearch/WebFetch. Se uma alegação depende de um fato atual, você busca esse fato da fonte real como sua evidência.
A forma mais rápida de sentir a diferença entre uma alegação e uma prova é colocá-las lado a lado. Abaixo está o equivalente a um turno de afirmações. Cada uma vem escrita como uma alegação por padrão — o tipo de frase confiante que soa pronta. Vire uma linha para prova e veja-a se reescrever na evidência de boundary real que de fato satisfaria o gate. O veredito embaixo só vira PROVADO quando toda linha está respaldada por evidência real.
Leia as duas formas de novo. A forma de alegação usa verbos de estado — "retorna", "é rejeitada", "é escrita" — descrevendo como o mundo supostamente é. A forma de prova usa ações no passado com saída capturada — "rodei curl … → HTTP/1.1 200", "escrevi e depois reli a linha id 4821". A própria gramática te diz se um boundary foi tocado: uma afirmação sobre o presente é uma alegação; uma observação registrada de uma ação é prova.
Uma linha provada não resgata três alegações — um turno é tão verificado quanto sua afirmação mais fraca. O veredito agregado espelha o Scope Gate: é o E (AND) de cada linha, então uma única alegação sem respaldo mantém o turno inteiro em NOT PROVEN. Isso é deliberado; prova parcial é exatamente como um "pronto" falso se infiltra.
Tudo à esquerda da linha abaixo é um modelo da realidade — seu código, seus tipos, seus mocks, seu raciocínio. Eles são úteis e você deve usá-los. Mas ainda são mapas. O Proof Gate mora exatamente na linha onde o mapa termina e o território começa. Prova é o que você só consegue ao cruzar essa linha e observar a coisa real.
Os três gates formam uma decisão que você pode percorrer como um fluxograma. Cada gate é uma pergunta sim/não, e o primeiro "não" se desvia — não para uma falha dura, mas de volta ao loop para corrigir aquela lacuna, ou para um handoff se for uma bifurcação só do usuário. Escolha um turno abaixo e aperte Próximo para traçá-lo gate por gate. Veja como uma passada limpa chega a Fechar o turno e um gate que falha roteia de volta para Loop de novo.
Comece aqui
Uma unidade delimitada chega ao VERIFY
Aperte Próximo para acompanhar o turno tudo provado pelos três gates. Troque o turno acima para ver como um gate o manda de volta ao loop.
O fluxograma é uma cadeia de early returns, com a verificação significativa mais barata primeiro, e a primeira falha curto-circuita o resto. Uma falha não lança exceção — ela retorna um veredito sobre o qual o passo DECIDE roteia. O caso "boundary inalcançável" é especial: ele não retorna LOOP (não há nada que o agente possa reexecutar para corrigir) — ele para e faz o handoff.
function verifyTurn(unit) { if (!scopeMet(unit)) return loop('scope: a done-when is unmet'); if (boundaryUnreachable()) return handoff('cannot prove — ask, do not claim'); if (!provenAtBoundary(unit)) return loop('proof: boundary disagreed'); if (!courseBuilt(unit)) return loop('course: not built yet'); return close(unit); // all three gates green }
Quando um turno termina, o loop emite um status — a resposta num relance para "este turno pode fechar?" Tem o mesmo formato de um dashboard de saúde de serviço: alguns números de destaque no topo (gates passados, contagem de evidências, reexecuções), depois uma tabela por gate com um selo colorido para cada. Lembre da regra AFK deste curso: o humano lê este status — ele não roda nada para produzi-lo. Aperte Atualizar para uma leitura nova, ou ligue o Ao vivo para acompanhar um turno que ainda está se assentando.
Status do verify — turno #18 · "limitar a taxa do endpoint de login"
loop · unidade delimitada · gates verificados no boundary real
| Gate | Status | Evidência | Última verificação |
|---|
Um único array de objetos de gate alimenta tanto a tabela quanto o pill de rollup. O banner geral é derivado do pior gate, exatamente como um rollup de serviço: qualquer bloqueado → vermelho "não pode fechar"; qualquer em andamento → âmbar; um aguardando-handoff → azul; só todos passando → verde "pode fechar". O rollup nunca pode ser mais verde que seu pior gate, e esse é todo o ponto — você não pode pintar um turno de "pronto" enquanto um gate está vermelho.
Esta é uma superfície de observabilidade, não um painel de controle. No modelo AFK (lição 7) o loop produz este status no LOOP-LOG.md; o humano o lê para saber onde as coisas estão e só intervém numa bifurcação genuinamente só do usuário. O carimbo "última verificação" é uma região aria-live; cada selo combina sua cor com um rótulo de texto, então o status nunca é só por cor.
Agora a história de advertência — a falha exata que o Proof Gate existe para pegar. Um turno foi marcado como pronto com base numa alegação, o gate foi pulado, e o bug foi entregue. Eis tudo isso como um relatório de incidente: uma linha do tempo do "pronto" falso até a recuperação, a causa raiz escavada com cinco porquês, o raio de impacto, e um checklist de correções que você pode marcar. Leia de cima a baixo — o momento em que a prova foi pulada está aceso em vermelho.
Pontos verde-oliva são rotina, cor de barro é um sinal de alerta, vermelho é o momento em que a prova foi pulada, verde é recuperação.
Unidade construída — o rate limiter
O EXECUTE adiciona o limite de 5 por minuto a POST /auth/login. O diff parece correto e se lê de forma limpa.
Type-check + testes de unidade passam
Todos os complementos estão verdes. O limiter mockado retorna 429 na 6ª chamada no teste. Parece terminado.
Marcado "pronto" — boundary nunca atingido
O log registra done: limiter returns 429. Mas ninguém nunca chamou o endpoint ao vivo. "Pronto" era uma alegação apoiada no mock.
O próximo turno depende disso
O turno #15 começa um trabalho que assume que o limiter está ao vivo. Ele faz o re-LEARN do estado real primeiro — e algo não fecha.
a jusanteO Proof Gate pega
Um curl real do endpoint ao vivo retorna 200 na 6ª tentativa — o limiter está ligado na ordem de middleware errada e nunca roda. O "pronto" era falso.
Corrigido, depois reprovado no boundary
Ordem de middleware corrigida. Um novo curl agora retorna 429 na 6ª chamada. Evidência capturada; o gate de fato passa desta vez.
curl real às 11:48.Continue perguntando "mas por que isso aconteceu?" A primeira resposta é um sintoma; a quinta é a que vale a pena corrigir.
Por que o bug foi entregue?
O turno foi marcado como pronto enquanto o endpoint ao vivo ainda retornava 200 na 6ª tentativa.
Por que foi marcado como pronto?
"Pronto" foi escrito a partir dos testes de unidade que passaram — uma alegação — sem ninguém bater no boundary real.
Por que o boundary não foi atingido?
O mock foi tratado como um substituto do endpoint real, não como um complemento a ele.
Por que se confiou tanto no mock?
Nenhum passo forçou uma observação real no boundary antes de "pronto" poder ser escrito. O Proof Gate era implícito, não imposto.
Causa raiz · por que a prova era opcional
O passo verify deixou uma alegação fechar um turno. Não havia regra dura de que evidência de boundary real — capturada, reexecutável — é exigida antes de "pronto", e nenhuma regra para reprovar após uma mudança. A correção é tornar o Proof Gate obrigatório e sua evidência explícita.
Atalhos laterais encurtaram o pavio: os testes de unidade mockavam o limiter numa camada acima do bug de ordenação de middleware, então nunca poderiam tê-lo pego; o caminho feliz era o único caso que alguém imaginou (nenhuma tentativa com entrada mais difícil, com 6 chamadas rápidas contra a rota ao vivo); e o template de log aceitava "pronto" em texto livre sem campo de evidência, então uma alegação e uma prova pareciam idênticas no registro.
Quem escreveu "pronto" agiu de forma razoável dadas as ferramentas — testes verdes pareciam prova. Uma correção sem culpados muda o sistema: exigir evidência de boundary real capturada antes de um turno poder fechar, e reexecutá-la após cada mudança. Aí "pronto" só pode significar "provado", para todo mundo, toda vez.
46 min
"Pronto" foi falso por1
Turno a jusante enganado∞
Tentativas de força bruta ainda abertas0
Entregue a usuários (pego antes)Cada correção transforma esta falha exata em uma que não pode recorrer. Marque os itens — a barra acompanha o progresso.
O VERIFY não para em "os gates passaram". Um turno também recebe um autoreview — uma leitura independente da própria mudança, linha por linha, do jeito que um colega cuidadoso revisa um pull request. Isso importa por um motivo deste curso: o revisor nunca é o construtor. O mesmo agente que escreveu o código não pode abençoá-lo; uma passada separada procura o que o construtor, perto demais, deixaria passar.
Abaixo está essa revisão da própria mudança do incidente acima. Linhas verdes são adicionadas, vermelhas removidas; os pills no topo são a leitura de risco num relance do revisor; os pontos cor de barro são notas fixadas a uma linha. Clique em qualquer linha pontilhada para ler a nota — e ache a marcada como bloqueante, porque uma nota bloqueante mantém o turno aberto por mais verdes que os gates parecessem.
Limita tentativas de senha a 5 / minuto por IP em POST /auth/login. 1 arquivo alterado · +9 −2
Cada linha pontilhada em cor de barro carrega uma nota. 1 é bloqueante — é exatamente o bug que o Proof Gate pegou depois. Veja se você consegue achá-la antes de seguir lendo.
O Proof Gate responde "o boundary faz a coisa certa agora?" O autoreview responde uma pergunta diferente: "esta mudança é boa — segura, clara, livre de armadilhas latentes — mesmo onde o gate por acaso passou?" Uma mudança pode passar por todos os gates no caminho feliz e ainda carregar uma falha bloqueante (aqui, a ordem de middleware) que só um leitor independente percebe. É por isso que os dois rodam, e por isso uma nota de revisão bloqueante mantém o turno aberto.
Esta é uma regra dura no modelo AFK (lição 9): o Validator é um agente diferente do Executor. A auto-revisão é estruturalmente fraca — você não consegue ver o ponto cego a partir do qual construiu. A severidade é explícita: blocking precisa ser resolvido antes de o turno fechar; nit é polimento opcional; praise reforça um bom padrão para que se repita.
O terceiro gate é específico de como este método entrega: todo turno que produz trabalho real precisa também entregar seu curso visual completo — a explicação multi-lição, self-contained, do que foi feito — antes de o turno terminar. Não esboçado, não "para ser redigido depois." Construído, completo, no mesmo turno.
Por que um gate e não um item opcional? Porque "eu documento depois" é a mesma espécie de mentira que "deveria funcionar." O depois raramente vem, e quando vem o contexto já se foi. Forçar o curso a existir agora faz a explicação ser capturada enquanto o trabalho está fresco — e dá ao humano algo real para ler no modelo AFK. A página que você está lendo é, ela mesma, este gate sendo satisfeito.
Pense nisto como… um chef que precisa empratar e escrever a ficha da receita antes de o prato sair do passe. Um prato sem ficha significa que o próximo cozinheiro o reinventa do zero. A ficha, escrita enquanto a panela ainda está quente, é parte do "pronto" — não uma tarefa para um dia mais calmo que nunca chega.
Ele é verificado como qualquer outro entregável: as lições existem como arquivos self-contained, abrem sem requisições externas, os dois builds de idioma estão presentes (EN + PT-BR neste conjunto), e a shared shell está intacta. Um curso pela metade falha no gate exatamente como uma mudança meio-provada falha no Proof. Você vai conhecer o motor que o produz na lição 13.
No modelo AFK o único trabalho do humano é observabilidade — e o curso é parte do que ele observa, ao lado de LOOP-LOG.md e review.md. Colocá-lo num gate a cada turno mantém a explicação em sincronia com o trabalho, então o registro nunca atrasa em relação à realidade.
Uma regra merece sua própria seção porque é a mais esquecida: após qualquer mudança, reexecute a prova. Uma prova é uma fotografia de um único momento. No instante em que você edita qualquer coisa — até uma correção "trivial" de uma linha para satisfazer uma nota de revisão — aquela fotografia fica desatualizada. A mudança que você acabou de fazer para corrigir uma coisa pode quebrar a coisa que você já tinha provado.
Então a verificação é um loop, não um checkpoint. Você prova, ajusta, prova de novo — e segue girando até uma passada completa não exigir mudança alguma. O ciclo só termina quando você roda a prova e nada precisa ser tocado depois.
A regra de reexecutar só permanece barata se sua prova for um comando capturado e reproduzível, e não um cutucão manual avulso. "Rodei curl … && echo $? e vi 200" pode ser reexecutado em uma tecla após a próxima edição; "cliquei por aí e pareceu bem" não pode. Investir em evidência reexecutável na primeira prova se paga toda vez que você precisa reprovar.
O loop tem garantia de terminar contanto que cada mudança reduza estritamente o conjunto de verificações que falham (sem oscilação). Se uma mudança piora as coisas ou troca uma falha por outra indefinidamente, isso em si é um sinal — re-LEARN, re-ANALYZE, possivelmente re-scope. A condição de saída é nítida: uma passada de prova que não disparou nenhuma mudança subsequente.
Eis o passo verify inteiro como uma função legível. Leia de cima a baixo: os três gates rodam em série, o boundary real é inegociável, um boundary inalcançável para em vez de alegar, e o veredito — não um efeito colateral — é o que sai. Esta é a forma pela qual todo turno passa antes de ter permissão para fechar.
def verify(unit, scope, boundary, course): evidence = [] # ── Gate 1 · Scope: every measurable done-when, with evidence ── for done_when in scope.conditions: result = check(done_when) # observe, don't assume evidence.append(result) if not result.met: return Verdict("LOOP", why=f"scope: {done_when} unmet", evidence=evidence) # ── Gate 2 · Proof: the REAL boundary, or stop and ask ── typecheck(unit); unit_tests(unit) # supplements — run, never sufficient if boundary.unreachable: return Verdict("HANDOFF", why="cannot reach boundary — ask, do not claim") observed = boundary.run(unit, inputs=hardest_cases()) # run it / hit it evidence.append(observed) if observed != expected: return Verdict("LOOP", why="proof: boundary disagreed", evidence=evidence) # ── Gate 3 · Course: the full visual course exists NOW ── if not course.built: return Verdict("LOOP", why="course: not built yet", evidence=evidence) return Verdict("CLOSE", evidence=evidence) # all three gates green → DECIDE closes
O passo verify e seus gates ficam sob o diretório gates/ do loop. Para ler a coisa real, e não este esboço didático:
# the verify entry point and each gate grep -rn "def verify" loop/ grep -rn "def proof_gate" loop/gates/ # the policy that says mocks never satisfy the Proof Gate sed -n '/^proof:/,/^[a-z]/p' loop/gates.yaml
Se você lembrar de uma única linha, que seja if boundary.unreachable: return HANDOFF. É o método se recusando a mentir: quando não consegue provar, ele pergunta em vez de alegar. Toda outra linha é só burocracia em torno desse único compromisso.
Vamos rodar um turno concreto do começo ao fim, para os três gates pararem de ser abstratos. A unidade: "adicionar um limite de 5 por minuto ao endpoint de login." O contrato de escopo da lição 2 tinha três linhas de done-when.
Gate 1 · Scope. Três condições: (a) a 6ª tentativa em um minuto é recusada; (b) uma recusa retorna 429 com too_many_attempts; (c) um minuto novo deixa as tentativas passarem de novo. Vamos linha por linha. (a) e (b) dá para testar; (c) dá para testar. Nenhuma é vaga — cada uma é verificável. O scope é satisfazível, então passamos ao Proof.
Gate 2 · Proof. Os complementos passam — os tipos estão bem, o teste de unidade mockado retorna 429. Tentador escrever "pronto." Não escrevemos. Batemos no endpoint real com a entrada mais difícil: seis chamadas curl rápidas em um minuto. A 6ª retorna… 200. O limiter nunca rodou — ordem de middleware errada. O boundary discordou do mock. O Proof está BLOQUEADO; o veredito é LOOP.
O loop gira. Fazemos o re-LEARN (a ordem de middleware é o bug), aplicamos a correção de uma linha e — porque a prova é perecível — reexecutamos o teste de seis chamadas. Agora a 6ª retorna 429. Também reverificamos (c): espera a janela passar, a 7ª chamada após o reset retorna 200. Evidência real, capturada, para cada done-when. O Proof agora está OK.
Gate 3 · Course. Construímos a lição que explica a mudança — self-contained, nos dois idiomas — antes de o turno terminar. Ela existe agora. O Course está OK.
Três verdes. Só agora o turno fecha, e o log registra "pronto" com a saída real do curl anexada — uma prova que qualquer um pode reexecutar, não uma alegação na qual qualquer um tem que confiar.
A diferença de que a lição inteira trata, feita concreta — esta é a linha de log do turno fechado:
# NOT this (a claim): done: limiter returns 429 on the 6th attempt # THIS (a proof — re-runnable evidence): done: limiter caps the 6th attempt scope: - 6th-in-window refused ✓ evidence: curl#6 → HTTP/1.1 429 - refusal body ✓ evidence: {"error":"too_many_attempts"} - window resets ✓ evidence: curl after 60s → HTTP/1.1 200 proof: boundary: POST /auth/login (the LIVE route, not a mock) command: for i in $(seq 1 6); do curl -s -o /dev/null -w "%{http_code}\n" ...; done observed: 200 200 200 200 200 429 # hardest input: 6 rapid calls reruns: 2 (after the middleware-order fix) course: lessons/0006-verify-gates.html built (EN + PT-BR)
Lembrar vence reler. Sem rolar para cima, responda estas quatro. Cada uma tem exatamente uma melhor resposta; escolha-a e o cartão te diz na hora se ela se sustenta num boundary real.
1. Seus testes de unidade passam contra um mock do serviço de pagamento. Sob o Proof Gate, isso conta como:
2. Você não consegue alcançar o endpoint ao vivo (sem credenciais). A jogada correta é:
3. Uma correção de uma linha satisfaz uma nota de revisão depois que você já provou a mudança. Você deve:
4. Qual linha de log de fato satisfaria a verificação?