Pular para o conteúdo

Metodologia de Confidence

Toda decisão de roteamento que a Floopy toma carrega um campo confidence — a crença auto-reportada do roteador de que sua escolha principal é a correta para o tráfego desta organização agora. Esta página explica exatamente como esse número é calculado, o que cada confidence_reason significa e por que null às vezes é a resposta honesta.

Confiança é uma heurística, não uma probabilidade. Uma confiança de 0.78 não significa “78% de chance de o roteador estar correto” — significa “os inputs que o roteador tem sobre este candidato (gap para o vice, contagem de amostras, variância de outcome) são mais fortes que os inputs na maioria das decisões recentes desta org”.

Expomos confiança para que clientes possam construir filas de revisão, alertas e a constraint confidence_threshold em cima de um sinal explícito — não para que ela seja tratada como uma probabilidade de correção.

A confiança é calculada inteiramente a partir dos inputs da própria organização requisitante (seus candidatos, suas contagens de amostras, sua variância). Ela não vaza informação cross-tenant.

gap_norm = clamp(gap_top2 / GAP_REF, 0.0, 1.0) GAP_REF = 0.20
n_norm = clamp(log1p(n_samples) / log1p(N_REF), 0.0, 1.0) N_REF = 30
var_norm = 1.0 - clamp(variance / VAR_REF, 0.0, 1.0) VAR_REF = 0.25
raw = W_GAP*gap_norm + W_N*n_norm + W_VAR*var_norm
W_GAP = 0.45, W_N = 0.35, W_VAR = 0.20
if phase == Day0: return min(raw, CAP_DAY0) // 0.6
if used_shared_pool_prior == true: return min(raw, CAP_SHARED) // 0.8
return raw
InputSourceMeaning
gap_top2score_top1 − score_top2 em RoutingAudit.candidatesQuão à frente está o vencedor.
n_samplesjanela rolante sobre o log de requisições para o vencedorQuanto tráfego real respalda a escolha.
variancevariância rolante de outcome do vencedor (qualidade composta)Quão estáveis têm sido os outcomes observados.
phaseFase do Feedback-Driven: Day0, Auto, NpsMaturidade dos dados da org.
used_shared_pool_priorboolean na auditoriaSe priors cross-tenant influenciaram o score.
  • W_GAP = 0.45 — uma separação clara entre os dois principais candidatos é a evidência mais direta de que a decisão de roteamento não é cara ou coroa.
  • W_N = 0.35 — a contagem de amostras importa, mas com forte retorno decrescente (note o log1p). Ir de 5 para 50 amostras te diz muito; ir de 500 para 5000 te diz menos.
  • W_VAR = 0.20 — estabilidade de outcome é um sinal confirmatório, não um sinal principal. Variância baixa com gap empatado ainda é confiança baixa.

Esses pesos são estáticos e não configuráveis pelo cliente na v1.

Quando a organização está na fase Day0 do Feedback-Driven (ainda sem feedback de NPS, apenas sinais automatizados), a fórmula pode calcular qualquer valor raw, mas a confiança retornada é capada em 0.6.

Por quê: em Day-0, por definição, não há sinal validado por usuário final. O roteador pode rankear candidatos bem, mas até que o feedback de uso real esteja no loop, “alta confiança” seria enganoso. O cap é uma forcing function: um cliente que quiser ver confiança acima de 0.6 precisa completar a rampa de cold-start.

CAP_SHARED = 0.8 — o cap de prior do pool compartilhado

Seção intitulada “CAP_SHARED = 0.8 — o cap de prior do pool compartilhado”

Quando a decisão de roteamento utilizou priors cross-tenant (used_shared_pool_prior == true), a confiança retornada é capada em 0.8.

Por quê: priors cross-tenant são por definição menos confiáveis que outcomes do próprio tenant. Capar em 0.8 reflete isso honestamente. O cap foi revisado e aceito na revisão de segurança (SEC-020 na Credibility & Auditability Initiative) — o boolean cross-tenant em si é exposto na auditoria, mas os priors subjacentes nunca são expostos.

