Curso / Lição 24
Lição 24 · Avançado · as decisões

A trilha de ADRs: as decisões que moldaram a fusão

O código diz o que o motor faz; os Architecture Decision Records dizem por quê — e por que as alternativas foram rejeitadas. Cinco ADRs formam a espinha de tudo que você aprendeu, e o ponto desta lição é que eles se restringem mutuamente: lidos juntos, eles deixaram a forma de @alembic/hermes quase forçada — não havia caminho mais fácil que respeitasse os cinco ao mesmo tempo.

Leia primeiro (fonte primária)
docs/adr/ — os cinco ADRs, lidos literalmente (0001, 0005, 0006, 0009, 0018)

Esta lição destila esses cinco arquivos do repo (todos com status Accepted). Os números, datas e identificadores são citados verbatim do docs/adr/* (rodapé). Por que importa pra missão: é a constituição que diz, antes de qualquer linha de código, o que a fusão podia e o que não podia fazer.

Objetivos desta lição
  • Explicar o que é um ADR e por que ele é append-only (decisões substituem, nunca editam).
  • Recitar a decisão central de cada um dos cinco ADRs (0001, 0009, 0006, 0005, 0018) e o que cada um proíbe.
  • Mostrar como os cinco se encaixam num grafo de restrições que estreita o espaço de design.
  • Provar por que a ADR-0018 teve que ser um ADAPT, e não um CLONE literal do Hermes.
0 ADRs
a espinha da fusão
0 aceitos
no total em docs/adr/
0 edições
append-only: só substituição
0 garantias
que a 0018 nomeia

01 · O que é, de fato, um ADR

Imagine o repo como uma cidade e cada decisão arquitetural como uma lei. Um ADR (Architecture Decision Record) é o texto dessa lei: um registro datado e imutável de uma decisão — o contexto, a escolha feita, as opções rejeitadas e as consequências. O repo os mantém em docs/adr/; dezoito estão aceitos.

A regra que muda tudo: são append-only. Quando o design muda, você não edita a lei antiga — você escreve uma nova que substitui a anterior, com sua própria data. A antiga permanece como história. Por isso a trilha é uma história verdadeira, não um instantâneo arrumado. A própria ADR-0001 já detalha o protocolo da sua futura reversão.

Anatomia de um ADR · as quatro partes

Todo ADR do repo tem a mesma forma. A parte que mais surpreende quem chega é a terceira — registrar o que foi rejeitado é o que torna a decisão executável (seção 08):

AS QUATRO PARTES DE UM ADR · exemplo: ADR-0009 (a cintura estreita)
1 · Contexto qual problema? 2 · Decisão o que escolhemos 3 · Rejeitadas o caminho NÃO tomado (datado) 4 · Consequências o que passa a valer A caixa 3 é o segredo: a opção rejeitada fica versionada e datada — um agente futuro não pode reintroduzi-la "para simplificar".

Append-only: a linha do tempo, não o "estado atual"

A diferença entre editar e substituir não é cosmética. Editar apaga a memória da decisão; substituir a preserva. Veja as duas culturas lado a lado:

EDITAR (apaga a história) vs SUBSTITUIR (append-only, preserva) — o repo usa a direita
✗ EDITAR no lugar decisão antiga … (sobrescrita) decisão nova (a antiga sumiu) não dá pra saber o que mudou nem por quê ✓ SUBSTITUIR (append-only) ADR antiga · permanece como história ADR nova · "supersedes" a antiga com data própria a trilha vira história auditável de decisões

02 · A trilha num relance

Antes de abrir cada ADR, veja os cinco juntos. Cada linha tem a decisão e, principalmente, o que ela proíbe à fusão — é essa coluna que vira o grafo de restrições da seção 08:

ADRA decisãoComo restringe a fusão
0001Alembic é um motor interno, não um SKU para clienteSem UI/billing/onboarding no motor — o @alembic/hermes entrega bibliotecas, não superfícies de produto
0009Uma chamada de modelo nunca lança; retorna um resultado discriminadoTodo subsistema hermes retorna ModelRunResult, injeta suas portas e é agnóstico de store
0006Profundidade frontier em tudo, via o modelo mais barato acima de um piso; o Validator é o portão de emissãoO loop de aprendizado deve passar um piso de qualidade antes de sedimentar — não pode auto-gravar
0005O portão humano fica no ship / gasto irreversívelO ClarifyGateway (Lição 10) é a superfície T4; aprender + distillar rodam sem humano (HITL-free)
0018Internalizar o loop do Hermes como uma passagem propose→dispose com gate de ValidatorA pedra angular: o revisor propõe, o Validator dispõe, nunca auto-aplica

As cinco restrições, aninhadas

Não são cinco regras soltas: elas se encaixam como caixas dentro de caixas. A 0001 é a fronteira mais externa; lá dentro, a 0009 define o contrato; dentro dela, os portões (0006 e 0005); e no centro, espremida por todas, a 0018:

CINCO ADRs COMO RESTRIÇÕES ANINHADAS · a 0018 fica dentro das quatro ao mesmo tempo
ADR-0001 — motor, não produto (a fronteira externa: sem superfícies de cliente no motor) ADR-0009 — run() nunca lança (o contrato que todo subsistema fala) ADR-0006 — Validator é o portão de emissão  ·  ADR-0005 — portão humano no gasto irreversível ADR-0018 — o loop de aprendizado com gate propor → gate (dispõe) → sedimentar — nunca auto-aplicar só sobra esta forma quando respeita as quatro restrições externas
Preveja antes de continuar
A ADR-0018 (a pedra angular do aprendizado) foi aceita bem depois das outras quatro. Olhando a data de cada uma no rodapé do repo, qual o intervalo entre a primeira leva (0001/0005/0006/0009) e a 0018? Chute antes de revelar.
~21 dias. As quatro primeiras foram aceitas em 2026-06-02; a ADR-0018 em 2026-06-23. Isso importa: a 0018 chegou num espaço de design já cercado pelas outras quatro — por isso ela não pôde inventar uma forma nova, só preencher o vão que sobrava. Decisões antigas restringem as novas, e a trilha registra essa ordem.

A trilha como linha do tempo (datada e append-only)

A ordem não é decoração: cada ADR carrega a data em que foi aceito, e é por isso que a 0018 herda as restrições das quatro anteriores. Veja as duas levas na linha do tempo — a primeira leva em 2026-06-02 ergueu as paredes; a 0018, ~21 dias depois, só pôde construir no espaço que sobrou:

LINHA DO TEMPO · primeira leva (2026-06-02) → ADR-0018 (2026-06-23), o intervalo de ~21 dias
tempo → 2026-06-02 primeira leva — ergue as paredes ADR-0001 ADR-0009 ADR-0006 ADR-0005 ~21 dias depois — espaço de design já cercado 2026-06-23 só preenche o vão que sobrou ADR-0018 a pedra angular

03 · ADR-0001 — motor, não produto

"Alembic é o motor/plataforma interno da Appfy, não um SKU para cliente hoje." A consequência é nítida: preocupações voltadas ao cliente — uma API pública para venda, billing, onboarding/marketing de tenant — "vivem em produtos … não no motor". É por isso que a fusão portou ferramentas como bibliotecas (um MemoryStore, uma função webSearch) e nunca um app de agente executável com UI.

A porta que fica aberta. A ADR não fecha a questão para sempre: "Se houver pull de mercado real, produtizar o Alembic como harness-as-a-service … pode virar uma nova decisão" — registrada como um ADR futuro substituindo o escopo deste, nunca uma edição. É o protocolo append-only aplicado à própria ADR-0001.

Como decisão, ela funciona como um filtro de forma: diante de qualquer capacidade do Hermes, a pergunta vira "isto é uma biblioteca consumível por um produto, ou uma superfície de cliente?". A primeira entra no motor; a segunda é rejeitada para o produto que consome o motor:

DIAGRAMA DE DECISÃO · ADR-0001 — o que entra no motor e o que é rejeitado
capacidade do Hermes candidata a portar é superfície de cliente? (UI/billing) SIM ✗ não vai p/ o motor pertence ao produto (ex.: FounderOS) NÃO ✓ entra no motor como biblioteca MemoryStore, webSearch, reviewAndLearn…

04 · ADR-0009 — a cintura estreita (o contrato)

Você conheceu isto como a cintura estreita da Lição 14. Como decisão, ela diz: toda chamada de modelo passa por um único contrato — run(input): Promise<ModelRunResult>, onde ModelRunResult é uma união discriminada, e "run() nunca lança: falhas são valores, não exceções". A própria ADR a chama de "a invariante mais importante do motor".

// ADR-0009 — o contrato, verbatim na forma da união discriminada
type ModelRunResult =
  | { ok: true, /* … */ }
  | { ok: false, error: { code, message, retryable }, /* … */ };

