ALEMBIC • LEARN COMPLETE • HOT PATH 01
CLI distill → runFunnel T0-T3 (Linha-a-Linha)
PATTERN: 13-FLOWCHART + 04-CODE-UNDERSTANDING (visual-teach-studio)

Hot Path: alembic distill → Funnel T0-T3

Traçado completo e anotado linha a linha do caminho mais comum de execução do Alembic. Começa no CLI, injeta adapters, entra no runFunnel, passa por T0 (determinístico $0), T1 (extração local + gate PII), T2 (frontier com budget) e T3 (council + verifier). Todo passo ancorado em arquivo:linha real.

Visão Geral do Fluxo (SVG)

CLI (commands.ts)runDistill:63 Harness FunnelrunFunnel:83 ETL T0 PipelinerunT0Pipeline Adapters L1registry + run Council T3debate + verifier Storesappend-only Invariantes exercidos: Result nunca lança • PII redaction gate antes de emit • Budget fail-closed • Append-only content-addressed Offline mode: adapters offline bound em todos os tiers → run 100% $0 e hermético

Estágios do Hot Path (Stepper)

1. CLI Entry
2. Registry + Preflight
3. runFunnel
4. T0 → Residue
5. T1 PII Gate
6. T3 Verifier

Estágio 1 — CLI (apps/cli/src/commands.ts)

63|export const runDistill = async (args, deps) => {
68|  const readable = await assertCorpusReadable(args.corpus);
69|  if (!readable.ok) return err(...);
75|  const adapters = buildRegistry(args.offline);
83|  const report = await runFunnel(args.corpus, { adapters, budget, dataDir, fs: nodeFsPort });
90|  renderDistill(...);
95|  return ok(report);
}
Por que Result aqui: todo erro vira err(). Nunca throw. Isso é a cintura do sistema (ver contracts/result.ts).

Estágio 2 — Registry + Preflight (commands.ts:52 + config.ts)

52|const buildRegistry = (offline) =>
53|  offline ? createAdapterRegistry({ offline: { asDefault: true } })
54|          : createAdapterRegistry(liveRegistryOptions());
76|if (!args.offline) {
77|  const pf = await preflightLiveProvider(adapters);
78|  if (!pf.ok) return err(...);
}
Quando offline: true, o adapter offline é bound em todos os tiers via asDefault. Run hermético $0 garantido.

Estágio 3 — Entrada no Funnel (harness/src/funnel.ts:83)

83|export async function runFunnel(corpus, opts: FunnelOptions) {
...
260|  const t0 = await runT0Pipeline(...);
...
// depois T1 extraction + emitSafeSignal (PII gate)
// T2 shortlist com BudgetGuard
// T3: council + verifyPanel
}

Estágio 4 — T0 Determinístico (etl/pipeline.ts + priors)

// T0 roda 100% do corpus (exceto Repos/Models + Prompts)
// dedupe por SHA-256, score 6 eixos, routesToResidue
// tudo antes de qualquer LLM
Este é o único tier que sempre executa e sempre é $0.

Estágio 5 — T1 + Gate PII (funnel.ts:243)

243|const emitSafeSignal = (entry) => {
244|  if (!isPrivateChannel(...)) return ...
246|  const redacted = redactSignal(...);
247|  const gate = assertRedactedForEmit(redacted, channel);
248|  return gate.ok ? redacted.signal : undefined;  // fail-closed
}
Invariante crítico: sinal de canal privado nunca é emitido sem redação. O gate é antes do store.

Estágio 6 — T3 Council + Verifier (council/verifier*.ts)

// debate → aggregate → verifyPanel (faithfulness + domain lenses)
// quorum + dissent preservado
// loop > MAX → parkedTier = T4 (humano)

Anotações Linha-a-Linha Críticas

Arquivo:linhaO que fazInvariante
apps/cli/src/commands.ts:68assertCorpusReadable via tryCatchAsync → ResultNever throws
commands.ts:75buildRegistry injeta adapters (offline ou live)Adapter-agnostic
harness/src/funnel.ts:243emitSafeSignal + assertRedactedForEmitPII gate
etl/src/pii.ts:246redactSignal + gate antes de qualquer writeFail-closed
council/src/verifier-panel.tsverifyPanel + quorum + preserve dissentDissent forçado
packages/contracts/src/result.tsok/err discriminado, tryCatchAsyncNarrow waist

Como Verificar Este Hot Path

pnpm build
node apps/cli/dist/index.js distill /caminho/para/corpus --offline --json
# ou
pnpm factory   # executa o ADW que usa o mesmo harness internamente

Observe no output: T0 sempre executa, T1/T2/T3 só tocam residue, custo só aparece em tiers pagos, e nenhum sinal privado sem redação chega ao store.

Common Confusions + Practice Task

Confusão 1: Achar que T1/T2/T3 sempre rodam. Não. Só o que passou no T0 (routesToResidue) chega neles. T0 é o filtro massivo e barato (ver etl/priors.ts + pipeline.ts:260). Residue é o único caminho para LLM.

Confusão 2: Achar que o PII gate é "depois do modelo". Falso. Em funnel.ts:243 o gate roda em emitSafeSignal antes de qualquer store write. Private channel → redact → assertRedactedForEmit → só então vira BusinessSignal.

Confusão 3: Achar que budget é só "número". Falso. createBudgetGuard envolve toda chamada T2/T3 (fail-closed). Se projeção excede, a chamada é bloqueada e o tier degrada.

Prática (toque o código real): 1. Rode alembic distill ./corpus --offline --dataDir /tmp/test1. 2. Abra /tmp/test1/_alembic-residue.jsonl. 3. Pegue um item de canal privado (whatsapp, discord etc). 4. Rode novamente com um adapter que não redige e observe t1PiiBlocked > 0 no report. 5. Depois leia emitSafeSignal em funnel.ts:243 e assertRedactedForEmit em etl/pii.ts. Anote as linhas.

Exercício avançado: Mude temporariamente o código de buildRegistry em commands.ts:52 para forçar offline mesmo sem flag. Rode o CLI. Observe que custoUsd fica 0 e nenhum adapter de rede é chamado. Depois desfaça e rode com --offline false (se tiver credenciais). Compare os dois FunnelReport.

Por que este caminho é o mais importante do sistema

Este é o único fluxo que todo usuário e todo job de factory toca quando quer destilar corpus em sinais de negócio ou learnings. Ele exerce simultaneamente as quatro invariantes centrais:

  • Result nunca lança — do CLI até o último appendOpportunityRecord
  • PII redaction + emit gate — obrigatório antes de qualquer dado privado sair
  • Budget fail-closed — T2 e T3 nunca gastam mais que o configurado
  • Append-only content-addressed — stores só crescem, nunca sobrescritos

Qualquer regressão neste path quebra a promessa de "destilação barata, segura e reprodutível" que justifica a existência do Alembic. Por isso todo novo adapter, toda mudança no verifier, todo ajuste de budget ou pii deve ser acompanhado de re-execução deste hot path com corpus de teste e inspeção do FunnelReport resultante. Este é o caminho de ouro que todo job de destilação e todo ciclo do factory percorre quando o objetivo é transformar corpus privado em sinais verificados sem surpresas de custo ou vazamento. Entender este fluxo linha a linha é pré-requisito para qualquer trabalho sério no engine.

Gerado com dados de subagentes + leitura direta de commands.ts:63, funnel.ts:83-253, etl, adapters/registry, council/verifier. Próximo: layer-l1-adapters.html ou hotpath-factory-loop.