Passo 3 · Alembic Completo · Camada L2 · Council
Alembic Completo · currículo fonte-de-verdade · Visual Course

Camada L2 · Council

O Council é o motor de decisão do Alembic. Ele junta um debate qualitativo entre membros (o maker) com uma verificação determinística sobre a evidência (o checker). É o que permite o sistema afirmar “decisão verificada, com dissent preservado” — não apenas “o LLM achou que era uma boa ideia”. Nesta lição você vai seguir uma decisão atravessando debate.tsverifier.tsverifier-panel.ts até o gate de emissão T3.

Cada bloco tem uma visão Simples e uma Técnica. Abra conforme a sua fome.
01

A grande ideia

Suposições tolas (o que presumimos de você)
  • Você já viu as camadas L0 (Contracts + ETL) e L1 (Adapters). Aqui usamos Result, tier e ModelAdapter sem reapresentá-los.
  • Você sabe que “LLM” é um modelo de linguagem. Não presumimos nada sobre teoria de votação ou design de sistemas de decisão.
  • Você lê código em diagonal. Os trechos aqui são pequenos e sempre vêm com tradução em português.
Ao fim desta lição você vai conseguir
  • Explicar a separação maker / checker e por que ela é o coração do Council.
  • Descrever o Debate Engine: phases seriais, membros paralelos, contrarian sempre por último.
  • Dizer por que o Verifier é read-only por arquitetura e o que são oráculos determinísticos.
  • Entender as três lentes do painel, o quorum e o veto de preserve-dissent que governa a emissão T3.
  • Saber o que acontece quando loopCount > MAX_LOOPS (parked em T4).

Imagine uma decisão cara: “vale a pena emitir este resultado para um tier pago?”. Você não quer que um único modelo responda “sim” e pronto. O Council resolve isso em dois tempos.

Primeiro, vários especialistas debatem — cada um dá uma nota por eixo e uma justificativa. Esse é o lado criativo, o maker. Depois, um auditor que não pode opinar confere se a evidência sustenta a conclusão: tem voto suficiente? a confiança passa do piso? há diversidade? Esse é o checker.

É como um artigo científico: os autores escrevem (maker), o peer review só checa se as afirmações têm dados por trás (checker). O revisor não reescreve o paper — ele só carimba “sustentado” ou “não sustentado”.

O que o pacote contém

O pacote @alembic/council (em packages/council/src/) implementa: debate.ts (o maker), verifier.ts + verifier-panel.ts (o checker), consensus.ts (quorum + spread), scoring.ts (parse e agregação de notas por eixo) e board.ts (o board loader que ordena os membros e força o contrarian por último).

O ponto central de design: o maker chama modelos e é, por natureza, probabilístico; o checker é uma função pura sobre evidência estruturada (votos, scores, spread, quorum) e nunca re-chama o modelo. É essa assimetria que transforma “o LLM concordou” em “a decisão foi verificada”.

debate.ts MAKER · debate verifier.ts CHECKER · read-only verifier-panel.ts 3 lentes + quorum Gate T3 emite ou barra Phases seriais • membros paralelos • contrarian por último • checker determinístico

Os quatro estágios do Council, da esquerda para a direita. Só o primeiro chama modelos; os três seguintes são código.

Antes de continuar — arrisque um palpite

Numa decisão cara (T3), qual estágio é o verdadeiro “portão de qualidade”: o debate dos modelos ou a verificação determinística?

É o checker (verifier + painel). O debate é só o maker — útil, mas probabilístico. O gate real de emissão T3 é o painel determinístico, e qualquer hard failure nele barra o sinal mesmo com quorum. Guarde isso: é o erro de leitura mais comum sobre o Council.
02

Maker e checker — a assimetria que tudo sustenta

Infográfico em forma de balança: prato esquerdo MAKER (debate.ts) com membros em paralelo, votos e contrarian por último; prato direito CHECKER (verifier.ts) read-only com oráculos determinísticos; seta DebateResult + ContextPack ligando os dois; chip de alerta loopCount maior que 3 vira parked T4.

A balança do Council: o maker produz a decisão; o checker, que não pode re-chamar o modelo, só pesa a evidência estruturada que o maker deixou.