Você pode identificar decisões influenciadas pelo pool compartilhado por:

  • O campo used_shared_pool_prior: true na auditoria, e
  • O header HTTP Floopy-Aggregation-Notice: contains-shared-pool-influenced-decisions em GET /v1/export/decisions, e
  • O aggregation_signal_present: true do trailer.

Toda decisão carrega um confidence_reason para que o cap ou caso de borda seja explícito, não implícito.

ValueMeaning
okA fórmula retornou raw e nenhum cap foi aplicado.
cap_day0Retornou raw, depois clampeou para CAP_DAY0 = 0.6. A org está na fase Day-0.
cap_sharedRetornou raw, depois clampeou para CAP_SHARED = 0.8. A decisão usou um prior do pool compartilhado.
no_router_invokedNenhum roteador rodou para esta requisição — confidence é null. Cache hit, caminho de legacy-model, ou outro short-circuit.
insufficient_samplesn_samples < N_MIN (default 3) e a org está além do Day-0. O score é raw * 0.5 para amortecer uma fórmula apressada com poucos dados.
single_candidateApenas um candidato foi considerado — gap_top2 é indefinido, então a confiança é null.

null é um valor de primeira classe e válido. Significa “nenhum roteador foi invocado para esta requisição” — por exemplo:

  • A resposta foi servida do cache (outcome.cache_hit == true).
  • O caminho de parsing de legacy-model assumiu porque nenhuma regra de roteamento se aplicou.
  • Uma regra de roteamento de candidato único fez short-circuit do scoring de candidatos.

Trate confiança null como “não audite esta linha buscando uma decisão de qualidade de roteamento — não houve uma”. Se você filtrar min_confidence > 0 em GET /v1/decisions, linhas null são excluídas por design.

Cenáriogap_top2n_samplesvariancephasesharedconfidenceconfidence_reason
Alta confiança, maduro0.181000.05Npsfalse0.917ok
Baixa confiança, empatado0.011000.05Npsfalse0.532ok
Day-0, prior perfeito0.200nenhumaDay0false0.45ok
Day-0, raw máximo0.20300.0Day0false0.6cap_day0
Amostras insuficientes0.181nenhumaAutofalse0.27insufficient_samples
Cache hitn/an/an/an/an/anullno_router_invoked
Candidato únicon/a500.05Npsfalsenullsingle_candidate
Prior compartilhado0.18300.05Autotrue0.8cap_shared

Estes casos são exercitados pela suíte de testes de confiança do gateway — eles são o contrato.

confidence e confidence_reason são populados em toda decisão da data de deploy em diante. Linhas anteriores à data de deploy têm confidence == null e confidence_reason == null. Escolhemos isso em vez de um backfill porque reconstruir n_samples, variance e phase para decisões históricas estaria errado mais frequentemente do que ajudaria — e um número errado de confiança é pior que nenhum número.

  • Como fila de revisão: GET /v1/decisions?max_confidence=0.5 retorna as decisões de roteamento que você deve revisar primeiro.
  • Como alerta: acompanhe a fração de decisões na sua janela com confidence < 0.6. Um salto geralmente significa que o formato do tráfego da org mudou, não que a Floopy piorou.
  • Como constraint de roteamento: PUT /v1/constraints com confidence_threshold: 0.7 faz o roteador cair para a baseline sempre que a confiança cair abaixo do threshold. Candidatos filtrados carregam reason: "constraint_confidence_below_threshold".

No v2 toda decisao que passa pelo router Feedback-Driven ou Smart-Cost carrega um bloco evidence ao lado de confidence e confidence_reason. Evidence e o pequeno conjunto de entradas que produziu o numero de confianca, exposto para que voce possa auditar o raciocinio, nao apenas o veredito.