function run(input): Promise<ModelRunResult> // nunca lança: falha é valor

A opção rejeitada é nomeada — "clientes convencionais que lançam (exceções em erro / 429 / timeout)" — porque eles "espalham try/catch pela orquestração, tornam ad hoc o tratamento de falha parcial, e acoplam chamadores a formatos de erro específicos de provedor". Compare as duas culturas de erro:

CLIENTE QUE LANÇA (rejeitado) vs run() NUNCA LANÇA (a decisão) — falha vira valor tipado
✗ cliente que lança chamada falha → throw (429/timeout) try/catch espalhado por toda orquestração acopla ao formato de erro do provedor tratamento de falha parcial vira ad hoc ✓ run() retorna resultado falha → { ok:false, error:{ retryable } } retry / circuit-break / orçamento / quórum tudo sobre resultados tipados uniformes o kernel nunca vê uma exceção de provedor

Como decisão, a 0009 instala um losango na fronteira de toda chamada de modelo: o resultado é uma exceção lançada (rejeitado) ou um valor tipado (a cintura)? Só o segundo caminho atravessa a cintura estreita — o primeiro é eliminado por contrato:

DIAGRAMA DE DECISÃO · ADR-0009 — toda chamada de modelo na fronteira: lança ou retorna valor?
chamada de modelo na fronteira run() lançaria exceção (429 / timeout)? SIM ✗ proibido por contrato — vira valor tipado NÃO ✓ ModelRunResult { ok:true } | { ok:false, error } atravessa a cintura estreita o losango não tem uma saída "exceção" — por isso o kernel a montante só conhece valores tipados.