A diferença mais importante do Council inteiro cabe em uma frase: quem decide não é quem aprova.

O maker (debate) gera votos, notas e justificativas. O checker (verifier + painel) recebe só o resultado pronto — um DebateResult mais um ContextPack — e aplica oráculos: funções puras que olham a evidência e devolvem “provado” ou “não provado”. O checker não tem acesso ao modelo, então não pode “ser convencido” pelo texto bonito do maker.

Tempo 1 · GERAR (maker) Tempo 2 · VERIFICAR (checker) o resultado pronto cruza a fronteira →
Dois tempos, dois papéis: primeiro alguém gera a decisão; depois um auditor independente a verifica. Quem gera nunca é quem aprova.
MAKER — debate.ts
M1 M2 M3 votos + axis scores

Probabilístico. Chama o modelo. Produz evidência.

CHECKER — verifier.ts + verifier-panel.ts
DebateResult + ContextPack oráculo → bool oráculo → bool

Determinístico. Não chama o modelo. Só pesa a evidência.

O checker VÊ (evidência estruturada) votos por membro axis scores spread + quorum ContextPack O checker NÃO VÊ (e não pode usar) o ModelAdapter (não recebe — não pode re-chamar) o texto “convincente” como argumento de autoridade
A fronteira read-only desenhada: o checker pesa números; ele não tem o modelo na mão para “refazer” a conclusão.
Para guardar Maker = debate (probabilístico). Checker = verifier + painel (determinístico). O checker é read-only por arquitetura: ele aceita só o resultado do maker, então não dá para “falar mais bonito” para passar — só dá para ter evidência.

A assinatura que impõe a fronteira

O verifier aceita apenas DebateResult + ContextPack. Não recebe um ModelAdapter, então literalmente não tem como re-chamar um modelo. A fronteira não é uma promessa em comentário — é imposta pelo tipo.

// verifier.ts:19
/** Maker-checker Verifier. READ-ONLY BY ARCHITECTURE.
 *  Aceita só DebateResult + ContextPack. Não pode re-chamar modelo. */

// verifier.ts:84
export type ClaimOracle =
  (evidence: VerifierEvidence) => { proven: boolean; evidence: string };

Um ClaimOracle é uma função pura de VerifierEvidence para { proven, evidence }. É isso que permite ao sistema escrever um VerificationReport auditável, em vez de devolver “o modelo disse que sim”.

03

O Debate Engine — phases seriais, membros paralelos

O debate acontece em fases (phases). As fases rodam uma depois da outra (seriais), mas dentro de cada fase os membros falam ao mesmo tempo (paralelos). Por que essa mistura?

Porque há um membro especial — o contrarian — que precisa ver tudo o que já foi dito antes de dar a sua nota. O board loader força esse membro a ser o último. Assim o contrarian sempre recebe as contribuições acumuladas das fases anteriores. Isso é sequenciamento real no código — não uma instrução no prompt pedindo “por favor, discorde”.

Phase 1 (Promise.all) membro membro membro Phase 2 (Promise.all) membro membro Phase final CONTRARIAN vê tudo (priorPhases)
As fases são seriais (setas) para que o contrarian, sempre na última, receba as contribuições acumuladas. Dentro de cada fase, os membros rodam em paralelo via Promise.all.
Passo a passo — o ciclo de um membro (debate.ts:108–159)
1
bindMember — liga o membro do board ao seu adapter de modelo.
2
buildModelInput — monta o prompt passando priorPhases para que o contrarian veja tudo que já foi dito.
3
adapter.run(input) — sempre devolve um Result e nunca lança. Se vier !result.ok, o membro vira um failure tratado, não uma exceção.
4
parseAxisScores — extrai as notas por eixo do texto, de forma tolerante (texto malformado não derruba a fase).
5
buildVote — constrói o voto { memberId, axes, rationale } que vai virar evidência para o checker.
6
Agora você: sem espiar abaixo, responda — se o adapter do membro 2 falhar, a fase inteira aborta? (Resposta: não. O Result isola a falha do membro; a fase segue com os demais votos.)

O núcleo do loop por membro

