# Matriz de paridade PIX: monetarie vs LegadoPIX (vendor) vs AutBank

Data: 2026-07-02. Fase A do mandato de paridade e best-of-breed.

Fontes comparadas com evidência direta (arquivo:linha, procedure, dados agregados):

- Monetarie PIX: `/Users/luizpenha/monetarie/pix/*` (umbrella Elixir: spi_service, dict_service, settlement_service, shared; admin Vue) e Core (`/Users/luizpenha/monetarie/core/*`).
- LegadoPIX vendor: `/Users/luizpenha/mwbank/LegadoPIX/*` (AdmWeb, CRK40, DICT, Multiliquidacao, SPI, `_decompiled` com cerca de 80 projetos C#, frontend Angular).
- AutBank: container local `monetarie-bak-mssql` (AB_PAGAMENTO_INSTANTANEO e satélites, cerca de 435 tabelas + procedures T-SQL) e staging `legacy_ab_pix` em `cc_pix` (postgres local).

Domínios: D0 rota P0 (PIX Out IB para Core para cabine para BACEN), D1 fluxo SPI, D2 DICT/MED, D3 cripto/certificados/canais, D4 liquidação/extrato/conciliação/relatórios, D5 administração/operação. Total: 160 itens comparados, com dedupe de overlaps entre domínios (marcados na coluna Ação).

Legenda de veredito: PARIDADE_OK (equivalente ou já coberto), MELHOR_NO_MONETARIE (manter monetarie), MELHOR_NO_LEGADO (portar a regra), FALTA_NO_MONETARIE (capacidade inexistente, portar), DIVERGENTE_VALIDAR (precisa de decisão ou prova adicional), OVERLAP_REMOVER (duplicidade a eliminar).

## 1. Resumo executivo

Esta matriz consolida a Fase A da paridade PIX entre o monetarie, o LegadoPIX do vendor e o AutBank, cobrindo 6 domínios e 160 itens comparados exclusivamente com evidência (código, procedures, dados vivos de banco e logs de HML). O P0 do mandato (suposta perda de persistência na rota IB para Core) foi RESOLVIDO como falso alarme de investigação: a rota funciona fim a fim, provada viva em HML, e o registro rejeitado mora em `failed_transactions` por desenho, com timeline completa em `pix_out_lifecycle_events`. A mesma investigação achou 3 defeitos reais confirmados no código e no banco: o código de rejeição do BACEN (AB03) se perde no parser do pacs.002, o saldo espelho PI da cabine vaza R$ 0,01 por rejeição (credit-back pulado por bug de `Map.put_new` sobre chave nula) e o PIX rejeitado some de todas as listas do IB. O núcleo validado vivo contra o BACEN (mTLS verify_peer, XMLDSig via HSM RTM 443, CID sync com sync-verification, canal ICOM com invariante persistência antes do ACK, DICT v2.11.0, camt.060 6/7) é superior aos dois legados e fica intocável. As maiores lacunas funcionais frente aos legados são: transferência interna mesmo-ISPB inexistente (PIX intra-Monetarie hoje vai ao BACEN), devolução automática pacs.004 quando o crédito pós-liquidação falha, agendamento de PIX único, e todo o lado inbound do DICT (reivindicações recebidas, relatos de infração recebidos e solicitações MED recebidas sem nenhum polling). Há automações construídas porém desligadas: timers de claim D+14/D+30 sem consumidor, motor MED do respondente sem gatilho de entrada, validação de posse OTP 100% stub 501 e tela de automação de mensagens sem runner do crontab. A fraqueza crônica dos kills do CPM (10 a 22 por dia) tem causa estrutural encontrada: o HealthMonitor mata o worker por `GenServer.call` de 5s enquanto ele está legitimamente bloqueado num long-poll de até 60s. Os legados são melhores em resiliência operacional: teste de conectividade a cada 5 minutos com evidência persistida (122 mil linhas), ingestão automática dos certificados de participantes publicados pelo BACEN, motor de alertas com 39 tipos e histórico real de produção, trilha before/after de parâmetros e conciliação 3 vias com divergências reais provadas (inclusive R$ 2 milhões num dia). Overlaps a remover no monetarie: 3 tabelas para o mesmo fluxo na cabine (`messages` canônica vs `transactions` quase vazia vs `payments`), logs sintéticos fabricados no endpoint de monitoração e o aparato de netting sessions sem contraparte regulatória (remoção a validar com o dono). O backlog consolidado tem 5 itens P0, 18 P1 e 21 P2, cada um com esforço (S/M/L) e risco, além de 14 pendências DIVERGENTE_VALIDAR que precisam de decisão do dono.

## 2. Veredito do P0 (rota IB para Core para cabine para BACEN)

### 2.1 Conclusão

NÃO houve perda de persistência no Core. Houve consulta às tabelas erradas durante a investigação. O P0 está resolvido com evidência viva; sobram 3 defeitos reais colaterais (2 P1 e 1 P2) e 1 investigação aberta (AB03 sistemático).

### 2.2 Rota real, provada viva

Código: IB `usePix.ts:233-247` POST `/api/accounts/:id/pix/send`, `router.ex:3020`, `V2.TransferController.create_pix_account` (`v2/transfer_controller.ex:257-307`, converte centavos para base_units via `MoneyUnit.from_cents`), `OutboundOrchestrator.execute` (`outbound_orchestrator.ex:42-64`: BalanceCheck, INSERT em `outbound_requests` stage 0, hold pending no TigerBeetle, dispatch), `Outbound.Pix.send_request` (`outbound/pix.ex:150`), dispatcher de provider por entidade, `InHouse.Adapter.send_pix` (`in_house/adapter.ex:25-30`), `Publisher.publish_async` NATS `monetarie.core.pix.payment_request` (Oban `nats_publish`), cabine `SettlementService.Workers.CoreEventProcessor.handle_payment_request` (`core_event_processor.ex:190-280`: E2E obrigatório da consulta DICT cacheada, block PI, cria `monetarie_spi.messages` com `json_input` do Core, publica `transaction.created` e `outbound.send`), `OutboundSender` assina e envia o pacs.008 ao BACEN.

Vivo (logs `/ecs/monetarie/homolog/pix-api`, 2026-07-02): 01:40:20.511Z `Payment request: PIXOUT-930838e5a6e4d908`; block criado; tx 232 criada; pacs.008 HTTP 200 às 01:40:22.425; débito PI de R$ 0,01 confirmado; 01:41:02.733 pacs.002 inbound; 01:41:03 `Transaction rejected: 232`. O `json_input` das messages 232/233 confirma origem CORE (transaction_id `PIXOUT-*`, account_id, hold_id, merchant_id, chave EVP, ISPB do credor).

### 2.3 Causa raiz do falso alarme (`transactions=0` e `outbound_requests=0`)

Por desenho, `outbound_requests` é tabela de staging: na rejeição a linha é MOVIDA (DELETE + INSERT em `Repo.transaction`) para `failed_transactions` (`core/backend/lib/monetarie/use_cases/payments/outbound_requests.ex:315` `move_to_failed`; `move_to_transactions` linha 125 só na liquidação). Prova viva em `mon_core`: `failed_transactions` tem as 2 linhas (PIXOUT-930838e5a6e4d908 failed_at 01:41:03 e PIXOUT-edd1ed546768d208 failed_at 01:57:56, amount 100 base_units = R$ 0,01, failure_reason `rejected`) e `pix_out_lifecycle_events` tem 4 transições cada (created, linked_created, api_sent, rejected: estágios 0/1/2/99). `audit_logs=0` porque o caminho `AtomicPaymentHandler` (`pix_consumer.ex:172-182`, precedência sobre `PixHandler`) não grava audit log; `oban_jobs=0` por pruning de jobs completed (a cabine provou o consumo). O hold TigerBeetle do cliente FOI voidado (`void_and_fail`): sem perda de dinheiro para o cooperado.

### 2.4 Defeitos reais achados (confirmados no código nesta síntese)

1. Reason code AB03 PERDIDO fim a fim (P1): `extract_document` (`shared/bacen/iso20022/message_parser.ex:378-399`) não extrai `//TxInfAndSts/StsRsnInf/Rsn/Prtry` do pacs.002 (só `//RjctgPtyRsn` e `//RsnDesc`, que não existem no pacs.002 RJCT), então `body[:reason_code]` chega nil ao `inbound_processor.ex:1440`, o log de rejeição sai com `reason=` vazio, o evento `transaction.rejected` vai ao Core com reason_code null e `failed_transactions.reason_code` fica NULL (vivo). O IB nunca saberá por que a operação falhou, apesar de o catálogo `ReasonCodes` do Core já mapear AB03.
2. Vazamento de saldo PI na cabine (P1, money-path): `enrich_rejection_message` (`spi_service/workers/status_updater.ex:328-332`) usa `Map.put_new`, mas o evento já traz `block_id` e `amount` com valor null (`inbound_processor.ex:2321-2333`), então o `put_new` não substitui e `credit_back_and_release(nil, ...)` é pulado (`status_updater.ex:663-666`). Como o débito PI já fora confirmado no envio (`confirm_block` decrementa blocked sem creditar available, `balances.ex:352-383`), o espelho PI ficou debitado R$ 0,01 por rejeição (R$ 0,02 acumulados) sem contrapartida no BACEN. O mesmo padrão de bug atinge `handle_timeout` (linha 425, `message["block_id"]` cru).
3. Invisibilidade do rejeitado no IB (P2): extrato lê só `transactions`, em trânsito lê só `outbound_requests` (`in_transit.ex`), comprovantes só `transactions`; `failed_transactions` só aparece no endpoint de status por id (`v2/pix_controller.ex:156-173`). Coerente com os screenshots 09-in-transit-empty e 10-receipts-no-pix-receipt.

### 2.5 Investigação aberta: AB03 sistemático

2 de 2 tentativas outbound em HML foram aceitas com HTTP 200 e rejeitadas com AB03 cerca de 40 segundos depois, na liquidação. O pre-check estrutural do `OutboundSender` flagou no log vivo (01:40:21.012) `Missing CdtTrfTxInf.PmtId.TxId` e `Empty AppHdr To/Fr` e deferiu ao gate XSD. Pela regra do dono (BACEN é verdade, o defeito é nosso e tem que ser provado), tratar como defeito nosso a apurar: comparar a pacs.008 assinada real (`bacen_outbound`) com o Catálogo 5.12 (PmtId/TxId presente? AppHdr Fr/To pós-assinatura?) e validar o pareamento E2E consulta-pagamento no balde de fichas. Só encerrar com uma pacs.008 liquidada (ACSC) viva, regra 11.

### 2.6 Correção proposta (ordem de execução)

1. Parser: extrair `reason_code` e descrição do `StsRsnInf/Rsn/Prtry` (com `Cd` como fallback) no `extract_document`, com teste unitário usando a pacs.002 RJCT AB03 real arquivada.
2. Cabine: trocar `Map.put_new` por merge que trata nil em `enrich_rejection_message` e no `handle_timeout`; backfill dos R$ 0,02 no espelho PI e reconciliação periódica available vs camt.060/053.
3. Core: `AtomicPaymentHandler.handle_status` (`atomic_payment_handler.ex:51-54`) passar `payload["reason_code"]/["reason_description"]` como opts a `void_and_fail` para popular `failed_transactions.reason_code`.
4. IB/Core: incluir `failed_transactions` no extrato, comprovantes e em trânsito com status Rejeitado e motivo em português via `ReasonCodes.description` (validar com screenshot, regra 11).
5. Processo: em investigação de PIX Out sumido, consultar SEMPRE `failed_transactions` e `pix_out_lifecycle_events` além de `transactions` e `outbound_requests`; registrar no runbook/CLAUDE.md do Core. Revisar a retenção do Oban `nats_publish` (o pruning apagou a prova de publicação e causou o falso diagnóstico).

## 3. Matriz de paridade por domínio

### 3.1 D0: Rota P0 e ciclo do PIX Out no Core (19 itens)

| Feature | Legado | Monetarie | Veredito | Ação |
|---|---|---|---|---|
| Rota de envio PIX Out IB > Core > cabine > BACEN (fila assíncrona, debit-then-send) | Vendor SPI src-workers (FilaEntrada + TratamentoRetornoApiBacen); AutBank ORDEM_PAGAMENTO + PROCESSA_ORDEM_PAGAMENTO_ID_IDEMPOTENTE (4.445/4.426 linhas) | usePix.ts:233 > router.ex:3020 > v2/transfer_controller.ex:257 > outbound_orchestrator.ex:42 > in_house/adapter.ex:25 > core_event_processor.ex:190 > OutboundSender; provado vivo | PARIDADE_OK | Manter como base intocável |
| Persistência do PIX Out no Core (staging para transactions/failed_transactions) | AutBank mantém a ordem na MESMA tabela com timeline STATUS_ORDEM_PAGAMENTO | outbound_requests.ex:315 move_to_failed e :125 move_to_transactions; failed_transactions vivo com as 2 linhas + 8 transições de lifecycle | PARIDADE_OK | Falso alarme do P0; documentar no runbook a consulta a failed_transactions |
| Propagação do código de rejeição BACEN (AB03/AC06) até o registro final e o cliente | AutBank STATUS_ORDEM_PAGAMENTO.INFORMACAO_ADICIONAL com motivo por extenso (vivo no staging); vendor SpiMessageHistory.DetStatus (UtilsInterno.cs:47) | AUSENTE: message_parser.ex:378-399 não extrai StsRsnInf/Rsn/Prtry; failed_transactions.reason_code NULL vivo | MELHOR_NO_LEGADO | P1: corrigir os 3 elos (parser, repasse, Core) |
| Crédito de volta do saldo PI na rejeição pós-débito confirmado | AutBank STATUS_BLOQUEIO_ORDEM_PAGAMENTO (8.765 linhas, ciclo bloqueio/desbloqueio); vendor Multiliquidacao controla saldo espelho | status_updater.ex:328-332 Map.put_new sobre chave null pula credit_back (:663-666); 2 blocks confirmed sem credit-back vivos | FALTA_NO_MONETARIE | P1 money-path: fix do merge + backfill R$ 0,02 + reconciliação periódica |
| Visibilidade do PIX rejeitado no extrato/comprovantes/em trânsito do IB | AutBank: ordem RECUSADA continua consultável com motivo | Extrato v2/account_controller.ex:428 lê só transactions; in_transit.ex só outbound_requests; failed_transactions só no status por id | FALTA_NO_MONETARIE | P2: incluir failed_transactions nas listas com motivo pt-br |
| Histórico de transições com detalhe e XML por status | Vendor SpiMessageHistory.DetStatus/XmlMsg/DadosRetorno (02-Criacao_Tabelas.sql:92-113) | Colunas status_details/return_data/status_origin existem (transaction.ex:266) mas ficam NULL vivas | MELHOR_NO_LEGADO | P2: popular status_details e return_data em record_status_history |
| Catálogo de motivos de rejeição com flag de reenvio | Vendor SpiReason (IdReason, DsReason, FlPodeReenviar) | monetarie_spi_ref.error_codes (161 códigos, is_retriable) + Core ReasonCodes | PARIDADE_OK | Gap é o encanamento do código, não o catálogo |
| Correlação pacs.002/admi.002 com a operação original (multi-estratégia) | Vendor FindByCdMsg (MessageIdOrig/EndToEndIdOrig/IdOperacaoOrig) | inbound_processor.ex:2352-2358 find_correlated_transaction (e2e, original_message_id, resource_id, hop bacen_outbound) | PARIDADE_OK | Manter; provado vivo |
| E2E do pagamento por chave = E2E da consulta DICT (balde de fichas) | AutBank DICT_CONSULTA (11.024) amarrada a ORDEM_PAGAMENTO | core_event_processor.ex:216-231 resolve_e2e_id fail-closed via Shared.E2eCache | PARIDADE_OK | Desenho monetarie mais rigoroso; provado vivo |
| Débito antes do envio com bloqueio de saldo PI | AutBank STATUS_BLOQUEIO_ORDEM_PAGAMENTO; vendor ValidaCredito.cs | core_event_processor.ex:238-278 check_and_block_balance; confirm_block no ACK | PARIDADE_OK | Manter; único defeito é o credit-back (linha própria) |
| Liberação do hold TigerBeetle do cliente na rejeição | AutBank estorno contábil em MOVIMENTOS_CONTABEIS_* na recusa | atomic_payment_handler.ex:161-215 void_and_fail atômico e idempotente | PARIDADE_OK | Provado vivo; sem perda para o cooperado |
| Auditoria (audit_logs) dos eventos de status de PIX Out rastreado | Vendor SpiMessageHistory grava toda transição; SpiEnvioApiBacen guarda cada request/response | AUSENTE no caminho quente: AtomicPaymentHandler não chama Audit.log (só PixHandler audita); audit_logs=0 vivo | FALTA_NO_MONETARIE | P2: Audit.log no AtomicPaymentHandler.handle_status |
| Retenção de evidência de publicação NATS (outbox) | AutBank PIBR001_REGISTRO_ENVIO (60.412) e afins, permanentes | Oban nats_publish com pruning de completed apaga a prova em horas | DIVERGENTE_VALIDAR | Validar retenção 7d na queue nats_publish ou espelho em audit |
| Resposta síncrona vs assíncrona ao usuário (em processamento > estado final) | AutBank: ordem nasce ENVIADA e evolui; consulta posterior mostra final | dispatch :accepted + polling do InTransitCard (PixSendConfirmView.vue:335-420); status lê failed_transactions | PARIDADE_OK | Gap residual é a visibilidade nas listas (linha própria) |
| Registro Payment (partes pagador/recebedor) no admin da cabine | Vendor SpiPayment com debtor/creditor completos | core_event_processor.ex:567-624 create_payment_record best-effort | PARIDADE_OK | Manter |
| Rejeição AB03 sistemática em outbound HML (2/2, RJCT ~40s pós-aceite) | AutBank enviava pacs.008 aceitas (EFETIVADA na maioria); rejeições por conta (AC06) ou msg (CH16) | Pre-check flagou Missing PmtId.TxId e Empty AppHdr To/Fr (log 01:40:21.012) e deferiu ao XSD | DIVERGENTE_VALIDAR | P1 investigação (BACEN é verdade): comparar pacs.008 real vs Catálogo 5.12; encerrar só com ACSC vivo |
| Timeout interno com pacs.002 RJCT AB03 emitida por nós (SLA 10s) | Vendor controla timeout no TratamentoRetornoApiBacen; AutBank status ERRO com motivo | status_updater.ex:413-442 handle_timeout + :827-861 send_ab03_rejection | PARIDADE_OK | Dedupe com D1 (timeout); atenção ao bug de block_id cru |
| Guard de estado terminal contra pacs.002 fora de ordem | Vendor timeline monotônica em SpiMessageHistory | inbound_processor.ex:2303-2312 terminal_status? + guard_not_terminal | PARIDADE_OK | Manter |
| Dedup/idempotência de consumo de eventos (redelivery NATS) | AutBank PROCESSA_ORDEM_PAGAMENTO_ID_IDEMPOTENTE | Core MessageDedup + TB transfer_id determinístico SHA-256; cabine BaseWorker + outbox msg_id | PARIDADE_OK | Manter |
| Notificação do originador além do Core (status.rejected paralelo) | AutBank MENSAGEM_BACEN_PSP/MENSAGEM_RESPOSTA_BACEN_PSP (contrato PSP persistido) | status_updater.ex:285-291 publica monetarie.spi.status.rejected (legacy) além de transaction.rejected; consumidor não localizado | DIVERGENTE_VALIDAR | Se status.rejected não tiver consumidor, candidato a OVERLAP_REMOVER |

### 3.2 D1: Fluxo SPI outbound/inbound (33 itens)

| Feature | Legado | Monetarie | Veredito | Ação |
|---|---|---|---|---|
| Ciclo de vida outbound pacs.008 (Enviada > aguardando > Efetivada/Rejeitada) | AutBank STATUS_ORDEM_PAGAMENTO (ENVIADA 4.445 / EFETIVADA 4.304 / RECUSADA 120); vendor enumStatusOperacao | Shared.Spi.StatusCodes (1 PDNG a 10 RTRN) + status_updater.ex:33-215 + outbound_sender.ex:85-91 | PARIDADE_OK | Superior (guard monotônico + settlement idempotente); revalidar os 4 ACSP presos da fase 5 |
| pacs.028 (consulta de status) | AUSENTE nas 3 fontes (Book v111 sem builder; AutBank sem tabela) | Removida por design (outbound_sender.ex:10; não está nos XSDs v5.12) | PARIDADE_OK | Atualizar pix/CLAUDE.md que ainda cita pacs.028 (doc stale) |
| Devolução automática pacs.004 quando o crédito de entrada falha pós-liquidação | AutBank ANOTACAO_CREDITO.COD_DEVOLUCAO_PACS004 (P_GERA_ANOTACAO_CREDITO) + 690 CANCELADO reais | AUSENTE: returns só por return_request do Core ou MED | FALTA_NO_MONETARIE | P0: falha terminal de crédito settled deve publicar return_request automático |
| Crédito de entrada em duas fases (autorizar > efetivar/cancelar) | AutBank STATUS_ANOTACAO_CREDITO AUTORIZADO(8.761) > EFETIVADO(8.071)/CANCELADO(690) | F-07 two-phase PIX IN (inbound_processor.ex:730-744) | PARIDADE_OK | Manter |
| Agendamento de PIX único (execução futura, cancelamento até a execução) | AutBank ORDEM_PAGAMENTO_AGENDADO + PARAMETROS_AGENDAMENTO (4 horários, IND_BLOQUEAR_EXECUCAO) + DBs AB_GX_* | AUSENTE (greps vazios; só recorrências pain.009) | FALTA_NO_MONETARIE | P1: portar como worker + tabela no Core/IB reusando payment_request |
| Recorrência / Pix Automático (pain.009/011/012 + scheduler) | Vendor Book v111 PAIN* + Worker.Agendamento; AutBank RECORRENTE_PAIN* | spi_service/recurrences.ex + scheduler_worker + notification_worker | PARIDADE_OK | Validar só a expiração (linha seguinte) |
| Expiração diária de cobranças/recorrências | Vendor WorkerAtualizaExpiracao.cs:33-58 (1x/dia) | Parcial: qr_check no momento do pagamento (inbound_processor.ex:435-439); sem sweeper diário localizado | DIVERGENTE_VALIDAR | Se não houver job, portar sweeper diário |
| Timeout de resposta do BACEN (SLA 10s) com pacs.002 AB03 automática | Vendor TimeoutDataAceite; AutBank ERRO com motivo | status_updater.ex:863-874 timeout 10s + handle_timeout:413-442 (RJCT + credit_back + AB03) | MELHOR_NO_MONETARIE | Manter; conferir quem publica TIMEOUT_CHECK; mesmo bug de block_id cru (D0) |
| Vigilância de outbound preso sem resposta terminal | AutBank MONITOR_PROCESSOS_AUTOMATICOS + CONTROLE_RETRY; vendor filas de reprocesso | stuck_outbound_checker.ex (scan 10min, >30min, só WARNING, nunca muda status) | PARIDADE_OK | Complementar com tela/alerta de operador (ver D5) |
| Reenvio/reprocessamento automático de mensagens com falha de envio | Vendor WorkerReprocessamentoBase/Api/FIN; AutBank ORDEM_PAGAMENTO_REENVIO (0 linhas) | BaseWorker NACK/redeliver JetStream + Oban outbox retry | PARIDADE_OK | Não portar reenvio automático de pacs.008 (risco de duplicidade; tabela legada vazia) |
| Mapeamento TxSts > status interno e tratamento de status desconhecido | Vendor StatusCodeXStatusOperacao (tabela em DB) + fallback seguro PendenteVerificacaoCredito (Interpretacao.cs:52) | map_pacs002_status hardcoded (inbound_processor.ex:1481-1487); desconhecido vira nil + warning (:1450-1452), sem trilha | MELHOR_NO_LEGADO | P1: status desconhecido deve gravar MessageHistory + flag de revisão |
| Granularidade de status por estágio de pipeline (45 status do vendor) | enumStatusOperacao.cs (status de fila/cripto/worker) | 10 status ISO + MessageHistory + telemetry/DLQ | PARIDADE_OK | Não portar os ~35 status de infra |
| Idempotência de criação de ordem (camada API) | AutBank ID_IDEMPOTENTE + P_GET_ORDEM_PAGAMENTO_ID_IDEMPOTENTE (durável, janela +-1 dia) | plugs/idempotency.ex (Redis SET-NX, TTL 24h, volátil) | MELHOR_NO_LEGADO | P2: persistir Idempotency-Key em tabela unique com Redis como cache |
| Idempotência/dedup de pacs.008 inbound (retransmissão BACEN) | AutBank PROCESSA_PACS008 + END_TO_END_SENDO_TRATADO | 3 camadas: Redis dedup + advisory lock pg + unique e2e (inbound_processor.ex:120-153, 2071-2117) | MELHOR_NO_MONETARIE | Manter |
| Hold-capture no envio (bloqueio > débito > captura/estorno) | AutBank BLOQUEIO_ORDEM_PAGAMENTO ciclo completo | Debit-then-send com estorno atômico fail-closed (status_updater.ex:591-758) | MELHOR_NO_MONETARIE | Manter, base intocável |
| Transferência interna mesmo-ISPB (PIX intra-PSP sem SPI) | AutBank MOVIMENTOS_INTERNOS + PROCESSA_TRANSFERENCIA_INTERNA + 5 tabelas de suporte | AUSENTE: CoreEventProcessor monta pacs.008 sem comparar creditor_ispb com 46026562; greps vazios no core | FALTA_NO_MONETARIE | P0: short-circuit book-transfer quando creditor_ispb = ISPB próprio |
| Mensagens LPI (avisos de liquidez/limite do SPI) | AutBank MENSAGENS_LPI + PARAMETROS_LPI0005 | AUSENTE: LPI cai em process_generic; LPI0006 chega ~2/dia em HML acumulando | FALTA_NO_MONETARIE | P1: handler mínimo (classificar, persistir, alertar) |
| Alçada / aprovação de operações (parâmetros, registros, vistos) | Vendor ParametroAlcada/RegistroAlcada/VistoAlcada + status PendenteAprovacao | spi_service/alcadas.ex + telas admin | PARIDADE_OK | CRUD ok; enforcement no pipeline é lacuna própria (ver D5) |
| Multiliquidação / lote de pagamentos com aprovação em bloco | Vendor Multiliquidacao.Worker.ImportacaoArquivos + aprovação restante de lote | Parcial: FileImporter existe; sem fluxo de lote de pacs.008 com alçada em bloco | DIVERGENTE_VALIDAR | Pendência do dono (consolida com D4 importação de lote) |
| Automação de mensagens periódicas (camt.060 etc. por janela/periodicidade) | Vendor ParametroAutomacaoMensagem (CdMsg, janelas, periodicidade, canal) | CRUD + tela existem, mas SEM runner do crontab (verificado nesta síntese: zero consumidores fora do controller) | DIVERGENTE_VALIDAR | Consolida com D5: implementar runner ou rotular a tela como manual |
| Conciliação movimento a movimento e de saldos com BACEN | AutBank CONCILIACAO_MOVIMENTOS_* + CONCILIACAO_SALDOS + CONSULTA_SALDO_BACEN_SPI | reconciliation.ex (runs/matches/discrepancies) + camt.053 EOD + Oban PixStatusReconciliation no Core | PARIDADE_OK | Estrutura ok; fontes erradas tratadas em D4 (linha própria) |
| Limites por horário/valor (noturno, teto por transação/cliente-dia, dia útil, produto, contraparte) | AutBank PARAMETROS_PAGAMENTO_HORARIO + variantes por produto/contraparte/cliente | limits.ex com janelas e tetos hardcoded (@night_start 22) | MELHOR_NO_LEGADO | P2: parametrização em DB mantendo defaults (canônico; D5 referencia) |
| Calendário de feriados/praças para dia útil | AutBank FERIADOS (384 linhas vivas) + LOG_FERIADOS + PRACAS | AUSENTE | FALTA_NO_MONETARIE | Consolida com D5 (feriados, canônico lá) |
| QR/cobrança vinculada ao pacs.008 de entrada (validação antes do crédito) | AutBank QR_CODE_* + CONTROLE_PAGAMENTO_COBRANCA | qr_check antes do crédito + maybe_link_qr_payment (inbound_processor.ex:435-439, 746-751) | PARIDADE_OK | Manter (phantom-credit fix #4) |
| MED / devolução especial (cautelar, parcial) | AutBank DEVOLUCAO_ESPECIAL, MED_PARCIAL, SOLICITACAO_DEVOLUCAO + pollings | spi_service/med.ex (cautelar 72h) + camt.029 + return_processor | PARIDADE_OK | Validar caso MED parcial com saldo insuficiente; gatilho inbound é lacuna de D2 |
| admi.002 correlacionada à operação original | Vendor ErroValidacaoRetorno + Rules.TrataRetorno; AutBank MENSAGEM_ERRO | inbound_processor.ex:1033-1183 process_system_event + correlação multi-estratégia | PARIDADE_OK | Concluir fix fase 5 (BizMsgIdr, 4 ACSP presas) e revalidar em HML |
| Retorno ao sistema de origem (multi-origem) após desfecho | Vendor MsgXOriginSystem + filas por sistema legado | Eventos NATS canônicos settled/rejected com outbox atômico | PARIDADE_OK | Não portar filas por origem; NATS fan-out cobre |
| Webhook/notificação de PIX recebido para sistemas externos | AutBank RECEBIDOS_WEBHOOK + ENVIO_ALERTAS + CONTROLE_RETRY | Partner API webhooks do Core + eventos NATS + retry Oban | PARIDADE_OK | Validar que crédito settled dispara webhook de parceiro (não só envio) |
| Overlap interno: 3 tabelas para o mesmo fluxo (messages vs transactions vs payments) | n/a (defeito interno do monetarie) | monetarie_spi.messages canônica; monetarie_spi.transactions quase vazia porém usada por transaction_controller/return_controller/statements/balances; payments só em 2 pontos | OVERLAP_REMOVER | P1: apontar controllers/statements/balances para messages; aposentar transactions; avaliar fundir payments |
| Assinatura, validação XSD e sanções no outbound (fail-closed) | Vendor SignXml + CadXSD; sem screening de sanções | outbound_sender.ex:68-71 (validate > sanctions > sign > XSD pós-assinatura) | MELHOR_NO_MONETARIE | Intocável |
| Echo/teste de conectividade (pibr.001/002) e monitoramento de canal | AutBank TESTE_CONECTIVIDADE + PIBR001_REGISTRO_ENVIO; vendor builders PIBR | pibr.001/002 + process_echo_response + ChannelRouter health com failover | PARIDADE_OK | Echo periódico automático é lacuna de D3 (canônico lá) |
| Devolução outbound pacs.004 (originada por nós, até 90 dias, MED) | Vendor PACS004 builder; AutBank PACS004_REGISTRO_ENVIO + ANOTACAO_DEVOLUCAO (19 reais) | return_processor.ex:38-63 (regras P5/P6/P7, RtrId 32c, bloqueio de saldo) + return_pix v2 do Core | PARIDADE_OK | Manter |
| pacs.002 fora de ordem e liquidada real (ACSC vs STLD) | Vendor interpreta por tabela (IdStatus 4 = sucesso) | ACSC e STLD mapeiam settled (inbound_processor.ex:1475-1487) + guard terminal | PARIDADE_OK | Manter |

### 3.3 D2: DICT + MED/infração/fraude/devolução especial (27 itens)

| Feature | Legado | Monetarie | Veredito | Ação |
|---|---|---|---|---|
| Registro/exclusão de chaves (CRUD, limites 5 PF/20 PJ, EVP server-assigned) | AutBank ENDERECAMENTO (303) + agendados; vendor IncluiChaveDTOUseCase/ExcluirChaveUseCase | keys.ex:31-36 (@key_limits), :69, :299, :1100 + operação externa correlacionada | PARIDADE_OK | Manter; EVP com Key vazio validado vivo |
| Ciclo OUTBOUND de reivindicação/portabilidade (5 ações) | AutBank CLAIM_OWNERSHIP/PORTABILITY (12 reais); vendor UnitOfWorkRecepcao/AlteracaoReivindicacao | claims.ex:77-308 (estados + prazos D+14/D+30 + transferência da chave) | PARIDADE_OK | Manter |
| Descoberta de reivindicações RECEBIDAS (polling como doador) | AutBank RECEBER_REIVINDICACAO_AGENDADA + CONTROLE_POLLING_DICT; vendor FilaWorkerBuscaSolicitacao.cs | AUSENTE: application.ex:26-38 só sobe CidSync + responders; único produtor inbound é o simulador | FALTA_NO_MONETARIE | P0: worker periódico list_claims (client já existe, dict_client.ex:432) |
| Timers automáticos do ciclo de claim (D+7/D+14/D+30) | Vendor FilaWorkerQuarentena*/Conclui*/Cancela*; AutBank NOTIFICACAO_REIVINDICADOR_POSSE_15_DIA | claims.ex:1156-1179 agenda via NATS Deliver-After; auto_confirm/auto_cancel (:421/:462) SEM nenhum consumidor (código morto) | FALTA_NO_MONETARIE | P0: consumer JetStream ou Oban cron chamando as funções prontas |
| Validação de posse de chave (OTP email/telefone) | Vendor ValidaProtecaoUseCase.cs; AutBank valida no canal | ownership_controller.ex: TODOS os 5 endpoints retornam 501 (verificado) | FALTA_NO_MONETARIE | P1: implementar OTP e amarrar a create_entry e complete_claim (obrigação do Manual DICT) |
| Retry/reconciliação de operações DICT externas com desfecho desconhecido | AutBank padrão *_AGENDADO/_ERRO + CONTROLE_RETRY | dict_external_reconciler.ex (9 tipos) + Oban cron */2min | MELHOR_NO_MONETARIE | Manter |
| CID sync (full + eventos) e verificação de sincronismo (VSync) | AutBank VERIFICA_SINCRONISMO + VSYNCS; vendor SincronismoUseCase | cid_sync_service.ex (full 6h + eventos 5min + POST /sync-verifications :532-556); validado vivo | PARIDADE_OK | INTOCÁVEL |
| Relato de infração OUTBOUND (criar/acknowledge/analisar/fechar/cancelar) | AutBank RELATO_DE_INFRACAO (391 reais); vendor IncluirInfracaoDTOUseCase | infractions.ex (estados DICT 2.11) + dict_client.ex:587-826 assinados | PARIDADE_OK | Manter; lado respondente é a linha seguinte |
| Polling de relatos de infração RECEBIDOS | AutBank CONTROLE_POLLING_RELATO_DE_INFRACAO + MSG_RELATO_RECEBIDA; vendor BuscaRelatoInfracaoUseCase | AUSENTE como automação (client list existe, nenhum worker materializa/acknowledge) | FALTA_NO_MONETARIE | P0 (com o polling de claims): prazo regulatório de acknowledge |
| Solicitação MED RECEBIDA > claim + bloqueio cautelar automático do respondente | AutBank CONTROLE_POLLING_SOLICITACAO_DEVOLUCAO + SOLICITACAO_DEVOLUCAO (205) + PROCESSA_MED | Máquina completa pronta (med.ex cautelar/parcial/cadeia + TimerEnforcer) mas create_fraud_claim tem ZERO chamadores de produção | FALTA_NO_MONETARIE | P0: poller inbound > create_fraud_claim > apply_cautelar/partial_block |
| MED 2.0 bloqueio parcial + bloqueio em cadeia (multi-hop) | AutBank MED_PARCIAL (0 rows, 1 hop) | med.ex:115-160 partial + chain_blocker.ex (5 hops, Res BCB 493/2025) + tracking_graph | MELHOR_NO_MONETARIE | Manter; só ligar o gatilho inbound |
| Devolução especial OUTBOUND (refund via DICT) | AutBank DEVOLUCAO_ESPECIAL (373) + FALLBACK_FECHAR | funds_recovery.ex + dict_client.ex:827-1024 + reconciler cobre o fallback | PARIDADE_OK | Manter |
| Marcação de fraude com persistência local e vínculo ao relato | AutBank MARCACAO_FRAUDE (8; ID_RELATO_INFRACAO) | Submissão assinada ok (admin/fraud_controller.ex) mas SEM schema local; consulta sempre ao vivo | DIVERGENTE_VALIDAR | Validar portar espelho local (id BACEN, status, vínculo com relato) |
| Estatísticas antifraude de chave/dono servidas de verdade | AutBank ESTATISTICA_CHAVE/DONO (espelho de 90+ colunas); vendor StatisticsUseCase | Transporte v2.11 pronto (dict_client.ex:1269/1287) mas statistics_controller.ex devolve MOCK hardcoded (verificado: comentários "In a real implementation") | FALTA_NO_MONETARIE | P1: ligar controller aos dados reais; dados falsos são pior que ausência |
| Listas locais de restrição por infração | AutBank RESTRICAO_INFRACAO_PF/PJ_0..9 (40 tabelas sharded, 1 row) | AUSENTE | FALTA_NO_MONETARIE | Validar com o dono; se sim, flag agregada derivada (não 40 tabelas) |
| Bloqueio judicial/administrativo de chaves com histórico | AutBank CHAVES_BLOQUEIO_JUDICIAL (0 rows) | keys.ex:347-462 block/unblock + blocked_until + block_events + rotas admin | MELHOR_NO_MONETARIE | Manter |
| Gestão client-side dos baldes de fichas DICT do BACEN (orçamento + restituição por pagamento) | AB_..._BALDES_DICT.PARAMETROS_BALDE_DICT (25+ baldes; consulta participante 8000 fichas, restitui 1 por pagamento; PF 200/penal 10) | AUSENTE no sentido outbound (DictRateLimit é só inbound) | FALTA_NO_MONETARIE | P1: contador Redis por balde relevante + restituição no settled |
| Rate limit INBOUND por categoria + por PayerId + penalidade 404 | AUSENTE no legado (não serve API DICT a terceiros) | dict_rate_limit.ex:31-177 (categorias A-H, per-payer 1/10, anti-enumeração) | MELHOR_NO_MONETARIE | Manter; ortogonal aos baldes outbound |
| Cache/read-model de consulta DICT com TTL e reuso por QR | AutBank CONSULTA_DICT_RESPOSTA (34; TEMPO_VALIDADE_SEGUNDOS, PROCESSADO_QR_CODE) | lookup_entry_via_bacen descarta a resposta; correlação só via E2eCache Redis 5min | DIVERGENTE_VALIDAR | Validar portar tabela dict_lookups para comprovante/antifraude |
| Grade horária / janela de funcionamento DICT por categoria | AutBank DICT_GRADE_HORARIA (A/B 24h, C 08:00-19:59) + restrições | AUSENTE | FALTA_NO_MONETARIE | Consolida com D5 (grade horária); necessário antes de portabilidade self-service no IB |
| Estatísticas próprias de operação (monitoração) | AutBank ESTATISTICA_CONTA/DONO_HISTORICO + MSG_ESTATISTICAS | dashboard.ex + metrics_controller + WebSocket dict:operations | PARIDADE_OK | Manter |
| Auditoria de mensagens DICT enviadas/recebidas por domínio | AutBank 16 tabelas MSG_*_ENVIADA/RECEBIDA | shared/audit (retenção 2 anos DICT, 10 anos ICOM, SHA-256, export JSONL) | PARIDADE_OK | Manter |
| Checagem de chaves em lote (CheckKeys <=200) | AB baldes FICHAS_PARTICIPANTE_CHECAGEM_CHAVES | dict_client.ex:1196 check_keys + rota | PARIDADE_OK | Contabilizar no balde outbound se o item de baldes for portado |
| Políticas DICT (GET /policies) | AB baldes FICHAS_POLICIES_* + MSG_POLITICA | AUSENTE no dict_client | FALTA_NO_MONETARIE | P3: útil para calibrar baldes automaticamente |
| Disputa (modelo antigo pré-MED) | AutBank DISPUTA (0 rows) | Substituído por infraction_reports + refunds + funds_recovery (MED 2.0) | OVERLAP_REMOVER | Não portar; absorvido pelo MED 2.0 |
| Versionamento/vigência da versão DICT e catálogo | AutBank PARAMETROS_VIGENCIA_VERSAO_DICT | Versão pinada em código (v2.11.0 / 5.12) | DIVERGENTE_VALIDAR | Registrar como decisão consciente (deploy por transição) |
| Histórico de mudanças de chave (versões da entry) | AutBank ENDERECAMENTO_HISTORICO/EVENTOS | Parcial: block_events + eventos NATS (7d) + cid_events | DIVERGENTE_VALIDAR | Validar exigência de compliance; se sim, tabela de snapshot simples |

### 3.4 D3: Assinatura/cripto/certificados/canais (24 itens)

| Feature | Legado | Monetarie | Veredito | Ação |
|---|---|---|---|---|
| Ordem persistência antes do ACK no long-poll ICOM (dedup + recuperação) | Vendor ReceiveService.cs:32-100 + persistência com PIResourceId | icom/cpm/worker.ex:53-61,338-423 + ack_tracker.ex:55-140 (invariante formal, dedup por message_id, republish no boot) | MELHOR_NO_MONETARIE | Intocável |
| Kills crônicos do CPM: watchdog mata worker em long-poll legítimo | Vendor roda poll em thread dedicada e julga por código de retorno (WorkerEntradaAPIBase.cs:46-92) | health_monitor.ex:64 (@worker_call_timeout_ms 5_000) mata "unresponsive" (:167-173) enquanto o pull inline usa receive_timeout 60s (client.ex:369) (verificado) | MELHOR_NO_LEGADO | P1: heartbeat via ETS antes/depois do Finch.request ou pull em Task supervisionada |
| Detecção de slot travado por idade do último ACK | AUSENTE no vendor (recuperação por Environment.Exit) | health_monitor.ex stuck 5min por last_ack_at | MELHOR_NO_MONETARIE | Manter; corrigir só o ramo unresponsive |
| Teste de conectividade periódico com evidência persistida (pibr.001/002) | AutBank TESTE_CONECTIVIDADE (122.245 linhas; 576/dia; enviados 61.840 vs recebidos 60.405) | AUSENTE como rotina (pibr manual só) | FALTA_NO_MONETARIE | P1: worker de echo por canal com evidência + métrica de echoes sem resposta (canônico; D5 referencia) |
| Health de canal ativo vs passivo (probe real vs estado de circuito) | AutBank probe real 5/5min; vendor Reconnect explícito | channel_router.ex:262-300 health_check só loga estados | FALTA_NO_MONETARIE | Ligar o echo periódico ao CircuitBreaker (half_open) |
| Ingestão automática dos certificados de participantes publicados pelo BACEN | AutBank DOWNLOAD_CERTIFICADOS_SITE (110 arquivos) + THUMBPRINT_SITE (263 ATIVOs) | cert_materializer.ex:27-31,54-55 só hidrata PEERPIA do BACEN; upload manual no admin | FALTA_NO_MONETARIE | P1: reusar trilha A do SPB (bacen_domain_certificates + refresh sem restart); antes, provar em HML um inbound assinado por outro PSP |
| Snapshot/histórico diário de certificados de peers | AutBank THUMBPRINT_SITE_HISTORICO (53.183 linhas) | AUSENTE | FALTA_NO_MONETARIE | P3: job diário de snapshot |
| Seleção de cert de verificação por janela de validade e data da mensagem (dtMsg) | Vendor CertificateReaderUseCase.cs:22-42 + ValidationRepository (InicioValidade<=now<=FimValidade) | certificate_pool.ex:247-260 filtra APENAS is_active | MELHOR_NO_LEGADO | P2: filtro por validade + CreDt do AppHdr (evita falso DS01 em rotação) |
| Modelo de revogação (CRL URL e status por cert de peer) | AutBank THUMBPRINT_SITE.URL_CERTIFICADOS_REVOGADOS + CERT_STATUS; vendor ServerCertificate.cs | AUSENTE (nenhuma referência a CRL/OCSP) | FALTA_NO_MONETARIE | P3: modelo de dados + job de conferência |
| Rotação quente do cert mTLS de conexão (CPIC) sem restart | Vendor LocalCertificateSelectionCallback relê cert ATIVO por handshake | CPIC cozida nas conn_opts do Finch no boot (cert_materializer.ex:69-104) | MELHOR_NO_LEGADO | P2: portar padrão OurCertStore do SPB (pickup sem restart), sem tocar o formato validado |
| Validação do certificado do servidor BACEN no mTLS outbound | Vendor whitelist de thumbprint em DB | application.ex:194-241 verify_peer + cadeia ICP-Brasil + hostname check + partial_chain | MELHOR_NO_MONETARIE | Intocável |
| Assinatura XMLDSig outbound (3 References, exc-c14n, RSA-SHA256) | Vendor SignedXml in-process (chave em memória) | xml_signer.ex:49-104, 262-272 (xmllint), 359-360 (HSM RTM por chamada) | MELHOR_NO_MONETARIE | Intocável (chave nunca sai do HSM) |
| Verificação XMLDSig inbound SPI fail-closed | Vendor valida mas config permite DESLIGAR | inbound_processor.ex:293-341 fail-closed DS01 para 9 tipos + xml_verifier.ex | PARIDADE_OK | Diferença de dtMsg tratada em linha própria |
| Verificação de assinatura das respostas DICT | Vendor infra completa de verificação no domínio DICT | verify_dict implementado (xml_verifier.ex:50-62) com ZERO callers | DIVERGENTE_VALIDAR | Ligar verify_dict ou registrar aceitação de risco (canal mTLS) formalmente |
| Compressão gzip no tráfego com o BACEN | Vendor POST gzip + Accept-Encoding gzip | client.ex:356-357 pede identity no pull; sem compressão outbound | MELHOR_NO_LEGADO | P3: avaliar gzip outbound atrás de flag; documentar decisão do identity |
| Limitador de TPS configurável por janela horária no envio | Vendor LimitaTransacao (LimiteTransacoesHorario) | AUSENTE no outbound SPI | FALTA_NO_MONETARIE | P3: config de runtime no OutboundSender (batch_size 100 fixo hoje) |
| Envio multipart em lote agrupado por ISPB | Vendor EnviaMultipart (UnitOfWorkEnvioApiBase.cs:376-430) | Um POST por mensagem (outbound_sender.ex:64-118) | MELHOR_NO_LEGADO | P3: otimização futura com flag; não mexer agora |
| Persistência e retomada da sessão long-poll (PI-Pull-Next) entre restarts/pods | Vendor PIResourceIdNext persistido | worker.ex:160-199 resume por icom_sessions + coordinator.ex (líder por advisory lock) | MELHOR_NO_MONETARIE | Manter |
| Estratégia de recuperação de erro do canal (backoff vs fail-fast) | Vendor Environment.Exit(1) + pausa fixa | Backoff exponencial com jitter + alarme + self-heal (worker.ex:509-578) | MELHOR_NO_MONETARIE | Garantir consumer do alarme (linha seguinte) |
| Fila de alerta operacional integrada ao pipeline | Vendor _envioAlerta commitado mesmo em rollback | Eventos :telemetry sem sink de operador comprovado | DIVERGENTE_VALIDAR | Verificar handler; se não houver, durabilizar alerta (consolida com motor de alertas de D5) |
| mTLS inbound (whitelist origem/thumbprint) para consumidores internos | Vendor CertificateMiddleware + ValidationRepository | AUSENTE em PIX (JWT + rede privada) | DIVERGENTE_VALIDAR | Validar com o dono se parceiro white-label exigirá mTLS de cliente |
| Host header sem porta e HTTP/1.1 no canal BACEN | Vendor força Host e Http11 | build_finch_request injeta Host sem porta (root-cause fix validado vivo) | PARIDADE_OK | Intocável |
| Monitoramento de vencimento de certificados próprios (30d/7d) com tela | AutBank THUMBPRINT_SITE validade + AdmWeb | certificate_manager_admin.ex:271-303 check_expiry + CertificatesView.vue | PARIDADE_OK | Gatilho periódico + alerta é lacuna de D5 (cross-ref) |
| Espelho de inbound ICOM no monitor dentro do caminho pré-ACK | Vendor separa logs em filas fora da unidade principal | ack_tracker.ex:88-93,153-184 mirror síncrono por linha no persist_batch | MELHOR_NO_LEGADO | P3: mover o espelho para depois do ack (async/batch) |

### 3.5 D4: Liquidação, extrato, conciliação e relatórios (25 itens)

| Feature | Legado | Monetarie | Veredito | Ação |
|---|---|---|---|---|
| Download do arquivo de extrato BACEN (RELACAO_LANCAMENTOS.csv) após camt.052 de retorno | Vendor CAMT052/v11.cs:39-96 (URLDOWNLOADARQUIVOSEXTRATOS + {ISPB}/{arquivo}, unzip, LogDownloadArquivos) | AUSENTE: dispatcher inbound sem case camt.052 (verificado, cai em process_generic); FileImporter sem publishers nem unzip/parse | FALTA_NO_MONETARIE | P1: handler camt.052 + download mTLS + unzip + parse + log de download (desbloqueia tx 199) |
| Tela/API de downloads de arquivos de extrato | Vendor LogsController.cs:120-160 (listar, baixar ZIP, excluir) | AUSENTE | FALTA_NO_MONETARIE | P2: junto com o item anterior |
| Conciliação diária de movimentos 3 vias (BACEN vs interno) | AutBank CONCILIACAO_MOVIMENTOS_* + DIVERGENTES com 20 linhas vivas (só BACEN=1, só PSP=12, valor distinto=7) | reconciliation.ex:323-338 compara tabela praticamente vazia vs camt.053; em prod sem camt.053 devolve "cannot reconcile" | MELHOR_NO_LEGADO | P1: manter o esqueleto e trocar as fontes (messages liquidadas vs arquivo de extrato) com as 3 categorias |
| Conciliação diária de SALDO persistida por data | AutBank CONCILIACAO_SALDOS (divergência real de -2.019.995,00 em 2025-12-30) | update_confirmed_balance só LOGA warning (balances.ex:740-769) | FALTA_NO_MONETARIE | P1: gravar linha por data (interno, BACEN, diff, conciliado) + tela/alerta |
| Remuneração da Conta PI (camt.053 CRE) | AutBank REMUNERACAO_SPI (143 dias) + PROCESSA_REMUNERACAO_CAMT053 | Parser extrai REMN/PSSR (camt053_parser.ex:68-69) mas NINGUÉM persiste | FALTA_NO_MONETARIE | P2: tabela de remuneração + controle diário + admin |
| Snapshot diário EOD de saldo da Conta PI | AutBank SALDO_CONTA_PI (215 snapshots) | calculate_opening_balance retorna 0.00 hardcoded (statements.ex:447, verificado) | FALTA_NO_MONETARIE | P2: job EOD (ispb, data, saldo) |
| Fonte de dados dos statements camt.052/053 gerados | AutBank monta do movimento real (EXTRATO_MOVIMENTO_GI, 13.250 staged) | statements.ex:51-55,134-139 usam monetarie_spi.transactions (quase vazia) | DIVERGENTE_VALIDAR | Consolida com D1 (overlap 3 tabelas): apontar para messages |
| CAMT.060: as 7 consultas Conta PI | Vendor ConversaoObjetos (mapa por ação) | camt060.ex:24-32 (@camt060_spec) provado vivo 6/7 | PARIDADE_OK | INTOCÁVEL na requisição; gap é o retorno-arquivo (linhas 1 e 16) |
| Materialização de saldo SADP/SABK com proveniência honesta | AutBank BALANCO_SALDO_SPI (1.382, guarda cada retorno cru) | inbound_processor.ex:1539-1611 + upsert_position com source honesto | PARIDADE_OK | Manter |
| Trilha contábil da cabine PIX (plano de contas + lançamentos) | AutBank MODELOS/CONDICOES/OPERACOES_CONTABEIS + 10 tabelas MOVIMENTOS_CONTABEIS_* + filas de erro | chart_of_accounts SEM seed; maybe_create_journal_from_event engole falha com else _ -> :ok (accounting.ex:181-201) | MELHOR_NO_LEGADO | P2 decisão do dono: semear COSIF fail-fast OU remover a trilha da cabine (Core já é a contabilidade oficial); nunca deixar meio-morto silencioso |
| Relatórios contábeis regulatórios/gerenciais + relatório de conciliação | AutBank CONTROLE_RELATORIO_CONTABIL_* + CONCILIACAO_SALDO_PIX | generator.ex:240-248 só COMPLIANCE/STATEMENT/AUDIT/QRCODE | FALTA_NO_MONETARIE | P3: 2 tipos novos no catálogo (CONTABIL, CONCILIACAO) |
| APIX001 (arquivo mensal regulatório) | Vendor ConsultaAPIX001_* (SQL) | Shared.Apix.SpiCalculator (port explícito) + apix.ex + serializer | PARIDADE_OK | Validar 1º arquivo pós-fix dos mapas status_id (fase 5); D5 referencia (massa RELATORIO_MENSAL) |
| Máquina de estados Multiliquidação (enumTipoSituacao 1-100) com erros granulares | Vendor enumTipoSituacao (erro débito=96, erro crédito=97, contingência) + HistSituacaoOperacao | status 1-10 + status_history + hold/release TB no Core | DIVERGENTE_VALIDAR | Validar remediação equivalente para cada estado de erro (especialmente crédito pós-liquidação) |
| Importação de arquivo de pagamentos em lote do cliente | Vendor Multiliquidacao.Worker.ImportacaoArquivos + status por arquivo e linha | AUSENTE (FileImporter só arquivos BACEN) | FALTA_NO_MONETARIE | Pendência do dono (consolida com D1 multiliquidação): renascer como lote na Partner API ou morrer |
| Agendamento e recorrência de pagamentos | Vendor Worker.Agendamento + enumTipoSituacaoRecorrencia | Recorrências pain.009 + scheduled jobs | PARIDADE_OK | Dedupe com D1 (recorrência ok; agendamento único é a lacuna, linha própria em D1) |
| TIR: demonstrativo/total de tarifa de intercâmbio (arquivo) | Vendor SUBDIRETORIOTIR + TIRRepository + telas | Requisição TRD/TRT provada viva; retorno-arquivo não processado; sem tela | FALTA_NO_MONETARIE | P3: rotear por Prtry após o pipeline de download existir |
| Extrato por cliente com semântica PIX rica (devolução, saque/troco, MED, iniciadora) | AutBank EXTRATO_MOVIMENTO_GI (50+ colunas) | Extrato de cliente vive no Core (materialização NATS); cabine tem statement_entry nível participante | DIVERGENTE_VALIDAR | Validar que o extrato Core carrega saque/troco, e2e original + motivo, CNPJ iniciadora, motivo MED |
| Trilha de mensagens do ciclo de reconciliação (payloads crus) | AutBank MSG_RECONCILIACAO_ENVIADA/RECEBIDA (1.341+1.341) | xml_audit_logs com SHA-256 e retenção 10 anos | PARIDADE_OK | Garantir que downloads futuros também sejam audit-referenciados |
| Dashboard horário de movimento (valor/quantidade + hora sem movimento) | AutBank RESULTADO_GRAFICO(+DETALHE) (5.159 pontos, STATUS_HORA) | Monitoring de saúde/latência superior, mas sem série horária de valores com flag de hora morta | DIVERGENTE_VALIDAR | Validar telas do pix-admin; se ausente, widget barato sobre messages |
| Alerta de saldo da Conta PI (threshold) | AutBank CONTROLE_ALERTA_SALDO | Enforcement de reserva mínima existe (balances.ex:104-136) mas sem alerta preventivo | FALTA_NO_MONETARIE | P3: threshold configurável + evento no monitor (consolida com motor de alertas D5) |
| Conciliação de previsões na interface com o legado contábil (AB_MGI) | SP_CONCILIA_PREVISAO (ab_mgi_modules.sql:3243) | AUSENTE na cabine (conceito de previsão de caixa não existe) | DIVERGENTE_VALIDAR | Validar no domínio Core/SPB (funding da Conta PI/Reserva) |
| Exportação de extrato multi-formato para o participante | AUSENTE no legado | statements.ex:19,268-296 (xml/json/csv/pdf/ofx/qif/mt940 com checksum) | MELHOR_NO_MONETARIE | Manter; valor real depende de corrigir fonte + opening balance |
| Bloqueio/desbloqueio de saldo PI com confirmação pós-liquidação | Legado bloqueava a OPERAÇÃO (Multiliquidação), não o saldo PI local | balances.ex:224-387 create/release/confirm_block | MELHOR_NO_MONETARIE | Manter, base intocável |
| Netting/sessões de liquidação internas da cabine | AUSENTE no legado (PIX é liquidação bruta em tempo real) | netting_positions/transactions + settlement_sessions + workers | OVERLAP_REMOVER | A validar com o dono: sem ciclo de netting BACEN para participante direto; hoje só confunde a reconciliação |
| Controle de extração/expurgo do extrato | AB_..._EXPURGO.CONTROLE_EXTRACAO_EXTRATO_TIPO | Partições + retention no audit; statements sem política explícita | DIVERGENTE_VALIDAR | Consolida com D5 (expurgo/tiering) |

### 3.6 D5: Administração e operação (32 itens)

| Feature | Legado | Monetarie | Veredito | Ação |
|---|---|---|---|---|
| Alçada: cadastro de parâmetros (faixa, N vistos, janela, tipos) com telas | Vendor ParametroAlcada.cs + telas | parameter.ex + alcadas.ex + ApprovalLimitsView.vue | PARIDADE_OK | Manter (dedupe com D1 alçada) |
| Alçada: enforcement no pipeline de envio (operação retida até aprovação) | Vendor WorkerPosAlcada + ValidacaoAlcadaRepository (mandatório) | check_and_register só no POST /alcada/check (advisory); zero referências no outbound | FALTA_NO_MONETARIE | P1: gate pending_alcada antes do OutboundSender |
| Alçada: limite por valor ACUMULADO no período + data-base overnight | Vendor VlrAcumulado + ObtemDataBase() | Campo accumulated_amount existe e é IGNORADO (matches_amount? só min/max, alcadas.ex:181-185) | MELHOR_NO_LEGADO | P1 (junto com enforcement): regra anti-fracionamento |
| Alçada: verificação por período dias úteis/não úteis | Vendor enumPeriodoVerificacao | AUSENTE (sem campo nem calendário) | FALTA_NO_MONETARIE | P2: depende de feriados |
| Alçada: aprovadores restritos por usuário/grupo + email | Vendor UsuariosAprovadores/GruposAprovadores + email | Qualquer usuário com permissão (só cannot_self_approve); sem notificação | MELHOR_NO_LEGADO | P2: lista de aprovadores por parâmetro + notificação; manter o guard de self-approve |
| Motor de alertas operacionais (catálogo, limiares, destinatários, histórico) | AutBank ALERTAS (39 tipos) + PARAMETROS_GERENCIAMENTO + ENVIO_ALERTAS + HISTORICO_ALERTAS (alerta 32 disparou 1.405x) | 2 checks derivados em request-time; acknowledge no-op; Swoosh sem nenhum deliver | FALTA_NO_MONETARIE | P1: portar o padrão sobre telemetry + Broadcaster + Oban cron + Swoosh |
| Alertas parametrizáveis por participante indireto | AutBank PARTICIPANTE_INDIRETO_PARAMETROS_ALERTAS | AUSENTE | FALTA_NO_MONETARIE | P3: junto com o motor de alertas (roadmap indireto) |
| Alertas por mensagem com filtros e usuários mapeados (inbox) | Vendor ParametroAlertaMsg + MarcaAlertaTelaLido | AUSENTE (sem sino/inbox no admin) | FALTA_NO_MONETARIE | P3: assinatura por message_type + filtro sobre o stream NATS |
| Alerta de vencimento de certificados automático | AutBank ALERTAS 19-24 + VENCIMENTO_CERTIFICADO (dias) | check_expiry existe mas só sob demanda; sem job nem email | DIVERGENTE_VALIDAR | P1 (dentro do motor de alertas): agendar check diário (episódio T010/EGEN9907 prova o valor); cross-ref D3 |
| Trilha de auditoria de parâmetros before/after por coluna | AutBank 14 tabelas LOG_PARAMETROS_* (55 alterações reais auditadas) | AuditLogger grava só a request nova; SystemConfig sem histórico | MELHOR_NO_LEGADO | P2: capturar changes + valores originais para configs/alçada/fees/jobs/certs |
| Auditoria de atividade de usuário (ações, IP, user-agent) com tela | Vendor LogAtividade + funcionalidades 50/63 | monetarie_auth.audit_logs via plug automático + AuditLogsView | PARIDADE_OK | Manter |
| Retenção regulatória 10 anos com purge automático e particionamento | Vendor ParametroExpurgo configurável; AutBank move para DB _EXPURGO | xml_audit_log.ex retention_years=10 + PartitionManager diário | MELHOR_NO_MONETARIE | Não regredir para retenção configurável em dados BACEN |
| Expurgo OPERACIONAL configurável com janela, histórico e arquivamento frio | AutBank DB _EXPURGO completo (configuração, execução, réplica) | Tier frio "GCS (future)" não implementado (xml_archiver.ex:11-13); Oban Pruner 7d fixo | FALTA_NO_MONETARIE | P3: arquivamento S3 com janela configurável e log, mantendo o piso de 10 anos imutável |
| Cadastro de feriados (praça, tipo, variável) com trilha | AutBank FERIADOS (384 vivas) + LOG_FERIADOS + PRACAS; vendor Feriado.cs | AUSENTE; cobv_calculator.ex:55 retorna business_day_calendar_unavailable por design | FALTA_NO_MONETARIE | P1 canônico (D1 referencia): tabela + tela + import das 384 linhas do staging; destrava CobV dia útil |
| Grade horária DICT por serviço (categorias A-D, manutenção) + restrição por data | AutBank DICT_GRADE_HORARIA + DICT_SERVICO_GRADE_HORARIA + RESTRICAO | AUSENTE | FALTA_NO_MONETARIE | P3 canônico (D2 referencia): config de janelas consultada pelos workers DICT |
| Grade horária de pagamentos: VLR_MAX por janela e dia útil (limite noturno) | AutBank PARAMETROS_PAGAMENTO_HORARIO(+CLIENTE) + LOG | AUSENTE na cabine como parametrização | MELHOR_NO_LEGADO | Consolida com D1 (limites): validar se o Core cobre o noturno antes de duplicar |
| Automação de mensagens periódicas com execução automática | Vendor ParametroAutomacaoMensagem + worker TarefasAutomaticas; AutBank SCHEDULER + SHEDLOCK | CRUD + tela + run_now, mas NENHUM runner consome o crontab (verificado nesta síntese) | DIVERGENTE_VALIDAR | P2: runner no padrão Reports.ScheduleWorker ou rotular a tela como manual (canônico; D1 referencia) |
| Relatórios gerenciais: templates, geração real, agendamento, custom | Vendor Report + Layout/Estrutura; AutBank CONTROLE_RELATORIO_* (16 tipos) | reports_controller + ScheduleWorker hourly + 9 telas | PARIDADE_OK | Mapear tipos faltantes (volumetria, conciliação, reprocessamento) como templates novos |
| Relatório mensal regulatório de estatísticas PIX (APIX001) | AutBank RELATORIO_MENSAL (13 reais: fraude, P50/P99, disponibilidade) | apix_controller (calcula/gera/exporta XML) | DIVERGENTE_VALIDAR | Usar os 13 RELATORIO_MENSAL como massa de validação pós-fix status_id (cross-ref D4) |
| Monitor de operações e Central de Mensagens com XML | Vendor func 5 + Repositories.LOG + TraduzXML | monitor_controller (RBAC, janelas 5m-7d) + MessageCenter/XmlViewer | PARIDADE_OK | Manter |
| Monitoração em tempo real via WebSocket (tx, saúde, filas, canais, SLA) | AUSENTE como push no legado | monitoring_channel (7 tópicos) + broadcaster + ans_monitor (SLA 1600ms) | MELHOR_NO_MONETARIE | Manter; base para o motor de alertas persistentes |
| Status de workers por instância (última execução/erro por rotina) | Vendor StatusServicoGrid (17 tipos); AutBank MONITOR_PROCESSOS_AUTOMATICOS | HealthChecker cobre serviços; workers individuais sem registro consultável em tela | DIVERGENTE_VALIDAR | P3: expor execuções Oban por worker (sucesso/erro/duração) |
| Logs de serviço exibidos na tela de saúde | Legado exibe logs reais | build_service_log_entries FABRICA logs sintéticos com crypto rand (monitoring_controller.ex:301-309) | OVERLAP_REMOVER | P2: remover mock; ligar fonte real ou vazio honesto (viola regra do dono de zero dado fabricado) |
| Reconhecimento (ack) de alertas persistido por usuário | Vendor MarcaAlertaTelaLidoMsg | acknowledge_alert responde ok sem persistir (no-op) | MELHOR_NO_LEGADO | Resolver dentro do motor de alertas persistentes |
| Monitor de não-integradas/não-processadas com reprocesso (DLQ) | Vendor funcs 67-70 + ListaMonitorNaoIntegradas | dlq_controller (list + replay JetStream) + StuckOutboundChecker + reprocesso admin no Core | PARIDADE_OK | Puxar o StuckOutboundChecker para tela/alerta (cross-ref D1) |
| Teste de conectividade automático com alerta de falha | AutBank TESTE_CONECTIVIDADE_AUTOMATICO + alerta 32 (1.405 disparos, o mais usado em produção) | Echo pibr validado manualmente; nenhum probe agendado | FALTA_NO_MONETARIE | Consolida com D3 (echo periódico, canônico lá) + alerta em falha |
| Gestão de usuários, grupos, permissões, senha, MFA, API clients | Vendor SecurityManager (300+ funcionalidades) | security/* views + RequirePermission + MFA TOTP + api_clients | PARIDADE_OK | Não portar o enum gigante; module+action basta |
| Controle de acesso por IP de origem e certificado autorizado | Vendor OrigemAutorizada/DestinoAutorizado/CertificadoAutorizado | Tela persiste security_ip_restrictions mas nenhum plug aplica por request (só rate_limit usa remote_ip) | DIVERGENTE_VALIDAR | Validar camada externa (SG/VPN); implementar o plug ou remover a tela |
| Buckets de rate-limit DICT com visão e reset por participante | AutBank DB BALDES_DICT (20 tabelas FICHAS_*) | dict_rate_limit.ex + GET bucket/POST reset admin | PARIDADE_OK | Manter (baldes outbound é lacuna de D2) |
| Tela de parâmetros do legado no admin | AutBank PARAMETROS_SISTEMA (60+ chaves) | LegacyParametersView.vue = empty state honesto sem backend | FALTA_NO_MONETARIE | P3: mapear e expor os parâmetros operacionais com trilha |
| Dashboard gerencial com gráficos e saldos | Vendor FiltroDashBoard; AutBank RESULTADO_GRAFICO | DashboardView + BalanceDashboard + AccountingDashboard + StatisticsView | PARIDADE_OK | Manter |
| Sessões de liquidação: abertura/fechamento/cancelamento | Vendor funcs 15/158 | session_controller + SessionListView | PARIDADE_OK | Alteração de horário de grade (func 158): cobrir no domínio SPB |
| i18n do console administrativo | Angular pt + poucos | 5 idiomas (pt-BR, en-US, es-ES, fr, zh-HK) | MELHOR_NO_MONETARIE | Manter |

## 4. Backlog priorizado

Esforço: S (até 1 dia), M (2 a 5 dias), L (mais de 1 semana). Risco: impacto de regressão sobre o caminho validado vivo.

### P0 (regra de negócio ausente com efeito de dinheiro/prazo regulatório)

| # | Item | Domínio | Esforço | Risco |
|---|---|---|---|---|
| P0-1 | Transferência interna mesmo-ISPB: short-circuit book-transfer no CoreEventProcessor/Core quando creditor_ispb = 46026562 (hoje PIX intra-Monetarie vai ao BACEN) | D1 | M | Médio (money-path novo, mas não toca o caminho SPI validado) |
| P0-2 | Devolução automática pacs.004 quando o crédito settled não puder ser aplicado (conta encerrada/bloqueada pós-validação), reusando o ReturnProcessor | D1 | M | Médio (reusa fluxo de return existente) |
| P0-3 | Polling inbound do DICT: worker Oban por domínio (claims recebidas, relatos de infração recebidos, refunds MED recebidos) usando os clients já prontos (dict_client.ex:432/660/923), materializando local + evento NATS | D2 | M | Baixo (só leitura do BACEN + persistência nova) |
| P0-4 | Ligar os timers do ciclo de claim: consumer dos subjects donor_notification/donor_timeout/claimer_timeout (ou Oban cron por deadline) chamando auto_confirm/auto_cancel já prontos (claims.ex:421/462) | D2 | S | Baixo (funções já existem, hoje código morto) |
| P0-5 | Conectar o gatilho MED respondente: poller de refunds/infrações inbound aciona create_fraud_claim + apply_cautelar_block/apply_partial_block (máquina completa pronta, zero chamadores) | D2 | S/M | Médio (bloqueia saldo de cliente; exigir testes) |

### P1 (defeito confirmado ou lacuna operacional de alto valor)

| # | Item | Domínio | Esforço | Risco |
|---|---|---|---|---|
| P1-1 | Reason code do pacs.002 fim a fim: extrair StsRsnInf/Rsn/Prtry no parser (message_parser.ex:378-399) + Core passar reason ao move_to_failed | D0 | S | Baixo |
| P1-2 | Credit-back do saldo PI na rejeição: fix do Map.put_new (status_updater.ex:328-332) e do handle_timeout (:425) + backfill R$ 0,02 + reconciliação periódica available vs camt.060/053 | D0 | S | Médio (money-path da cabine) |
| P1-3 | Investigação AB03 sistemático: comparar pacs.008 assinada real vs Catálogo 5.12 (PmtId/TxId, AppHdr Fr/To) + pareamento E2E; encerrar só com ACSC vivo | D0 | M | Baixo (só leitura + eventual fix de builder) |
| P1-4 | Kills do CPM: heartbeat via ETS antes/depois do Finch.request (ou pull em Task supervisionada); HealthMonitor deixa de julgar liveness por GenServer.call 5s | D3 | S/M | Médio (toca o canal ICOM; não mexer no protocolo pull-next/pré-ACK) |
| P1-5 | Echo pibr.001 periódico (5 min) com evidência persistida + métrica de sem-resposta + probe alimentando o CircuitBreaker | D3/D5 | S | Baixo |
| P1-6 | Ingestão automática de certs de participantes BACEN (reusar trilha A do SPB); antes, provar em HML um inbound assinado por outro PSP (risco DS01) | D3 | M | Médio |
| P1-7 | Pipeline do arquivo de extrato: handler camt.052 + download mTLS + unzip + parse RELACAO_LANCAMENTOS.csv + log de downloads (desbloqueia tx 199) | D4 | L | Médio |
| P1-8 | Conciliação diária real: 3 vias contra monetarie_spi.messages + conciliação de saldo persistida por data com alerta | D4 | M | Baixo (depende de P1-7) |
| P1-9 | Motor de alertas operacionais persistente (catálogo + limiares + destinatários + histórico + email Swoosh + ack real), incluindo vencimento de certificado diário e StuckOutboundChecker publicando alerta | D5 | L | Baixo |
| P1-10 | Enforcement de alçada no pipeline (pending_alcada antes do OutboundSender) + ativação do accumulated_amount com data-base | D5 | M | Médio (retém envio; exigir flag de rollout) |
| P1-11 | Repositório de feriados (tabela + tela + import das 384 linhas do staging + trilha); destrava CobV dia útil, alçada por dia útil e limites | D5 | S | Baixo |
| P1-12 | Estado seguro para TxSts desconhecido: gravar MessageHistory + flag de revisão em vez de drop com warning (inbound_processor.ex:1450-1452) | D1 | S | Baixo |
| P1-13 | Handler LPI (classificar por MsgDefIdr, persistir, alertar); LPI0006 já acumula ~2/dia em HML | D1 | S | Baixo |
| P1-14 | Remover overlap de tabelas: apontar transaction_controller/return_controller/statements/balances para monetarie_spi.messages; aposentar monetarie_spi.transactions; avaliar fundir payments | D1/D4 | M | Médio (toca leituras de API; não toca escrita canônica) |
| P1-15 | Agendamento de PIX único no Core/IB (janelas, cancelamento até execução, política de recusa) reusando payment_request | D1 | L | Médio |
| P1-16 | Substituir o mock do StatisticsController por get_person_statistics/get_key_statistics reais e usar na decisão antifraude | D2 | S | Baixo |
| P1-17 | Validação de posse OTP (email/SMS) nos 5 endpoints stub 501 + amarração ao create_entry e ao claim | D2 | M | Baixo |
| P1-18 | Orçamento client-side dos baldes DICT (contador Redis por balde + penalidade + restituição de ficha no settled) | D2 | M | Baixo |

### P2 (portar/corrigir com valor médio)

| # | Item | Domínio | Esforço | Risco |
|---|---|---|---|---|
| P2-1 | failed_transactions no extrato/comprovantes/em trânsito do IB com motivo pt-br (validar com screenshot, regra 11) | D0 | S | Baixo |
| P2-2 | Popular message_history.status_details/return_data em record_status_history | D0 | S | Baixo |
| P2-3 | Audit.log no AtomicPaymentHandler.handle_status + retenção do Oban nats_publish (~7d) ou espelho em audit | D0 | S | Baixo |
| P2-4 | Idempotency-Key durável em tabela unique com Redis como cache | D1 | S | Baixo |
| P2-5 | Parametrizar limites em DB (janela noturna, tetos, dia útil, produto, contraparte) mantendo defaults | D1 | M | Médio |
| P2-6 | Tela/endpoint de reprocesso acoplado ao StuckOutboundChecker (sem mudar a semântica de nunca alterar status sem evidência) | D1 | S | Baixo |
| P2-7 | Sweeper diário de expiração de cobranças/recorrências + validação do MED parcial com saldo insuficiente | D1 | S | Baixo |
| P2-8 | Persistência local de fraud markers (id BACEN, status, vínculo com relato) | D2 | S | Baixo |
| P2-9 | Read-model de consultas DICT (dict_lookups com TTL, e2e, reuso QR) | D2 | M | Baixo |
| P2-10 | Seleção de cert de verificação por janela de validade + data da mensagem (CreDt) | D3 | S | Médio |
| P2-11 | Rotação quente da CPIC sem restart (padrão OurCertStore do SPB) | D3 | M | Médio |
| P2-12 | Decidir e documentar verify_dict (ligar ou aceitar risco formalmente) | D3 | S | Baixo |
| P2-13 | Corrigir fonte dos statements da cabine + snapshot EOD de saldo (opening balance deixa de ser 0,00) | D4 | M | Baixo |
| P2-14 | Persistir remuneração da Conta PI (camt.053 CRE) com controle diário e admin | D4 | S/M | Baixo |
| P2-15 | Decisão do dono sobre a trilha contábil da cabine: semear COSIF fail-fast OU remover (preferível: Core como contabilidade única); eliminar o modo silencioso | D4 | M | Médio |
| P2-16 | Runner do scheduled_message_jobs (padrão Reports.ScheduleWorker) ou rotular a tela como manual | D5 | S | Baixo |
| P2-17 | Trilha before/after de parâmetros (configs, alçada, fees, jobs, certs) | D5 | M | Baixo |
| P2-18 | Remover mocks de monitoração (logs sintéticos + ack no-op) por fonte real/vazio honesto e ack persistido | D5 | S | Baixo |
| P2-19 | Tela/API de downloads de arquivos de extrato BACEN (com P1-7) | D4 | S | Baixo |
| P2-20 | Webhook de parceiro no PIX RECEBIDO (validar e completar se faltar) | D1 | S | Baixo |
| P2-21 | Alçada: período dias úteis/não úteis + aprovadores restritos com notificação | D5 | M | Baixo |

### P3 (otimizações e complementos, não mexer agora no caminho validado)

Gzip outbound, multipart em lote por ISPB e limitador de TPS por janela (todos atrás de flag); snapshot diário e CRL de certs de peers; espelho de monitor fora do caminho pré-ACK; grade horária DICT por serviço; tipos CONTABIL e CONCILIACAO no catálogo de relatórios; TIR (rota + tela); alerta preventivo de saldo PI; GET /policies do DICT; tiering frio S3 do audit (mantendo piso de 10 anos); tela de parâmetros legados; widget de série horária com hora morta; alertas por participante indireto e inbox de alertas por mensagem; validação do APIX001 contra os 13 RELATORIO_MENSAL reais do backup.

### Remover por overlap (após confirmação)

1. `monetarie_spi.transactions` (tabela paralela quase vazia) após redirecionar os 4 consumidores para `messages` (P1-14).
2. Logs sintéticos de `build_service_log_entries` e ack no-op (P2-18).
3. Evento `monetarie.spi.status.rejected` paralelo ao `transaction.rejected`, se confirmado sem consumidor.
4. Aparato de netting sessions da cabine PIX (sem contraparte regulatória para participante direto), somente com aprovação do dono.
5. Não portar do legado: os ~35 status de infra do enumStatusOperacao, reenvio automático de pacs.008 (tabela legada vazia, risco de duplicidade), filas por sistema de origem, pacs.028 (ausente nas 3 fontes), domínio DISPUTA (0 rows, absorvido pelo MED 2.0), 40 tabelas sharded RESTRICAO_INFRACAO, espelho gigante ESTATISTICA_* e whitelist de thumbprint do servidor BACEN (verify_peer é superior).

## 5. Intocáveis (validado vivo, NÃO mexer)

1. mTLS verify_peer com cadeia ICP-Brasil pinada, customize_hostname_check, depth 5 e partial_chain (`shared/application.ex:194-241`); Host sem porta no canal BACEN (root-cause fix validado vivo).
2. Assinatura XMLDSig com normalização xmllint e chave privada no HSM RTM em HTTPS 443 (`xml_signer.ex`); nunca reintroduzir :6443 nem chave em processo/repo.
3. Invariante persistência antes do ACK no long-poll ICOM com dedup por message_id, republish no boot e eleição de líder por advisory lock (`icom/cpm/worker.ex`, `ack_tracker.ex`, `coordinator.ex`); o fix dos kills (P1-4) muda só o sinal de vida, não o protocolo.
4. CID sync completo (full 6h + eventos 5min + POST /sync-verifications) e GetEntry com PI-EndToEndId, validados vivos contra o BACEN.
5. Mapa camt.060 das 7 ações (provado 6/7 vivo), materialização SADP/SABK com proveniência honesta e cadeia de gates do outbound (validate > sanctions > sign > XSD pós-assinatura, fail-closed).
6. Debit-then-send com estorno atômico fail-closed na cabine e void_and_fail atômico/idempotente no Core (hold TigerBeetle); correlação multi-estratégia de pacs.002/admi.002; guard de estado terminal; dedup em 3 camadas do inbound.
7. Retenção regulatória de 10 anos fixa em código com particionamento e purge automáticos (não regredir para retenção configurável).
8. Contrato do canal CPM/CSM com o BACEN (pull-next, sessões, backoff com jitter) e o APIX001 portado do SQL do legado (validar dados, não reescrever o mecanismo).

## 6. Pendências DIVERGENTE_VALIDAR (precisam do dono ou de prova em HML)

1. AB03 sistemático no outbound HML (2/2): apuração como defeito nosso; encerrar só com pacs.008 liquidada viva (D0).
2. Evento `monetarie.spi.status.rejected` paralelo: tem consumidor real? Se não, remover (D0).
3. Retenção do Oban `nats_publish` no Core: definir política (7 dias ou espelho em audit) para não cegar investigações (D0).
4. Sweeper diário de expiração de cobranças/recorrências: existe job não localizado? Se não, portar (D1).
5. Multiliquidação/lote de pagamentos do cliente: renascer como lote na Partner API/Core ou morrer (D1/D4).
6. Espelho local de fraud markers: portar persistência mantendo o BACEN como fonte? (D2).
7. Read-model de consultas DICT (dict_lookups) para comprovante/antifraude (D2).
8. Versionamento por parâmetro da versão DICT/catálogo vs deploy: registrar decisão consciente (D2). Histórico versionado de entry: exigência de compliance? (D2).
9. verify_dict sem callers: ligar ou aceitar risco de canal mTLS formalmente (D3).
10. mTLS de cliente para parceiro white-label na API: necessário? (D3).
11. Consumer real dos eventos :telemetry de alarme ICOM: existe sink de operador? (D3/D5).
12. Trilha contábil da cabine: semear COSIF fail-fast ou remover (Core como contabilidade única, preferível) (D4). Netting sessions da cabine: remover ou documentar propósito interno (D4). Extrato do Core cobre os campos PIX ricos do legado (saque/troco, e2e original, iniciadora, motivo MED)? (D4). Previsões de caixa (SP_CONCILIA_PREVISAO): pertencem ao Core/SPB? (D4).
13. Restrição de IP prometida pela tela de segurança: aplicada por alguma camada (SG/VPN)? Implementar plug ou remover a tela (D5). Execução automática de scheduled_message_jobs: confirmar em HML que não existe runner e decidir (D5).
14. Limite noturno: o Core já cobre? Não duplicar na cabine antes de validar (D1/D5). Widget de série horária com detecção de hora morta: já existe em alguma tela do pix-admin? (D4/D5).

## 7. Nota de método

Todos os vereditos desta matriz vêm de evidência direta: arquivo:linha no monetarie e nos decompilados do vendor, tabelas/procedures e contagens reais no container `monetarie-bak-mssql` e no staging `legacy_ab_pix`, e logs/linhas vivas de HML citados no P0. Fatos com dúvida residual foram rebaixados a DIVERGENTE_VALIDAR em vez de afirmados. Os 8 fatos mais carregados (move_to_failed, Map.put_new do credit-back, parser sem StsRsnInf, HealthMonitor 5s vs long-poll 60s, statistics mock, ownership 501, dispatcher sem camt.052, opening balance 0,00 e ausência de runner do crontab) foram re-verificados no código na data desta síntese.
