Curso / Lição 18  ·  EN
Lição 18 · Motor & método · 5 de 8

Council & Verifier: debater, pontuar, provar

O motor de decisão L2 é um kernel em camadas: um DebateEngine que preserva o dissenso, um sistema quantitativo de pontuação 0–10, um Verifier maker-checker independente, e um painel N-lentes que é o portão de emissão T3+. O truque que o torna confiável: contrarian-last e verificação read-only são impostos estruturalmente, não por prompts. Fonte: packages/council/src/{debate,verifier,board}.ts, governado pela ADR-0003.

O DebateEngine — fases seriais, membros paralelos

As fases rodam na ordem declarada do board (serial), e os membros dentro de uma fase rodam em paralelo. Como as fases são seriais, uma fase posterior recebe as contribuições acumuladas das anteriores. É isso que faz "o contrarian vê tudo e fala por último" ser sequenciamento real, não um claim de prompt — o próprio comentário de cabeçalho do motor diz isso:

// packages/council/src/debate.ts:30-44 — o contrato do motor, intenção literal
// As fases rodam na ordem declarada do board (SERIAL entre fases) e os
// membros dentro de uma fase são despachados EM PARALELO. … A fase contrarian é
// ordenada por último pelo board loader, então "o contrarian vê tudo e fala
// por último" é sequenciamento REAL — fases anteriores já produziram suas
// declarações antes de os inputs de modelo da fase contrarian sequer serem montados.
serial → Fase 1 membro A ‖ B (paralelo) Fase 2 vê a fase 1 Contrarian (último) vê tudo contrarian_not_last = erro duro de board-load agregar votos ponderados → ConsensusResult <3 votos válidos ⇒ NO_GO (fail-closed) chamadas de adapter obedecem nunca-lança: o motor ramifica em ModelRunResult.ok, sem try/catch em run()

As chamadas de adapter obedecem ao invariante nunca-lança (lição 14): cada run() resolve para um ModelRunResult discriminado por ok, então o motor ramifica no resultado em vez de envolver chamadas em try/catch. Um membro que falha ao fazer bind, dá erro ou retorna um voto não-parseável é registrado como um MemberFailureReason — nunca uma exceção lançada.

Pontuação — 0–10, e o risco não é invertido

Cada membro emite scores de eixo sobre SCORING_AXES (feasibility / revenue / cx / ttm / risk) ponderados .25/.25/.20/.15/.15. GO_THRESHOLD = 7, PIVOT_THRESHOLD = 5. O detalhe de correção não-óbvio: o eixo risk é pontuado de modo que 10 = baixo risco, somando na mesma direção de todo outro eixo — não há normalização 1 - risk para errar de cabeça pra baixo:

// packages/council/src/scoring.ts — direção uniforme; nomes de eixo são fonte única
SCORING_AXES = ['feasibility', 'revenue', 'cx', 'ttm', 'risk'];  // typo não zera um eixo em silêncio
// score alto → GO; risk 10 = baixo risco; SEM inversão — todos os eixos somam igual

Quórum fail-closed. aggregateConsensus retorna NO_GO antes de consultar qualquer score quando há menos que MIN_VALID_AGENTS = 3 votos válidos (consensus.ts:101-125). "Um board esparso ou degradado nunca deve dar sinal verde." Um board que perdeu dois membros por falha de adapter não pode passar por acidente com um voto otimista.

O Verifier — read-only por arquitetura

O Verifier maker-checker é a encarnação do invariante ④ (lição 16). Aceita apenas vistas readonly, não expõe superfície de adapter ou mutação, e prova claims atômicos com oráculos determinísticos sobre a evidência estruturada — nunca sobre a prosa do maker:

O painel N-lentes — o portão de emissão T3+

Para T3 e acima, a emissão tem portão por verifyPanel / isPanelEmissionApproved — três lentes de perspectiva diversa agregadas por quórum com um veto de preservação-de-dissenso:

LenteCheca
COHERENCE= verifyDecision reusado — quórum, verdict↔score, auto-consistência
FAITHFULNESSevidência presente e ultrapassa pisos de confiança/força
DOMAINum GO precisa de um sinal validation; evidência não é monocultura
Quórum E um veto — ambos, de propósito

O painel aprova por quórum (padrão 2 de 3) mas uma rejeição dura em qualquer lente única veta o painel inteiro (preservação-de-dissenso), e escalate-after-N propaga. Então uma maioria confiante de duas lentes ainda pode ser detida por uma lente que achou uma falha fatal. Esta conjunção — maioria para passar, qualquer-veto para bloquear — é da qual o GO-verificado do funil (lição 15) depende. É deliberadamente mais difícil de passar que um voto simples.

1. Como "o contrarian fala por último" é garantido?
Correto: c. Os membros dentro de uma fase são paralelos, mas as fases são seriais e a fase contrarian é a última, então declarações anteriores existem antes de seus inputs serem montados. O board loader rejeita um board onde o contrarian não é o último. Sequenciamento real, imposto no load — não um prompt.
2. Um board produz só 2 votos válidos (um membro falhou ao fazer bind). Qual o veredito?
Correto: b. O quórum é checado primeiro: menos de 3 votos válidos é NO_GO automático. Um board degradado nunca deve dar sinal verde, e a falha de bind é registrada como um MemberFailureReason, não um throw.
3. Duas de três lentes do painel aprovam, mas a lente DOMAIN emite uma rejeição dura (sem sinal de validation para um GO). O painel aprova a emissão?
Correto: d. O painel precisa de quórum e nenhum veto duro. A regra de preservação-de-dissenso significa que uma lente achando uma falha fatal bloqueia a emissão mesmo quando as outras passam. É a conjunção da qual o GO-verificado do funil depende.

Confusões comuns

"Score de risco maior deve significar mais risco." Não — nesta pontuação, risk = 10 significa baixo risco, então soma na mesma direção de feasibility/revenue. Não há deliberadamente um passo 1 - risk; errar isso inverteria toda decisão, então os eixos são mantidos uniformes e os nomes de eixo são fonte única de verdade.
"O Verifier é só mais um membro do council." Não — ele não tem adapter e nenhuma superfície de mutação. É read-only por arquitetura e prova claims com oráculos determinísticos sobre evidência estruturada, não perguntando a um modelo. É isso que o torna uma checagem, não mais uma opinião.