Passo 6 · O Loop · O Loop · Loop Engineering ENPT
Módulo 2 · O Loop · Passo 4 do ciclo

VERIFY e os gates: prove, não alegue

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.

Leia a versão simples, ou abra a camada técnica em qualquer seção.
1

A grande ideia: 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:

  • O Scope Gate — todo "done-when" mensurável do contrato de escopo está atendido, e você consegue apontar a evidência de cada um.
  • O Proof Gate — a mudança foi provada no boundary real: você de fato rodou, bateu nele, ou alimentou com a entrada mais difícil. Um type-check ou um mock complementam essa prova; nunca a substituem. E se o boundary real estiver inalcançável, você para e pergunta — você não alega.
  • O Course Gate — o entregável que precisa sair junto com este trabalho (aqui, o curso visual completo) está de fato construído antes do turno terminar, não prometido para depois.

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.

VERIFY vs DECIDE — dois passos diferentes

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.

Por que "o boundary real" é inegociável

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.

A regra do boundary inalcançável

À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.

2

Os três gates, em série


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.

turno unidade pronta Scope Gate todo done-when atendido PASSOU Proof Gate boundary real atingido PASSOU Course Gate curso construído agora PASSOU fechar turno bloqueado → loop de novo
Três portas em um corredor. O turno só sai quando as três marcam PASSOU; qualquer BLOQUEADO o manda de volta ao loop.
Todos os gates verdes — o turno pode fechar.

Por que em série, não em paralelo

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.

"BLOQUEADO" é um desfecho normal, não um crash

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.

3

Em uma imagem: da unidade ao veredito


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ó.

EXECUTE uma unidade VERIFY Scope Gate todo done-when mensurável atendido, com evidência Proof Gate rode · bata · alimente a entrada mais difícil — nunca uma alegação Course Gate curso visual completo construído antes do turno terminar todos verdes? → emite veredito DECIDE fechar · loop · handoff qualquer mudança → reexecute a prova
A unidade delimitada entra; três gates a julgam; um único veredito sai para o DECIDE. Toda correção volta pelo Proof.
4

Gate 1 · Scope — todo done-when, com evidência


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.

Scope também é o gate anti-scope-creep

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.

Evidência por linha, não um "parece bom" genérico

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.

5

Gate 2 · Proof — o coração do método


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

O que o Proof Gate exige

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.

A hierarquia da evidência

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.

Determinismo e reexecutabilidade

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).

O medidor de evidência — encha-o para abrir o gate

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.

mudança a verificar somar prova evidência coletada BLOQUEADO gate
Leia esquerda → direita: a evidência enche o medidor; o gate só marca PROVADO quando o boundary real é atingido, não antes.
evidência 0 / 4 · gate BLOQUEADO

O código — como um Proof Gate se lê na prática

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.

loop/gates/proof.py
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)

Encontre você mesmo: grep -rn "def proof_gate" loop/

FAQ

Testes que passam são complementos fortes, mas provam seu código contra as suposições que você escreveu nos mocks. O serviço real pode retornar uma forma que seu mock nunca imaginou, ou estar fora do ar, ou aplicar uma config que você esqueceu. O Proof Gate quer o próprio boundary observado pelo menos uma vez. Mantenha os testes — eles te deixam rápido — e então bata de fato na coisa real.
Então você para e pergunta — você nunca escreve "pronto" sobre uma mudança não verificada. Exponha o bloqueio exato (sem credenciais, dispositivo não conectado, ação destrutiva precisa de aprovação) como um handoff pronto para decisão e deixe o humano destravá-lo. Um honesto "bloqueado, é disto que eu preciso" vence uma mentira confiante toda vez.
Sim. A prova era sobre o estado antes da mudança; depois de qualquer edição, essa prova está desatualizada. Uma correção de um caractere pode quebrar o boundary tão completamente quanto uma reescrita. Reexecute a prova após cada mudança — e, como boa prova é um comando capturado e reexecutável, fazer isso é barato.
No boundary real deles também — que, para a web ao vivo, é a Bright Data CLI (lição 11), nunca um chute de memória e nunca WebSearch/WebFetch. Se uma alegação depende de um fato atual, você busca esse fato da fonte real como sua evidência.
6

Alegação vs prova — vire cada linha para ver a 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.

As afirmações do turno

Alternar: alegação → prova no boundary real.

Alternar: alegação → prova no boundary real.

Alternar: alegação → prova com entrada mais difícil.

Alternar: alegação → prova no boundary real.

O que o log registraao vivo

        

O sinal está no verbo

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.

Por que o veredito depende das quatro

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.

7

A fronteira da prova: onde os modelos param e a realidade começa


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.

MODELOS DA REALIDADE · complementos "deveria funcionar" type-check mock / stub teste de unidade A FRONTEIRA DA PROVA mapa termina · território começa Proof Gate O BOUNDARY REAL · a prova mora aqui processo ao vivo · exit code + stdout endpoint real · status + corpo UI renderizada · o DOM de verdade banco de dados · a linha realmente escrita
Os modelos à esquerda te dão velocidade; só cruzar a linha tracejada te dá prova. O gate fica no cruzamento.
8

Percorra a decisão do verify, um passo de cada vez


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.

