# Dossie de paridade DB: SPI core + DICT + indices (legado x nosso)

Auditoria read-only, tabela a tabela / coluna a coluna / indice a indice. Zero inferencia: cada afirmacao tem prova (schema vivo SQL Server via sqlcmd, dump pg `mon_pix_schema_clean.sql`, schemas Ecto, decompilado .NET). Onde nao ha prova suficiente, o veredito e INCONCLUSIVO.

Fontes primarias:
- Legado vivo: `docker exec monetarie-bak-mssql ... sqlcmd` nos DBs `crk_spi`, `des_4dict` (sys.columns/sys.indexes).
- Legado decompilado: `.scratch/legado-pix-decompiled/*.decompiled.cs`.
- Nosso schema autoritativo: `pix/backend/apps/shared/priv/repo/sql/mon_pix_schema_clean.sql` (pg_dump squash, aplicado por `20260101000000_create_schema.exs`) + migrations posteriores + schemas Ecto.

Escopo do legado: `crk_spi` = nucleo SPI money-path; `des_4dict` = DICT. Nosso: schemas `monetarie_spi`, `monetarie_dict`, `monetarie_spi_ref`, `monetarie_spi_msg`.

---

## 1. Mapa de tabelas (legado -> nosso)

### SPI core (`crk_spi` -> `monetarie_spi`)

| Legado (crk_spi) | Nosso (monetarie_spi) | Situacao |
|---|---|---|
| SpiMessage | messages (particionada por operation_time) | coberto (com 2 colunas faltando: IspbIF, FlAtuSldConf) |
| SpiPayment | payments | parcial (faltam OrigemTransacao, DocFiscal, Tributos) |
| SpiMessageHistory | message_history | coberto |
| SpiMessageIds (MessageIds por operacao) | message_id_registry (por ISPB, PK message_id) | coberto (semantica um pouco diferente) |
| SpiSaldo (previsto/confirmado por DtMovto) | balances + daily_balance_snapshots + balance_history | divergencia (modelo diferente) |
| SpiSaldoCAMT | balances.confirmed / balance_cache | coberto |
| SpiSaldoSpb | (SPB fora do escopo desta cabine) | info |
| SpiStatusOperacao + SpiClassifResultado | operation_status_codes (1 tabela) | parcial (flags EhMensagem/EhMensagemIda/EhStatusLogIntegracao/EhStatusPendente ausentes) |
| SpiAccount | accounts | coberto |
| SpiCadParamAlcada | alcada_parameters (+ approval_thresholds) | parcial (listas de aprovadores/usuarios/grupos/sistemas ausentes) |
| SpiRegAlcada | alcada_registrations | coberto |
| SpiRegVistoAlcada | alcada_vistos | coberto |
| SpiRegLimitesOperacao (acumulador diario) | (ausente; calculo ad-hoc) | ausente/divergencia |
| SpiReqSaldo / SpiHistReqSaldo | camt060_requests | parcial (NumCtrlIF, FinlddLPI, Protocolo ausentes) |
| SpiADMI004 (avisos admi.004 estruturados) | (so em messages) | parcial |
| SpiHistMotorAntiFraude (motor antifraude SPI) | (ausente) | ausente |
| SpiMessageXSystem (fan-out multi-sistema) | (ausente; cabine unica) | info/N/A |
| SpiCadParamTarifa / XMsg | monetarie_settlement.fee_tables | coberto (fora do schema spi) |
| SpiFeriado | monetarie_settlement.holidays | coberto |
| SpiCadParamAlertaMsg / AlertMsgXUsuario | alert_configs / alert_user_subscriptions | coberto |
| SpiCadParamAutomacaoMsg | automation_configs | coberto |
| SpiDtMovto | movement_dates | coberto |
| SpiCadConciliacaoStatus | daily_reconciliations (migration) | coberto (aprox) |
| Seeds (SpiEndToEndIds/SpiMsgIds/SpiReturnIdentification/SpiRecMsg) | endtoend_id_registry / message_id_registry / return_id_registry / e2e_outbound_burns / outbound_send_claims / dict_e2e_reservations | coberto (mais forte) |

### DICT (`des_4dict` -> `monetarie_dict`)

