# Construtor de Mensagens (PIX admin) — matriz de gaps vs catálogo SFN/SPI v5.12.1

Data: 2026-07-06. Mandato do dono: revalidar TODAS as mensagens do "Construir Mensagem" batendo campo a campo com o catálogo. Levantamento exaustivo (código + XSDs oficiais v5.12.1). Implementação pendente; este relatório é a base do plano.

## Arquitetura da tela (fatos)

A tela não tem catálogo próprio: renderiza o que `GET /api/v1/messages/types` devolve.

| Camada | Onde | Papel |
|---|---|---|
| Catálogo de campos | `pix/backend/apps/settlement_service/lib/settlement_service_web/controllers/message_controller.ex:1041-1339` (`message_type_catalog/0`) | `required_fields`/`optional_fields` como arrays de string à mão. É daqui que sai o "Campos obrigatórios: 3" do pacs.008. |
| Whitelist fatal | `message_controller.ex:46-67` (`@known_params`) + `convert_params/1` (`:861`) | Campo fora da lista é descartado em silêncio antes do builder. |
| Parity guard | `message_controller.ex:1341` | Só valida códigos de mensagem, nunca campos. |
| Form | `pix/frontend/admin/src/views/messages/MessageBuilderView.vue:128,383-403` | Um `<input>` por campo; nenhum `<select>`. |
| Builders | `pix/backend/apps/shared/lib/shared/bacen/iso20022/message_builder.ex` | Leem `p[:...]` — vários campos que o whitelist nunca deixa chegar. |

**Causa raiz comum:** catálogo (`:1041`), whitelist (`:46`) e os `p[:...]` de cada builder são três listas desacopladas, sem validação cruzada. Correção precisa alinhar as três + UI.

## Gaps críticos (XML sai incompleto/inválido sem como corrigir pela tela)

- **pacs.008**: builder lê `debtor_document`, `creditor_document`, `debtor_branch`, `creditor_branch`, `*_account_type` (`message_builder.ex:180-186`) — nenhum no `@known_params` → `<Id></Id>` vazio, tipo de conta sempre `CACC`, finalidade sempre `IPAY`. Pelo XSD, `Dbtr/Nm`, CPF/CNPJ das partes, contas e `Tp/Cd` são obrigatórios; o catálogo diz "3 obrigatórios". Confirma a queixa do dono na íntegra.
- **pacs.004**: `debtor_ispb`/`creditor_ispb` do `OrgnlTxRef` (`:345`) fora do whitelist → `<MmbId></MmbId>` vazio. `return_reason` é obrigatório no XSD, marcado opcional.
- **trck.002**: `execution_datetime` é obrigatório no catálogo e é DROPADO pelo whitelist.
- **reda.016 / reda.017 / reda.041**: expostos no catálogo mas SEM cláusula em `build_document/2` → `raise "Unknown message type"` → 422 garantido.

## Gaps altos (form desconectado do builder / rótulo enganoso)

- **reda.022**: 10 campos de contato/diretor no form 100% ignorados (builder espera `modifications` estruturado que a UI nunca monta).
- **pain.011**: rotulado "MandateAmendmentRequest", builder gera **MndtCxlReq** (cancelamento). **pain.012**: rotulado "Cancellation", builder gera **MandateAcceptanceReport** e ignora os campos do form.
- Campos declarados que o builder não lê: camt.014 (os 3 do form), camt.055 `original_msg_id`, camt.054 `notification_id`, camt.060 `balance_type` (builder lê `p[:prtry]`), pain.014 `original_msg_id`, pibr.002/admi.002.
- **camt.053**: `from_date`/`to_date` obrigatórios no form e não usados pelo builder.

## Gaps médios (texto livre onde deveria haver SELECT com domínio)

| Campo | Domínio | Dado já disponível |
|---|---|---|
| ISPB (todos) | Diretório BACEN de participantes | `GET /api/v1/bacen/pix-participants` (+`/summary`), front já tem `services/participants.ts` + `stores/participants.ts`; o MessageBuilder não importa a store |
| Tipo de conta | CACC/OTHR/SLRY/SVGS/TRAN (XSD) | estático |
| Finalidade | GSCB/IPAY/IPRT/OTHR/REFU | estático |
| Prioridade | HIGH/NORM (Priority2Code); pacs.004 Priority3Code | estático |
| Forma de iniciação | APDN/APES/AUTO/DICT/INIC/MANU/QRDN/QRES | estático |
| Status/motivos | enums BACEN (ref em `monetarie_spi_ref`) | tabela de referência existente |
| Frequência (pain) | MNTH/... | estático |

## Plano de correção (proposto)

1. Fonte única: derivar catálogo de campos por tipo de um módulo só (campos, obrigatoriedade, domínio/select, mapeamento para o `p[:...]` do builder), com teste de paridade cruzada catálogo × whitelist × builder (quebra o build se desalinhar).
2. Críticos primeiro (pacs.008, pacs.004, trck.002, reda.016/017/041), com XSD v5.12.1 como verdade e teste por tipo (XML gerado validado por xmllint contra o XSD).
3. UI: `<select>` para ISPB (participants store), tipo de conta, finalidade, prioridade, status/motivo; agência e CPF/CNPJ das partes como campos novos.
4. Corrigir rótulos pain.011/012 e remover/ligar campos mortos.
5. Regra 11: screenshot por mensagem revalidada.

## Relacionado (mesmo dia)

- Envio manual pacs.008 falhou com `%Finch.TransportError{reason: :closed}` cru na tela: fix `43dfb161` (failover p/ struct + `humanize_send_error`).
- Agrupamento pibr.001↔002 no monitor: fix `0a0a3375` (chave Data/OrgnlData).
