O CI rodava lint, typecheck, testes e build, e nada mais: os drivers de
Postgres e Redis nunca eram exercitados, e não havia build de imagem nem
pipeline de deploy.
- Job `services`: Postgres e Redis efêmeros. Roda a suíte de serviços, aplica
as quatro migrations, confere idempotência, confere que `--dry-run` não
altera nada e que o shim é pulado com ADAPTER_APPLY_IDENTITY_SHIM=0.
- Job `image`: build da imagem Linux e validação do artefato. Conteúdo de
runtime, usuário não-root, ausência de .env, docs, testes e vitest na
imagem, os oito scripts operacionais transformando e executando, entrypoint
recusando subcomando desconhecido, fail-fast com código diferente de zero
na web e no worker, liveness com cabeçalhos de segurança, compose completo
até `ready`, heartbeat do worker, jornada assíncrona entre processos e
desligamento gracioso exigindo `SIGTERM recebido` em menos de 25s.
- `.github/scripts/async-journey.sh` percorre web → Redis → worker → download
dos três formatos, atravessando a fronteira de processo que a suíte de
testes não cobre.
- Deploy com gatilho único `workflow_dispatch`: não há deploy automático em
push, tag ou merge. Migration, deploy e liberação da feature flag são jobs
separados, cada um com seu ambiente de aprovação manual.
- Nenhum segredo entra em comando de shell. Um input de workflow interpolado
em `run:` é injeção, então `workspace_id` passa por variável de ambiente e
é validado como UUID antes de qualquer escrita. O deploy usa heredoc citado
e `permissions: contents: read` no topo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>