# Handoff — Item 5 do fluxo do cliente: devolução de PIX (pacs.008 recebida -> pacs.004) no trilho verdadeiro — 2026-07-17 (noite)

`origin/main = 81d62008`, working tree limpa, tudo pushado. RETOMAR POR ESTE HANDOFF na próxima sessão (prompt pronto no fim).

## 1. O que foi entregue nesta sessão (tudo com TDD RED primeiro + revisão adversarial de 3 lentes)

### 1a. Auditoria da frente inteira (6 trilhas paralelas)
Relatório canônico: `docs/reports/2026-07-17-auditoria-fluxo-cliente-partner-api-telas.md` (commit `6592a859`).
Classificação (a)/(b)/(c) por item 1-18 com arquivo:linha; 10 defeitos novos achados. Plano priorizado aprovado pelo dono (Fases A Partner API -> B P0 telas -> C P1 telas -> D docs/Postman/deploys).

### 1b. Item 5 IMPLEMENTADO (devolução iniciada pelo cliente), 12 commits `f9387b47..81d62008`
Design validado: `docs/plans/2026-07-17-devolucao-pix-fluxo-cliente-design.md` (com §8 = achados da revisão adversarial).
Plano executado: `docs/plans/2026-07-17-devolucao-pix-fluxo-cliente-plan.md` (Tasks 0-12 concluídas; Task 13 = validação viva pós-deploy).

DESCOBERTA CENTRAL (provada): a devolução iniciada pelo cliente (IB e Partner) NUNCA chegava ao BACEN — o
`handle_return_request` criava pacs.004 FANTASMA (sem RtrId/XML) e publicava `transaction.returned`, que
ninguém consome para envio; o hold do cliente ficava preso para sempre. Além disso o refund do partner era
CEGO (aceitava :id inexistente ou de PIX enviado).

Entregue:
1. `Shared.ReturnIdBurn` — queima estrutural do RtrId no `return_id_registry` (tabela do baseline, estava morta), com opção `:repo` (rollback junto).
2. `ReturnProcessor` — burn na MESMA tx da linha; candidato DETERMINÍSTICO da identidade do evento (replay sem return_id não vira 2a pacs.004); colisão regenera; bloqueio PI revertido em colisão/replay/erro; offset sub-minuto determinístico no `operation_time` (o unique `(e2e, operation_time)` engolia a 2a parcial do MESMO minuto em silêncio, provado no RED); **desfechos TERMINAIS para origin=client** (razão/janela/teto/esgotamento publicam `return.rejected` com referências do edge e ACKam — nunca DLQ muda); identidade forte no replay (linha REJEITADA não engole pedido novo; `transaction_id` tem que casar); tracking fail-loud com `conflict_target` explícito.
3. `handle_return_request` REFEITO — deriva a VERDADE da pacs.008 INBOUND liquidada (valor em centavos via payments/json_input, data, contrapartes; NUNCA do payload) e publica `RETURN_CREATED` origin=client no trilho verdadeiro; falha de derivação = `transaction.error` terminal (libera hold); `initiated_at` propagado (minuto do RtrId = pedido, não o e2e original de até 89 dias).
4. `StatusUpdater` — `monetarie.spi.return.settled` NOVO (a liquidação da nossa pacs.004 era suprimida sem NENHUM evento ao Core) + transição CAS dedicada p/ linhas de devolução (`settle_outbound_return_line`/`reject_outbound_return_line` — corrida settled x rejected morre no WHERE do UPDATE); `return_rejected_event` com origin/edge refs.
5. Core — `handle_return` PULA materialização p/ origin=client (decisão do dono: hold no edge + skip); consumer com rota DEDICADA p/ `return.settled` (o catch-all mandava para a MATERIALIZAÇÃO); **fronteira de unidade POR SUBJECT** (`monetarie.spi.return.*` fala CENTAVOS — antes convertia como reais = 100x latente nas devoluções da cabine); desfechos do hold: settled efetiva + `pix.refund.completed`; rejected libera pelo funil HoldRelease + `pix.refund.failed` (novo no catálogo); `pix.payout.returned` ligado no caminho legado vivo (devolução recebida de PIX enviado notifica o parceiro, valor da PARCIAL, dedup por RtrId).
6. Partner API — refund VALIDA a original (existência, conta sem vazar entre contas, direção INBOUND, liquidada, janela 90d, whitelist BACEN de 13 razões, restante devolvível contando pendentes) ANTES do hold; resposta `{data: {refundId, endToEndId, amount, remainingRefundable, status}}`; **trilha nova `GET /pix/payments/:id/refunds`** (original + restante + cada devolução com rtrId/status/motivo/datas; OpenAPI `PixRefundTrailResponse`); hold LIBERADO no rollback (era órfão invisível). IB v2 no MESMO contrato (fonte única `PaymentTransactions.fetch_refundable_original`/`refundable_remaining_cents`/`valid_return_reason?`).
7. Front IB — `PixRefundView.vue` em CENTAVOS ponta a ponta (a PARCIAL enviava base_units = 100x, e o trilho agora é real). StaleHoldChecker NUNCA resolve devolução com timeout cego (quarentena barulhenta + telemetria `monetarie.refund.hold_stale`).
8. Produtores de `RETURN_CREATED` carimbam identidade forte: auto-return `AUTORET<e2e>`, MED `MEDFR01-<id>`, admin `ADMRET-<id>` (+ gerador do gateway emitia RtrId de 29 chars INVÁLIDO — delegado ao MessageBuilder).

