Files
Enterprise-MCP-Service-Bus/RI/docs/Production-Recommendations.md
2026-09-14 14:54:28 -03:00

107 lines
6.7 KiB
Markdown

# 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`](AS-BUILT.md#limitações-e-achados-arquiteturais-reais)
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 substituiria `RouterFn` por 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 `ModeBOrchestrator` invoca 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 de `JourneyState`/`build_journey_graph` para 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 demo `could`). 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
substituiria `ModeBOrchestrator._combine` por um `NBADecisionModel` cross-domain de verdade.