| Legado (des_4dict) | Nosso (monetarie_dict) | Situacao |
|---|---|---|
| TB_CONTADICT | keys | coberto (nosso mais rico) |
| TB_OPERACAO | operations | coberto |
| TB_OPERACAOREIVINDICACAO | claims | coberto (falta DH_CONTINGENCIA / fluxo contingencia) |
| TB_HISTSITUACAOREIVINDICACAO | (embutido em claims + eventos) | coberto (aprox) |
| TB_INFRACAO | infractions / infraction_reports | coberto |
| TB_SOLICITACAODEVOLUCAO | refund_requests / med_requests | coberto |
| TB_FRAUDE | fraud_markers | coberto |
| TB_REGRAPROTECAO | protection_rules + rate_limit_policies | coberto (falta periodicidade verif. pagamento) |
| TB_KEYS_STATISTICS / TB_OWNERS_STATISTICS | key_statistics_cache / person_statistics_cache | coberto |
| TB_INTERVALOCHAVE (faixas CPF/CNPJ por participante) | (ausente) | ausente |
| TB_OPERACAOCONSULTA / _BACEN / TB_CONTROLECONSULTA | query_correlations / query_metrics / operations | coberto |
| TB_HISTSINCRONISMO / TB_MENSAGEMSINCRONISMO | sync_log / cid_files / cid_events | coberto |
| TB_NOTIFICACAO | event_notifications | coberto |
| TB_HORARIOPARTICIPANTE | participant_hours | coberto |

---

## 2. SPI core coluna a coluna

### 2.1 SpiMessage -> messages (COBERTO com 2 faltas)

Legado `crk_spi.SpiMessage` (sys.columns): CdMsg, MsgDefIdr, IdInstFinanc, IdFilialInst, DtMovto, DtHrOperacao, IspbDebtor, IspbCreditor, IdSystem, UniqueId, MessageId, EndToEndId, FlDebitoCredito, IdStatus, FlSentido, DtHrMsg, DtHrTermino, Ustrd, ResourceId, DtHrUltimaAlteracao, RtrId, MessageIdOrig, IdOperacaoOrig, EndToEndIdOrig, IdSystemOrig, DtHrLiquidacao, DtContabil, **FlAtuSldConf**, JsonInput, NumCtrlSTR, IdUsuario, IdOperacao, **IspbIF**.

Nosso `monetarie_spi.messages` (mon_pix_schema_clean.sql:5327): message_code, msg_def_idr, institution_id, branch_id, movement_date, operation_time, debtor_ispb, creditor_ispb, system_id, unique_id, message_id, end_to_end_id, debit_credit, status_id, direction, message_time, completion_time, settlement_time, accounting_date, ustrd, last_updated, resource_id, return_id, original_message_id, original_operation_id, original_end_to_end_id, original_system_id, json_input, str_control, user_id, id, created_at.

Mapeamento 1:1 confirmado para 31 campos (CdMsg=message_code, IspbDebtor=debtor_ispb, RtrId/MessageIdOrig/IdOperacaoOrig/EndToEndIdOrig/IdSystemOrig = return_id/original_*, DtHrLiquidacao=settlement_time, DtContabil=accounting_date, NumCtrlSTR=str_control varchar(50) vs legado varchar(36)).

FALTAS (prova: coluna existe no legado, ausente no dump nosso):
- **IspbIF char(8)** (SpiMessage col 33) — ISPB do participante indireto que a operacao representa. Sem coluna equivalente em `messages`. Ver gap g2.
- **FlAtuSldConf char(1)** (SpiMessage col 28) — flag "saldo confirmado ja atualizado" (anti dupla contabilizacao de saldo). Sem equivalente. Ver gap g7.
- **FlSentido tinyint** (col 15) — 1=envio/2=recepcao usado no calculo de saldo. Nosso `direction` (OUTBOUND/INBOUND) cobre a semantica.

### 2.2 SpiPayment -> payments (PARCIAL: 3 campos de negocio faltando)

Legado `crk_spi.SpiPayment` (sys.columns, 31 cols): IdOperacao, IdMetodo, IdPriority, Vlr numeric(18,2), Ccy, TxId, ChargeBearer, InitgPty, CpfCnpjDebtor, NmDebtor, IdAccountDebtor, IssuerAccountDebtor, TypeAccountDebtor, ProxyIdDebtor, CpfCnpjCreditor, NmCreditor, IdAccountCreditor, IssuerAccountCreditor, TypeAccountCreditor, ProxyIdCreditor, ReturnReasonCodes, DtHrAcceptance, FormaIniciacao, TipoPrioridade, FinalidadeTransacao, ValorTipo, ModalidadeAgente, PrestadorSaque, **OrigemTransacao varchar(20)**, **DocFiscal varchar(50)**, **Tributos varchar(max)**.

