# Handoff 2026-07-25 (madrugada): destrave do CCS, deploy do Core e do pix-api nos 2 ambientes

Sessao curta e de execucao. O bloqueio do deploy do Core caiu, Core e pix-api
foram deployados nos dois ambientes, e apareceu um achado novo em producao que
NAO e do deploy e continua aberto.

Regra que guiou tudo: **BACEN e a verdade, ache o NOSSO defeito e PROVE, zero
inferencia.** Onde os dados nao provam, esta escrito que nao provam.

---

## 1. Estado do repositorio e dos ambientes

- `main` == `origin/main` == **`ca60072f`** (push feito com OK explicito do dono).
- Working tree limpo (so os untracked pre-existentes: `LegadoPIX/`, `md/`, etc).
  Nenhum arquivo do codex tocado.

| servico | HML | PRD | imagem | digest |
|---|---|---|---|---|
| core-api | td 215 -> **216** | td 104 -> **105** | `ca60072f-qrpurpose-20260724` | `sha256:f2c9d752` |
| pix-api | td 210 -> **211** | td 81 -> **82** | `ca60072f-dictdedup-20260724` | `sha256:94b4b25a` |

Guard de digest MATCH nos dois retags, e o diff da task definition provando que
**so a imagem mudou**. Servicos estaveis: core desired=1 running=1, pix desired=3
running=3, 1 deployment cada.

---

## 2. O bloqueio do CCS era do TESTE, nao do codigo

O handoff anterior registrou "2 falhas PRE-EXISTENTES dependentes de DATA
(esperam 20260725, recebem 20260727)" e pediu correcao ou decisao do dono. A
causa, lida no codigo e nao inferida:

- `CCS.movement_day/1` chama `Calendar.next_business_day/1` (`calendar.ex:60`),
  que e o **primeiro dia util A PARTIR de hoje**, e o arquivo grava esse mesmo dia
  em `dt_movto` (`ccs.ex:494,508`). E a grade CCS01: o arquivo do dia e entregue
  ate as 8h do dia util seguinte.
- Rodando as 22:58 BRT de sexta, o **UTC ja era sabado 25/07**, logo o dia de
  movimento era **segunda 27/07**. Os testes montavam o prefixo com
  `Date.utc_today()` cru, um sabado, dia em que o CCS nunca tem movimento.

Ou seja: **producao esta certa, o teste e que estava errado.** A falha so aparecia
de sexta 21h BRT ate domingo, e em vespera de feriado. Em dia util passava, e foi
por isso que ninguem viu antes.

**Fix (`ca60072f`):** o prefixo passa a vir do calendario (a mesma fonte que o CCS
consome, e nao a funcao sob teste) e somei um assert de `dt_movto`, para a regra
ficar explicita no teste em vez de apenas contornada.

**Suites:** Core **8886 testes, 0 falhas**. Pix: shared 1919/0, settlement 1025/0,
spi 1090/0, dict 476/0.

---

## 3. Migration do pix: so existe na imagem NOVA

Achado que muda o procedimento: `20260724190000_create_dict_nats_request_
deduplications` **nao estava aplicada em nenhum dos dois ambientes** (a ultima era
`20260724050000`), e o container ANTIGO reporta **0 pendentes** justamente porque
a migration nao existe no release dele.

Entao ela nao pode ser "rodada antes" a partir do que esta no ar. O caminho certo,
e o que foi feito nos dois ambientes:

1. registrar a TD nova (imagem nova) sem atribuir ao servico;
2. `aws ecs run-task` one-off com essa TD e override
   `bin/monetarie_pix eval "Shared.Release.migrate()"` -> **exit 0**;
3. conferir a tabela e a versao em `schema_migrations`;
4. so entao `update-service`.

Nota: o `pix-mtls-sidecar` sai com exit 2 na task efemera (esperado, `essential=false`).
Em PRD a rede do servico usa `assignPublicIp=DISABLED`; herdar a config do proprio
servico evita task presa em PROVISIONING.

---

## 4. Validado vivo (por RPC no release em execucao)

- **`purpose` (HML e PRD):** `"pagamento"` -> `IPAY`, `REFU` preservado, lixo ->
  `IPAY`. `build_pix_params/1` e pura (monta o mapa, nao publica nem move
  dinheiro), entao o probe nao inicia PIX nenhum.
- **QR (HML):** gerando QR estatico **sem passar `pix_key`**, usou a chave EVP
  ATIVA da conta (`75737aed-...`) e **nao** o documento do titular
  (`00035012137`). E a regra do coreproviders.
- **RequestDedup (HML):** mesmo `operation_id` duas vezes -> handler roda 1x, a
  duplicata replica o resultado, linha persistida.
- **QR em PRD:** `qrcodes` segue com as **2 linhas historicas, ambas `cancelled`**,
  nenhum QR novo. **O buraco esta fechado**: PRD nao roda mais o codigo com
  fallback ao documento.