// debate.ts:31
/** The DebateEngine. Phases serial, members within phase IN PARALLEL.
 *  Contrarian is forced last by board loader — real sequencing,
 *  not prompt claim. */

// debate.ts:130
const result = await boundMember.adapter.run(input);  // nunca lança
if (!result.ok) { return failure }
const scores = parseAxisScores(result.text);
const vote = buildVote({ memberId, axes: scores.value, rationale: result.text });

debate.ts:162runPhase usa Promise.all para despachar os membros de uma fase em paralelo. As fases entre si permanecem seriais, então a ordenação do board (com o contrarian por último) é respeitada.

O fato de o adapter sempre devolver Result (e nunca lançar) é o que deixa o debate fail-closed sem precisar de try/catch espalhado: um membro que falha é evidência de falha, não um crash.

Por que importa: o sequenciamento real (contrarian por último, via board loader) é uma garantia de código. Um prompt que pede “seja crítico” pode ser ignorado pelo modelo; uma ordem de execução, não.

Anatomia de um voto

Cada membro não devolve um “sim/não” — devolve um voto estruturado. É exatamente essa estrutura que o checker vai pesar depois.

Vote memberId axes (notas por eixo) rationale (texto — informativo, NÃO é o que o checker mede) vira evidência para os oráculos do checker
O rationale ajuda humanos a entender; os axes (e o spread entre eles) são o que os oráculos medem. parseAxisScores é tolerante: texto malformado não derruba a fase.
04

O Verifier — maker-checker e oráculos determinísticos

O verifier é o auditor. Ele recebe a evidência que o debate produziu e aplica oráculos: pequenas funções que respondem perguntas objetivas sobre essa evidência. “Quantos agentes válidos votaram?” “O spread entre as notas é apertado o suficiente?” “Atingiu o quorum?”. Nenhuma dessas perguntas olha o texto do maker — só os números estruturados.

E o verifier sabe parar. Se a verificação entra em loop e ultrapassa o limite de tentativas, a decisão não é forçada: ela é estacionada (parked) em T4 — ou seja, mandada para um humano. Travar com elegância é melhor que carimbar uma decisão fraca.

0
MAX_LOOPS — acima disso, parked em T4 (humano)
read-only
o verifier não recebe ModelAdapter — não pode re-chamar o modelo
oráculos
funções puras sobre votos, scores, spread e quorum
loop 1 loop 2 loop 3 loopCount > MAX_LOOPS (3) → parkedTier = T4 (humano) Até 3 tentativas determinísticas; depois disso, a decisão sobe para uma pessoa.
O verifier não insiste para sempre: MAX_LOOPS = 3. Acima disso, a decisão é estacionada em T4 em vez de ser forçada.

O contrato do verifier

// verifier.ts:19
/** Maker-checker Verifier. READ-ONLY BY ARCHITECTURE. */

// verifier.ts:49
export const MAX_LOOPS = 3;
// loopCount > 3 → parkedTier = T4 (humano)

// verifier.ts:84
export type ClaimOracle =
  (evidence: VerifierEvidence) => { proven: boolean; evidence: string };

Os oráculos operam sobre VerifierEvidence — uma estrutura derivada de consensus.ts (que conhece MIN_VALID_AGENTS e o spread das notas). Cada oráculo devolve não só proven mas também uma string evidence, que entra no VerificationReport e torna a decisão auditável linha a linha.

verifier.ts:22–37 — o comentário de arquitetura explica a separação maker/checker e por que o verifier é read-only. Vale ler na fonte: é o melhor resumo da filosofia do pacote.

O oráculo como função pura

Um ClaimOracle entra com evidência e sai com um booleano mais uma string que explica o porquê. Essa string é o que torna a decisão auditável.

VerifierEvidence votos · scores · spread · quorum ClaimOracle função pura · sem modelo { proven, evidence } → entra no VerificationReport
Mesma entrada, mesma saída, sempre — é isso que “determinístico” significa aqui. A string evidence registra a razão, não só o veredito.
05

O painel de verificação + o gate de emissão T3

