vanna-clubpetro/promotion-manifest.yaml
Dalton Alvarenga f4a2ee44ca
All checks were successful
CD / build (pull_request) Successful in 5m2s
[lab] chore(promotion): prepara serviço para gates lab -> homolog
Adequa o repo ao guia de promoção lab -> homolog mantendo Python (Gate 0 via
stackException). Cumpre os gates aplicáveis:

- promotion-manifest.yaml: stackException (Python/Vanna), Gate B N/A, Gate D/G
  declarados, capacidade e deltas.
- k8s/hml/: overlay homolog — secret DB dedicado (vanna-clubpetro-db, Gate G),
  probes httpGet /health (Gate E), resources.requests, replicas:1, non-root
  securityContext; host homologation.clubpetro.com (sem host de lab).
- server.py: rota GET /health (alvo das probes).
- Dockerfile: usuário non-root uid/gid 10001 + HOME/cache graváveis (Gate E).
- .env.example: remove literal lab.clubpetro.com do CORS (Gate D).
- k8s/ flat movido para k8s/lab/ (simetria lab/hml); cd.yml aplica k8s/lab/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-11 18:50:22 -03:00

116 lines
5.1 KiB
YAML

# promotion-manifest.yaml
# Manifesto de promoção lab -> homolog (ClubPetro).
# A PR de promoção deve ser marcada com [lab] e conter este arquivo.
# O pipeline lê os campos abaixo pra rodar os gates 0 + A-F + G + admissao.
#
# OBS: o schema exato é definido pelo parser do pipeline (referências vivas:
# backend=external_apis, seed=action-plan). As chaves aqui são auto-descritivas;
# reconcilie com o parser se ele exigir nomes específicos.
apiVersion: v1
kind: PromotionManifest
service:
name: vanna-clubpetro
kind: backend # serviço HTTP (não é MFE)
description: >
Deploy do Vanna 2.0 (text-to-SQL sobre LLM) que responde perguntas em
pt-BR consultando o ClickHouse Cloud (database gold) com RLS por tenant
(program_id + store_id).
owner: dados-plataforma # TODO: confirmar squad/owner
runtimePort: 8765
promotion:
from: lab
to: homolog
# Onde o pipeline re-materializa o código (branch limpa, sem histórico do lab).
kubernetesOverlay: k8s/hml
# ---------------------------------------------------------------------------
# Gate 0 — Stack
# ---------------------------------------------------------------------------
stack:
language: python
runtime: python-3.11
framework: vanna-2.0 + fastapi + uvicorn
packageManager: pip
# Stack padrão do core é NestJS>=10/TypeORM0.3 (yarn) OU MFE React17/MUI5.
# Python é NO-GO por padrão -> exceção formal abaixo (Gate 0).
stackException:
requested: true
reason: >
O serviço é um deploy da biblioteca Vanna 2.0, que é Python e não tem
equivalente em NestJS. O núcleo (agente LLM, memória vetorial ChromaDB,
runner RLS do ClickHouse e o web component <vanna-chat>) vem do upstream
vanna-ai/vanna. Reescrever em Node significaria reimplementar toda essa
cadeia — inviável e sem ganho. Mantém-se Python; todos os demais gates
aplicáveis são cumpridos (ver abaixo).
approvedBy: "" # TODO: preencher com o aprovador humano do stackException
# ---------------------------------------------------------------------------
# Gate B — Migrations
# ---------------------------------------------------------------------------
migrations:
applicable: false
reason: >
O serviço não possui schema relacional próprio. O ClickHouse Cloud
(database gold) é gerido fora do serviço; o "treino" (train.py) apenas
popula um vector store ChromaDB local, idempotente e reconstruível
(rm -rf chroma_db/ && python train.py). Não há migrations TypeORM.
Toda query ao ClickHouse é parametrizada via settings do clickhouse_connect
(RLS), nunca por interpolação de string — ver rls_runner.py.
# ---------------------------------------------------------------------------
# Gate D — Atalhos / segurança
# ---------------------------------------------------------------------------
security:
envVersioned: false # apenas .env.example versionado; .env no .gitignore
hardcodedSecrets: false # segredos vêm de k8s Secret (envFrom), nunca do git
hardcodedLabHost: false # overlay homolog usa homologation.clubpetro.com
npmrcVersioned: false # sem .npmrc no repo
# ---------------------------------------------------------------------------
# Gate G — Isolamento de credenciais de banco
# ---------------------------------------------------------------------------
database:
# Credenciais do ClickHouse em secret DEDICADO ao serviço (não genérico).
credentialsSecret: vanna-clubpetro-db
genericSecret: false # NÃO usa sqlhomologation / sqluserhomolgeneric etc.
engine: clickhouse-cloud
database: gold
# ---------------------------------------------------------------------------
# Admissão de capacidade
# ---------------------------------------------------------------------------
capacity:
replicas: 1 # ChromaDB é SQLite-based; réplicas > 1 corrompem o store
strategy: Recreate # PVC ReadWriteOnce — não dá 2 pods montando ao mesmo tempo
resources:
requests:
cpu: "200m"
memory: "1Gi"
limits:
cpu: "1"
memory: "2Gi"
persistentVolume:
size: 5Gi
accessMode: ReadWriteOnce # store vetorial + cache ONNX + CSVs
# ---------------------------------------------------------------------------
# Deltas (avisos — não bloqueiam)
# ---------------------------------------------------------------------------
deltas:
A_architecture: >
Tenant (program_id/store_id) resolvido via RequestContext e validado por
regex ^[A-Za-z0-9_-]+$ (agent.py). O embed confiável passa os IDs por query
param do <vanna-chat> — não há token JWT nesta arquitetura de embed.
C_contract: >
OpenAPI auto-servido pelo FastAPI (/openapi.json, /docs). Rotas de chat já
versionadas: /api/vanna/v2/chat_sse|chat_websocket|chat_poll (upstream).
E_ops: >
Probes de liveness/readiness em GET /health; replicas: 1; Dockerfile
multi-stage rodando como usuário non-root (uid 10001).
F_ci: >
CI/CD via .gitea/workflows/cd.yml (build remoto no Cloud Build + rollout
no GKE). bitbucket-pipelines.yml N/A: o repo vive no Gitea self-hosted.