A lista de consequências é a parte que sustenta a fusão: "retry, circuit-breaking, medição de orçamento e quórum de council operam todos sobre resultados tipados uniformes". Essa uniformidade é exatamente por que todo subsistema hermes pôde adotar a mesma forma de resultado sem casos especiais — e a ADR ainda registra que essa invariante é "load-bearing" para o comportamento fail-closed (ADR-0011) e para o replay (ADR-0008).

05 · ADR-0006 — o Validator é o portão 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 sua cláusula sustentadora para a fusão é o princípio de emissão: nada sedimenta sem passar um piso de qualidade. Essa é a regra que o loop de aprendizado teve que obedecer.

Proposta ≠ verdade. A saída de um revisor não é fato; é um candidato. Um gate decide se ele vira memória durável. O default scoreThresholdGate(0.7) é a codificação conservadora desse piso até o Validator real do @alembic/coda se ligar. "Auto-gravar" sem esse gate é exatamente o modo de falha que a 0006 existe para impedir.

Como decisão, a 0006 instala um losango obrigatório entre "candidato" e "memória". Sem ele, um aprendizado não validado endurece na memória durável:

DIAGRAMA DE DECISÃO · ADR-0006 — o piso de qualidade entre candidato e sedimento
candidato (proposta do revisor) passa o piso de qualidade? SIM ✓ sedimenta vira memória durável NÃO ✗ descartado (não endurece) o losango é o "portão de emissão": sem ele, lições não validadas viram verdade durável.

06 · ADR-0005 — o portão humano no gasto irreversível

Onde um humano precisa estar no loop? A ADR-0005 dá um critério único e contra-intuitivo. O pipeline da Venture Factory — discover → validate → design → plan → build → ship — roda autônomo até o build, porque "código numa branch é reversível". O critério decisivo é "reversibilidade/externalidade, não posição no pipeline — o portão fica onde um erro autônomo deixa de ser 'apagar uma branch' e vira dinheiro ou reputação".

O que é HITL-free (reversível): "Destilação (T0–T3 → Signal/Learning) e discover → build são HITL-free" — é o "no human-in-the-loop" do WIKI_LLM e a doutrina de "<5% de intervenção humana" da holding. Errar aqui é só apagar uma branch.
O que é T4-park (irreversível): ship e gasto real (deploy público, marketing pago) defaultam para T4-park (fail-closed); um GO humano os libera. DEFAULT_TIER = T4: na dúvida, pára e espera o humano.

A decisão é melhor lida como um fluxograma sobre o pipeline: cada estágio passa pelo mesmo losango — "este passo é reversível?". Enquanto a resposta for sim, segue autônomo; no primeiro "não", entra o portão humano T4. Siga as setas:

FLUXOGRAMA · ADR-0005 — o portão humano cai onde a reversibilidade se esgota (não numa etapa fixa)
discover validate design plan build ship ↑ tudo reversível → roda autônomo (HITL-free) reversível? (dinheiro/reputação?) NÃO ⛔ T4-park (fail-closed) espera GO humano · ClarifyGateway é a superfície T4 Destilação T0–T3 → Signal/Learning + aprender (reviewAndLearn): reversível → rodam sem humano (HITL-free)

É o princípio que o ClarifyGateway implementa: uma pergunta estruturada e bloqueante é a superfície humana T4, usada só onde a reversibilidade se esgota. As duas opções rejeitadas confirmam o critério — "Gate antes do build" foi rejeitada (reintroduz humano onde nada toca o mundo) e "Totalmente autônomo até o ship" também (expõe dinheiro e reputação a um erro não supervisionado).

07 · ADR-0018 — a pedra angular, e por que é ADAPT, não CLONE

A mais nova dos cinco (aceita em 2026-06-23) é a que autoriza todo o subsistema de aprendizado. O Hermes tinha a peça que faltava — depois de um turno, ele forka um revisor "memory/skill-only" que pergunta "algo deve ser salvo ou atualizado?" e grava direto nos stores duráveis (agent/background_review.py). O Alembic internaliza esse loop como @alembic/hermes/learning, mas "remodelado às invariantes do motor": o revisor propõe, e o Validator do Alembic dispõe — gravações são "com gate de Validator, nunca auto-aplicadas".

A ADR declara, palavra por palavra, por que isso é um ADAPT e não um CLONE literal — por duas razões:

Leia esses dois pontos e você vê a trilha funcionando como sistema: a 0018 não pode clonar o Hermes porque a 0006 proíbe emissão sem gate e a 0009 proíbe lançar — então a única forma que sobra é o propose→gate→apply sobre portas injetadas. Aqui está a forma que a ADR fixa:

FLUXOGRAMA · ADR-0018 — reviewAndLearn(summary, { proposer, gate, memory }): propor → dispor → aplicar
ReviewProposer 1 call ModelAdapter ReviewProposal[] { target, op, rationale, score } ReviewGate: score ≥ 0.7? SIM ✓ aplica no MemoryStore reusa dedup: reforça, não duplica NÃO ✗ descartado (não sedimenta) fail-closed + Zod na fronteira erro de proposer/gate → a passagem inteira falha (err) write rejeitado pelo store → vai p/ failed, nunca lança summary vazio ou zero propostas = no-op válido ("Nothing to save.")
// ADR-0018 — o kernel, dependendo de portas injetadas APENAS (ADR-0009)
reviewAndLearn(summary, { proposer, gate, memory })

// gate default conservador: "aprenda só de vitórias validadas"
const gate = scoreThresholdGate(0.7); // score >= 0.7 aprova
// o Validator real do @alembic/coda entra depois, fornecendo SEU ReviewGate
// — sem mudar reviewAndLearn (opt-in por injeção)

A decisão nomeia as quatro garantias: (1) portas injetadas apenas — nenhum adapter ou store concreto construído dentro; (2) gravações com gate de Validator, não auto-aplicadas; (3) default conservador scoreThresholdGate(0.7) com um gate mais rico (o Validator do coda) opt-in por injeção; (4) a passagem é fail-closed, com a saída do proposer Zod-validada na fronteira porque em produção é saída de modelo não-confiável.

ADAPT vs CLONE, lado a lado

A diferença entre copiar o Hermes ao pé da letra (CLONE) e remodelá-lo às invariantes (ADAPT) é o resumo de toda a lição:

AspectoCLONE literal do Hermes (rejeitado)ADAPT do Alembic (a decisão)
Mecanismothread daemon / processo forkado (background_review.py)passagem síncrona pós-unit sobre portas injetadas
Gravaçãoauto-aplica direto na memória durávelrevisor propõe; o Validator dispõe (gated)
Viola?sim — fura o portão de emissão (ADR-0006)não — compõe com a pipeline de gates
Dedupmecanismo novo dentro do loopreusa o dedup do MemoryStore (reforça, não duplica)
Por que isso é elegante, não burocrático

A ADR-0018 também registra o que não faz: "Ainda não conectado ao @alembic/coda nem ao harness — este ADR entrega só as portas e o kernel." Conectar o Validator do coda como o ReviewGate e invocar reviewAndLearn como passe pós-unit é um follow-up que consome essa API sem mudá-la. A restrição (portas injetadas) virou a extensibilidade.

