Files
adaptador-planilhas/docs/spreadsheet-adapter/21-checklist-validacao.md
T
camilafagundesandClaude Opus 5 5b11496cd9
ci / lint, typecheck, testes e build (push) Has been cancelled
ci / Postgres e Redis reais (push) Has been cancelled
ci / imagem Docker Linux (push) Has been cancelled
Runbook único de homologação, checklist de evidências e ADR do ambiente
Havia dois runbooks sobrepostos, escritos para o piloto, e nenhum documento do
ambiente de homologação.

- `20-homologacao-runbook.md` consolida os dois e cobre DNS, TLS, Nginx,
  Supabase de homologação, banco com a decisão do shim, bucket privado,
  containers, worker, observabilidade, flag, rollback, diagnóstico e smoke.
  Os dois runbooks antigos ficam no repositório marcados como histórico,
  preservando o registro das decisões.
- Rollback de imagem com comandos: identificar o que está no ar, listar tags,
  desligar a flag antes de trocar, subir só web e worker com `--no-deps`,
  conferir saúde, religar a flag. As migrations de segurança — RLS e auditoria
  append-only — estão declaradas sem caminho de volta: desfazê-las afrouxa o
  isolamento entre workspaces, então um rollback que precise disso está errado
  por definição.
- `21-checklist-validacao.md` separa o que foi executado do que depende de
  infraestrutura, com a evidência de cada item e a tabela dos quatro defeitos
  encontrados. Nada está marcado PASS por inspeção de código.
- ADR 0007 registra o ambiente lógico e a autenticação de homologação, com as
  alternativas descartadas e o motivo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-15 20:40:08 -03:00

16 KiB

Checklist de validação e evidências — homologação

Estado em 15 de outubro de 2026, nesta máquina de desenvolvimento, sem acesso ao servidor do ecossistema, ao Supabase de homologação nem ao banco do Elo Pro.

Sem runtime de contêiner nesta máquina. O Docker Desktop está instalado e foi iniciado, mas o WSL2 não tem distribuição instalada (wsl --list reporta nenhuma), então o engine Linux não sobe. Não há Postgres, Redis, Podman nem nerdctl locais. O que exige contêiner ou serviço real foi validado por simulação fiel do layout de runtime da imagem (apenas node_modules de produção + src + scripts + migrations + tsconfig.json, executado com node --import tsx) e, onde nem isso alcança, está PENDENTE para o CI.

Regra de preenchimento: PASS só com evidência executada. Sem infraestrutura ou credencial, o item é PENDENTE — nunca aprovado por inspeção de código.

A. Verificação local do repositório

# Item Resultado Evidência
A1 npm run lint PASS sem apontamentos
A2 npm run typecheck PASS tsc --noEmit sem erro
A3 npm test PASS 17 arquivos, 102 testes, 1 skip proposital (smoke real)
A4 npm run build PASS 25 rotas + Proxy, zero avisos, saída standalone com 70 MB contendo só .next, node_modules, migrations, src, package.json e server.js
A5 Testes HTTP das rotas (novos) PASS tests/http/routes.test.ts, 12 casos
A6 Testes do proxy (novos) PASS tests/http/proxy.test.ts, 7 casos
A7 Política de ambiente e workspace (novos) PASS tests/unit/staging-policy.test.ts, 22 casos
A8 Suíte com Postgres e Redis reais PENDENTE npm run test:services reporta 15 ignorados sem ADAPTER_TEST_DATABASE_URL/ADAPTER_TEST_REDIS_URL. O CI executa no job services
A9 Sintaxe do compose local PASS docker compose -f docker-compose.yml config sem erro
A10 Sintaxe do compose de homologação PASS docker compose -f docker-compose.staging.yml config resolve todas as variáveis
A11 Build da imagem Docker PENDENTE Docker Desktop está instalado nesta máquina, foi iniciado durante o trabalho e o engine Linux não chegou a responder (500 no pipe dockerDesktopLinuxEngine). O CI executa no job image
A12 docker compose up local PENDENTE mesmo motivo de A11
A13 Artefato standalone roda de verdade PASS node .next/standalone/server.js sobe, responde e atende as rotas (ver B6, C14, D3)
A14 Deps de produção cobrem a árvore traçada PASS npm ci --omit=dev em diretório limpo: 318 pacotes contra 153 traçados, zero divergência de versão entre os compartilhados; 3 pacotes existem só na traçada (@emnapi/runtime, isarray, supports-color) e o COPY do Docker mescla sem removê-los
A15 Worker e scripts rodam sem devDependencies PASS os 13 pacotes externos usados por src/ e scripts/ existem no install de produção; tsx 4.23.15 e esbuild 0.28.2 presentes
A16 Scripts operacionais executam no layout de runtime PASS no layout simulado: verify-config, migrate, migrate --dry-run, seed-dev, cleanup-temp, set-flag (recusa workspace inexistente), seed-staging (recusa em development) — todos com o código de saída correto