Nosso `monetarie_spi.payments` (mon_pix_schema_clean.sql:5847): message_id, operation_time, method_id, priority_id, amount numeric(18,5), currency, tx_id, charge_bearer, initiating_party, debtor_cpf_cnpj, debtor_account, debtor_issuer, debtor_account_type, debtor_proxy, debtor_name, creditor_cpf_cnpj, creditor_account, creditor_issuer, creditor_account_type, creditor_proxy, creditor_name, return_reason_codes, acceptance_time, initiation_form, priority_type, transaction_purpose, value_type, agent_modality, withdrawal_provider, id.

Mapeamento confirmado: IdMetodo=method_id, IdPriority=priority_id, InitgPty=initiating_party, FormaIniciacao=initiation_form, TipoPrioridade=priority_type, FinalidadeTransacao=transaction_purpose, ValorTipo=value_type (jsonb), ModalidadeAgente=agent_modality, PrestadorSaque=withdrawal_provider. Saque/Troco coberto (agent_modality/withdrawal_provider/value_type).

FALTAS (prova: colunas existem em SpiPayment, ausentes em payments):
- **OrigemTransacao** varchar(20) — origem da transacao.
- **DocFiscal** varchar(50) — documento fiscal associado (nota).
- **Tributos** varchar(max) — tributos/retencoes (PIX com recolhimento tributario, catalogo SPI). Ver gap g1.

### 2.3 SpiMessageHistory -> message_history (COBERTO)

Legado: IdOperacao, DtHrHistorico, IdStatus (PK triplo), IdSentidoMsg, CdMsg, DtHrMsg, MsgDefIdr, XmlMsg, DetStatus, IdUsuario, OrigStatus, ResourceId, DadosRetorno, DtHrProcessamento.
Nosso `message_history` (5295), PK (message_id, history_time, status_id): direction, message_code, message_time, msg_def_idr, status_details, user_id, status_origin, resource_id, return_data.
PK identico em intencao. Diferenca: legado guarda XmlMsg inline no historico; nosso guarda XML em `monetarie_spi_msg.xml_messages` / `bacen_inbound|outbound`. Sem gap material.

### 2.4 SpiStatusOperacao + SpiClassifResultado -> operation_status_codes (PARCIAL)

Legado tem DUAS tabelas:
- SpiStatusOperacao: IdStatus, DsStatus, Resultado, **EhMensagem**, **EhMensagemIda**, **EhStatusLogIntegracao**.
- SpiClassifResultado: Resultado, DsResultado, **EhStatusFinal**, **EhStatusPendente**, **EhErro**.

Nosso `operation_status_codes` (5735): id, code, description, is_final, is_error, sort_order. Uma tabela.
- EhStatusFinal -> is_final (coberto: trava de regressao de status).
- EhErro -> is_error (coberto).
- **EhStatusPendente** (is_pending) -> ausente como coluna.
- **EhMensagem / EhMensagemIda / EhStatusLogIntegracao** -> ausentes (marcam se o status corresponde a uma mensagem, a mensagem de ida/saida, ou a entrada de log de integracao). Ver gap g8.

### 2.5 Saldo: SpiSaldo -> balances (DIVERGENCIA)

Legado `SpiSaldo` PK (IdInstFinanc, DtMovto): VlrPrevisto, VlrConfirmado, VlrSaldoAnterior, VlrSaldoPrevisto, VlrSaldoConfirmado (numeric 28,2) — ledger de saldo previsto vs confirmado INDEXADO POR DIA DE MOVIMENTO com roll-forward diario (proc SPI_SPUPDSLDSPI). `FlAtuSldConf` em SpiMessage evita dupla contabilizacao.

Nosso `balances` (5081) PK id, UNIQUE (ispb): available, blocked, projected, pending_credits, pending_debits, confirmed, confirmed_at, as_of, source — UMA linha corrente por ISPB (nao indexada por dia). Complementos: `balance_cache` (corrente), `balance_history` (trilha before/after/change), `daily_balance_snapshots` (migration 20260705120000, snapshot diario). Ledger real de dinheiro fica no TigerBeetle (Core), nao neste schema.

