# Deep audit MED — camt.025 / camt.029 / camt.055 (legado x nosso x gaps)

Auditor: parity senior PIX. Data: 2026-07-23. READ-ONLY, zero inferencia (afirmacoes com prova arquivo:linha /
tabela.coluna; sem prova = INCONCLUSIVO). pt-br sem travessao.

Fontes:
- Legado decompilado: `.scratch/legado-pix-decompiled/{GID.Api,GID.Core.Application,SPI.Core.Application,
  SPI.Core.Mensageria.Application.Book.v111,SPI.Core.General,SPI.Core.Worker.TratamentoRetornoApiBacen.Infrastructure,
  Multiliquidacao.Core.Application,Multiliquidacao.Core.General}.decompiled.cs`
- Legado DB vivo (SQL Server): DB `gid` (TB_TRCK002, TB_CAMT025, TB_RECUPERACAOVALOR, TB_EVENTO), DB `crk_spi`.
- Legado scripts: `LegadoPIX/Pix/Med_gid/scripts/{01.Inicial,02.TabelaCamt025,03.AjusteTabela}.sql`
- Nosso backend (Elixir): `pix/backend/apps/{spi_service,shared}`
- Nosso XSD: `pix/backend/apps/shared/priv/xsd/spi/v5.12.1/camt.{025,029,055}.spi.*.xsd`

---

## 0. Semantica: os tres codigos vivem em DOIS dominios distintos no legado

O ponto central da auditoria: no legado, camt.025/029/055 NAO sao um unico fluxo. Sao dois:

1. **GID / MED 2.0 (Recuperacao de Valores)** — DB `gid` (`CRK_GDI`). Aqui vive o **TRCK002** (registro de
   rastreamento/bloqueio cautelar enviado ao SPI/BACEN) e o **camt.025** que retorna como RECIBO desse TRCK002,
   fechando o status da tabela `TB_TRCK002`. Prova: `GID.Api.decompiled.cs:260` (MED20Controller),
   `GID.Core.Application.decompiled.cs:761` (AddTRCK002) e `:802` (RetCAMT025).

2. **SPI / Multiliquidacao — Cancelamento de Solicitacao de Pagamento** (Pix Cobranca/agendado/automatico) — o
   **camt.055** e o pedido de cancelamento de uma ordem de pagamento e o **camt.029** e a resolucao (aceite ACCR /
   rejeicao RJCR). Prova: `Multiliquidacao.Core.Application.decompiled.cs:8223` (CancelarSolicitacaoPagamento, monta
   `SPI_CAMT055`), `SPI.Core.Worker.TratamentoRetornoApiBacen.Infrastructure.decompiled.cs:3828`
   (EfetuaValidacaoCancelamentoSolicitaPgto: camt.055 recebida gera camt.029), `SPI.Core.Application.decompiled.cs:2686`
   (Valida CAMT055).

**Nosso lado** funde os tres no modulo MED de fraude (`SpiService.Med`) + um recibo advisory:
- `camt.055` inbound -> abre um claim MED `operational_failure` (`SpiService.Med.open_inbound_cancellation_claim/1`,
  `pix/backend/apps/spi_service/lib/spi_service/med.ex:125`), consumido por
  `SpiService.Med.CancellationConsumer` (`.../med/cancellation_consumer.ex:31`).
- `camt.029` inbound -> libera bloqueio cautelar (`SpiService.Med.release_cautelar_from_resolution/1`, `med.ex:539`),
  consumido por `SpiService.Med.ResolutionConsumer` (`.../med/resolution_consumer.ex:31`).
- `camt.029` outbound -> emitido em approve/deny (`emit_resolution/3`, `med.ex:655`).
- `camt.025` inbound -> `process_receipt/2` (`.../workers/inbound_processor.ex:2578`): log + broadcast, sem persistir.

Dispatch inbound nosso: `inbound_processor.ex:204-209`.

---

## 1. Evidencia empirica de uso (DB legado vivo)

DB `gid`:
- `TB_TRCK002` = **0 linhas**; `TB_CAMT025` = **0 linhas**; `TB_RECUPERACAOVALOR` = **0 linhas**; `TB_EVENTO` = **0
  linhas** (query: `SELECT COUNT(*) FROM gid.dbo.*`). O GID/MED (TRCK002 + camt.025 + funds-recovery) esta montado
  estruturalmente mas NAO teve trafego neste backup.
