# Handoff 2026-07-20 (fim de tarde) — P0 QR 59/60 + lote B/C IB/merchant + PR #20, tudo deployado

Fecho da sessão de 20/07 tarde. **Todo fato abaixo foi validado empiricamente no
fecho (~18:55 UTC): AWS por `describe-services`/`describe-task-definition`,
banco por rpc no BEAM vivo, git por `rev-parse` pós-fetch.** O que NÃO foi
validado está marcado como tal.

## 1. Estado do código (verificado)

- `main == origin/main == 032227d8`, working tree limpa.
- Commits da sessão: `0bdf3df9` + `631b17b6` (P0 QR), `edf4e791` (lote B/C),
  `3f5c9e20` (merge do PR #20, commit `8f9918b5` do Micael), `92b93545` +
  `032227d8` (docs).

## 2. Revisões vivas (verificadas na AWS, todas COMPLETED 1/1)

| Ambiente | Serviço | Revisão | Imagem | Rollback |
|---|---|---|---|---|
| HML | core-api | :181 | `homolog-3f5c9e20-lote0720-20260720` | :180 |
| HML | pix-api | :195 | `homolog-631b17b6-qr5960b-20260720` | :193 |
| HML | core-banking-ui | :35 | `homolog-3f5c9e20-lote0720-20260720` | :34 |
| HML | core-merchant-ui | :22 | `homolog-3f5c9e20-lote0720-20260720` | :21 |
| PRD | core-api | :76 | `prod-3f5c9e20-lote0720-20260720` | :75 |
| PRD | pix-api | :67 | `prod-631b17b6-qr5960-20260720` | :66 |

- Digest MATCH homolog→prod provado por imagetools: core `sha256:c3f21d76...`,
  pix `sha256:08579d38...`.
- **Fidelidade importante: o PRD core:76 roda a imagem do LOTE inteiro** (P0 QR
  + backend do lote B/C + PR #20), não só o P0. As UIs do lote B/C estão SÓ em
  HML (PRD banking:7 / merchant:5 seguem as da manhã).
- Intocados hoje à tarde: spb-api (HML:70 / PRD:40), admin-ui (HML:33 / PRD:26).
- Sem migration em nenhum swap.

## 3. P0 QR (tags EMV 59/60 vazias) — RESOLVIDO

Bancos reais recusavam QR nosso ("cod inválido"); decode provou tags 59/60
(Merchant Name/City) com len 0. Causa: cadeia CobV inteira sem merchant fields
(Core `build_cobv_attrs` não enviava → `cobv_wire_to_attrs` não mapeava →
builder `|| ""` → encoder aceitava vazio). O RED provou também que ACENTO
corrompia o payload (len TLV em chars, apps leem bytes).

Fix em 4 camadas com TDD: encoder fail-closed (vazio = raise) + transliteração
NFD→ASCII; defaults institucionais `QR_DEFAULT_MERCHANT_NAME/CITY`
("MONETARIE SCD"/"SAO PAULO") resolvidos UMA vez e persistidos na linha (o
resolver JWS lê `qr.merchant_name`); handler mapeia; Core envia o titular
(`Monetarie.Util.BrCodeText` translitera em vez de descartar letras).

Provas vivas no fecho:
- HML: **0 QRs quebrados de 61 totais** (23 CobV reparados por rpc); o QR exato
  que o dono compartilhou valida (CRC C232, `5913MONETARIE SCD6009SAO PAULO`);
  fio Core→cabine emitiu `5925CAMILLE ZANETTI CONCEICAO` vivo.
- PRD (task nova pós-swap): encoder GUARD_OK (vazio = raise), transliteração
  {CONCEICAO, SAO PAULO}, defaults carregados, **0 QRs na tabela** (nenhum
  reparo necessário).
- **Strings antigas do QR quebrado (ex.: as coladas no WhatsApp) continuam
  inválidas — são texto morto. Copiar o brcode NOVO do painel/API.**

## 4. Lote B/C IB/merchant (handoff das pendências 20/07) — deployado em HML

Com TDD (RED observado antes de cada GREEN):
- **B1** Devolução PIX executável: botão Devolver no histórico (credit
  liquidado ≤90d) e no comprovante (inbound liquidado); contexto
  `refund_<id>` em sessionStorage (CENTAVOS); hub → histórico
  `?filter=received`. Harness ganhou `renderWithPluginsReady`.
- **B2** Defesa de infração do IB: `infractionApi.submitDefense` roda o fluxo
  MED composto existente (`/v2/meds/:id/defense` + `/documents` + `/submit`;
  `fetch_owned_block` aceita `infraction_report_id`, escopado por posse). A
  rota `POST /infractions/:id/defense` NÃO existe no scope do IB (só
  admin/partner) — era o 404.
- **B2-backend** MerchantPortal `list/show_infractions` desembrulha o reply
  real da cabine (`{status, data: {infractions, total}}`) e usa o seam
  `pix_provider()`.
- **B3** Envelopes triplos desembrulhados: ComplianceView (MED + infrações),
  InfractionDetailView, InfractionDefenseView, MedsView (recoveries).
- **C1** QrCodeDetailView (merchant) desembrulha `{data}`.
- **C4** usePix carrega a mensagem humana do 422 real da cabine
  (`{error: {message, reason}}`) + `pixErrors.default` nos 3 locales.
- **C7** MedsView (merchant) deixou de ser hardcoded `[]`: busca
  `/med-cautelar-blocks` real + botão "Apresentar defesa" → MedDefenseView.
- **C3 NÃO reproduz** (webhook `pix.charge.paid` 100x): `money_fields_to_cents`
  central já converte; teste de regressão trancado em `charge_paid_test.exs`.

Suítes no fecho: banking 205/205, merchant 19/19, core merchant_portal 16/16,
charge_paid 3/3, partner 64/64; builds prod verdes. Cabine pix: shared 1840/0,
spi 970/0, settlement 1008/0.

## 5. PR #20 (NumCtrlIF ≤20) — MERGEADO e vivo

- Validação pré-merge: MERGEABLE, 0 conflitos vs main com os commits da
  sessão, merged-state testado em worktree (unit 6/6 + blast radius 96/0).
- Prova viva pós-deploy: `TransactionId.generate("TRF")` = 20 chars em HML E
  PRD; PIXOUT = 32.
- **Correção ao MD do PR (provada viva): `monetarie_spi.messages.message_id` é
  varchar(64) hoje** (alargado em 15/07) — a justificativa "estouro do
  varchar(32)" está datada; o cap 32 segue correto (`end_to_end_id` é 32).
- Follow-ups não-bloqueantes: `generate/2` pode exceder `max_len` quando
  prefixo+data+piso(4) não cabem (silencioso; nenhum chamador real atinge —
  sugerir raise); `open_finance.ex:896` gera OFTED de 22 chars = mesma classe
  LATENTE (Open Finance é stub/DLQ hoje); convergir os geradores já-conformes
  (`ted_controller:310`, `outbound_request:149`, partner) para o helper.

## 6. Pós-swap (verificado)

- ICOM PRD reassumido às 19:23:57 UTC (CSM "resuming 4" + CPM "resuming 3").
- TGs healthy: PRD `mon-core-api-50`/`mon-pix-api-50`; HML `mon-core-api-h-45`/
  `mon-core-ib-h-45`/`mon-core-merchant-h-45`. NATS Connected no PRD core.

## 7. NÃO validado (pendências da própria sessão)

1. **Validação visual das telas do lote B/C** — deployadas em HML com testes
   verdes, mas SEM screenshot (VPN indisponível na sessão; regra #11). Cobrir:
   Devolver PIX (histórico + comprovante + fluxo completo), painéis
   MED/infrações + defesa no IB, MedsView + defesa + detalhe do QR no merchant.
2. **TED viva pelo IB em HML** — fecho ponta a ponta do PR #20 (STR0008
   passando no gate `:xsd_oficial` com NumCtrlIF de 20).

## 8. Pendências herdadas (fonte: handoff 2026-07-20-pendencias-mapeadas)

- **Frente B restante**: B4 Documentos>Devoluções vazia; B5 paginação morta;
  B6 PIX Agendados lê fonte errada; B7 TransferSendView "Minhas contas" 422;
  B8 comprovante 404 nos Documentos; B9 coluna Data do Extrato "-"; B10-B13.
- **Frente C restante**: C2 QR estático com valor; C5 EventsView/LogsView;
  C6 secret de webhook; C8 TEF sem POST; C9 withdrawal 501/saldos hardcoded;
  C10 telas mock; C11 authorized? barra colaboradores; C12 chamadas mortas.
- **Frente A (SPB P2)**: itens 1-8 do handoff de pendências (e-mail fim de
  semana, MessageWatch, BACEN_DLQ, MQBridge, unknown_sent, RSTR fail-open,
  cir_handler Decimal 0, TES grupo 50).
- **Terceiros/negócio**: RTM MES01 :12522 DROP; CIR0008 (contratação);
  Vulci item 6 (SLB); solicitação de apoio ao cliente de 19/07 (SES/DNS,
  conta tesouraria, AMES-SIMBA, infração/MED com transação liquidada).

## 9. Como retomar

1. Ler este handoff + `docs/handoff/2026-07-20-pendencias-mapeadas-spb-ib-merchant-handoff.md`
   + memória auto `monetarie-qr-5960-lote-ib-merchant-0720` + Serena
   `monetarie/live-state-2026-07-20`.
2. Com VPN: validação visual das telas do lote (screenshots) + TED viva pelo
   IB (PR #20 E2E).
3. Depois: B4-B9 (maior valor restante do IB), C2/C5/C6/C8, Frente A.
4. Deploy: runbook `docs/operator/2026-06-03-deploy-manual-runbook.md`;
   PRD sempre por retag imagetools com guard de digest; NUNCA deploy pix/spb
   durante operação money-path ao vivo do dono.
