Lição 07 · Alembic Completo v3 · Destilação · ADR-0002 · rota Learnings
Alembic Completo v3 · Visual Course

O funil e a rota Learnings

Ao fim desta lição você entende as DUAS cadeias de valor do ADR-0002 sobre um único T0 determinístico, por que os budgets são separados e fail-closed, como a rota Learnings produziu pela primeira vez na história (06-07: 1.022 learnings) — e as duas armadilhas que quase impediram isso.

Leia primeiro (fonte primária)
ADR-0002 — Two value-chains over a shared deterministic T0

Esta lição destila o ADR-0002 (status: Implemented 2026-07-03) + a implementação em packages/harness/src/funnel.ts e packages/etl/src/budget.ts — e a primeira produção REAL da segunda cadeia.

Você vai conseguir
  • Explicar por que sinais e learnings têm cadeias e budgets SEPARADOS
  • Rastrear um item: T0 → residue → T1/T2/T3 (signals) ou T2 (learnings)
  • Diagnosticar o "residue 0 silencioso" da gotcha family-prefix
  • Contar a história do empate T2 (PR #157) e do primeiro lote de 1.022
  • Dizer o estado real dos 3 stores e qual decisão ainda está aberta
Leia a versão simples, ou abra a camada técnica em qualquer seção.
1

A grande ideia — duas cadeias, um T0


O funil de destilação tem dois clientes com ROI diferente: Signals (negócio — semeiam ventures/receita, vão para Business/opportunity-graph.jsonl) e Learnings (engenharia — melhoram o próprio motor, vão para Skills/learning/learnings.jsonl). O ADR-0002 decide: as duas cadeias compartilham o T0 determinístico (caminhada + score + dedupe + índice, $0, roda uma vez) e se separam nos tiers pagos, cada uma com SEU budget, SEU store e SUA cadência.

"a single frontier budget is contested by ~128k community items and ~2k learning items at once, starving learning or forcing an arbitrary per-family cut" docs/adr/0002-two-value-chains-shared-t0.md — a opção "one funnel, two outputs" rejeitada

E o roteamento é por prior, não por partição (mesmo ADR): a família do item é um prior barato aplicado no T0 — mas um repo estrelado pode render um Learning E um Signal.

Pense como… uma vinícola com uma única prensa (T0) e duas linhas de engarrafamento com verbas separadas: vinho de venda (signals) e vinho de estudo do enólogo (learnings). Esgotar a verba de uma linha PARA aquela linha — a prensa e a outra linha seguem. Quebra: na vinícola a uva vai para UMA garrafa; aqui o mesmo item pode virar as duas coisas.

Por baixo do capô

O knob dos signals é --budget (ou ALEMBIC_BUDGET_USD); o knob OPCIONAL dos learnings é --learnings-budget (ou ALEMBIC_LEARNINGS_BUDGET_USD) — presente, ativa a segunda cadeia via RouteBudgets/resolveRouteBudgets (packages/etl/src/budget.ts, conforme a linha de status do próprio ADR-0002). Ausente, a run é byte-idêntica à de um knob só — inclusive o payload --json, que nem carrega a chave routes. Cada rota reporta seus registros no SEU store: "signals → opportunity-graph, learnings → learnings" (packages/harness/src/funnel.ts:109, RouteReport).

2

Em uma imagem — o Y do funil


fusao · 01-the-engine · s1
T0 determinístico · $0 · roda UMA vez walk + score + dedupe SHA-256 + índice + prior de família residue (piso por família) cadeia SIGNALS · --budget T1 local → T2 frontier → T3 council budgetBlocked soma T1+T2+T3-council → Business/opportunity-graph.jsonl cadeia LEARNINGS · --learnings-budget T2 (extrator de learnings) — opt-in cap próprio · fail-closed SÓ desta rota → Skills/learning/learnings.jsonl report.routes.signals report.routes.learnings
O Y do ADR-0002: um T0, duas cadeias. A chave `routes` só EXISTE no relatório de runs com os dois knobs (funnel.ts:157) — run de um knob é byte-idêntica ao passado.
3

Budgets separados, fail-closed por rota


O contrato de gasto é duro: cada rota consome do SEU cap e, esgotado, aquela rota bloqueia — a outra segue intacta. No código: runLearningsRoute cobra "against the learnings cap ONLY — exhausting it fail-closes THIS route without" afetar a irmã (funnel.ts:809-814). Um cap de $0 para learnings não é "grátis": é a rota ATIVA e imediatamente bloqueada — o que torna o budget significativo (funnel.ts:753).

Spend-safety na extração: o extrator de learnings pede um shape estrito ("Keys: statement (a concise reusable lesson), confidence (number 0-1)", funnel.ts:775) — resposta malformada parseia para ZERO learnings, $0, nenhuma fabricação (funnel.ts:811).

Camada técnica — copy-paste
# um knob: só a cadeia SIGNALS (byte-idêntico ao comportamento antigo)
alembic distill /Users/acf/Documents --offline --budget 5

# dois knobs: ativa a cadeia LEARNINGS com cap PRÓPRIO
alembic distill /Users/acf/Documents --budget 5 --learnings-budget 2

# no --json de uma run de DOIS knobs (e só nela) aparece:
#   report.routes.signals   {records, budgetBlocked, ...}
#   report.routes.learnings {records, budgetBlocked, ...}
# e a linha-resumo "learnings-route:" no texto
4

06-07 — a primeira produção real da segunda cadeia


Até 06-07 a rota Learnings era código testado que nunca tinha produzido um registro. Aí veio a primeira run real sobre Bookmarks — e a cadeia entregou:

fusao · 15-the-funnel · s0
1.022
learnings únicos (1ª produção da história)
100%
com sourceRefs + hash de proveniência
μ0.94
confidence média do lote
$isolado
store em ~/.alembic-learnings-bkm
Proveniência não é enfeite: cada learning nasce apontando para a fonte — no extrator por-item, sourceRefs: [item.sourcePath] (funnel.ts:796); no learning derivado de consenso do council, sourceRefs herda os sourceRef dos sinais do pack (funnel.ts:666). É por isso que o lote fechou com 100% de sourceRefs: o campo é estrutural, não boa vontade.
5

A gotcha family-prefix (e o truque cpio)


A armadilha que custou uma noite: classifyFamily (packages/etl/src/priors.ts:70) deriva a família do PRIMEIRO segmento do path relativo ao corpus. Se você aponta o distill na RAIZ da família (ex.: …/Resources/Bookmarks), o primeiro segmento relativo vira o conteúdo interno — nenhuma família reconhecida ⇒ Unknown ⇒ prior tier T0/priority 0.1 (priors.ts:63) ⇒ residue 0, silenciosamente. Nada falha; simplesmente nada sobe.

ERRADO — corpus = raiz da FAMÍLIA corpus: …/Resources/Bookmarks item: items/dev/abc123/… 1º segmento relativo = "items" classifyFamily → Unknown (prior 0.1) residue: 0 — e NENHUM erro na tela CERTO — corpus = PAI de Resources corpus: /Users/acf/Documents item: Resources/Bookmarks/items/… 1º segmento útil = "Bookmarks" classifyFamily → Bookmarks (T1, 0.5) residue povoado → a cadeia produz
O mesmo comando, dois corpora: o path decide a família (priors.ts:70). Unknown não é erro — é silêncio. Verifique o residue ANTES de culpar o budget.

E como escopar UMA família sem pagar a caminhada do resto? O truque cpio: materialize num diretório de trabalho só os package.jsonl (as bridge-lines) da família desejada, PRESERVANDO o prefixo do path — cpio -pdm copia a árvore relativa exatamente como listada. O distill enxerga um corpus mínimo com o prefixo de família correto.

Camada técnica — copy-paste
# escopo de 1 família com prefixo preservado (o truque cpio)
cd /Users/acf/Documents
find Resources/Bookmarks -name 'package.jsonl' | cpio -pdm /tmp/corpus-bkm
alembic distill /tmp/corpus-bkm --budget 0 --learnings-budget 2

# cheque de sanidade: a família apareceu no residue?
alembic status
Gotcha irmã (mesma noite): walkCorpus NÃO segue symlinks — um corpus montado por links simbólicos caminha vazio. Materialize arquivos reais (o cpio resolve as duas coisas de uma vez).
6

O prereq invisível — PR #157 e o empate de 0.0005


A segunda armadilha não era path — era roteamento de modelo. pickCheapestForTier (packages/contracts/src/registry.ts:244) escolhe o modelo mais barato do tier; num EMPATE de custo, fica o PRIMEIRO declarado no registry. No T2 havia um empate de 0.0005 — e o primeiro declarado era um modelo cujo acesso o gateway NEGAVA (deepseek-v4-pro, AccessDenied). Resultado: a cadeia inteira montada, e o extrator batendo num modelo proibido.

O fix (PR #157) foi de UMA linha de intenção: declarar gemini-3.5-flash ANTES do deepseek-v4-pro no registry — o empate agora resolve para o modelo que o gateway realmente serve. Sem isso, os 1.022 nunca teriam nascido.

antes — empate resolve para o inacessível
registry: [deepseek-v4-pro, gemini-3.5-flash]
T2 tie 0.0005 → deepseek-v4-pro
gateway → AccessDenied → rota morta
depois (PR #157) — ordem é decisão
registry: [gemini-3.5-flash, deepseek-v4-pro]
T2 tie 0.0005 → gemini-3.5-flash
gateway → OK → 1.022 learnings
Lição de engenharia
Num sistema com pickCheapestForTier, a ORDEM de declaração no registry é uma decisão de produção, não estética. Está no rol de gotchas oficiais do curso: "empate de custo = ordem de declaração".
7

Os 3 stores hoje — e a decisão aberta


Estado real dos stores destilados na verdade de 2026-07-06:

storevolumeobservação
signals (Business/opportunity-graph)2.589a cadeia de negócio, acumulada
enriched2.677676 plausíveis · 399 força-4 (enriquecimento T3 local)
learnings1.022únicos, 100% sourceRefs+hash, μ0.94 — isolados em ~/.alembic-learnings-bkm

A decisão pendente: promoção. Os 1.022 learnings existem, com proveniência — mas ainda estão em quarentena num store isolado, e nenhuma perna do motor os LÊ de volta (é a "perna 2" aberta que a Lição 10 detalha). Promover significa decidir: quem consome, com que piso de qualidade, para dentro de quê. A régua doutrinária já existe — o ADR-0006 fixa "frontier-quality via o modelo mais barato acima de um piso de profundidade" como o padrão de qualidade do corpus — mas a decisão de promoção dos stores destilados segue aberta com o founder.

Quiz — você roda alembic distill <corpus> --budget 5 SEM --learnings-budget. O que acontece com a cadeia Learnings?
Sem o segundo knob a cadeia Learnings fica DESLIGADA e a run é byte-idêntica (nem a chave routes aparece no --json — ela só existe em runs de dois knobs, funnel.ts:157). Budgets nunca se misturam: cada rota tem cap, spend e bloqueio próprios (ADR-0002).
Recall: duas cadeias (1) sobre um T0 só (2), caps independentes fail-closed (3), primeira produção provada com proveniência estrutural (4) — desde que você aponte o corpus no PAI da família (5) e o tier T2 resolva para um modelo que o gateway serve (6). O que falta não é código: é a decisão de promoção (7).
Teaser da Lição 08: a mesma disciplina de "$0 por default, gasto só com dupla prova" aplicada a vídeo com marca real — a fábrica de marketing multi-tenant que rendeu o unblock das referências ROLED com a C.D.