- `TB_RECUPERACAOVALOR_STATUS`: 1 CREATED, 2 TRACKED, 3 AWAITING_ANALYSIS, 4 ANALYSED, 5 REFUNDING, 6 COMPLETED,
  7 CANCELLED (confere com `enumFundsRecoveryStatus`, mapa 08 §6).
- `TB_TIPOEVENTO`: FUNDS_RECOVERY_ANALYSED / _COMPLETED / _INFORMATION_UPDATED / _CANCELLED.
- `crk_spi`: unica tabela camt e `SpiSaldoCAMT` (camt.052/053/054 saldo); nao ha tabela dedicada de camt.055/029/025 no
  SPI (o legado persiste como `MessageFull` na mensageria generica).

Leitura: o risco pratico do gap camt.025<->TRCK002 (GID) e baixo por falta de uso historico do TRCK002 do GID, MAS a
NOSSA cabine EMITE trck.002 por outro caminho (liquidacao interna BOK1,
`settlement_service/.../workers/core_event_processor.ex:1869`), que tambem recebe camt.025 como recibo — logo o gap de
correlacao camt.025 permanece relevante para o trck.002 vivo.

---

## 2. camt.025 (Receipt / Recibo de status)

### 2.1 Legado — GID (fecha TB_TRCK002)

`GID.Core.Application.decompiled.cs:802` `RetCAMT025(CAMT025ApiDTO)`:
- Le `RctDtls` (namespace removido), para cada `RctDtls`: `OrgnlMsgId/MsgId` (msgId) e
  `ReqHdlg/Sts/Cd == "ACPT" ? Efetivado : Rejeitado`.
- `AtualizaTRCK002(msgId, status, xmlRecibo)` -> `UPDATE dbo.TB_TRCK002 SET [Status]=..., RetornoBACEN=... WHERE
  MessageId=...` (`:1146`). Ou seja, o camt.025 **fecha o TRCK002 correlato por MessageId**.
- Status TRCK002 (SQL `getStatusOperacao`, `:1090`): 1 Registrado, 2 Enviado, 3 ErroEnvio, 4 Efetivado, 5 Rejeitado;
  `aceito = (Status==4)`; motivo de rejeicao vem de `RctDtls/ReqHdlg/StsRsn/Rsn/Prtry` + `StsRsn/AddtlInf`.

### 2.2 Legado — SPI (persiste + reencaminha ao GID)

`SPI.Core.Worker.TratamentoRetornoApiBacen.Infrastructure.decompiled.cs:2557` `ConverteToCAMT025MsgFull`:
- Extrai `Rct/MsgHdr/MsgId`, `Rct/RctDtls/OrgnlMsgId/MsgId` (`MessageIdOriginal`),
  `RctDtls/ReqHdlg/Sts/Cd` (`SituacaoTransacao`), `.../Sts/Rsn/Prtry` (`CodigoErro`), `.../Sts/AddtlInf`
  (`DetalheErro`). `IdSystem=5`.
- `ImportaCAMT025` (`:2638`): converte para `MessageFull`, `NumeraOperacoes`, adiciona a `MensagensImpactadas` com
  `MessageIdOriginal` (correlaciona a mensagem original) E chama `_enviaRetornoCAMT025GidUseCase.EnviaCAMT025(XmlOrigem)`
  (`:2653`) — **reencaminha o recibo cru ao GID** para fechar o TB_TRCK002.

DTO: `CAMT025DTO` (`SPI.Core.General.decompiled.cs:8588`) tem `SituacaoTransacao/CodigoErro/DetalheErro/MessageIdOriginal`.
Tabela `TB_CAMT025` (script `02.TabelaCamt025.sql`, DB `gid`): UniqueId(PK), CdMsg, MessageId, MessageIdOriginal,
MsgDefIdr, DtHrOperacao, DtHrMsg, SituacaoTransacao, CodigoErro, DetalheErro, IdSystem(=5 GID), IspbIF + indices por
MessageId/MessageIdOriginal.

### 2.3 Nosso — process_receipt (advisory)

`inbound_processor.ex:2578` `process_receipt/2`:
- `record_audit_inbound(message, "camt.025", xml)` (auditoria XML).
- `MessageParser.extract_receipt/1` (`shared/.../message_parser.ex:393`): le `RctDtls/ReqHdlg/Sts/Cd` (status),
  `ReqHdlg/StsRsn/Rsn/Prtry` (reason), `RctDtls/OrgnlMsgId/MsgId` (original_msg_id), `RctDtls/OrgnlPmtId/PrtryId`
  (original_payment_id).
