# Handoff: port best-of-breed AvivPay para o Monetarie (04/07/2026)

Execução completa do plano `docs/plans/2026-07-04-port-aviv-best-of-breed.md` em 20 commits na branch `feat/spb-cert-selfservice` (`e246ef27..4d91cf7d` + fix final), método subagent-driven: cada task passou por implementador, revisor de conformidade com o spec (verificação independente lendo código, sem confiar no relatório) e revisor de qualidade, com rodadas de correção provadas por TDD vermelho-verde. Base de decisão: relatório comparativo `docs/reports/2026-07-04-comparativo-aviv-coreproviders-monetarie.pdf` (produção AVIV com 812.654 PIX em 03/07, medida por nós).

## 1. O que entrou (10 tasks, todas com dupla revisão)

| Task | Entrega | Commits principais |
|---|---|---|
| A1 P0 | Export de tarifas REAL (Oban + streaming Repo.stream + criação transacional Multi + download protegido). Fim do stub `status: "ready"` falso do fee export | `e246ef27`, `7e84bb20` |
| A2 P1 | Manutenção de partições blindada. ERRATA: `transactions` já era particionada (DDL no pg_dump da squash); o valor real foi cobrir `message_timeline`/`fee_transactions`/`fee_split_transactions` no worker, fechar runway com buracos (fee_split sem partição a partir de jun/2026) e resolver colisão de nomes legados por comparação semântica de range (bound canonizado em UTC, IF NOT EXISTS, schema qualificado) | `91c5348c`, `d6290d5e` |
| A3 P2 | BalanceCheckpoint + prefold 00:10 BRT atrás de `BALANCE_CHECKPOINT_ENABLED` (default OFF), paridade centavo a centavo com a via legada provada por teste, e proteção contra retro-datação (watermark via `updated_at` no trigger das summaries; cenário real: outbound liquidado horas depois cruzando a meia-noite BRT, como no outage do HSM de 03/07) | `d2efa37a`, `3c646cf2` |
| A4 P2 | 3 caches opt-in (UsageCache 15min, TxStatusCache por shape 5s/300s/30s, BalanceCache display 10s) com flags default OFF, passthrough byte-idêntico provado, guarda executável de que o BalanceGuard não referencia o BalanceCache (beam atoms), hardening (sweeper, crash window, docs honestos sobre PubSub node-local, terminal_states fonte única) | `be0b7514`, `ea0cb972` |
| A5 P1 | Breakdown de saldo bloqueado cruzando TigerBeetle (MED por verdade do TB via user_data_128, in-transit, judicial exposto sem subtrair, órfãos clampados) + OrphanHoldReconciler em DRY-RUN (05:20 BRT), com proteções: página truncada = dúvida, bloco `transferred` nunca voidado, status `reconciled` para limpeza sem void | `bf2e5388`, `076f63b0` |
| B1 P1 | Logs PERF por fase na cabine (MSG_RECV end2end_ms com prioridade FctvIntrBkSttlmDt, MSG_OK duration/handler, PUB_OK) parseáveis por Logs Insights, padrão que nos permitiu auditar a produção AVIV inteira | `ee315ca6` |
| B2 P1 | Malha de watchdogs (IcomLag p95 vs ANS 1600ms, ConsumerLiveness dos 8 duráveis reais, DlqDepth, PixInOkRate) + poison policy no BaseWorker (6a falha vai a `monetarie.dlq.poison.*` durável e ACK; janela fixa de TTL) | `2aa6b5ca`, `3d332aa2` |
| B3 P1 | PromEx unificado (`Shared.PromEx`) com métricas de negócio no `/metrics` interno do settlement: message_processed (native->ms), end2end milliseconds (buckets no ANS), counters `_total` dos watchdogs e do poison | `7758dcf9`, `12cc3c4c` |
| C1 P2 | Graceful drain (lameduck 5s + drain 90s) core-api e cabine (só settlement, único target do ALB; dict/spi param depois pela ordem do release) | `5d938aaf`, `4d91cf7d` |
| C2 P2 | Fee preview no envio PIX do IB: fix de paridade do client_type com a cobrança real (member_pj com CPF é PJ), debounce 350ms, testes que não existiam (5 backend + bloqueio no front) | `a3da9386`, `0e5a1554` |

## 2. Verificação final consolidada

- Cabine PIX (umbrella): spi_service 515/0; shared 1185/15 (baseline pré-existente provado por stash pelos agentes); settlement isolado 659/17 = baseline exato; dict 256/1 com dict_service intocado no dia (diff vazio). No run completo do umbrella o settlement oscila para 25 falhas: as 8 extras são TODAS da família pré-existente `build_cobv_payload (com vencimento)` sob interferência de ordenação (warnings de shared mode do sandbox). Follow-up de higiene registrado.
- Core: baseline em `3cffa9dc` = 6759 testes / 777 falhas pré-existentes (suite completa nunca era rodada por inteiro; as áreas tocadas hoje estão verdes nas suites próprias). HEAD = 6860 / 790. VEREDITO FINAL do diff com seed fixo (0): os conjuntos de testes falhando em HEAD e no baseline sao IDENTICOS (99 falhas deterministicas de cada lado, comm vazio nas duas direcoes). ZERO regressao dos 20 commits do dia. O delta 790 vs 777 sob seed aleatorio e flakiness de ordenacao pre-existente da suite (com seed fixo ambos caem de ~780 para 99), registrada como follow-up de higiene 6b.
- Grep de unidade no diff inteiro do dia: nenhuma ocorrência monetária de subcentavos fora de teste/comentário/TTL.
- Migrações do dia (4) aplicam em sequência num banco zerado (provado pelo revisor de integração).
- Revisão final de integração (cross-task): árvores de supervisão coerentes, runtime.exs sem colisão, fluxo da mensagem que falha 6x rastreado fim a fim (MSG_FAIL x6, poisoned_total x1, DLQ x1), poison × ok-rate sem conflito. Veredito: pronto para deploy HML com a condição do stopTimeout (abaixo).