Infográfico de três lentes lado a lado — Coherence, Faithfulness (confidence ≥ 0.5 e strength ≥ 3) e Domain (GO precisa de validation evidence e diversidade) — sobre uma barra de quorum 2 de 3, com um selo de veto preserve-dissent em vermelho que rejeita tudo num hard failure, e uma seta final para Emissão T3.

O painel olha a mesma evidência por três ângulos diferentes. Verificar por três lentes só compensa porque cada lente enxerga uma coisa distinta.

Um único verificador, repetido, não traz informação nova. Por isso o painel usa três lentes diferentes — cada uma faz perguntas distintas sobre a mesma evidência:

  • Coherence — a decisão é internamente consistente? (reusa o verifyDecision do verifier).
  • Faithfulness — há evidência presente, com confiança média ≥ 0,5 e força de pico ≥ 3?
  • Domain — um GO tem evidência de validação e diversidade suficientes?

Para emitir, o painel precisa de um quorum: por padrão, 2 das 3 lentes precisam verificar. Mas há uma trava acima do quorum: o veto de preserve-dissent. Se qualquer lente tem uma falha dura (hard) — por exemplo, um GO sobre zero evidência — o painel inteiro é rejeitado, mesmo que as outras duas lentes aprovem.

As três lentes
Coherence verifyDecision Faithfulness conf ≥ 0.5 strength ≥ 3 Domain GO precisa de evidência+diversidade
Quorum vs. veto
QUORUM = 2 de 3 → emite hard failure em QUALQUER lente → rejeita tudo (vence o quorum)
Cuidado O quorum não é a palavra final. Um hard failure numa única lente derruba a emissão mesmo que duas lentes tenham passado. A trava de segurança (preserve-dissent veto) está acima da votação por maioria.

Veja na prática: o veredito do painel

Marque quais lentes passam e se há um hard failure. Observe como o veto pode vencer o quorum.

Coherenceverifica
Faithfulnessverifica
Domainverifica
Veredito: 3/3 lentes verificam, quorum atingido (≥ 2), sem hard failure → EMITE (T3)

Os pisos e o quorum, na fonte

// verifier-panel.ts:40
export const FAITHFULNESS_CONFIDENCE_FLOOR = 0.5;
export const FAITHFULNESS_STRENGTH_FLOOR = 3;
/** Número padrão de lentes que precisam verificar (de três). */
export const DEFAULT_PANEL_QUORUM = 2;

Cada lente é um VerifierLens: um conjunto de claims mais a lista de quais são hard (hardClaimIds). Em lensVerdict, se qualquer claim hard falha, a lente é rejected; caso contrário, ela só verifica se todos os seus claims passam.

A lente Faithfulness tem hardClaimIds: ['evidence-present'] — então “GO sobre zero evidência” é um hard failure por construção. É essa modelagem que dá força ao veto de preserve-dissent: o quorum agrega, mas um hard failure rejeita o painel inteiro.

verifier-panel.ts:31–33 (comentário): “a HARD failure in ANY lens … rejects the whole panel; otherwise emission needs a quorum of lenses to verify.” Esse é, textualmente, o gate de emissão T3.

Como uma lente decide (lensVerdict)

claims da lente algum claim HARDfalhou? sim não verdict = rejected verifica SE todosos claims passarem
É por isso que “GO sobre zero evidência” derruba a lente Faithfulness: evidence-present é um hardClaimId. Um hard claim que falha é rejected imediato.

O quorum, visto de cima

verifica verifica não importa quorum ✓ (2/3) DEFAULT_PANEL_QUORUM = 2 — desde que NENHUMA lente tenha hard failure
Com 2 das 3 lentes verificando e nenhum hard failure, o painel emite. O quorum agrega sinal; o veto protege contra o pior caso.
06

Como o dissent é preservado

Mesa de debate vista de cima com cinco assentos numerados; quatro membros em oliva e o último em clay etiquetado contrarian forçado por último pelo board.ts; seta tracejada mostra contribuições acumuladas chegando ao contrarian; à direita um relatório VerificationReport com consenso registrado e dissent reportado, e um X riscando a ideia de forçar consenso.

O contrarian é estruturalmente o último a falar, e o relatório guarda a discordância em vez de apagá-la.