- Se `status == "RJCT"`: Logger.error. Sempre: `broadcast_event("receipt.received", ...)`.
- **NAO persiste** o recibo, **NAO correlaciona** ao `MessageIdOriginal`, **NAO atualiza status** de nenhuma mensagem
  original (ex.: a trck.002 BOK1 registrada em `monetarie_spi.messages`, `core_event_processor.ex:1906`).

### 2.4 Gap camt.025

| Dimensao | Legado | Nosso |
|---|---|---|
| Persistir recibo | TB_CAMT025 (GID) + MessageFull (SPI) | so auditoria XML, sem linha propria |
| Correlacionar a original | MessageIdOriginal (SPI) + MessageId (GID) | nao correlaciona |
| Fechar status da original | UPDATE TB_TRCK002 Efetivado/Rejeitado | nao atualiza (trck.002 fica no status de envio) |
| Reencaminhar ao GID/MED | EnviaCAMT025(XmlOrigem) | inexistente (nao ha GID separado) |
| Path do reason | GID: StsRsn (XSD-ok); SPI import: Sts/Rsn (XSD-divergente) | StsRsn (XSD-ok) — **nosso melhor** |
| Detectar RJCT | ACPT->Efetivado; else Rejeitado | RJCT->Logger.error + broadcast |

Nota XSD (prova): `camt.025.spi.1.0.xsd` `RequestHandling4` = `Sts` (RequestStatus1Choice/Cd) + `StsRsn` (minOccurs 0,
StatusReasonInformation14 = Rsn + AddtlInf) — o reason e irmao de Sts (`StsRsn`), nao filho (`Sts/Rsn`). O nosso
builder+parser usam `StsRsn` (correto); o import SPI legado usa `Sts/Rsn` (divergente do XSD 5.12).

---

## 3. camt.055 (Customer Payment Cancellation Request)

### 3.1 Legado — OUTBOUND (solicitante pede o cancelamento de uma ordem de pagamento)

`Multiliquidacao.Core.Application.decompiled.cs:8223` `CancelarSolicitacaoPagamento`:
- Busca a `SolicitacaoPagamento` original por (`idFimaFimOriginal`, `idConciliacaoRecebedorOriginal`) — FF08 se nao
  achar; AB09 se o ISPB pagador nao bate.
- Gera `idCancelamentoAgendamento` (formato `CA...`, regex `^CA\d{8}\d{8}[a-zA-Z0-9]{11}$`, `SPI.Core.General:4113`).
- `direcao == Saida`: monta `SPI_CAMT055` e envia por `_sendSPI.CancelIniciacaoPgto`. `TipoSolicitacaoCancelamento =
  (ispb == solPgto.NrSpbPagador) ? "DHIP" : "DHSR"`.
- Integracao conta: chama o legado AutBank e seta `solPgto.idStatus = enumSituacaoCobranca.CANCELADA`.
- XML builder camt.055: `SPI.Core.Mensageria.Application.Book.v111.decompiled.cs:6084+` (CstmrPmtCxlReq com
  `Undrlyg/OrgnlPmtInfAndCxl/PmtCxlId`, `OrgnlPmtInfId`, `CxlRsnInf/Orgtr/Id/PrvtId/Othr/Id`, `Rsn/Prtry`,
  `TxInf/OrgnlEndToEndId`, `SplmtryData/.../CxlPrcgTp` DHIP/DHSR).

Validacao OUTBOUND (`SPI.Core.Application.decompiled.cs:2686` `Valida(CAMT055DTO)`):
- EndToEndIdOrig 32 chars, formato `E\d{8}\d{12}[a-zA-Z0-9]{11}`, data yyyyMMddHHmm valida, e p/ Pix automatico
  substring(17,4)=="1500" (`ValidarEndToEndIdOrig`, `:2773`).
- `TipoSolicitacaoCancelamento` in {DHIP,DHSR} (`:2750`).
- `MotivoCancelamento` in {ACCT,BLCK,CCLD,FAIL,OTHR,SLBD,SLCR} (`:2754`).
- `CpfCnpjDebtor` obrigatorio + documento valido (`:2758-2762`).
- `IdConciliacaoOriginal` nao vazio e len<=35 (`:2745`).
- Participante creditor/debtor local e externo validos.