Suítes no fecho: cabine shared 1761/0, settlement 992/0, spi 876/0, dict 405/0; Core subset alvo (nats+workers+use_cases+partner+v2+api_spec, com :integration/TB real) 2475/1 — a ÚNICA falha é `StaleHoldCheckerReleaseTest`, PRÉ-EXISTENTE dos commits da sessão paralela (ver §3). Suíte cheia do Core: 7874 testes, 7 falhas + 10 invalid, TODAS atribuídas (sessão paralela ou ambiente/TB residual/ETL 5544) — prova documental no fim da conversa (meus 25 arquivos não tocam nenhum módulo que falha).

## 2. MANDATOS DE DEPLOY DO ITEM 5 (obrigatórios, da revisão adversarial)

1. **ORDEM: core-api ANTES de pix-api.** O core velho (:61) manda `return.settled` para a MATERIALIZAÇÃO via catch-all (COSIF fantasma a 100x nas devoluções da cabine; com origin=client, débito REAL na conta do cliente). Janela curta entre os dois.
2. **ROLLBACK do core para :61 é PROIBIDO com devoluções origin=client em voo** (mesmo vetor + estorno com `Wallet.deposit` 100x + StaleHold devolvendo o hold = dinheiro grátis).
3. core novo + pix velho (janela): edge novo publica contrato que a cabine velha não resolve -> DLQ bounded; hold destravado em 30min pelo StaleHoldChecker (as txs ainda não terão metadata pacs.004 consumida pela cabine... na prática a janela deve ser MINUTOS). Documentado, aceitável.
4. rpc do pix-api no deploy: `Shared.Release.migrate()` roda `20260717170000` e `20260717171000` (da sessão paralela, idempotentes, no-op limpo sobre o rpc já aplicado) + **`20260717150000` (CHECK key_type UPPER, pendência antiga)**. Nenhuma migration nova MINHA (o `return_id_registry` é do baseline).
5. Recomendações de task-def da sessão paralela AUTORIZADAS pelo dono para este deploy: `SIDECAR_TLS_SESSION_CACHE` no sidecar pix (partida fria do POST ICOM) e `PIX_SHARED_POOL_SIZE` 8 -> 32+.
6. Devoluções da CABINE em voo cruzando o swap do core ficam com COSIF de unidades mistas (reconciliável; avisar operador).
7. Pós-deploy: validação viva em HML (receber PIX -> devolver parcial 2x + total -> RtrId único nas linhas -> teto na 3a -> webhooks no receptor externo) + RELATÓRIO DE VALIDAÇÃO no padrão do cliente (chamada+retorno+erro; recusas em seção própria; responsabilidade do cliente). Em PROD não existe teste.

## 3. Sessão PARALELA na mesma árvore (coordenação!)

Outra sessão commitou na MESMA main durante esta: `13bde54f` (TED destravada + PIX-in com pagador + fim do crash de status_update) e `e075c84a` (pool de liquidação com ledger no id, layout `MPOL|ledger|pool`). Quebras DELA visíveis na suíte (avisar/deixar para ela): `OutboxAtomicityTest` do TedController (assert de fonte) e `StaleHoldCheckerReleaseTest` (`account_not_found` no pool TB). Handoff operacional dela (recado do dono): as 2 migrations acima no deploy do pix-api; task-def sidecar/pool; pendências dela = retest da TED pelo cliente, prova viva do netting no próximo ciclo, triagem da DLQ (19 mensagens), CAS terminal do StatusUpdater (o das LINHAS DE DEVOLUÇÃO já fechei aqui; o de pagamento comum segue aberto).