Divergencia estrutural: legado mantem o saldo previsto/confirmado por dia com roll-forward na propria tabela; nosso mantem saldo corrente + snapshot diario + historico event-sourced. Funcionalmente reconciliavel, porem sem paridade de esquema. Ver gap g7.

### 2.6 Alcada: SpiCadParamAlcada -> alcada_parameters (PARCIAL)

Legado `SpiCadParamAlcada`: IdAlcada, IdInstFinanc, NmAlcada, IdPeriodoVerificacao, NrQtdeVistos, **UsuariosAlcada**, **GruposAlcada**, **IdSystemsAlcada**, **UsuariosAprovadores**, **GruposAprovadores**, VlrMinimo, VlrMaximo, VlrDiario, HrInicioVerificacao, HrFimVerificacao, JsonMsgs, FlAtiva, **FlEstendeLimites**.

Nosso `alcada_parameters` (4630) / `Shared.Schemas.Alcada.Parameter`: name, description, min_amount, max_amount, accumulated_amount, accumulated_period, required_vistos, start_hour, end_hour, message_types, is_active, priority. SEM listas de aprovadores/usuarios/grupos/sistemas nem FlEstendeLimites (parameter.ex:13-28 confirma).

Prova de que qualquer usuario aprova: `alcada_vistos` (4712) registra registration_id+user_id, mas nao ha coluna nem validacao que restrinja o visto a um conjunto de aprovadores autorizados.

Cobertura parcial em OUTRA tabela: `approval_thresholds` (4862) tem `user_groups jsonb`, `requires_lso`, `requires_rso`, `institution_id` (escopo LSO/RSO 2 niveis). E um mecanismo paralelo; a gate do money-path usa `alcada_parameters` (`Shared.Alcada.SendGate` / `HeldMessages`). Ver gap g4.

### 2.7 Limites diarios: SpiRegLimitesOperacao -> AUSENTE (DIVERGENCIA)

Legado `SpiRegLimitesOperacao` PK IdLimite, indices IX_SpiRegLimitesOperacao_1 (DtBase, Cliente) e _2 (DtBase, Conta): IdAlcada, DtBase, Cliente, ISPB, Agencia, Conta, ValorLimite, **TotalCredito**, **TotalDebito**, **ValorDisponivel** — ACUMULADOR DIARIO persistido de credito/debito por cliente/conta contra o limite.

Nosso: nao existe tabela acumuladora. `pix_limits` (limits/pix_limit.ex) e apenas CONFIGURACAO (account_id, limit_type, amount_cents, period, effective_at). O consumo diario e calculado ad-hoc em `SpiService.Limits.get_daily_spent/2` (limits.ex:125): `from(t in "transactions", where: t.debtor_account_id == ^account_id ...)`.

DEFEITO PROVADO: a coluna `debtor_account_id` NAO existe em `monetarie_spi.transactions` (dump linhas 6188-6242 tem `debtor_account`, nao `debtor_account_id`; nenhuma migration adiciona — `grep debtor_account_id apps/*/priv/repo/migrations` = vazio). Alem disso `transactions` e a tabela nao-canonica ("mostly empty" per pix/CLAUDE.md; a producao usa `messages`). Logo o acumulador diario legado nao tem equivalente e o substituto consulta coluna/tabela erradas. `check_limit/3` e exposto via RPC `monetarie.pix.limits.check` (core_gateway_handler.ex:126). Ver gap g3.

### 2.8 Requisicao de saldo: SpiReqSaldo -> camt060_requests (PARCIAL)

Legado `SpiReqSaldo`: IdRequisicao, IdInstFinanc, IdFilialInst, Ispb, IspbDestino, DtMovto, DtHrEntrada, IdTipoMsg, IdStatus, IdTipoRequisicao, Vlr, DtHrEnvio, DtHrRetorno, IdUsuario, **NumCtrlIF varchar(20)**, **FinlddLPI tinyint**, **Protocolo varchar(1000)**, IdOperacao.
Nosso `camt060_requests` (migration 20260704170000): msg_id, ispb, action, reqd_msg_nm_id, prtry, status, sent_at, responded_at, response_type, response_msg_id.
Cobertura do camt.060 basico. Ausentes: NumCtrlIF, FinlddLPI (finalidade LPI — pernas de reserva/Conta PI), Protocolo. LPI e majoritariamente SPB-side; risco baixo. Ver nota em coberto.