### 3.2 Legado — INBOUND (recebe camt.055 e responde camt.029 AUTOMATICAMENTE)

`SPI.Core.Worker.TratamentoRetornoApiBacen.Infrastructure.decompiled.cs:3828` `EfetuaValidacaoCancelamentoSolicitaPgto`:
- Desserializa `CAMT055DTO`, roda `ValidacaoCancelamentoSolicitaPgtoUseCase.Validacao(objDto)`.
- Se invalido: extrai codigo do erro; se fora do whitelist `AB09|AB10|AG12|CH16|CRNC|DENC|DS27|FBRD|FF08|PRJL|RC09|RC10`
  usa AB09 (E2E contem ISPB creditor) ou AB10.
- Monta `CAMT029DTO` de resposta com IspbDebtor/Creditor **invertidos**,
  `StatusCancelamento = validacao.OK ? "ACCR" : "RJCR"` (`:3866`), `CodigoRejeicao = codRetorno`, carregando
  EndToEndIdOrig/IdCancelamento/IdConciliacaoOriginal. Converte para MessageFull -> despacha camt.029.
- Import da camt.055 recebida: `ImportaCAMT055` (`:2217`).

**Conclusao: o legado FECHA a malha automaticamente — camt.055 recebida sempre gera camt.029 (ACCR ou RJCR com codigo
de rejeicao valido).**

### 3.3 Nosso — INBOUND (abre claim, NAO responde camt.029)

`inbound_processor.ex:3128` `process_cancellation_request/2`:
- `MessageParser.extract_cancellation_request/1` (`message_parser.ex:488`): le `Undrlyg/OrgnlPmtInfAndCxl/PmtCxlId`
  (cancellation_id), `CxlRsnInf/Rsn/Prtry` (reason_code), `TxInf/OrgnlEndToEndId`, `Assgnr/.../MmbId`
  (requesting_ispb), `Orgtr/.../Othr/Id` (originator_document), `CxlPrcgTp` (processing_type DHIP/DHSR),
  `OrgnlPmtInfId`. Paths XSD-corretos (bug antigo StsRsnInf ja corrigido, coberto).
- publica `monetarie.spi.med.cancellation_requested`.
- `Med.open_inbound_cancellation_claim/1` (`med.ex:125`): resolve a operacao original pela pacs.008 INBOUND
  (`find_original_inbound/1`, `med.ex:201`) para obter valor (camt.055 nao carrega Amt), abre claim
  `operational_failure` status "open", reason default "OTHR". Idempotente por E2E + advisory lock.
- **NAO valida** motivo (ACCT..SLCR whitelist), DHIP/DHSR, formato E2E, documento, IdConciliacao<=35 (confia no BACEN).
- **NAO responde camt.029** automaticamente. O claim fica "open" indefinidamente.

### 3.4 Nosso — resolucao do claim (approve/deny) e DEAD CODE

`Med.approve_claim/2` (`med.ex:451`, emite camt.029 ACCR) e `Med.deny_claim/2` (`med.ex:462`, emite camt.029 RJCR)
existem, mas **nenhum caller de producao** os invoca. Prova (grep em `apps/`):
- unicas referencias fora de `def`: testes (`med_test.exs`), o proprio moduledoc/comentarios.
- `apps/spi_service/lib/spi_service_web/router.ex`: nenhuma rota MED/claim/cancellation.
- nenhum controller referencia `SpiService.Med`.
- `Med.TimerEnforcer` (`med/timer_enforcer.ex`) apenas ESCALA (seta `escalated=true`,`:200`) e expira janela de 90 dias
  para "expired" (`:118-139`); nao aprova/nega/emite camt.029.

**Conclusao: nossa cabine recebe camt.055, abre um claim, e NUNCA envia camt.029 de volta. O PSP solicitante fica sem
resolucao (o legado sempre responde). approve/deny/emit_resolution/build_camt055 sao caminho morto em producao.**

### 3.5 Nosso — OUTBOUND camt.055 inexistente

`build_camt055` (`message_builder.ex:742`) existe mas so e usado por simulador/Construtor de Mensagens
(`message_form_catalog.ex`, `simulator_seed.exs`). Nao ha fluxo de negocio que ENVIE camt.055 (grep: unica referencia
"camt.055" em `med.ex:172` e o `notification.payload.message_type` de um recibo INBOUND). Ou seja, a feature legada
"Solicitar Cancelamento de Ordem de Pagamento" (`CancelarSolicitacaoPagamento`, com update de
`SolicitacaoPagamento -> CANCELADA`) NAO tem equivalente na nossa cabine.