## 3. Flags LIGADAS em HML (adendo 04/07 ~15h50 BRT, autorizado pelo dono)

Task-def `core-api:83`: `BALANCE_CHECKPOINT_ENABLED=true`, `USAGE_CACHE_ENABLED=true`, `TX_STATUS_CACHE_ENABLED=true`, `BALANCE_CACHE_ENABLED=true`, `MED_ORPHAN_RECONCILER_MODE=void`, `TB_POOL_SIZE=4`. Validado vivo: dry-run do reconciler ANTES do void = zero candidatos/zero erros no banco HML; paridade checkpoint vs legada centavo a centavo em 3 contas com saldo (maior: 9.687.387.300 subcentavos), 4 folds criados por self-heal; logs limpos pos-flip. TigerBeetle segue 1 no em HML por decisao do dono (3 replicas so em producao); Aurora reader/ReadRepo e OTel NAO ligados (nao existe codigo; sao desenvolvimento futuro, nao flag). Pre-condicoes originais abaixo permanecem como referencia para PRODUCAO.

## 3b. Pré-condições originais (referência para produção)

- `BALANCE_CHECKPOINT_ENABLED`: o mecanismo de retro-datação cobre o trigger; o `DailyAggregationWorker.aggregate_day` (deprecated, só backfill manual) tem `on_conflict replace` que NÃO sobe `updated_at`: rodar `rebuild/2` manual após qualquer backfill, ou corrigir o replace antes.
- `USAGE_CACHE_ENABLED` / `TX_STATUS_CACHE_ENABLED` / `BALANCE_CACHE_ENABLED`: hardening já aplicado (`ea0cb972`); staleness cross-task = TTL (sem cluster BEAM entre tasks ECS).
- `MED_ORPHAN_RECONCILER_MODE=void`: proteções de página truncada e bloco transferred já aplicadas (`076f63b0`); ainda assim, primeira ativação com acompanhamento e após leitura dos dry-runs.
- Drain (liga por default em prod): **subir `stopTimeout` para >= 100s nas task definitions de core-api e pix-api no próximo deploy** (default ECS 30s mata o drain de 90s no meio), OU reduzir `DRAIN_SHUTDOWN_TIMEOUT_MS` por env até lá.

## 4. Follow-ups (por prioridade)

1. stopTimeout dos task defs (condição do deploy, seção 3).
2. UI do breakdown de bloqueado: consumir `tbOk` (TB fora não pode renderizar como "nada bloqueado") ou 503 no controller; tipos da UI ganham `tbOk`/`judicialBlocks`/`truncated`.
3. Extrair helper único de client_type: a regra existe em TRÊS cópias (pix_handler, spb_handler, fee preview controller); a divergência já aconteceu uma vez.
4. Front do fee preview: falha do preview vira fee 0 e libera o botão (servidor ainda barra); tratar como "tarifa indisponível".
5. QueueMonitor legado da cabine monitora consumers `spi-*` que não existem (cego desde sempre); apontar para os nomes reais ou remover em favor do ConsumerLivenessMonitor novo.
6a. Higiene de suite (core): ~680 falhas dependentes de ordenacao sob seed aleatorio (99 deterministicas com seed 0); sanear ownership do sandbox por area.
6b. Higiene de suite (cabine): família CobV `build_cobv_payload` flaky sob run completo (sandbox shared mode); corrigir ownership. Investigar a falha única do dict (`KeysBacenIntegrationTest`, pré-existente ao dia).
7. Cooldown/dedup nos alertas dos monitores (hoje re-disparam a cada ciclo, padrão AnsMonitor).
8. Undercount de crash no ramo concorrente do BaseWorker na métrica message_processed (status=error não emite no rescue de task).
9. PUB_OK em :info em todo publish do umbrella: avaliar nível/sampling antes de produção (custo CloudWatch).
10. Janela de drain do settlement: NATS/Workers param antes do Endpoint drenar (documentado em `4d91cf7d`); avaliar reorder com revalidação de boot.
11. Dupla via de parking (legacy `Nats-Num-Delivered` na 5a vs poison na 6a): dashboard deve olhar DLQ depth + poisoned_total juntos (documentar no runbook de operação).
12. Export de resumo de tarifas vizinho entrega subcentavos sob header ambíguo `amount` (o novo export detalhado usa sufixo `_subcent`); alinhar.
13. Stub restante de treasury_reconciliation (`coreproviders_parity_controller.ex:1184`, `status: "ready"` falso) fora do escopo do A1; mesma receita do export real.

## 5. Fora do escopo do dia (decisões de infra com o dono)

- TigerBeetle 3 réplicas em produção (PRD da AVIV roda tigerbeetle-0/1/2 em 3x m6g.xlarge; nosso TB é 1 nó).
- Aurora reader + ReadRepo (split writer/reader com work_mem alto só no reader).
- OpenTelemetry (hoje entrou PromEx; OTel depois).
- Dev portal completo no IB.

## 6. Deploy HML (proposto, aguardando aprovação)

Pacote: core-api (migrations `20260704120000..180000` + código) e pix-api (código; sem migration nova) pelo pipeline padrão buildx arm64 + ECR + task-def nova (com stopTimeout ajustado) + rollout COMPLETED + validação viva (export de tarifas real na tela, /metrics respondendo, logs MSG_OK no CloudWatch, watchdogs logando ciclo). UIs: core-banking-ui (fee preview). Todas as flags novas ficam OFF no primeiro deploy.