Traçar turno:
sim sim sim não não não Unidade delimitada pronta Scope atendido? Provado no boundary? Course construído? ✓ Fechar o turno ↺ Loop / handoff
Leia de cima → baixo. Cada losango é um gate; o primeiro "não" roteia à direita para Loop/handoff, uma passada limpa chega a Fechar o turno.
Passo 0 de 4

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.

A decisão como guard clauses

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
}
9

O status do loop: como o veredito se lê num relance


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 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

Todos os gates verdes — turno pode fechar
verificado agora mesmo
Gates passados
3/3
+1 desde a reexecução
Itens de evidência
7
+3 capturados
Alegações não provadas
0
−2 resolvidas
Reexecuções da prova
2
após cada edição
Status por gate
Gate Status Evidência Última verificação

Um modelo, duas visões — e um rollup que nunca mente

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.

O humano lê, o loop escreve (AFK)

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.

10

Quando a prova falha: um "pronto" que não era, e a recuperação


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.

ALEGADO-PRONTO

O turno que disse "pronto" sem bater no boundary

Alegado prontoturno #14 · 11:02
Pegoverify do turno #15 · 11:48
Intervalo46 min sobre uma mentira
Gate puladoProof (boundary real)
Recuperado porre-LEARN → reprovar
10·1

Linha do tempo do "pronto" falso

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.

  1. 10:40

    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.

    unidade pronta
  2. 10:55

    Type-check + testes de unidade passam

    Todos os complementos estão verdes. O limiter mockado retorna 429 na 6ª chamada no teste. Parece terminado.

    complementos verdes
  3. 11:02

    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.

    prova pulada
  4. 11:30

    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 jusante
  5. 11:48

    O 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.

    pego
  6. 12:05

    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.

    resolvido
10:40 unidade pronta 10:55 testes verdes 11:02 "pronto" — prova pulada 11:30 a jusante 11:48 pego 12:05 reprovado
A mentira viveu por 46 minutos — da prova pulada às 11:02 até o curl real às 11:48.
10·2

Causa raiz — cinco porquês

Continue perguntando "mas por que isso aconteceu?" A primeira resposta é um sintoma; a quinta é a que vale a pena corrigir.

  1. Por que o bug foi entregue?

    O turno foi marcado como pronto enquanto o endpoint ao vivo ainda retornava 200 na 6ª tentativa.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

Fatores contribuintes (não a raiz única)

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.

Por que corrigimos o sistema, não a pessoa

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.

10·3

Raio de impacto

46 min

"Pronto" foi falso por

1

Turno a jusante enganado

Tentativas de força bruta ainda abertas

0

Entregue a usuários (pego antes)
10·4

Correções — marque-as

Cada correção transforma esta falha exata em uma que não pode recorrer. Marque os itens — a barra acompanha o progresso.

0 de 5 prontas
  • P1
  • P1
  • P2
  • P2
  • P3
11

O autoreview: uma passada independente sobre a mudança


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.

REVIEW  turno #14 · construído pelo executor · revisado pelo validator (nunca o construtor)
Adicionar rate limiting ao endpoint de login

Limita tentativas de senha a 5 / minuto por IP em POST /auth/login. 1 arquivo alterado · +9 −2

Segurançavetor de força bruta fechado Latência~ estável (em memória) Modos de falharisco de ordem de middleware Superfície de ataquetaxa de chute estrangulada 99%
src/routes/auth.ts+9−2
@@ -11,9 +11,16 @@ router.post('/auth/login', async (req, res) => {
1111 const { email, password } = req.body;
13+ const hits = await limiter.incr(key, { windowSec: 60 });
15+ return res.status(429).json({ error: 'too_many_attempts' });
16+ }
1217 const user = await db.users.findByEmail(email);
19+ if (!ok) return res.status(401).json({ error: 'bad_credentials' });
1520 return res.json({ token: sign(user.id) });
0 / 4 notas abertas Aprovar com mudanças

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.

Os gates provam comportamento; a revisão julga a mudança

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.

O revisor nunca é o construtor

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.

12

Gate 3 · Course — construído agora, não prometido para depois


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.

O que "curso completo" significa como gate

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.

O course-gate é o entregável de observabilidade

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.

13

Reexecute após qualquer mudança: a prova é perecível


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.

Provar rode no boundary mudança precisa? Faça a mudança corrija a lacuna Fechar passou, intocado sim reexecute a prova sem mudança → fechar
Provar → mudar → reprovar, repetidamente. A saída para Fechar só abre numa prova que não precisou de mudança.

É por isso que a prova precisa ser reexecutável

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.

Terminação

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.

14

No código: o passo verify, de ponta a ponta


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.

loop/verify.py — a sequência de gates de um turno
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

Chegue lá você mesmo

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

A linha que mais importa

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.

15

Exemplo resolvido: um turno pelos gates


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.

Como o "pronto" se parece com a evidência anexada

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)
16

Verificação rápida: alegação ou prova?


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?

Responda as quatro para ver sua pontuação.
Sua vez de contestar. Acha o Proof Gate exagero para uma mudança de uma linha, ou não tem certeza de onde está o "boundary real" no seu caso específico? Essa é exatamente a conversa para se ter — pergunte, e vamos resolver isso contra a sua situação real. Eu sou seu professor aqui: me diga onde isto ainda não encaixa no que você está construindo, e vamos fechar a lacuna. A seguir: o loop em movimento — AFK, onde você observa e não dirige.