B. Fail-fast de configuração

# Item Resultado Evidência
B1 Configuração incompleta é recusada PASS tests/unit/staging-policy.test.ts: assertDeployedEnv lista DATABASE_URL e REDIS_URL ausentes
B2 ADAPTER_DEV_AUTH=1 recusado fora de development PASS teste de política e devAuthEnabled()
B3 ADAPTER_JOB_MODE=inline recusado em staging e produção PASS teste de política; jobRunsInline retorna false
B4 Shim de identidade exige decisão explícita PASS ausência de ADAPTER_APPLY_IDENTITY_SHIM entra em configIssues
B5 Sem DATABASE_URL nunca cai em PGlite PASS requireDatabaseUrl lança em staging e produção
B6 O processo sai com código 1, em vez de responder 500 PASS executado no artefato construído: ADAPTER_ENV=staging node .next/standalone/server.js imprimiu a lista de variáveis, saiu com código 1 e a porta ficou sem nada ouvindo. Antes desta entrega o mesmo comando deixava o servidor no ar respondendo 500 em todas as rotas, inclusive /api/health/live
B7 npm run verify:config recusa e explica PASS em ADAPTER_ENV=staging sem variáveis: 9 itens nomeados, saída com código 1
B8 O worker também recusa configuração ausente PASS no layout de runtime, ADAPTER_ENV=staging sem variáveis: saída com código 1 antes de tocar banco ou Redis
B9 Contêiner da web e do worker saem com código ≠ 0 PENDENTE passo Configuração ausente encerra com código diferente de zero do job image, que inspeciona .State.ExitCode dos dois

C. Autenticação e multi-tenant

# Item Resultado Evidência
C1 API do módulo sem sessão responde 401 PASS tests/http/routes.test.ts
C2 Página protegida sem sessão vai ao login PASS tests/http/proxy.test.ts
C3 Cookie de workspace não é prova de autorização PASS resolveWorkspace ignora dica sem associação real; teste com dica forjada e com injeção
C4 Gravar workspace de terceiro é recusado PASS POST /api/auth/workspace → 403 e cookie não gravado
C5 Associações listadas são só as do usuário PASS teste com Eva, que só vê Beta
C6 Módulo desligado bloqueia o workspace PASS teste com Diego em Beta
C7 Papel sem permissão não altera configuração PASS teste com Bruno (agent)
C8 Login de homologação indisponível fora de staging PASS /api/auth/staging/session → 404
C16 Dev auth não liga em homologação, em nenhuma combinação PASS tests/unit/dev-auth-guard.test.ts, 18 casos: matriz de ambientes na função, recusa na validação de configuração, e o provedor local fora da lista de provedores em staging e produção. Um token de dev válido é recusado quando o ambiente é staging
C9 Isolamento entre workspaces na suíte de aplicação PASS tests/security/isolation.test.ts, 6 casos
C10 RLS em PostgreSQL real, papel app_user sem BYPASSRLS PENDENTE tests/services/postgres.test.ts escrito; roda no CI e no banco de homologação
C11 Login real no navegador, com conta do Supabase de homologação PENDENTE exige o projeto Supabase de homologação. O caminho equivalente foi executado no nível de development (C14)
C14 Login real e isolamento no artefato em execução PASS contra node server.js: sessão emitida, GET /api/auth/workspace devolveu só o workspace da identidade, POST com workspace de terceiro → 403 sem gravar cookie, POST com o próprio → 200, /adaptador → 200
C15 Cookie de workspace forjado é ignorado em execução PASS três tentativas com a sessão de Ana (Alpha): cookie apontando Beta, cookie com ' or 1=1 -- e cookie com UUID inexistente. Em todas a resolução permaneceu em Alpha; Beta nunca foi alcançado
C12 Troca de workspace na interface PENDENTE exige duas associações reais em homologação
C13 Sessão expirada volta ao login PENDENTE exige sessão real

D. Infraestrutura e processamento