Muitos sistemas de “consenso” escondem a discordância: pegam a média e seguem em frente. O Council faz o oposto — ele preserva o dissent de propósito, por dois mecanismos:

1. O contrarian é forçado por último. O board loader (em board.ts) coloca o membro contrarian no fim da última fase, então ele sempre vê tudo que foi dito e pode discordar com base completa.

2. O verifier e o painel reportam o dissent. Eles foram desenhados para aceitar e registrar a discordância explicitamente, em vez de forçar um consenso artificial. É por isso que o painel tem um preserve-dissent veto: a discordância não é ruído a ser suavizado — é sinal.

Forçar consenso (o que NÃO fazemos) média a discordância (clay) some na média Preservar dissent (o Council) report: dissent a discordância vira sinal registrado
À esquerda, a média apaga a minoria. À direita, o Council reporta a discordância — o contrarian (clay) não é suavizado, é registrado.
A frase que resume L2

O Council consegue afirmar “decisão com dissent preservado e grounded evidence” — em vez de “o LLM achou que era uma boa ideia” — porque separa o maker (debate) do checker (verifier + painel) e baseia o checker em oráculos determinísticos com um veto que protege a discordância.

Onde isso vive no código

board.ts — o board loader ordena os membros e força o contrarian por último; isso é sequenciamento de execução, não uma instrução de prompt.

consensus.ts — define MIN_VALID_AGENTS e calcula o spread das notas; é a base de evidência sobre a qual os oráculos do verifier operam.

verifier-panel.ts — a agregação por quorum com o preserve-dissent veto: a discordância é reportada no VerificationReport, não eliminada.

07

Explorar o pipeline — maker → checker → gate

Clique em cada estágio para ver o que ele faz, onde ele vive e a camada que ele acende.

maker

Debate qualitativo

debate.ts — maker verifier.ts — checker verifier-panel.ts — gate T3 parkedTier = T4 (humano)

Flashcard
Por que o debate roda fases seriais mas membros paralelos?
clique para virar
Resposta
Para o contrarian, forçado por último, ver as contribuições acumuladas (priorPhases). Dentro da fase, Promise.all roda os membros juntos.
Flashcard
O que torna o verifier “read-only por arquitetura”?
clique para virar
Resposta
Ele aceita só DebateResult + ContextPack — nunca um ModelAdapter. Sem modelo, não há como re-chamar; a fronteira é imposta pelo tipo.
Flashcard
Quorum padrão do painel?
clique para virar
Resposta
DEFAULT_PANEL_QUORUM = 2 de 3 lentes. Mas um hard failure em qualquer lente rejeita tudo, vencendo o quorum.
Flashcard
O que acontece quando loopCount > MAX_LOOPS?
clique para virar
Resposta
MAX_LOOPS = 3. Acima disso, parkedTier = T4: a decisão sobe para um humano em vez de ser forçada.
08

Como verificar esta camada

A fonte primária — leia isto antes de tudo
packages/council/src/verifier.ts:19–37

O comentário de arquitetura do maker-checker. São poucas linhas e contêm a filosofia inteira do pacote: por que o checker é read-only e por que isso permite afirmar “verificado”.

Rode os testes do pacote e olhe três arquivos de teste em foco. Eles são a prova viva de cada afirmação desta lição.

pnpm test packages/council
# Foco:
# - debate.test.ts            → phases seriais, membros paralelos, contrarian por último
# - verifier*.test.ts         → oráculos determinísticos + parked T4
# - verifier-panel.test.ts    → 3 lentes + quorum + dissent veto
Tarefa prática (5 passos)
1
Leia debate.ts:31 (comentário sobre o contrarian sequencing).
2
Leia verifier.ts:19–37 (a arquitetura maker-checker).
3
Rode um council T3 e capture o VerificationReport completo.
4
Identifique qual lente sofreu hard failure num caso de NO-GO.
5
Compare o que muda quando loopCount > MAX_LOOPS (a decisão vira parked T4).

Source anchors (evidência direta)

