Lição 24 · Curso de Fusão·Parte 5 · Engenharia · A trilha de ADRs
Alembic × Hermes · O Curso de Fusão · Visual Course
A trilha de ADRs: as decisões que moldaram a fusão
O código te diz o que o motor faz; os Architecture Decision Records te dizem por quê — e por que as alternativas foram rejeitadas. Cinco ADRs formam a espinha de tudo o que você aprendeu: que o Alembic é um engine, não um produto (0001); que o gate humano fica no gasto irreversível (0005); que o Validator é o gate de emissão (0006); que uma chamada de modelo nunca lança exceção (0009); e que o loop de auto-melhoria é Validator-gated (0018). Cada um é uma restrição que a fusão teve de honrar — lidos juntos, explicam por que @alembic/hermes tem a forma que tem, e não uma forma mais fácil.
Esta lição destila 0001-alembic-internal-engine-not-product.md, 0005-human-gate-at-ship.md, 0006-frontier-quality-depth-cheapest-above-floor.md, 0009-narrow-waist-run-never-throws.md e 0018-internalize-validator-gated-self-improvement-loop.md. Todo trecho entre aspas vem de um arquivo real — nada é inventado.
Leia a versão simples, ou abra a camada técnica em qualquer seção.
O que você vai conseguir fazer
Explicar o que é um ADR e por que ele é append-only — uma decisão nova supersede a antiga, nunca a edita.
Nomear as cinco decisões da espinha e dizer, para cada uma, qual opção ela remove do espaço de design.
Ler a trilha como um grafo de restrições: por que, quando 0018 é escrito, a implementação já está quase forçada.
Justificar por que o loop de aprendizado (0018) é um ADAPT, não um CLONE literal do Hermes — citando os dois motivos do ADR.
Suposições tolas (o que presumimos de você — bem pouco)
Você já viu as lições anteriores de relance — sabe que existe uma cintura estreita (lição 14), um Validator (lição 18) e um loop de aprendizado (lição 23). Vamos relembrar cada um.
Você não precisa ter escrito um ADR antes. A gente constrói o conceito do zero.
Você sabe ler uma tabela e um diagrama simples. Não precisa de TypeScript — traduzimos cada trecho de código.
1
A grande ideia
O código mostra o que o sistema faz. Os ADRs mostram por que ele não faz de outro jeito — e essa é a informação que não cabe em comentário nenhum.
Imagine herdar uma casa cheia de paredes estranhas. Sem explicação, você é tentado a derrubar uma para "simplificar" — até descobrir, tarde demais, que ela era estrutural. Um ADR (Architecture Decision Record) é a plaquinha presa em cada parede dizendo: "esta parede sustenta o telhado; estas outras três formas de fazer foram tentadas e rejeitadas; aqui está a consequência se você mexer." A trilha de ADRs do Alembic é a planta estrutural inteira da fusão.
Pense como… as regras de um jogo de tabuleiro impressas na tampa da caixa: cada regra remove jogadas possíveis. Quando você lê todas, percebe que a "jogada óbvia" muitas vezes é proibida por uma regra escrita lá atrás — e é exatamente isso que impede um agente futuro de "consertar" o sistema reintroduzindo uma decisão já rejeitada. A analogia quebra num ponto: aqui as regras têm data e nunca são apagadas; uma regra nova entra por cima, e a antiga fica como história.
Por baixo do capô
O repo mantém os ADRs em docs/adr/; dezoito estão aceitos. São append-only: uma decisão posterior supersede uma anterior (com seu próprio registro datado), nunca a edita — então a trilha é uma história verdadeira, não um retrato "arrumado". Cinco deles formam a espinha de toda a fusão @alembic/hermes: 0001, 0005, 0006, 0009 e 0018.
A propriedade que faz a trilha valer ouro: cada ADR registra também as opções consideradas e rejeitadas. Em 0009, por exemplo, a opção rejeitada é nomeada — "conventional throwing clients (exceptions on error / 429 / timeout)". Gravar o caminho rejeitado é o que transforma a decisão em restrição executável, não em mera informação.
O código pode ser reescrito amanhã; o ADR registra a decisão e a razão da rejeição — por isso a trilha é vinculante, não decorativa.
0
ADRs aceitos em docs/adr/
0
formam a espinha da fusão
0
restrições aninhadas que cercam o keystone (0018)
Guarde istoUm ADR não diz "o que o código faz" — isso o próprio código mostra. Ele diz por que, e por que não os outros jeitos. É a única peça que impede alguém de desfazer uma decisão estrutural por engano.
2
O que é um ADR — e por que append-only
Um ADR é um registro datado e imutável de uma decisão de arquitetura: o contexto, a escolha, as opções rejeitadas e as consequências. Quando a realidade muda, você não reescreve o ADR — você cria um novo que supersede o antigo. O antigo continua lá, como história. É a diferença entre um diário (append-only) e um quadro-branco (apagável).
Preveja antes de revelar
Um requisito muda e a decisão registrada no ADR-0001 ("engine, não produto") deixa de valer. O que a equipe faz com o arquivo 0001-...md?
Nada — o arquivo fica intacto. A nova decisão entra como um ADR novo, datado, que supersede o escopo do 0001. O próprio 0001 já antecipa isso na sua seção "Future note": productizar o Alembic "should be recorded as a new ADR superseding this one's scope." A trilha cresce; nunca é editada.
Superseder é empilhar, não apagar. O ADR-0001 até descreve o protocolo da sua própria futura reversão.As cinco partes de um ADR. A caixa tracejada — opções rejeitadas — é a que transforma o documento em restrição, não em ata.
Flashcard · sigla
O que significa ADR?
clique para virar
Architecture Decision Record. Um registro datado e imutável de uma decisão de arquitetura: contexto, escolha, opções rejeitadas, consequências.
Flashcard · regra
Pode-se editar um ADR quando a decisão muda?
clique para virar
Não. São append-only. Uma decisão nova supersede a antiga com seu próprio registro datado; a antiga fica como história.
Flashcard · por quê
Por que registrar a opção rejeitada?
clique para virar
Para que ninguém "simplifique" reintroduzindo um caminho já descartado — a rejeição fica versionada e datada, virando restrição executável.
Propriedade
ADR (append-only)
Doc editável comum
Quando muda
cria-se um novo que supersede
edita-se o texto no lugar
Histórico
preservado, datado
perdido (sobrescrito)
Opções rejeitadas
registradas, vinculantes
geralmente ausentes
Função p/ agente futuro
restrição que ele não pode desfazer por engano
sugestão facilmente ignorada
A trilha é um grafo de restrições aninhadas: cada ADR externo remove uma opção, e quando o ADR-0018 (núcleo) é escrito, o espaço de design já está estreito o bastante para quase forçar a implementação.
3
A trilha num relance
As cinco decisões, e — para cada uma — a opção que ela remove e como ela aperta a fusão. Leia a coluna do meio como "o que deixou de ser possível".
Nada aqui é novo de mecanismo — você já praticou cada peça. A novidade é ler a decisão (o porquê) por trás de cada uma.
ADR
A decisão
Como restringe a fusão
0001
O Alembic é um engine interno, não um SKU vendável
Nada de UI/billing/onboarding no engine — @alembic/hermes entrega bibliotecas, não superfícies de produto
0005
O gate humano fica no ship / gasto irreversível
O ClarifyGateway (lição 10) é a superfície T4; aprendizado e distill rodam sem humano no loop
0006
Profundidade frontier em tudo, via o modelo mais barato acima de um piso; o Validator é o gate de emissão
O loop de aprendizado precisa cruzar um piso de qualidade antes de sedimentar — não pode auto-escrever
0009
Uma chamada de modelo nunca lança; devolve um resultado discriminado
Todo subsistema do hermes devolve Result, injeta suas portas e é agnóstico a store
0018
Internalizar o loop do Hermes como um passo propose→dispose com gate do Validator
O keystone: o revisor propõe, o Validator dispõe, nunca auto-aplica
De fora para dentro, cada anel remove opções. Quando se chega ao 0018, a forma da implementação já está quase determinada.Os quatro fundadores vêm primeiro; 0018 chega 21 dias depois, já cercado pelas restrições que decidem a sua forma.
A leitura-chave. Esta não é uma lista de desejos independentes — é um grafo de restrições. 0001 remove "construir um produto". 0009 remove "lançar exceção". 0006 remove "auto-aplicar". 0005 remove tanto "dar gate em tudo" quanto "não dar gate em nada". Quando 0018 entra, o espaço de design ficou tão estreito que a implementação é quase forçada.
4
ADR-0001 — engine, não produto
"O Alembic é o engine/plataforma interno da Appfy, não um SKU voltado ao cliente hoje." A consequência é afiada: concerns de cliente — uma API pública à venda, billing, onboarding/marketing de tenant — "vivem nos produtos … não no engine".
O texto, e o que ele força
Por isso a fusão portou ferramentas como bibliotecas (um MemoryStore, uma função webSearch) e nunca um app de agente executável com UI. O ADR também deixa uma porta aberta: "If there is real market pull, productizing Alembic as harness-as-a-service … may become a new decision" — registrada como um ADR futuro que supersede o escopo deste, nunca uma edição.
A fronteira mais externa da fusão: o engine entrega peças componíveis; toda superfície de cliente fica do lado de fora.O engine fica no meio, consumido por produtos. Vender é trabalho dos produtos — por isso 0001 mantém UI/billing fora do @alembic/*.
5
ADR-0009 — o contrato que torna tudo componível
Você conheceu isto como a cintura estreita da lição 14. Como decisão, ela diz: toda chamada de modelo passa por run(input): Promise<ModelRunResult>, uma união discriminada, e "run() nunca lança: falhas são valores, não exceções".
A opção rejeitada e a consequência que carrega tudo
A opção rejeitada é nomeada — "conventional throwing clients" — porque elas "espalham try/catch pela orquestração … e acoplam quem chama a formatos de erro específicos do provedor". A parte que sustenta o resto: retry, circuit-breaking, medição de orçamento e quórum do council "todos operam sobre resultados tipados uniformes". Essa uniformidade é exatamente por que todo subsistema do hermes pôde adotar o mesmo formato Result sem casos especiais.
// a cintura: a forma que todo subsistema do hermes falatype ModelRunResult =
| { ok: true; value: … }
| { ok: false; error: { code; message; retryable } }
// run() NUNCA lança — a falha é um valor, não uma exceçãoconst r = await adapter.run(input)
if (!r.ok) { /* trate o err como dado, sem try/catch */ }
"run() nunca lança" não é estilo — é o que permite que council, retry e budget operem sobre o mesmo formato sem casos especiais.
6
ADR-0006 — o Validator é o gate de emissão
A manchete deste ADR é sobre custo (profundidade frontier no corpus inteiro, via o modelo mais barato acima de um piso de profundidade). Mas a cláusula que sustenta a fusão é o princípio de emissão: nada sedimenta sem cruzar um piso de qualidade.
De "barato e profundo" a "nada emite sem gate"
O ADR decide que o roteador vira cheapest-above-depth-floor: pickCheapestForTier ganha uma restrição de piso de qualidade em vez de pegar o modelo mais barato direto. Para a fusão, a leitura load-bearing é outra: a proposta de um revisor não é verdade, é um candidato, e um gate decide. O default scoreThresholdGate(0.7) é a codificação conservadora desse piso até o Validator real do @alembic/coda ser ligado.
O piso de qualidade é a regra que o loop de aprendizado teve de obedecer: candidato vira memória só se cruzar o gate.
7
ADR-0005 — o gate humano no gasto irreversível
Onde um humano tem de estar no loop? Não no momento do design — "código numa branch é reversível". O critério decisivo é "reversibilidade/externalidade, não a posição no pipeline — o gate fica onde um erro autônomo deixa de ser 'apagar uma branch' e vira dinheiro ou reputação".
Reversibilidade decide, não a etapa
Por isso ship e gasto real defaultam para T4-park (fail-closed), enquanto "Distillation (T0–T3 → Signal/Learning) e discover→build são HITL-free". Esse é o princípio que o ClarifyGateway implementa: uma pergunta estruturada e bloqueante é a superfície humana T4, usada só onde a reversibilidade acaba. As duas opções rejeitadas estão nomeadas no ADR: "gate before build" (reintroduz humano em trabalho reversível) e "fully autonomous through ship" (expõe dinheiro e reputação a um erro não supervisionado).
Distill e discover→build correm sozinhos porque são reversíveis; ship e gasto ficam parados até um GO humano.Por que 0018 é um ADAPT e não um CLONE: o Hermes escreve direto na memória (rejeitado, viola 0006); o Alembic faz o revisor propor e o Validator dispor, sobre portas injetadas e fail-closed.
8
ADR-0018 — o keystone, e por que é ADAPT não CLONE
O mais novo dos cinco (aceito em 2026-06-23) é o que autoriza todo o subsistema de aprendizado. O Hermes tinha a peça que faltava — um revisor pós-turno que escreve direto na memória durável — mas o Alembic não pôde copiá-la ao pé da letra, por dois motivos que o ADR enuncia com todas as letras.
"O Alembic não tem um AIAgent Python para forkar como daemon thread" — então o mecanismo vira um passo sobre portas injetadas, não uma thread de fundo.
"E — mais importante — auto-escrever na memória durável violaria o princípio do validator-como-gate-de-emissão (ADR-0006)." Então o revisor propõe e o Validator do Alembic dispõe.
As quatro garantias, e por que a forma é forçada
Leia os dois itens acima e você vê a trilha funcionando como sistema: 0018 não pode simplesmente clonar o Hermes porque 0006 proíbe emissão sem gate e 0009 proíbe lançar exceção — então a única forma que sobra é exatamente o propose→gate→apply sobre portas injetadas que você construiu no Lab 2 (lição 23). O ADR ainda nomeia as quatro garantias: (1) só portas injetadas; (2) Validator-gated, não auto-aplicado; (3) default conservador scoreThresholdGate(0.7) com gate mais rico opt-in; (4) o passo é fail-closed, com Zod na fronteira porque, em produção, é saída de modelo não-confiável.
// 0018: a forma que 0006 + 0009 deixam como única possível
reviewAndLearn(summary, { proposer, gate, memory })
// proposer (1 chamada ModelAdapter) → ReviewProposal[]// gate dispõe: scoreThresholdGate(0.7) aprova score ≥ 0.7// aprovados aplicam ao MemoryStore (reusa dedup: reforça, não duplica)// erro de proposer/gate → err (fail-closed); empty summary → no-op
O diagrama de consequência do próprio ADR-0018: distill e o review fork alimentam a memória com gate, fechando o loop sem desviar do pipeline existente.
A trilha é um grafo de restrições, não uma lista de desejos
Cada ADR remove opções. 0001 remove "construir um produto". 0009 remove "lançar exceção". 0006 remove "auto-aplicar". 0005 remove "dar gate em tudo" e "não dar gate em nada". Quando 0018 é escrito, o espaço de design ficou tão estreito que a implementação é quase forçada. Esse é o valor de escrever as decisões: um agente futuro não pode "simplificar" reintroduzindo uma opção rejeitada, porque a rejeição está versionada e datada.
9
Explorador de restrições
Clique em cada ADR para ver qual opção ele remove e que anel do grafo de restrições ele acende. Repare como os anéis externos vão fechando o cerco até o núcleo (0018).
ADR-0001
Engine, não produto
O Alembic é o engine interno, não um SKU vendável. Superfícies de cliente vivem nos produtos.
remove: "construir um produto dentro do engine"docs/adr/0001-...md · @alembic/hermes entrega bibliotecas
ADR-0001 → acende o anel externo (a fronteira do engine).
10
Exemplo guiado: ler a trilha como um sistema
Vamos derivar a forma do loop de aprendizado apenas a partir dos ADRs — sem olhar o código. A ideia: as restrições, lidas em ordem, deixam só uma forma possível.
Derivando a forma do loop a partir das restrições
1
Comece pela necessidade. Queremos que um run termine e o sistema fique "mais inteligente": algum aprendizado precisa virar memória durável. (É a peça que o Hermes tinha e o Alembic não — a §1.10 do mapa do Hermes.)
2
Aplique 0009. "run() nunca lança" e o kernel é agnóstico a adapter/store. Logo o loop não pode construir um adapter concreto nem lançar exceção: ele recebe portas injetadas e devolve Result.
3
Aplique 0006. Nada sedimenta sem cruzar um piso de qualidade. Logo o loop não pode auto-escrever: o que ele produz é um candidato que precisa de um gate.
4
Combine. "Portas injetadas + Result" (passo 2) e "candidato precisa de gate" (passo 3) só cabem em uma forma: reviewAndLearn(summary, {proposer, gate, memory}) — o revisor propõe, o ReviewGatedispõe, e só o aprovado aplica ao MemoryStore.
5
Conclua com 0001. Como é engine, isso é uma biblioteca (o kernel + as portas), não um app com UI. O ADR-0018 confirma: "ships the ports and the kernel only".
A derivação da lição em uma imagem: três restrições empilhadas afunilam o espaço de design até a única forma que sobra — a do Lab 2.
Agora você. Pegue o ADR-0005 ("reversibilidade decide o gate"). Pergunta: o passo "escrever um aprendizado na memória durável" precisa de um gate humano (T4)?
Resposta: não de um gate humano — escrever memória é reversível (dá para corrigir/superseder um registro) e interno, não toca dinheiro nem reputação. Por isso o gate aqui é o Validator (0006), automático, e não o ClarifyGateway humano (que 0005 reserva para ship/gasto). Você acabou de usar duas restrições juntas para localizar o tipo certo de gate.
11
Confusões comuns
"ADRs são atualizados quando o design muda." Não — são append-only. Uma decisão nova supersede a antiga com seu próprio registro datado; a antiga fica como história. O ADR-0001 até descreve o protocolo da sua própria futura reversão na seção "Future note".
"0006 é só sobre dinheiro." A manchete é custo (profundidade barata acima de um piso), mas a cláusula em que a fusão se apoia é o princípio de emissão — nada sedimenta sem cruzar um piso de qualidade. Essa única ideia é o que torna o aprendizado gated em vez de automático (0018).
"0018 só copiou o Hermes." É um ADAPT, não um CLONE literal. Dois motivos no ADR: não há AIAgent Python para forkar como thread; e — mais importante — auto-escrever violaria o gate de emissão (0006). Por isso o revisor propõe e o Validator dispõe, em vez da escrita direta do Hermes.
Escrever memória passa pelo gate da esquerda (automático, reversível); só ship e gasto passam pelo da direita (humano, irreversível).
CuidadoNão confunda os dois gates. O gate de emissão (0006, Validator, automático) decide o que sedimenta na memória. O gate humano (0005, ClarifyGateway, T4) decide o que toca o mundo (ship, gasto). Escrever memória passa pelo primeiro, não pelo segundo.
12
Recapitulando
Os pontos da lição em sequência — avance os slides com os botões, as setas do teclado ou os pontinhos.
Recap · 1 de 6
O ADR responde "por quê"
Código mostra o que o sistema faz; o ADR registra por que — e por que as alternativas foram rejeitadas. É a única peça que impede um agente futuro de desfazer uma decisão estrutural por engano.
1
Recap · 2 de 6
Append-only
Uma decisão nova supersede a antiga com registro datado; a antiga fica como história. São 18 ADRs aceitos; 5 formam a espinha da fusão.
2
Recap · 3 de 6
0001 e 0009 — fronteira e contrato
0001 remove "construir um produto" (só bibliotecas). 0009 remove "lançar exceção" (todo subsistema fala Result, portas injetadas, store-agnóstico).
3
Recap · 4 de 6
0006 e 0005 — os dois gates
0006 remove "auto-aplicar": nada sedimenta sem cruzar um piso (Validator). 0005 põe o gate humano onde a reversibilidade acaba — em ship/gasto, não numa etapa fixa.
4
Recap · 5 de 6
0018 — o keystone (ADAPT, não CLONE)
Sem AIAgent Python para forkar; e — mais importante — auto-escrever violaria 0006. Logo o revisor propõe e o Validator dispõe: propose→gate→apply sobre portas injetadas.
5
Recap · 6 de 6
A trilha é um grafo de restrições
Cada ADR remove opções. Quando 0018 entra, o espaço de design está tão estreito que a implementação é quase forçada. Decisão escrita = restrição que ninguém desfaz por engano.
6
Slide 1 / 6Use ←→
Em uma frase, para você mesmo: "Um ADR registra ____ e ____; é append-only porque ____; e a trilha é um grafo de restrições porque ____." Se você preenche as quatro lacunas, está pronto para a lição 25.
13
Verifique seu entendimento
Três perguntas. Escolha e leia o porquê de cada opção — o feedback ensina tanto quanto a pergunta.
Checagem cumulativa
Acerte as três para fechar a lição. A pontuação aparece abaixo.
1. O ADR-0018 diz que o loop de aprendizado é um ADAPT, não um CLONE literal do Hermes. O motivo mais importante apontado é:
(c). O ADR lista dois motivos (não há AIAgent Python para forkar; e o princípio do gate de emissão) e marca o segundo como "more importantly". 0006 proíbe sedimento sem gate, o que força a forma propose→dispose em vez da escrita direta do Hermes.
2. Pelo ADR-0005, o que decide se uma ação precisa de um gate humano?
(b). O ADR é explícito: "the deciding criterion is reversibility/externality, not pipeline position". Por isso distill e discover→build são HITL-free (reversíveis), mas ship e gasto real defaultam para T4-park.
3. Por que o projeto registra as opções rejeitadas dentro de cada ADR (ex.: "throwing clients — rejeitado")?
(d). Registrar o caminho rejeitado é o que torna a decisão vinculante, não só informativa. A rejeição datada transforma a trilha num grafo de restrições que ninguém pode desfazer por engano.
Acertos: 0/3
As ideias para levar desta lição
Um ADR registra por que — e por que não os outros jeitos. O código só mostra o "o quê".
ADRs são append-only: a decisão nova supersede a antiga; a antiga fica como história.
São 18 ADRs aceitos em docs/adr/; cinco formam a espinha da fusão.
0001 — engine, não produto: @alembic/hermes entrega bibliotecas, não superfícies de cliente.
0009 — run() nunca lança: todo subsistema fala Result, injeta portas, é store-agnóstico.
0006 — o Validator é o gate de emissão: nada sedimenta sem cruzar um piso de qualidade.
0005 — o gate humano fica onde a reversibilidade acaba (ship/gasto), não numa etapa fixa.
0018 — o keystone: o revisor propõe, o Validator dispõe; é ADAPT, não CLONE.
A trilha é um grafo de restrições: cada ADR remove opções até quase forçar a implementação.
Registrar a opção rejeitada é o que torna a decisão vinculante — impossível "simplificar" por engano.