# Item Resultado Evidência
D1 Rate limiting devolve 429 com Retry-After PASS tests/http/routes.test.ts
D2 Cabeçalhos de segurança configurados PASS next.config.ts: CSP, HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy, COOP
D18 Smoke prepara a fase autenticada do Supabase PASS no script / PENDENTE na execução scripts/smoke-staging.ts tem as duas fases; sem ADAPTER_SMOKE_EMAIL/PASSWORD a fase 2 imprime PENDENTE. Credenciais listadas na seção 13 do runbook
D3 Cabeçalhos presentes na resposta HTTP real PASS no artefato / PENDENTE atrás do Nginx resposta de /api/health/live trouxe CSP, HSTS, X-Frame-Options: DENY, Referrer-Policy, Permissions-Policy, COOP, X-Content-Type-Options e Cache-Control: no-store. Falta confirmar que o Nginx não sobrescreve
D4 Redis e Supabase reutilizados por processo PASS singleton em src/infra/redis/index.ts e src/infra/storage/index.ts
D5 Namespace separado por aplicativo e ambiente PASS resourceNamespace; teste confirma que staging ≠ production
D6 Listagem de bucket paginada PASS src/infra/storage/supabase.ts pagina com offset e desce em subpastas
D7 Bucket privado conferido PENDENTE npm run check:bucket exige o bucket real
D8 Lock entre processos com Redis real PENDENTE tests/services/redis.test.ts; roda no CI
D9 Processamento assíncrono entre processos PENDENTE .github/scripts/async-journey.sh percorre web → Redis → worker → download no compose; roda no job image
D9b Jornada assíncrona pelo loop real do worker PASS tests/integration/worker.test.ts: a web enfileira e devolve queued, o download falha antes do tick, o tick conclui e os três formatos saem; o modelo original não muda
D9c Job sobrevive à perda da fila do Redis PASS fila drenada à mão: a varredura do Postgres acha o job queued e conclui
D9d Worker relê o contexto do dono PASS flag do módulo desligada entre o enfileiramento e o tick: o job não é processado
D10 Worker recusa iniciar com migration pendente PASS por construção pendingMigrations no start; a execução real é PENDENTE
D11 Desligamento gracioso do worker PASS no loop / PENDENTE no sinal shutdown() para de aceitar trabalho, espera o tick corrente sair, e o job que não começou fica queued com o lock reservado para ele; concluído, o lock é liberado. A entrega do SIGTERM ao processo é PENDENTE: no Windows não há sinal real, e o job image do CI confere SIGTERM recebido, [worker] encerrado e exit 0 em menos de 25 s
D17 Heartbeat do worker e healthcheck PASS worker no layout de runtime gravou o heartbeat; docker/worker-health.mjs aprovou com 1 s e reprova quando o arquivo falta
D12 Download XLSX, CSV e PDF ponta a ponta PASS no local / PENDENTE no ambiente tests/integration/journey.test.ts cobre o fluxo; falta a jornada em homologação
D13 Modelo original não é alterado PASS tests/unit/xlsx-fixtures.test.ts compara bytes
D14 TTL de temporários aplicado PASS no local / PENDENTE no ambiente tests/integration/journey.test.ts; falta observar o vencimento real
D15 Health check responde ready com dependências satisfeitas PASS primeira chamada com banco frio: {"status":"ready"} com config, database, migrations, redis, storage e job_mode em ok, sem connection string na resposta
D16 Health check aponta a dependência que falhou PASS campo reasons traz só o nome do erro e os ids de migration pendente

E. Observabilidade

# Item Resultado Evidência
E1 Payload do Sentry sem conteúdo de célula PASS tests/unit/pilot-policy.test.ts com sentinela
E2 Ambiente e release por ambiente PASS sentryInitOptions usa ADAPTER_ENV e SENTRY_RELEASE
E3 onRequestError registrado PASS export em src/instrumentation.ts
E4 Evento real chega ao projeto Sentry de homologação PENDENTE exige DSN real
E5 Sourcemap com stack legível PENDENTE exige SENTRY_ORG, SENTRY_PROJECT e SENTRY_AUTH_TOKEN no build
E6 Auditoria sem conteúdo de célula PASS tests/integration/rls.test.ts e sanitizeAuditMetadata

F. Ambiente e deploy