A 0018 compõe — não substitui — o funil e a pipeline

A consequência que a ADR registra textualmente é que o loop "compõe com o funil de destilação e a pipeline de gates em vez de substituir qualquer um dos dois". Dois fluxos alimentam a mesma memória durável, e o resultado é que a próxima run começa mais inteligente:

ARQUITETURA · SOURCE → distill → Learnings ─┐ ; run → review fork ─┘ → memória (com gate) → próxima run mais esperta
SOURCE distill Learnings run (terminada) review fork(ReviewProposer) ReviewProposal[]propõe, não grava gate de Validator scoreThresholdGate(0.7) MemoryStore durável (com dedup) → a próxima run começa mais esperta (o loop fechado que faltava)

08 · A trilha é um grafo de restrições, não uma lista de desejos

Aqui fecha a ideia central. Cada ADR remove opções. A 0001 remove "construir um produto". A 0009 remove "lançar no erro". A 0006 remove "auto-aplicar". A 0005 remove tanto "dar gate em tudo" quanto "dar gate em nada". Quando a 0018 é escrita, o espaço de design encolheu tanto que a implementação é quase forçada.

Clique em cada ADR no grafo abaixo para acender as restrições que ele impõe sobre a 0018 — repare como as setas convergem todas para o mesmo ponto:

GRAFO DE RESTRIÇÕES · como os quatro ADRs externos forçam a forma da ADR-0018 (clique num nó)
− "construir produto" − "lançar no erro" − "auto-aplicar" − "gate em tudo / em nada" ADR-0001 motor, não produto ADR-0009 run() nunca lança ADR-0006 portão de emissão ADR-0005 portão humano ADR-0018 propose→gate→apply As quatro setas convergem: a forma da 0018 é o que sobra depois das quatro remoções.

É o valor de escrever decisões: um agente futuro não pode "simplificar" reintroduzindo uma opção rejeitada, porque a rejeição é versionada e datada. Recordar isso fecha o objetivo desta lição.

Outra forma de ver o mesmo fato: pense no espaço de design como um funil. No topo, muitas formas plausíveis para o loop de aprendizado; cada ADR é um estreitamento que descarta um conjunto delas; no fim do funil sobra uma. Quando a 0018 foi escrita, o funil já estava quase fechado:

FUNIL DE RESTRIÇÕES · cada ADR estreita o espaço de design até sobrar uma única forma
muitas formas plausíveis para o loop de aprendizado ADR-0001 − remove "construir um produto" (app/UI) ADR-0009 − remove "lançar no erro" (vira valor tipado) ADR-0006 − remove "auto-aplicar" (exige gate) ADR-0005 − remove "gate em tudo / em nada" (só no irreversível) 1 forma: propose → gate → apply

09 · Rastreie uma decisão pela trilha (passo a passo → agora você)

Você viu o grafo. Agora rastreie uma escolha de design da fusão pela trilha, devagar — depois um exercício é seu. Recuperar o procedimento (não só ver a conclusão) é o que fixa.

Exemplo resolvido · "o revisor pós-turno pode gravar direto na memória?"
1
Comece pela capacidade do Hermes. O background_review.py forka um revisor que grava direto nos stores duráveis. Tentação: clonar igual.
2
Passe pela ADR-0001. É uma biblioteca consumível (um passe de aprendizado), não uma superfície de cliente. Entra no motor ✓ — mas como ainda não está decidido.
3
Passe pela ADR-0009. O proposer é uma chamada de modelo → tem que retornar ModelRunResult, nunca lançar. Isso elimina "thread que estoura exceção". Remove "lançar no erro".
4
Passe pela ADR-0006. Gravar direto = sedimentar sem piso de qualidade = furar o portão de emissão. Remove "auto-aplicar" — a gravação tem que passar por um gate.
5
Veredito. Sobrou uma única forma: o revisor propõe (ReviewProposer), um gate dispõe (scoreThresholdGate(0.7)), e só o aprovado aplica no MemoryStore. É exatamente a ADR-0018.
Agora você: "o passe de aprendizado pode pedir confirmação humana a cada vez?" Rastreie pela ADR-0005 antes de revelar.
Não — e a ADR-0005 explica por quê. O critério é reversibilidade. Um aprendizado é reversível (dá pra apagar uma linha de memória), então pertence ao trilho HITL-free (como distill). Pôr humano aí violaria a doutrina de "<5% de intervenção". O portão humano fica só onde a reversibilidade se esgota (ship/gasto), não no aprendizado. Dica: o procedimento é sempre o mesmo — passe a escolha por cada ADR e veja quais opções cada um remove.