CampoTipoSignificado
samplesintegerA contagem rolante de amostras n_samples sobre o vencedor. Mesmo numero que alimenta o termo n_norm na formula.
top2_score_gapnumberO gap de score entre o vencedor e o segundo colocado (gap_top2). Mesmo numero que alimenta gap_norm.
outcome_variancenumberA variancia rolante de resultados sobre o vencedor, na escala de qualidade composta. Mesmo numero que alimenta var_norm.
recent_regressionstagged unionContagem bucketizada de alertas de regressao sobre o (provider, model) do vencedor nos ultimos 7 dias. Veja abaixo.
last_regression_atISO8601 | nullTimestamp da regressao mais recente na janela de 7 dias, arredondado para o multiplo de 5 minutos mais proximo. null quando nao ha regressao na janela.

Quando nenhum router foi invocado (cache hit, candidato unico, amostras insuficientes para a estrategia), o campo evidence e ausente — null e um valor de primeira classe, igual a confidence.

recent_regressions e bucketizado, nao uma contagem bruta

Seção intitulada “recent_regressions e bucketizado, nao uma contagem bruta”

O campo recent_regressions e uma tagged union com dois formatos:

{ "kind": "exact", "exact": 3 }
{ "kind": "at_least", "at_least": 10 }
{ "kind": "at_least", "at_least": 50 }

Os limites dos buckets estao fixados no gateway:

Contagem brutaBucket emitido
0..=9Exact { exact: n }
10..=49AtLeast { at_least: 10 }
>= 50AtLeast { at_least: 50 }

Os buckets comprimem um sinal de evento de regressao em escala de frota em uma forma de 3 buckets. Eles preservam “tem algo errado com meu modelo?” — qualquer contagem exata diferente de zero ou qualquer AtLeast dispara o ramo “regression_detected” no endpoint de verificacao — sem vazar volumes precisos que poderiam ser correlacionados entre tenants.

O timestamp da regressao mais recente e arredondado para baixo no multiplo de 5 minutos mais proximo antes de sair do gateway. Uma regressao disparada em 2026-05-07T14:32:18Z e reportada como 2026-05-07T14:30:00Z. O arredondamento existe pelo mesmo motivo do bucketing: sinal suficiente para investigar, resolucao insuficiente para usar como side-channel.

recent_regressions e last_regression_at sao calculados sobre uma janela rolante de 7 dias. A janela e fixa e nao e configuravel pelo cliente no v2.

A consulta e org-scoped: o gateway busca alertas de regressao cujo organization_id corresponde a organizacao chamadora, com join no (provider, model) do vencedor. Nao ha agregacao cross-tenant nesse caminho.

Cada campo de evidence segue regras null-safe:

  • evidence em si e ausente (nao null) em linhas onde nenhum router foi invocado.
  • last_regression_at e null quando a janela de 7 dias nao tem regressoes, mesmo com o restante de evidence populado.
  • Um lookup de regressao falho (timeout no PostgREST, erro transitorio) renderiza recent_regressions: { "kind": "exact", "exact": 0 } e last_regression_at: null — fail-safe para “nenhuma regressao observada”, com uma metrica incrementada no lado do gateway para sabermos com que frequencia isso acontece. A decisao nao e bloqueada por um lookup de regressao.

A consulta da janela de 7 dias tem timeout duro de 150 ms e cache Redis positivo-e-negativo (TTL 60 s). A latencia da decisao fica limitada; o sinal de regressao fica atualizado.

Evidence e explicativo, nao load-bearing. O numero confidence e calculado das mesmas entradas (gap, samples, variance) mais os caps de phase e used_shared_pool_prior; recent_regressions nao alimenta confidence diretamente. Expomos evidence para que um revisor possa ler a linha de auditoria e ver com o que o router estava trabalhando — do mesmo jeito que o texto de explicacao recita os mesmos numeros em prosa simples.