Arquivo:linhaConceito
council/src/debate.ts:31DebateEngine — phases seriais, membros paralelos, contrarian por último
council/src/debate.ts:130adapter.run por membro (sempre Result, nunca lança)
council/src/verifier.ts:19Maker-checker Verifier (read-only por arquitetura)
council/src/verifier.ts:49MAX_LOOPS = 3 → parked T4
council/src/verifier.ts:84ClaimOracle — função pura sobre evidência
council/src/verifier-panel.ts:40FAITHFULNESS floors (0.5 / 3) + DEFAULT_PANEL_QUORUM = 2
council/src/consensus.tsMIN_VALID_AGENTS + spread
council/src/board.tsBoard loader + contrarian por último
debate.test.ts verifier.test.ts verifier-panel.test.ts phases seriais · membros paralelos · contrarian último oráculos determinísticos · parked T4 (MAX_LOOPS) 3 lentes · quorum · preserve-dissent veto
Cada afirmação desta lição tem um teste correspondente. Rodar pnpm test packages/council é a prova viva — não um “deveria funcionar”.
Confusão comum Achar que “Council é só um debate de LLMs”. Não — o debate é só o maker. O checker (verifier + painel) é programático, determinístico, e é o verdadeiro gate de qualidade.
09

Recapitulando — em cinco slides

Slide 1 · A ideia

Quem decide não é quem aprova

O Council separa o maker (debate, probabilístico) do checker (verifier + painel, determinístico). É essa assimetria que sustenta “decisão verificada”.

1
Slide 2 · O debate

Fases seriais, membros paralelos

Membros falam em paralelo (Promise.all); as fases são seriais para que o contrarian, forçado por último, veja tudo (priorPhases).

2
Slide 3 · O verifier

Read-only por arquitetura

Aceita só DebateResult + ContextPack. Oráculos puros pesam a evidência. MAX_LOOPS = 3; acima disso, parked em T4.

3
Slide 4 · O gate T3

Três lentes, quorum, veto

Coherence + Faithfulness + Domain. Quorum padrão 2/3 — mas um hard failure em qualquer lente rejeita tudo (preserve-dissent veto).

4
Slide 5 · A frase

Dissent preservado, evidência aterrada

Por isso o Alembic afirma “decisão verificada, com dissent preservado” — não “o LLM achou bom”. É o núcleo de “decisão confiável” do projeto.

5
Slide 1 / 5 use
As cinco coisas para nunca esquecer de L2
  1. Maker ≠ checker. Debate decide; verifier + painel aprovam.
  2. Read-only por arquitetura. O verifier não recebe modelo, então não pode ser “convencido”.
  3. Oráculos determinísticos. O checker pesa votos, scores, spread e quorum — nunca o texto do maker.
  4. Hard failure vence o quorum. O preserve-dissent veto está acima da maioria.
  5. Trava com elegância. loopCount > 3 → parked T4, em vez de forçar uma decisão fraca.
10

Verifique seu entendimento

Quiz de revisão — 3 perguntas
1. No Council, o checker (verifier + painel) é:
(b). O verifier aceita só DebateResult + ContextPack; não recebe ModelAdapter, então não pode re-chamar o modelo (a). Ele é o gate real, não opcional (c).
2. Duas lentes verificam (quorum 2/3 atingido), mas a Faithfulness teve um hard failure (GO sobre zero evidência). O painel:
(c). Um hard failure em qualquer lente rejeita o painel inteiro, mesmo com quorum (a). Não há re-debate automático aqui (b): o veto barra o sinal.
3. Por que o contrarian é forçado a ser o último membro pelo board loader?
(a). A ordenação serial das fases garante que o contrarian receba as contribuições acumuladas. É sequenciamento de código (board.ts), não latência (b); e nenhum membro re-chama o modelo no checker (c).
Acertos: 0/3
Em uma frase, para você mesmo: “O Council separa ____ de ____; o checker é ____ porque ____; e a emissão T3 é barrada quando ____.” Se você preenche as cinco lacunas, está pronto para a Camada L3 · Swarm.
Próximo: Camada L3 · Swarm — como o Alembic paraleliza trabalho entre muitos workers. Depois de L2 (decisão confiável) + L1 (adapters), L3 mostra como escalar a execução. Siga em “Próxima”.