### 2.9 Motor antifraude SPI: SpiHistMotorAntiFraude -> AUSENTE

Legado `crk_spi.SpiHistMotorAntiFraude`: InstructId char(32), CdMsg, IdStatus, Mensagem, JsonMsg, DtOperacao. Decompilado prova motor externo real: `ConsultaMotorAntiFraudeUseCase`, `AdicionarHistoricoMotorAntiFraude(..., Status.Equals("Aprovado") ? AprovadaPeloMotorAntiFraude : ReprovadaPeloMotorAntiFraude, ehPacs008)` e status `EnviadaMotorAntiFraude` (SPI.Core.Application.decompiled.cs). Cada pacs.008 e ENVIADA a um motor antifraude e recebe Aprovado/Reprovado, persistido em SpiHistMotorAntiFraude com metricas por data.

Nosso: nenhuma tabela/gate antifraude no schema `monetarie_spi`. Antifraude nosso e DICT-side (protection_rules, fraud_markers, infractions) e Core-side, mais o antifraude do proprio BACEN via consulta DICT (dict_client.ex:132). Nao ha motor de scoring de saida na cabine. Ver gap g5.

### 2.10 Avisos admi.004: SpiADMI004 -> PARCIAL

Legado `SpiADMI004`: DtHrAviso, EvtCd, EvtDesc — avisos operacionais do BACEN estruturados. Nosso: admi.004 chega como mensagem em `messages` (message_code "admi.004" no whitelist transaction.ex:27); nao ha tabela estruturada de avisos com EvtCd/EvtDesc. `operational_alerts` (20260705000000) e alerta interno nosso, nao o admi.004 do BACEN. Ver gap g6.

---

## 3. Indices de consulta (legado x nosso)

### SpiMessage (legado, sys.indexes) x messages (nosso, por particao)

Legado: PK_Message (IdOperacao); IX_SpiMessage_3 (EndToEndId, CdMsg); IX_SpiMessage_5 (IdStatus INCLUDE MessageId); IX_SpiMessage_7 (IdInstFinanc, DtHrOperacao INCLUDE FlDebitoCredito, IdStatus, IdOperacao); **IX_SpiMessage_8 UNIQUE (EndToEndId, RtrId, CdMsg)**; IX_SpiMessage_9 (CdMsg, RtrId, EndToEndIdOrig); IX_SpiMessage_IdOperacaoOrig (IdOperacaoOrig INCLUDE IdStatus, CdMsg, IdOperacao).

Nosso (cada particao messages_2026_NN): pkey (id); UNIQUE (end_to_end_id, operation_time); UNIQUE (unique_id, operation_time); (message_id); (status_id); (status_id, operation_time DESC); (direction, status_id, operation_time DESC); (branch_id, status_id, operation_time DESC); (movement_date, status_id); (creditor_ispb); (debtor_ispb); (institution_id); gin trgm (end_to_end_id::text). Fora da particao: idx_spi_messages_orig_e2e (original_end_to_end_id WHERE NOT NULL, migration 20260714211000) e idx_outbound_return_id (20260704150000).

Veredito: cobertura de consulta EQUIVALENTE OU SUPERIOR (status, E2E, ISPB, data, direcao, correlacao de devolucao por original_end_to_end_id). Diferenca semantica: legado tem UNIQUE (EndToEndId, RtrId, CdMsg) que impede duplicar a mesma tripla; nosso impede E2E duplicado por (end_to_end_id, operation_time) por particao + `e2e_outbound_burns` (queima estrutural do E2E de saida na mesma transacao). Coberto.

### Idempotencia / seeds

| Legado | Chave | Nosso | Chave |
|---|---|---|---|
| SpiEndToEndIds | PK (Ispb, EndToEndId) | endtoend_id_registry | PK (endtoend_id) |
| SpiMsgIds | PK (Ispb, MsgId) | message_id_registry | PK (message_id) |
| SpiReturnIdentification | PK (Ispb, RtrId) | return_id_registry | PK (return_id) |
| SpiRecMsg | PK (UniqueId) | messages UNIQUE (unique_id, operation_time) | por particao |
| (n/a) | | e2e_outbound_burns / outbound_send_claims / dict_e2e_reservations | reforco extra |