10 · A trilha em duas camadas (Simples / Técnico)

A mesma ideia, em dois níveis. Comece pelo "Simples"; quando estiver firme, abra o "Técnico" para a forma precisa:

Em uma frase: as decisões antigas são paredes; quando você vai construir algo novo (a 0018), só pode erguê-lo no espaço que as paredes deixam livre. Como cada parede está escrita e datada, ninguém pode derrubá-la "para simplificar" sem escrever uma parede nova no lugar. Por isso a fusão tem a forma que tem: era a única que cabia entre as paredes.
Na forma precisa: ADR-0001 restringe o artefato (biblioteca, não SKU). ADR-0009 restringe a assinatura (run(): Promise<ModelRunResult>, união discriminada, nunca lança; adapter/store-agnóstico). ADR-0006 restringe a emissão (nada sedimenta sem piso de qualidade). ADR-0005 restringe o gate humano (só no irreversível; DEFAULT_TIER = T4). A interseção dessas quatro é exatamente reviewAndLearn(summary, { proposer, gate, memory }) com scoreThresholdGate(0.7), fail-closed e Zod na fronteira — a ADR-0018.

11 · Confusões comuns

Duas leituras erradas aparecem sempre. A primeira: tratar ADR como "estado atual" editável. A segunda: ler a ADR-0006 só pela manchete (custo) e perder a cláusula em que a fusão de fato se apoia.

"ADRs são atualizados quando o design muda." Não — são append-only. Uma nova decisão substitui uma antiga com seu próprio registro datado; a antiga permanece como história. A própria ADR-0001 detalha o protocolo para sua reversão futura (um novo ADR substituindo seu escopo, nunca uma edição).
"A 0006 é só sobre dinheiro." A manchete é custo — profundidade frontier no corpus inteiro via o modelo mais barato acima de um piso. Mas a cláusula em que a fusão se apoia é o princípio de emissão: nada sedimenta sem passar um piso de qualidade. Essa única ideia é o que torna o aprendizado com gate (0018) em vez de automático.

Vale ver a 0006 nas suas duas camadas lado a lado — o que está na manchete vs. o que carrega a fusão:

ADR-0006 EM DUAS CAMADAS · a MANCHETE (custo) vs a CLÁUSULA SUSTENTADORA (princípio de emissão)
A manchete (o que salta aos olhos) profundidade frontier no corpus inteiro via o modelo mais barato acima do piso é sobre custo e roteamento de modelo verdadeiro — mas não é o que a fusão usa A cláusula sustentadora (a que carrega) princípio de emissão: nada sedimenta sem piso de qualidade o Validator é o portão de emissão ↳ é dela que a ADR-0018 depende ler só a manchete faz perder exatamente a regra que torna o aprendizado gated, não automático.

12 · Como isso se encaixa

Esta lição não é sobre uma peça do motor — é sobre a camada que moldou todas elas. Os ADRs são a entrada anterior a qualquer código: são as restrições que decidiram a forma da cintura estreita, do gate de Validator, do loop de aprendizado e do portão humano. Por isso, no mapa da metodologia, a trilha de ADRs fica acima da pipeline, escrevendo as regras que cada estágio depois obedece.

O fluxo abaixo mostra isso: a trilha de ADRs (esta peça, destacada) é a fonte; cada ADR desce e esculpe uma peça concreta da pipeline contracts → adapters → council → harness → gates → loop de aprendizado. Clique nos passos para acender cada restrição na peça que ela moldou:

COMO SE ENCAIXA · a trilha de ADRs (upstream) molda cada peça da pipeline (downstream)
a trilha de ADRs · docs/adr/ ◀ você está aqui upstream: as restrições, escritas antes de qualquer código ADR-0001motor, não produto ADR-0009run() nunca lança ADR-0006portão de emissão ADR-0005portão humano ADR-0018o loop fechado cada ADR desce e molda ▾ uma peça concreta downstream: a pipeline que obedece as regras contractsfronteira do motor adaptersa cintura estreita harness · T4portão humano gatesValidator/emissão loop aprendiz.reviewAndLearn → o loop realimenta a memória durável: a próxima run começa mais esperta a leitura de cima para baixo: a decisão (ADR) molda a peça (pipeline).
Clique num passo acima para acender qual ADR moldou qual peça da pipeline.