---

## 5. O que NAO esta provado (nao vender como pronto)

- **PIX de saida real com `<Purp><Cd>IPAY</Cd>`**: falta. So o dono dispara.
- **AB03:** desde o fix do canal (24/07 21:32Z) houve **0 admi.002 "canal
  diferente"** (eram 7) e **0 pacs.002 com AB03** (eram 10 nas 96h; a ultima foi
  24/07 16:28Z, antes do fix). **Mas so 1 pacs.008 chegou na janela.** Com esse
  trafego, e sendo o defeito intermitente (so dispara com circuito aberto ou POST
  falho), isso e *compativel* com o fix e **nao e prova**. A prova pede volume,
  que vem na segunda.
- **QR gerado pelo IB em PRD**: falta exercitar o caminho vivo.

---

## 6. Achado novo em PRD, NAO causado pelo deploy: conn_limited volta com uptime

Detalhe em [[monetarie-conn-limited-volta-com-uptime-0725]].

O `conn_limited` dado como resolvido em 24/07 **voltou sozinho**, sem deploy no
meio: 74/h as 20h UTC, zero as 22h-23h, e entao **2901 as 00h, 8314 as 01h**,
comecando abruptamente as **00:22Z (21:22 BRT)**.

**Nao foi o meu deploy** (que so comecou as 02:32Z) e **nao estava parando o
money-path**: `icom_received` manteve ~550 msg/h constantes durante todo o pico. A
ausencia de pacs.008 desde 22:00Z e madrugada de sabado, nao travamento.

**O que o zerou foi trocar as tasks.** Durante o rolling td81 -> td82 a taxa caiu
junto com a substituicao: 135/min (02:32), 80/min (02:38), 9 (02:39), **zero de
02:40 em diante**, com o ICOM seguindo normal. Como a td82 so acrescenta o dedup
de request DICT (nao toca conexao ICOM), a conclusao e que **e estado que degrada
com o uptime**, nao codigo.

Hipotese NAO provada: conexoes de leitura do stream `/out` que ficam penduradas e
seguram os 6 slots do §2.2.2.10 ate todo pedido novo tomar 429.

A fazer: achar o gatilho das 00:22Z (ou o ponto de ~3h de vida), instrumentar
slots em uso por canal, e decidir sobre reciclagem preventiva. **Nao tratar como
resolvido pelo restart.**

**Colateral do mesmo deploy:** o ECS matou 1 task com `Target is in an
Availability Zone that is not enabled for the load balancer` (TG `mon-qrc-pub-p`).
O service tem 3 subnets e esse TG nao tem as 3 AZs habilitadas, entao todo deploy
cuja alocacao calhe na AZ errada recicla uma task. Nao derruba (chegou a steady
state), mas atrasa e polui o deploy.

---

## 7. Fila da proxima sessao

1. **Validar em PRD com transacao real** (secao 5): PIX de saida com IPAY;
   refazer a correlacao admi.002 x AB03 com volume de verdade; QR pelo IB.
2. **conn_limited** (secao 6): fechar a causa, nao viver de restart.
3. **QR**: partner API -> ib-front e merchant-front -> `api.monetarie.com`.
4. **Pendencias do cliente em HML**: persistir `txid` do QR e o tipo de iniciacao
   do QR no PIX-out.
5. **E2E divergente**, com o desenho ja fechado pelo dono (DICT com E2E da cabine
   e validacao, MANU com E2E do Core persistido, reserva por OPERACAO).
6. **Metade 2 do port PIX-in**: recovery por camt.060 via `SpiService.OperationQuery`,
   que precisa do subject NATS novo. A flag `:pix_in_fail_closed_enabled` esta
   ausente nas TDs dos dois ambientes, entao o port foi para producao DESLIGADO
   (default `false`, conferido).
7. **DLQ**: PRD com 20 dead letters (estavel, anterior ao deploy); HML com 34,
   sendo `monetarie.dlq.pix.failed=18` e `spb.failed=6`.
8. Menor: espelho `qrcodes` do Core nao recebe a expiracao da cabine.

---

## 8. Ferramentas

Os helpers desta sessao ficaram FORA do repo (em `scratchpad/` de sessao), porque
`scratchpad/` nao esta no `.gitignore` e sujaria o working tree que o codex divide:

- `rpc.sh <cluster> <servico> <container> "<bin> rpc" <arquivo.exs>` (codigo por
  base64, via ECS Exec).
- `probe_purpose.exs`, `probe_qr.exs`, `probe_dedup.exs`, `probe_migration.exs`,
  `probe_pending.exs`, `probe_ab03.exs`, `probe_fluxo.exs`.

Log groups corretos: `/ecs/monetarie/{prod,homolog}/{core-api,pix-api}` (note o
ambiente NO MEIO do caminho).
