6.7 KiB
Production Recommendations — o que muda para um ambiente produtivo real
Síntese do que um deployment de produção real precisaria mudar em relação a esta Reference
Implementation (RI), derivada das limitações reais encontradas e documentadas durante a
implementação (ver AS-BUILT.md
para o detalhe de cada achado). Nada aqui é hipotético: cada item corresponde a uma lacuna real
verificada em teste, não a uma suposição sobre o que "poderia" faltar.
Público-alvo: quem vai avaliar ou adaptar esta RI para um cenário real.
Identity Provider
Um IdP real em alta disponibilidade (cluster Keycloak, ou equivalente gerenciado), não a
instância única do docker-compose.yml. A extensão para mTLS/workload identity — cobrindo casos
em que client_credentials não é forte o suficiente (ex.: workloads em malha de serviço) — já
está documentada como ponto de extensão em docs/adr/ADR-019-extensao-de-identidade.md; produção
implementaria essa extensão, não reinventaria o middleware de autenticação do zero.
PDP
Distribuição de política via bundle OPA real (um bundle server, não push_client_profile
ponto-a-ponto no boot do Gateway) — permite versionamento, rollback e distribuição consistente
para múltiplas réplicas do Gateway. policy_version deixaria de ser um hash de arquivos locais
(pdp/client.py:compute_policy_version, suficiente para provar que o campo flui ponta a ponta)
e passaria a ser a revisão real do bundle publicado.
Registry
Um store durável (Postgres) em vez do SQLite atual (registry/store.py) — SQLite prova o
contrato/lifecycle corretamente, mas não é a escolha certa para concorrência de escrita entre
múltiplas réplicas do Gateway em produção. Um endpoint administrativo real para
revogação/lifecycle de capability também não existe hoje: as transições de estado
(registry/lifecycle.py) são exercitadas via chamada direta aos métodos internos em teste, não
via uma API HTTP protegida que um sistema de governança externo possa chamar.
Audit
Um sink durável (Postgres, ou uma fila como Kafka/SQS) em vez do JSONL append-only atual
(audit/sink.py). Mais importante: um alerta real conectado à falha do sink. O comportamento
atual do Gateway — engolir qualquer exceção de audit_sink.emit() (gateway/server.py: _emit_audit) para nunca transformar uma falha de auditoria numa operação de baixo risco em erro
500 — é correto por design, não um bug a remover; mas em produção, uma falha silenciosa do
sink que nunca é observada é, na prática, um blackout de auditoria sem alarme. Produção precisa
de observabilidade dedicada sobre o próprio sink (métrica de falha de emit, alerta), não de
mudar o comportamento fail-open do Gateway.
Approval workflow
Um store persistente (não o dict em memória de approval/service.py, que perde todo o estado
de aprovações pendentes num restart do processo) e uma integração real de
notificação/UI para o aprovador — hoje grant()/deny() são chamados via CLI/teste, sem
interface real para um humano.
Rate limiting e anti-replay
Nenhum dos dois existe nesta RI hoje — gaps reais, documentados e cobertos por teste adversarial
dedicado (tests/adversarial/test_protocol_identity.py), nunca escondidos. Um Gateway de
produção precisa de ambos: anti-replay (nonce, ou uma janela de deduplicação por
mcp_request_id) para fechar o vetor de replay de requisição byte-idêntica com um token ainda
válido; rate limiting para conter exfiltração em massa via chamadas de leitura legítimas
repetidas — hoje mitigado apenas por detectabilidade a posteriori via auditoria, nunca por
prevenção em tempo real.
Observabilidade
O otel-collector + Jaeger do perfil observability tem a configuração validada
(docker compose config), mas não recebeu tráfego real de um teste automatizado — produção
precisa de um coletor/backend OTLP real de fato recebendo e retendo tráfego, com dashboards e
alertas sobre os span attributes de correlação já emitidos (decision_id,
policy_decision_id, entitlement_version). O Langfuse self-hosted (EP-13-T02) é o único
consumidor OTLP desta RI validado com tráfego real, e apenas manualmente — replicar essa
validação como parte de CI é um investimento real, não apenas ligar o profile.
Segredos
Um gerenciador de segredos real (Vault, um KMS gerenciado, ou equivalente) em vez de variáveis
de ambiente com valores de desenvolvimento (SALES_DOMAIN_SERVICE_TOKEN,
GATEWAY_TOKEN_EXCHANGE_CLIENT_SECRET, etc., ver .env.example) — o mecanismo de indireção
(BackendConfig.service_account_token_env_var guarda o nome da variável, nunca um valor
literal, validado por field_validator) já está correto e se mantém: produção troca apenas de
onde a env var é populada, não a forma como o Gateway a consome.
Escala e alta disponibilidade
O Gateway não mantém estado compartilhado entre requisições — cada tools/call abre uma sessão
própria a montante (gateway/server.py:_with_downstream_session), sem pool de conexão
persistente nem estado de sessão em memória entre chamadas. Isso é favorável a escalar
horizontalmente (múltiplas réplicas atrás de um load balancer, sem sticky sessions). PDP,
Registry e Approval, por outro lado, cada um precisa de sua própria estratégia de HA em
produção (ver seções acima) — nenhum dos três foi desenhado para múltiplas réplicas na RI.
Multiagente (ADR-024)
- Modo A: o roteador do
GlobalSupervisor(agent_runtime/global_supervisor.py) é um stand-in deliberadamente simples baseado em palavra-chave — não é, e nunca pretendeu ser, uma reivindicação de qualidade de roteamento. Produção substituiriaRouterFnpor uma classificação de intenção real (LLM ou motor de regras), sem qualquer mudança na fronteira de segurança (cada backend continua resolvendo seu próprio entitlement de forma independente, invariante que não depende da qualidade do roteador). - Modo B: o
ModeBOrchestratorinvoca o journey graph uma vez por client e combina os resultados numa camada acima do grafo — não escala nativamente para muitos domínios sem uma extensão deJourneyState/build_journey_graphpara múltiplos clients num único run (decisão de design documentada no próprio módulo, deliberadamente não tentada nesta RI para não arriscar um componente já testado numa democould). A regra de combinação atual ("Finance sempre vence Sales") também é uma regra de referência, não um modelo de ranking real — produção substituiriaModeBOrchestrator._combinepor umNBADecisionModelcross-domain de verdade.