Note a direção: ao contrário das outras lições — que pegam uma peça e mostram o que entra e o que sai dela — aqui a peça é a própria camada de decisão, e o que "sai" dela é a forma de todas as outras. É a entrada da entrada.

Onde você está na metodologia

No mapa interativo da metodologia, a trilha de ADRs é a constituição — a camada de governança que fica antes do Scope Gate e que toda a pipeline (Scope → Council → Proof → Validator → Publish) herda como restrição. Quando você lê o motor de baixo para cima, os ADRs são o teto; quando você o constrói de cima para baixo, são o alicerce. Veja o conjunto inteiro e como cada peça se conecta no mapa da metodologia.

As 3–5 peças que esta trilha conecta (cada link abre a lição da peça que o ADR moldou):

13 · Na prática

A trilha não é um conceito abstrato: são arquivos de texto no repo que você pode ler agora. O melhor jeito de internalizar esta lição é abrir docs/adr/ e percorrer a trilha com seus próprios olhos — o objetivo da lição é exatamente rastrear um ADR até o código que o honra.

Comece listando a trilha inteira e lendo um ADR de ponta a ponta:

# 1 · liste a trilha inteira (os 18 ADRs aceitos)
ls docs/adr/
# → 0001-alembic-internal-engine-not-product.md
#   0005-human-gate-at-ship.md   0006-frontier-quality-...md
#   0009-narrow-waist-run-never-throws.md   …   0018-internalize-...md

# 2 · leia a pedra angular de ponta a ponta (contexto, decisão,
#     OPÇÕES REJEITADAS, consequências — a caixa 3 é o segredo)
cat docs/adr/0018-internalize-validator-gated-self-improvement-loop.md

Os comandos acima são ls/cat simples — a trilha é só texto versionado, então não há comando alembic dedicado a "ler um ADR". O que existe no CLI alembic é o que materializa uma decisão de escopo num diretório de run, que é o passo seguinte natural a uma decisão registrada.

DO ADR AO CÓDIGO · a trilha (texto) → o comando que a executa → o artefato que a honra
1 · a decisão (texto) cat docs/adr/0009-…md 2 · o código que a honra grep -r "ModelRunResult" packages/ 3 · a restrição, viva a união discriminada está lá — nenhum throw atravessa a cintura a decisão escrita… …aparece no código… …e o motor a obedece.

Adicionar um ADR (o protocolo append-only)

Quando uma decisão nova surge, você não edita um ADR antigo — escreve um novo com o próximo número e sua própria data. O CLAUDE.md do repo aponta docs/adr/ como o registro canônico de decisões de domínio. O padrão dos arquivos existentes é o contrato:

# o próximo número é o maior + 1 (hoje o maior aceito é 0018)
# crie docs/adr/0019-<slug-curto>.md seguindo a anatomia das 4 partes:
#   # ADR-0019: <título imperativo>
#   **Status:** Accepted (AAAA-MM-DD)   ← a SUA data, append-only
#   <contexto> / ## Decision / ## Considered options / ## Consequences
# se a decisão REVISA outra, ela "supersedes" a antiga — nunca apaga.

[uncertain] não há um subcomando alembic adr … no CLI canônico para gerar o arquivo — a trilha é mantida à mão (criar/editar o .md). Se você precisar de um comando que consome uma decisão já registrada, use o fluxo de escopo abaixo.

Experimente · rastreie um ADR até o código que o honra (5 passos reais)
1
Entre no repo e liste a trilha. cd /Users/acf/Documents/Projects/appfy/alembic e então ls docs/adr/. Você verá os 18 arquivos numerados — confira que o maior é 0018-….
2
Leia uma decisão inteira. cat docs/adr/0009-narrow-waist-run-never-throws.md. Procure a seção ## Considered options — é a caixa 3 (rejeitadas) que a seção 01 desta lição destacou.
3
Ache o código que honra a decisão. A 0009 promete que run() retorna um ModelRunResult. Rode grep -rn "ModelRunResult" packages/contracts/src e veja a união discriminada { ok: true } | { ok: false, error } declarada — a decisão virou tipo.
4
Prove que a restrição vale. Rode a baseline do repo — pnpm -r typecheck && pnpm -r build && pnpm -w test. Se o motor tivesse um throw atravessando a cintura, os tipos ou os testes reclamariam: a restrição da ADR-0009 é executável, não só documental.
Agora você: escolha outro ADR e repita o trilho. Sugestão: a ADR-0006 (portão de emissão) → grep -rn "scoreThresholdGate" packages/hermes/src e veja o default 0.7 que a trilha citou. Cada decisão deve apontar para uma linha de código que a obedece — se não apontar, é só uma intenção, não uma restrição.

