Módulo 3 · Launch Academy · Arquitetura técnica a fundo
Alembic Launch Academy · Módulo 3 · Arquitetura

Arquitetura técnica a fundo

Esta lição abre o Alembic e mostra a sala de máquinas: seis camadas (de L-1 a L4), os fluxos de dados que as atravessam, onde mora o estado, quais APIs existem hoje — e os riscos técnicos que um arquiteto precisa governar. Tudo apontando para o arquivo real onde a propriedade vive.

Cada bloco tem uma versão Simples e uma Técnica. Abra a técnica quando quiser o código real.
1

A grande ideia


Ao terminar esta lição você vai saber
  • Nomear as seis camadas do Alembic — L-1 ingestion, L0 ETL/contracts, L1 adapters, L2 council, L3 swarm, L4 harness — e o pacote real de cada uma.
  • Seguir o fluxo de dados do corpus até o ship: Ingest → T0 → T1/T2 → Council → Swarm → L4.
  • Por que a cintura estreita (o ModelAdapter) é a dobradiça de toda a arquitetura.
  • Onde o estado vive — JSONL append-only — e quais APIs (CLI, HTTP/SSE, MCP) existem hoje.
  • Os riscos técnicos ativos e qual arquivo prova cada um.
O que assumimos de você
  • Você já viu o Módulo 1 (o sistema operacional do código) e o Módulo 2 (produto e negócio). Aqui descemos para a engenharia.
  • Você sabe que no Alembic erro recuperável vira Result (ok/err) em vez de exceção — a biblioteca não lança.
  • Você não precisa decorar nada: cada afirmação aponta para o arquivo onde ela é verdade.

Pense no Alembic como uma fábrica em andares. No subsolo entram matérias-primas (páginas, transcrições, repositórios) — sem nunca serem alteradas. Cada andar acima refina um pouco: limpa e barateia, protege contra a variação dos modelos, decide com um conselho, executa com uma equipe limitada e, no topo, entrega o resultado por uma porta de cada vez (linha de comando, web, ou um protocolo seguro).

A arquitetura inteira é uma resposta a uma pergunta: como confiar num sistema construído sobre modelos não-determinísticos? A resposta do Alembic é estrutural — contratos estreitos, gates que falham fechado, e estado auditável. Não é "o prompt certo"; é a moldura em volta do modelo.

O contrato de leitura