## 4. FRENTE NOVA AUTORIZADA (sessão dedicada): capacidade extrema do PIX

Ordem do dono (17/07): após o deploy com as task-defs acima, ACOMPANHAR OS LOGS DE PRD garantindo que
nenhum limite junto ao Banco Central estoure; que apenas POSTs reais e válidos sejam enfileirados e
executados com sucesso; e implementar o EMPACOTAMENTO de até 10 transações por mensagem quando houver
muitos PIX no mesmo instante, como o fluxo do BACEN permite (pacs.008 em lote), para capacidade extrema
com uso real. Insumos: relatório de latência da sessão paralela (baleia = seq scan dedup auditoria já
indexado; partida fria TLS), `Shared.Bacen.ChannelRouter`/OutboundSender como pontos de enfileiramento,
manual ICOM v5.12 (limites de sessão/mensagens), ANS 1.6s. Trabalhar em SESSÃO NOVA com foco total.

## 5. Fila da frente do fluxo do cliente (plano aprovado, nada perdido)

- Fase A restante: item 1 Infrações (cliente DICT completo na cabine, create ÓRFÃO — destravar via dispatch de escrita no `dict_api_responder` + superfície partner + defesa), item 3 MED (expor list/cancel/refund especial/notificações/tracking + consertar rota 404 do `recovery_complete_refund` + SUPERVISIONAR a máquina MED do SPI que está morta), item 2 Claims (listagem + `POST /pix/claims/:id/complete`), item 4 defesas pelo partner, item 6 devolução de TED (motor STR0010 da SPB COMPLETO, consumer aceita `devolution_request`; falta rota partner + use case Core resolvendo crédito TED->NumCtrlSTR + consumer `monetarie.spb.credits.return_status` + webhooks `ted.refund.*`; nota da sessão paralela: automação STR0010 OFF em PROD e matching de TED credita sem conferir CPF/nome), item 17 accounts/:id/events.
- Fase B (P0 telas): QR real nas telas (gateway `use_cases/pix/gateway/qr_code.ex`), copia-e-cola (consultar -> confirmar -> pagar; backend pronto), cobrança paga visível (serializer mapeia paid->used + criação pela tela é 501).
- Fase C (P1): TED agendada no v2, limites do usuário, TEF, PIX Automático DLQ, rotas v1, chamadas mortas do merchant (webhooks já estão vivos).
- Fase D: portal trilíngue + Postman (mantida À MÃO em 2 cópias idênticas `docs/postman/` + `docs/partner-portal/public/`; PEDIDO DO TIME: adicionar `POST /pix/qrcodes/static` valor aberto E fechado + `GET /ping`; docs do refund novo: shape `{data:{...}}` + rota da trilha; portal do parceiro NÃO tem infra no Terraform — decidir onde publicar). Relatórios de validação por API nova no padrão do PDF de 17/07.
- Follow-ups (task #23): sweeper de blocks PI órfãos; materialização cabine-origem sem conta no Core (DLQ + journal dup em redelivery, pré-existente); COSIF misto no swap; flake de ordenação `account_events_test` sob suíte cheia; `TransactionsTest` not-null em `account_daily_summaries` (pré-existente, avisar time).

## 6. Ambiente e receitas

Containers de teste: `monetarie-pg` :15432 + `monetarie-tb-test` (+ NATS/redis locais). Testes: cabine `cd pix/backend && mix test apps/<app>/test/...`; Core `cd core/backend && mix test ... --include integration` (TB real). Revisões vivas INALTERADAS: HML core:157 pix:181 spb:66 / PROD core:61 pix:58 spb:37 (nada deployado nesta sessão). Deploy: receitas no handoff de 17/07 tarde (`docs/handoff/2026-07-17-partner-api-deploy-validacao-fixes-handoff.md` §7).

## 7. Memórias atualizadas
CLAUDE.md (estado canônico 2026-07-17 NOITE), MEMORY.md + `monetarie-devolucao-cliente-trilho-verdadeiro-0717.md`, Serena `monetarie/devolucao-cliente-item5-0717`, task list da sessão (23 tarefas).