O que procurar na saída: em (1) o arquivo 0018-… presente; em (3) a definição do tipo (não só usos); em (4) exit code 0 — verde é a prova de que a decisão escrita continua honrada pelo código. [uncertain] os caminhos exatos dos arquivos-fonte podem variar conforme o pacote evolui; o grep é o jeito robusto de localizar a linha viva.

Fixe os conceitos (flashcards)

Clique pra virar. Tente lembrar a resposta antes de virar — recuperação ativa fixa mais que reler.

ADR-0009
Qual o contrato da cintura estreita?
clique pra virar ↻
Resposta
run(input): Promise<ModelRunResult> — união discriminada; nunca lança (falha é valor). A invariante mais importante do motor.
ADR-0006
Qual o princípio de emissão?
clique pra virar ↻
Resposta
Nada sedimenta sem passar um piso de qualidade. Default scoreThresholdGate(0.7). Proposta ≠ verdade; um gate decide.
ADR-0005
O que decide se precisa de portão humano?
clique pra virar ↻
Resposta
Reversibilidade/externalidade, não posição no pipeline. ship/gasto → T4-park; distill + discover→build são HITL-free.
ADR-0018
Por que ADAPT e não CLONE?
clique pra virar ↻
Resposta
Sem AIAgent Python p/ fork; e — mais importante — auto-gravar violaria a 0006. Logo: revisor propõe, Validator dispõe.

Revisão cumulativa — recupere de memória

Antes de clicar: responda de cabeça. As quatro opções têm o mesmo tamanho de propósito — sem pista pela forma.

1. A ADR-0018 diz que o loop de aprendizado é um ADAPT, não um CLONE literal do Hermes. A razão mais importante dada é:
Correto: c. A ADR lista duas razões (sem AIAgent Python para fork; e o princípio do portão de emissão) e marca a segunda como "mais importante". a erra o motivo: a ADR não diz que TS não cria threads — diz que "uma thread é a unidade errada" e que não existe runtime AIAgent. b é falso: a fusão leu o background_review.py como fonte de record. d não aparece na ADR — velocidade nunca é o argumento; o argumento é a invariante (0006).
2. Pela ADR-0005, o que decide se uma ação precisa de portão humano?
Correto: b. A ADR é explícita: "o critério decisivo é reversibilidade/externalidade, não posição no pipeline". a é justamente a opção que a ADR rejeita ("Gate antes do build" e "Totalmente autônomo até o ship" são ambas rejeitadas; a posição não é o critério). c confunde o tier (o nível de escalada) com o critério do gate. d inventa uma condição que a ADR não menciona — o gate é sobre reversibilidade, não sobre presença do usuário.
3. Por que o projeto registra as opções rejeitadas dentro de cada ADR (ex.: "clientes que lançam — rejeitado")?
Correto: d. Registrar o caminho rejeitado é o que torna a decisão executável, não só informativa: a opção volta a ser proibida por escrito. a não é o motivo dado — é uma disciplina de engenharia, não jurídica. b inverte a intenção: a caixa "rejeitadas" existe para vincular, não para encher linguiça. c está errado por outro ângulo — a opção rejeitada é útil justamente depois, como a parede que impede reintroduzi-la.
4. Por que a ADR-0009 ("run() nunca lança") é pré-condição para a forma da ADR-0018?
Correto: a. A 0018 depende explicitamente da 0009: o proposer "em produção é uma call de ModelAdapter moldada pela cintura estreita", então erros são valores e a passagem inteira pode falhar fechado (err) sem try/catch espalhado. b contradiz a 0006 (nada auto-aplica). c confunde a 0009 (contrato) com a 0006 (custo/modelo barato). d contradiz a 0001 (sem superfície de cliente no motor).
💬 Travou em algo? Eu sou seu professor neste curso — pergunte. "Por que 0.7 e não outro limiar?", "O que muda quando o Validator do coda entra como ReviewGate?", "Qual ADR eu citaria para justificar não ter UI no motor?". É só dizer.