Numeramos as camadas para que a dependência seja sempre para baixo: uma camada superior conhece a inferior, nunca o contrário. A L0 (contracts) é a única que todas importam — ela é a cintura. Cada caixa do mapa abaixo é um pacote pnpm em packages/*, e o app em apps/cli é só um cliente fino de tudo isso.

Por que isso importa para um arquiteto

Quando uma camada falha, você sabe exatamente onde olhar — e a fronteira de cada uma é um tipo Zod, não uma convenção informal. Mudar um schema exportado em @alembic/contracts obriga a atualizar testes e um caminho de compatibilidade. É de propósito: a cintura é o que mantém o resto substituível.

A melhor leitura primária
packages/contracts/src/model.ts — a interface ModelAdapter e os schemas Zod que toda a arquitetura compartilha

Se você só puder ler um arquivo, leia este. Tudo o mais é substituível em volta dele.

2

O mapa em uma imagem


A arquitetura por camadas, lida de baixo para cima: cada pacote tem uma função no pipeline que vai de L-1 a L4.

Infográfico vertical das seis camadas do Alembic, de baixo (L-1 ingestion read-only) para cima (L4 harness exposto por CLI, HTTP/SSE e MCP), com uma seta de fluxo subindo pela pilha e uma coluna de chips nomeando os pacotes reais: contracts, etl, adapters, council, swarm, harness, marketing-factory, infra.

As seis camadas empilhadas — a ingestão entra embaixo, a superfície utilizável sai em cima. Cada faixa nomeia o pacote que a implementa.

Como lerSetas apontam dependência: quem aponta para contracts depende dos tipos dele. Ninguém aponta de volta — a cintura não conhece seus clientes.
3

As seis camadas


Clique numa camada para acendê-la na pilha e ver o que ela faz, onde mora e por que existe.

L-1

Ingestion captura sem mutar

agent-browser aceita apenas verbos de leitura e o collector materializa pacotes wiki com um cursor monótono. Nada é alterado na fonte: a captura é read-only por desenho.

packages/ingestion/src/
L4 · harness L3 · swarm L2 · council L1 · adapters L0 · etl / contracts L-1 · ingestion

O passo a passo de baixo para cima

a unidade sobe um andar de cada vez
CamadaO que fazInvariante
L-1 ingestionCaptura páginas/repos/transcrições e materializa pacotes wiki.Read-only — só verbos de leitura.
L0 ETL/contractsValida o contrato, scoreia, deduplica por SHA-256 e manda só o residue para os tiers caros.Barato primeiro; o que não resolve sobe.
L1 adaptersFala com cada modelo (cliproxy, local, CLI, offline) por trás de uma interface única.Devolve Result; nunca lança exceção.
L2 councilFases serializadas acumulam contribuições; membros rodam em paralelo; o verifier vira gate.Decisão só sai pelo verifier.
L3 swarmorchestrator → lead → worker, com profundidade máxima e gates de dependência.Limitado; T4 vai para park.
L4 harnessExpõe o núcleo por CLI, HTTP/SSE e MCP — sem misturar transporte com lógica.MCP é read-only por desenho.
Faça sua aposta antes de revelar

Uma página recém-capturada chega na L0 mas não atinge a pontuação mínima de sinal. Para onde ela vai?

Vira residue append-only. A L0 não joga nada fora: o que não "resolve" barato é registrado e fica disponível para os tiers T1/T2/T3 mais caros decidirem depois. Descartar seria perder auditabilidade.
4

O fluxo de dados


Fluxo detalhado: ingestion read-only, ETL determinístico (T0), modelos guardados, council, swarm e as superfícies. Tudo é JSONL append-only — auditável e replayável.

Fluxograma horizontal do funil de dados do Alembic: Ingest read-only, T0 gate de contrato com scoring e dedupe, T1/T2 extração de BusinessSignal com PII redaction e budget guard, Council com verifier, Swarm L3 com T4 park, e L4 emitindo por CLI, HTTP/SSE e MCP; uma barra append-only JSONL atravessa todos os estágios e um cadeado marca o MCP como read-only.

A esteira do funil — o que não resolve barato vira residue e sobe; o estado vive todo em JSONL append-only.

O stepper do fluxo

Avance um passo de cada vez pela jornada de uma unidade de trabalho.

passo 1 de 4

Corpus

Arquivos .jsonl com pacotes wiki entram por um corpus local. O T0 ignora famílias como Models/Prompts.

passo 2 de 4

Residue

O que não resolve no T0 vira residue append-only para os tiers T1/T2/T3.

passo 3 de 4

Signal

O T1 extrai um BusinessSignal com PII redaction e um budget guard ao redor dos tiers pagos.

passo 4 de 4

Decision

O council pontua, agrega consenso, verifica claims e só então emite oportunidades/learnings.

A direção importaO fluxo é de mão única: nunca um tier caro empurra trabalho de volta para um barato. Barato filtra; caro decide. Inverter isso quebraria a economia do funil.
5

A cintura estreita


Toda conversa com um modelo passa por um único ponto fino: o ModelAdapter. É a "cintura" da arquitetura — larga em cima (muitos modelos diferentes), larga embaixo (muitas camadas que precisam de um modelo), estreita no meio.

É como a tomada de parede: do lado de dentro há uma rede elétrica complexa; do lado de fora, qualquer aparelho que respeite o formato do plugue funciona. O ModelAdapter é o formato do plugue. Trocar o "aparelho" (o modelo) não exige reformar a casa.

O contrato never-throws

O adapter recebe um input validado e devolve uma união ok / err — ele não lança. Isso é o que impede a variação dos modelos (timeout, erro de gateway, resposta malformada) de vazar exceção para as camadas de cima. O erro vira dado, e o chamador decide o que fazer.

type ModelRunResult =
  | { ok: true;  value: { text: string; usage: TokenUsage } }
  | { ok: false; error: ModelError }   // never throws

O roteamento sem fallback silencioso

Antes do adapter, o roteador escolhe o modelo: o tier define a faixa de risco, pickCheapestForTier(tier) pega o mais barato da faixa quando nenhum modelId está fixado, e o roteador se recusa a trocar de modelo/adaptador em silêncio — se o alvo não existe, devolve err. Um fallback invisível é um bug de governança, não uma conveniência.

# prova: pickAdapter falha fechado quando o alvo não existe
rg -n "pickCheapestForTier|no_model_for_tier|adapter_not_registered" packages/adapters/src
Exemplo resolvido · escolher e chamar um modelo
1
Tier entra. Uma unidade T2 chega sem modelId fixado.
2
Escolhe o mais barato. pickCheapestForTier('T2') devolve o modelo T2 de menor custo no registry.
3
Resolve o adapter. O roteador mapeia esse modelo ao seu adapterId (em geral cliproxyapi). Se não houver, err — nunca um substituto silencioso.
4
Chama e devolve Result. O adapter roda e devolve ok/err. Exceção nenhuma sobe.
5
Agora você: abra packages/contracts/src/registry.ts e ache o modelo T2 mais barato. Depois confirme em packages/adapters/src que o roteador falha quando o adapterId não existe.
Recapitulando: a cintura compra substituibilidade. É por isso que boa parte da inferência é delegada (empurrada para baixo da cintura, ao gateway/MLX) e não reescrita aqui em cima.
6

Estado & APIs


Onde o Alembic guarda a verdade — e por quais portas ela entra e sai.

O estado é JSONL append-only

O Alembic não exige banco externo. A fonte de verdade são arquivos .jsonl em que só se acrescenta — nunca se sobrescreve. Stores de oportunidades e de learnings têm caminhos fixos relativos ao dataDir (ex.: Business/opportunity-graph.jsonl, Skills/learning/learnings.jsonl); o run grava events.jsonl e um cache; manifests de marketing são versionados; o swarm guarda seu próprio estado.

append
só acrescenta, nunca sobrescreve
replay
events.jsonl + cache reconstroem o run
$0
sem banco externo no core
FsPortPacotes (fora de ETL/CLI) não tocam fs direto: usam um FsPort injetável. Isso torna o IO testável e mantém a determinação onde ela é exigida.

Três superfícies sobre um núcleo

No topo (L4), CLI, HTTP/SSE e MCP leem ou acionam o mesmo HarnessCore. O transporte nunca se mistura com a lógica — cada superfície é um adaptador fino.

SuperfíciePara quêPropriedade
CLIOperador local: plan, run, serveA porta de entrada do dia a dia.
HTTP/SSEServidor stateful; POST /runs e replay de eventos via SSE.Eventos viajam em swimlanes; dá pra reconectar.
MCPExpor o harness a outros agentes.Read-only por desenho — sem start/fanout.

Tabela de arquivos, funções e comandos

onde olhar para provar cada peça
ElementoOnde olharPor que importa
Model waistpackages/contracts/src/Input/Result/Adapter, união ok, never throws.
Routingpackages/adapters/src/tier → modelo → adapter sem fallback silencioso.
T0 pipelinepackages/etl/src/walk, validate, score, dedupe, residue.
Storespackages/etl/src/Stores append-only de oportunidade e learning.
Councilpackages/council/src/Fases seriais e membros em paralelo + verifier.
Swarmpackages/swarm/src/Orquestração com profundidade limitada, resume e T4 park.
Harness serverpackages/harness/src/HTTP do Node, replay SSE e o bind MCP.
7

Confusões comuns


JSONL não é falta de arquitetura

Aqui o JSONL é escolha de auditabilidade e replay. Um banco externo não é requisito do core — é uma opção que se adiciona quando o caso de uso pedir.

MCP read-only é segurança

Não procure start/fanout no MCP: a ausência é uma propriedade de segurança, não um recurso faltando. Outros agentes podem ler, não disparar.

Delegar não é gap

Empurrar a geração de tokens para o gateway/MLX é delegação consciente, não buraco. O TS não reimplementa cache de atenção de propósito.

Seam de fornecedor ≠ integração final

O wrapper sobre o CLI externo (ex.: marketing/higgsfield.ts) é uma camada anticorrupção tipada, com comentários [uncertain] marcando quais flags/envelopes ainda não foram confirmados num run autenticado real. O seam existe; o acabamento é gated.

cintura
Por que o adapter devolve Result em vez de lançar?
clique para virar
Para que a variação dos modelos (timeout, erro de gateway) vire dado, não exceção vazando para cima. O chamador decide; a biblioteca nunca lança.
funil
O que acontece com o que o T0 não resolve?
clique para virar
Vira residue append-only e sobe para os tiers T1/T2/T3. Nada é descartado — auditabilidade acima de tudo.
segurança
Por que o MCP não tem start?
clique para virar
Porque o MCP é read-only por desenho. A ausência de verbos de disparo é a propriedade — outros agentes leem o harness, não o acionam.
cintura
O que pickCheapestForTier faz?
clique para virar
Escolhe o modelo mais barato da faixa de risco quando nenhum modelId foi fixado. Custo é decisão de arquitetura, não acaso.
8

Como eu verifico isso no código


Não acredite no diagrama: prove cada afirmação no checkout. Aqui estão os atalhos.

Checar o no-fallback. Leia o roteador em packages/adapters/src e confirme que ele falha quando o modelo/adaptador não existe.
rg -n "pickCheapestForTier|no adapter" packages/adapters/src
Checar a redaction. Procure a redação de PII e o gate de emissão no funil — nada com PII deve sair sem passar por ele.
rg -n "redact|assertRedacted|PRIVATE" packages
Checar o SSE. Leia o stream SSE em packages/harness/src para entender replay e frames ao vivo.
rg -n "sse|stream|replay" packages/harness/src
Checar o estado. Leia os stores append-only para ver que eles são a fonte de verdade.
rg -n "OPPORTUNITY_GRAPH_PATH|appendStoreRecord" packages/etl/src
A regra de evidênciaToda afirmação desta lição tem um arquivo. Se você não consegue apontar o arquivo, trate a afirmação como hipótese — não como fato.
9

Riscos técnicos


Um arquiteto governa riscos, não só componentes. Estes são os que estão ativos — cada um com a pergunta que o prova.

RiscoO que olharPor que importa
Seam de fornecedor inacabadopackages/marketing-factory/src/higgsfield.ts e seus [uncertain].O envelope/flags do CLI real pode divergir do typed wrapper.
Sinal do usuário em abertoapprovals / rejections gravados, mas não realimentados.O veredito humano não volta para o sistema — laço aberto.
Caminho de query vetorial ausenteÍndices de embeddings são construídos, não consultados.Há build de RAG, falta o read path (cosine/topK/rerank).
Determinação frágil em plansDate.now() / Math.random() num alembic.plan.ts.A VM rejeita; quebra replay se escapar.
Exercício — risk review. Liste três riscos técnicos atuais e, para cada um, diga qual arquivo prova o risco. Depois proponha o menor commit testável que reduziria um deles sem quebrar a superfície existente.
Honestidade é o valor do curso. Estes "gaps" não são vergonha — são o roadmap. Marcar uma lacuna como lacuna (em vez de fingir que está pronta) é o que separa um mapa confiável de um folheto de marketing.
10

Recapitulando


Seis cartões, a lição inteira. Use as setas ou os botões.

A forma

Seis camadas, dependência para baixo

L-1 ingestion · L0 ETL/contracts · L1 adapters · L2 council · L3 swarm · L4 harness. Cada uma é um pacote real.

A dobradiça

contracts é a cintura

Todos importam @alembic/contracts; ele não importa ninguém. Mudar um schema exige teste + caminho de compatibilidade.

O caminho

O funil sobe pelos tiers

Ingest → T0 → T1/T2 → Council → Swarm → L4. Barato filtra, caro decide. O que não resolve vira residue.

O estado

JSONL append-only

Sem banco externo no core. Stores acrescentam; events.jsonl + cache dão replay. FsPort mantém o IO testável.

As portas

CLI · HTTP/SSE · MCP

Três adaptadores finos sobre um HarnessCore. O MCP é read-only por desenho — sem start, sem fanout.

A honestidade

Os gaps são o roadmap

Seam de fornecedor a reconciliar, sinal do usuário em aberto, RAG só de build. Marcar a lacuna como lacuna é o valor do mapa.

1 / 6setas
As dez verdades da arquitetura
  1. A dependência é sempre para baixo; ninguém aponta de volta para a cintura.
  2. contracts é o único pacote que todos importam.
  3. O adapter devolve Resultnever throws.
  4. O roteador não troca de modelo em silêncio: alvo ausente é err.
  5. O T0 filtra barato; o que sobra vira residue.
  6. O council só emite pelo verifier.
  7. O swarm é limitado em profundidade; T4 vai para park.
  8. O estado é JSONL append-only — replay, não banco.
  9. O MCP é read-only por desenho.
  10. Os gaps são o roadmap, não vergonha.
11

Verifique seu entendimento


Quiz de revisão

Três perguntas. As explicações aparecem ao escolher.

1. Por que o ModelAdapter devolve Result em vez de lançar exceção?
A união ok/err transforma timeout, erro de gateway ou resposta malformada em dado que o chamador trata. A biblioteca nunca lança — é o que impede a não-determinação de contaminar as camadas superiores.
2. O que o MCP não oferece, e por quê?
A ausência de verbos de disparo no MCP é uma propriedade de segurança deliberada: outros agentes podem ler o harness, mas não acioná-lo. Não é um recurso faltando.
3. Para onde vai o que o T0 não resolve barato?
O T0 não descarta nada: o que não "resolve" barato é registrado como residue e fica disponível para os tiers caros decidirem. Descartar quebraria a auditabilidade que justifica o JSONL.
Acertos: 0/3
Pergunta para levar adiante: se você tivesse que adicionar um read path de RAG ao Alembic, em qual camada ele entraria — e que tipo Zod novo (ou existente) seria a fronteira dele? Guarde a resposta: o Módulo 4 entra na engenharia agêntica e de harness, onde esse laço aparece de novo.