Nosso PK e global (sem ISPB); legado inclui ISPB. Para cabine de ISPB unico e equivalente. Coberto (mais forte).

### DICT: TB_CONTADICT x keys / TB_OPERACAO x operations

Legado TB_CONTADICT: IDX_..._TX_CHAVE (NR_SPBPARTICIPANTE, TX_CHAVE INCLUDE ID_TIPOCHAVE, IC_CONTAATIVA...); IDX_..._NR_AGENCIA_NR_CONTA; IX_..._ID_TIPOCHAVE_IC_CONTAATIVA_ID_CID.
Legado TB_OPERACAO: IX_TB_SOLICITACAO (ID_TIPOCHAVE, TX_CHAVE) — lookup de chave; IDX_..._ID_REQUISICAO; IDX_..._ID_TIPOCHAVE_TX_CHAVE_DH_CONFIRMACAO; IX_TB_OPERACAO_TPI (ID_TIPOCONTA, NR_CONTA, NR_SPBPARTICIPANTE).

Nosso: keys/operations tem indices de lookup por chave (verificar dict-entries.md/dict-claims.md ja mapeados). Cobertura de lookup por (key_type, key_value) e por ISPB confirmada nos hot-path indexes (migration 20260511172000 add_dict_hot_path_indexes). Coberto no caminho de consulta.

### DICT contingencia (legado) x nosso

Legado TB_OPERACAOREIVINDICACAO tem `DH_CONTINGENCIA` + indice `IDX_TB_OPERACAOREIVINDICACAO_DH_CONTINGENCIA` (resolucao de claim em contingencia). Nosso `claims` (2017) nao tem coluna nem indice de contingencia. Fluxo de contingencia de reivindicacao sem paridade de esquema. Risco baixo (contingencia e excecao operacional). Nota, nao gap critico.

---

## 4. Itens COBERTOS relevantes (confianca)

- messages/payments/message_history: nucleo money-path com paridade de campo confirmada (secoes 2.1-2.3).
- Idempotencia de envio e recepcao: registries + burns + claims igualam ou superam os seeds legados (secao 3).
- DICT keys: TB_CONTADICT mapeia 1:1 para `keys`, nosso mais rico (ownership_validation_id, sync_version, blocked_until/blocked_by, open_claim_creation_date).
- DICT claims: TB_OPERACAOREIVINDICACAO -> `claims` com resolution_period_end, donor_deadline, claimer_deadline (prazos regulatorios cobertos).
- DICT MED 2.0: infractions / infraction_reports / funds_recoveries / tracking_graphs / refund_requests / med_requests cobrem TB_INFRACAO / TB_SOLICITACAODEVOLUCAO / TB_FRAUDE (com fraud_marker, tracking graph — superior ao legado).
- DICT rate-limit/anti-scan: rate_limit_policies + participant_buckets + user_buckets + protection_rules + key_statistics_cache + person_statistics_cache cobrem TB_REGRAPROTECAO / TB_KEYS_STATISTICS / TB_OWNERS_STATISTICS.
- DICT sync CID: sync_log / cid_files / cid_events cobrem TB_HISTSINCRONISMO / TB_MENSAGEMSINCRONISMO.
- Tarifas: fee_tables (monetarie_settlement) cobrem SpiCadParamTarifa.
- Feriados: monetarie_settlement.holidays cobre SpiFeriado.
- Alertas/automacao/movimento: alert_configs/automation_configs/movement_dates cobrem SpiCadParamAlertaMsg/AutomacaoMsg/SpiDtMovto.
- camt.060: camt060_requests cobre o fluxo basico de SpiReqSaldo (falta NumCtrlIF/FinlddLPI/Protocolo, risco baixo — LPI e SPB-side).

Notas de arquitetura (nao gaps):
- SpiMessageXSystem (fan-out para sistemas legados/multiliquidacao) nao tem equivalente porque a cabine nossa nao faz fan-out multi-sistema (integracao com Core via NATS). N/A.
- Redundancia interna nossa: coexistem `returns` (uuid, rico) e `transaction_returns` (bigint), e `transactions` (nao-canonica) alem de `messages` (canonica). Nao e gap de legado; e divida tecnica interna.