---

## 4. camt.029 (Resolution of Investigation)

### 4.1 Legado — OUTBOUND builder

`SPI.Core.Mensageria.Application.Book.v111.decompiled.cs:6278+` (`CAMT029.v10.ToXml`):
- `tipoAceiteRjc = (StatusCancelamento=="ACCR") ? "DHAC" : "DHRC"` (`:6287`) -> `SplmtryData/.../CxlPrcgTp`.
- `codRejeicao = CodigoRejeicao vazio ? "" : "<CxlStsRsnInf><Rsn><Prtry>{CodigoRejeicao}</Prtry></Rsn></CxlStsRsnInf>"`
  (`:6288`).
- Estrutura: `RsltnOfInvstgtn/Sts/Conf=INFO` + `CxlDtls/OrgnlPmtInfAndSts/{OrgnlPmtInfCxlId=IdCancelamento,
  OrgnlPmtInfId=IdConciliacaoOriginal, PmtInfCxlSts=StatusCancelamento, [CxlStsRsnInf], TxInfAndSts/OrgnlEndToEndId}`.

### 4.2 Legado — INBOUND (resolucao recebida pelo solicitante)

O trilho de cancelamento de ordem cross-referencia a `SolicitacaoPagamento` (status -> CANCELADA) na confirmacao
(`ConfirmarCancelamentoSolicitacaoPagamento`, `Multiliquidacao.Core.Application.decompiled.cs:8320+`). enumSituacaoCobranca
inclui REJEITADA/CANCELADA (`Multiliquidacao.Core.General.decompiled.cs:6446-6449`).

### 4.3 Nosso — OUTBOUND builder + emit

`build_camt029` (`message_builder.ex:579`): estrutura conforme XSD (`Assgnmt/Assgnr/Assgne`, `Sts/Conf=INFO`,
`CxlDtls/OrgnlPmtInfAndSts`, `SplmtryData/CxlPrcgDtls`). `emit_resolution/3` (`med.ex:655`) passa
`cancellation_status` (ACCR em approve / RJCR em deny), `confirmation:"INFO"`, `original_end_to_end_id`,
`cancellation_id`, `rejection_reason`, `claimant_ispb`, `respondent_ispb`.

Divergencias do builder+emit (dentro do caminho ja morto §3.4):
- `OrgnlPmtInfCxlId` = `p[:original_payment_cancellation_id] || p.msg_id` (`message_builder.ex:595`), mas
  emit passa `cancellation_id:` (nao `original_payment_cancellation_id:`) -> resulta em `p.msg_id` (id da propria
  camt.029), NAO o PmtCxlId da camt.055 original. Legado usa `objDto.IdCancelamento` (o PmtCxlId original).
- `CxlPrcgTp` = default fixo "DHAC" (`message_builder.ex:601`); emit nao passa `cancellation_processing_type`. Numa
  rejeicao (RJCR) o legado emitiria "DHRC"; o nosso emitiria "DHAC" (inconsistente com PmtInfCxlSts=RJCR).
- **Nao emite `CxlStsRsnInf/Rsn/Prtry`** (codigo de rejeicao). O legado emite quando ha CodigoRejeicao. `emit_resolution`
  passa `rejection_reason: notes` mas o builder nao le nenhum campo de reason -> a camt.029 de rejeicao sai SEM o codigo
  de motivo.

### 4.4 Nosso — INBOUND (resolucao recebida -> libera cautelar)

`process_med_resolution/2` (`inbound_processor.ex:2608`) + `MessageParser.extract_cancellation_resolution/1`
(`message_parser.ex:434`, le `OrgnlPmtInfAndSts/PmtInfCxlSts` ACCR/RJCR, `CxlStsRsnInf/Rsn/Prtry`,
`OrgnlPmtInfCxlId`, `OrgnlEndToEndId`, `Conf`). Publica `monetarie.spi.med.resolution_received`.
`release_cautelar_from_resolution/1` (`med.ex:539`): correlaciona por `OrgnlEndToEndId` (reforco por cancellation_id
UUID do claim), mapeia outcome -> "settled" (ACCR/ACSP/ACSC/ACCC/RTRN/...) ou "denied" (RJCR/RJCT/...) via
`resolution_outcome_status/1` (`med.ex:590`), libera chain blocks e grava notification "resolution". COBERTO em nivel
funcional (libera bloqueio cautelar; o legado equaliza o status da cobranca — semantica diferente mas analoga).