# Item Resultado Evidência
F1 Dockerfile multistage com standalone PASS Dockerfile + output: "standalone"
F2 Scripts operacionais funcionam sem devDependencies PASS executados no layout de runtime simulado (ver A15 e A16), não apenas por construção
F12 Job de build Docker Linux no CI com validação da imagem PASS no workflow / PENDENTE na execução job image: build, conteúdo, usuário não-root, ausência de segredo/docs/testes, carga dos scripts, fail-fast dos dois processos, liveness com cabeçalhos, compose completo, jornada assíncrona entre processos e desligamento gracioso
F13 Rollback de imagem documentado PASS runbook seção 10: identificar a imagem no ar, listar tags, desligar a flag antes, trocar só web e worker com --no-deps, conferir saúde, religar a flag. 0003_rls.sql e 0004_audit_append_only.sql declaradas sem caminho de volta
F3 Node e gerenciador fixados PASS .nvmrc 24.11.1, engines.node >=22.12 <25, packageManager npm@11.6.2
F4 Compose isolado dos outros aplicativos PASS nome de projeto, rede e volume próprios; portas só em 127.0.0.1; deploy com --no-deps
F5 .env.staging.example sem segredo PASS todos os campos sensíveis vazios
F6 Migration, deploy e flag em jobs separados com aprovação PASS .github/workflows/deploy-staging.yml, ambientes hml-migracao, hml-deploy, hml-flag
F7 Deploy real em hml-ada.elopro.app PENDENTE exige servidor, DNS e segredos
F8 DNS e TLS do subdomínio PENDENTE exige acesso ao DNS
F9 Nginx do novo server PENDENTE exige acesso ao servidor
F10 Smoke de homologação PENDENTE npm run smoke:staging exige o ambiente
F11 Ensaio de rollback PENDENTE exige duas imagens publicadas e o ambiente

Resumo

Quantidade
PASS com evidência executada 54
PENDENTE por falta de infraestrutura ou credencial 20
FAIL 0

Nada foi marcado PASS por inspeção de código. Os PENDENTE que dependem só de Docker (A11, A12, A8, B9, C10, D8, D9, F12) executam no CI no primeiro push; os demais dependem de infraestrutura do ecossistema.

Defeitos encontrados nesta rodada de validação

Os quatro apareceram justamente ao exercitar o layout de runtime da imagem, e nenhum aparecia na suíte de testes ou no build.

# Defeito Efeito em homologação Correção
1 O CLI do tsx cria processo filho SIGTERM do docker stop pararia no pai; o worker nunca rodaria o handler, o lock esperaria o TTL de 120 s e o stop_grace_period só atrasaria um SIGKILL entrypoint usa node --import tsx; PID conferido igual
2 Top-level await nos scripts com --import tsx migrate, worker, seed-staging, set-flag, cleanup e check-bucket falhariam com Transform failed. O worker não subiria e a migração não rodaria runScript/runWithDb em scripts/_bootstrap.ts; nenhum script usa top-level await
3 import "server-only" em worker-loop.ts o pacote lança fora do bundler do Next: o worker morreria no start removido do módulo compartilhado, com o motivo registrado no arquivo
4 @react-pdf/renderer carregado no import de process-job.ts ERR_PACKAGE_PATH_NOT_EXPORTED ao resolver a hifenização fora do bundler: derrubava o worker e o cleanup import tardio dentro do ramo de PDF, que só o download usa

Bloqueios para liberar homologação

Todos externos ao repositório. Nenhum depende de código.

  1. DNS de hml-ada.elopro.app e certificado TLS.
  2. Projeto Supabase de homologação, com contas de teste e bucket privado.
  3. Banco de homologação com DATABASE_URL e a decisão do shim conferida.
  4. Servidor com Docker, HML_DEPLOY_PATH e os segredos dos ambientes do GitHub.
  5. DSN do Sentry de homologação.

Bloqueios para discutir produção

Além de tudo acima, concluído:

  1. Smoke real completo, com evidência, em homologação.
  2. Ensaio de rollback executado, com evidência.
  3. SSO do Elo Pro integrado e validado no navegador.
  4. Schema real do Elo Pro confirmado e identity-port.ts apontando para ele.
  5. Tokens oficiais do Design System. O azul #0B3D91 continua provisório.

Evidências a anexar

Para cada item PENDENTE que for executado, registre aqui: data, quem executou, comando ou tela, e saída obtida. Resposta de GET /api/health/ready (sem segredo), log do worker concluindo um job, print do download dos três formatos, print do evento sanitizado no Sentry e log do ensaio de rollback.