---

## 5. Defeito de audit no claim de camt.055 (nosso, real)

`do_open_inbound_cancellation_claim` (`med.ex:171`) chama `record_notification(claim, "cancellation_request",
"inbound", ...)`. Mas `SpiService.Med.Notification` (`med/notification.ex`) tem
`@valid_notification_types = ["cautelar_request","cautelar_response","analysis_request","resolution","settlement",
"tracking_request","tracking_response","escalation","infraction_report","recovery_request"]` (nao inclui
"cancellation_request") e o changeset aplica `validate_inclusion(:notification_type, @valid_notification_types)`
(`notification.ex:45`). `record_notification` faz `Repo.insert` (nao `insert!`) e o retorno e IGNORADO
(`med.ex:169-177`), e a falha e de validacao (nao de SQL, nao aborta a transacao). Resultado: o claim abre, mas a
notificacao de auditoria da camt.055 recebida e **silenciosamente descartada** (nenhuma linha em `med_notifications`).
Gap de trilha de auditoria.

---

## 6. Tabela consolidada de gaps

| id | titulo | tipo | risco |
|----|--------|------|-------|
| g1 | camt.055 recebida nao gera camt.029 (sem resolucao ao solicitante) | ausente | alto |
| g2 | camt.025 nao correlaciona nem fecha status da mensagem original (trck.002) | divergencia | alto |
| g3 | camt.055 outbound (solicitar cancelamento de ordem) inexistente | ausente | medio |
| g4 | camt.029 outbound: OrgnlPmtInfCxlId/CxlPrcgTp/CxlStsRsnInf divergentes (caminho morto) | divergencia | baixo |
| g5 | notification "cancellation_request" descartada (audit da camt.055 perdida) | divergencia | medio |
| g6 | camt.055 inbound sem validacao de negocio (motivo/DHIP-DHSR/E2E/doc) | parcial | baixo |
| g7 | camt.029 inbound -> libera cautelar + settled/denied | coberto | info |
| g8 | camt.025 parser (StsRsn XSD-correto) + deteccao RJCT | coberto | info |
| g9 | camt.055 parser (CxlRsnInf/PmtCxlId/DHIP-DHSR) XSD-correto | coberto | info |
| g10 | GID/MED (TRCK002/CAMT025/funds-recovery) sem trafego no backup | coberto | info |

---

## 7. Recomendacoes (nao executar sem OK)

1. g1: fechar a malha camt.055->camt.029. Decidir com o dono se a resolucao e AUTOMATICA (espelhar o legado:
   validar o pedido e responder ACCR/RJCR com codigo do whitelist AB09|AB10|AG12|CH16|CRNC|DENC|DS27|FBRD|FF08|PRJL|
   RC09|RC10) ou operator-driven (expor rota/UI que chame approve_claim/deny_claim). Hoje o PSP solicitante nunca recebe
   resposta.
2. g2: em `process_receipt`, correlacionar por `original_msg_id`/`original_payment_id` e atualizar o status da mensagem
   original (ex.: trck.002 -> settled/rejected) espelhando `RetCAMT025`->TB_TRCK002.
3. g4: corrigir `emit_resolution`/`build_camt029` para passar `original_payment_cancellation_id` = PmtCxlId da camt.055
   original, `cancellation_processing_type` DHAC/DHRC por ACCR/RJCR, e emitir `CxlStsRsnInf/Rsn/Prtry` na rejeicao.
4. g5: adicionar "cancellation_request" a `@valid_notification_types` (ou usar tipo valido) e checar o retorno de
   `record_notification`.
5. Semantica: alinhar com o dono se camt.055/029 devem viver no MED de fraude (atual) ou no dominio de cancelamento de
   ordem de pagamento (legado). A fusao atual mistura os dois.

Limitacoes honestas: (a) TB_TRCK002/TB_CAMT025/TB_RECUPERACAOVALOR estao vazias no backup (sem lastro de dados reais do
GID/MED); (b) a semantica exata do dominio (MED fraude vs cancelamento de ordem) e uma decisao de produto que a prova de
codigo nao resolve sozinha; onde nao havia prova, marquei coberto/info em vez de afirmar gap.
