# Pedidos ao time: o que falta para destravar a frente de receita e a Partner API

Data: 2026-07-27. Levantado contra fonte viva (AWS, bancos de HML e PRD, git e o
ensaio local do ETL WEBCTB). Cada item diz **de quem** eu preciso, **o que**
exatamente, e **por que trava**. O que eu consigo fazer sozinho está na seção 6 e
não precisa ser pedido a ninguém.

---

## 1. Contabilidade: 14 contas COSIF que ainda não existem

**De quem:** contador da Monetarie, com o Bruno.
**Trava:** o motor de tarifa, o split e o caixa institucional, inteiros.

`MappedCosifAccounts` exige **20 rubricas obrigatórias**. O ETL WEBCTB de 27/07
criou **6** delas (as de tarifa) mais o caixa institucional. **Faltam 14.**
Enquanto faltar uma única, `MappedCosifAccounts.load!()` levanta e **nada é
cobrado**, com flag ligada ou desligada.

Conferi contra o plano do cliente já carregado: **nenhuma delas tem equivalente**.
Não é erro de mapeamento, é ausência real. O plano veio do balancete de maio da
operação legada, que não tinha trânsito de PIX, TED, título nem conta SPI.

Pedido: **código COSIF, nome e aval** para cada linha abaixo. A sugestão é seguir
a faixa reservada que o Bruno inaugurou (`seg7 >= 100`), fora da faixa que vem do
placon do cliente.

| # | Alias no motor | Natureza | Grau | Nome de referência | Para que serve no fluxo |
|---|---|---|---|---|---|
| 1 | `spi` | ATIVO | 6 | CONTA SPI - BCB | saldo da instituição no SPI, contraparte de todo PIX |
| 2 | `investment_asset` | ATIVO | 6 | TITULOS PUBLICOS FEDERAIS - COMPROMISSADAS | lastro aplicado |
| 3 | `settlement_pool` | ATIVO | 6 | VALORES A RECEBER - BOLETOS EMITIDOS | boletos emitidos a receber |
| 4 | `client_liability` | PASSIVO | 5 | CONTA PRE-PAGA - SALDOS DE LIVRE MOVIMENTACAO | **o saldo dos clientes**; contraparte de todo crédito e débito de conta |
| 5 | `boleto_transit` | PASSIVO | 4 | COBRANCA DE TERCEIROS EM TRANSITO | cobrança de terceiros em trânsito |
| 6 | `capital` | PL | 5 | CAPITAL | capital integralizado |
| 7 | `cash_itau_main` | ATIVO | 7 | CC PRINCIPAL NO BANCO LIQUIDANTE | conta corrente principal |
| 8 | `cash_itau_boletos` | ATIVO | 7 | CONTA BOLETOS NUCLEA | conta de boletos |
| 9 | `cash_reserve_bank` | ATIVO | 7 | BANCO RESERVA LIQUIDEZ | reserva de liquidez |
| 10 | `pix_out_transit` | PASSIVO | 7 | TRANSITO PIX CASH-OUT | PIX saindo, entre débito e liquidação |
| 11 | `pix_in_transit` | PASSIVO | 7 | TRANSITO PIX CASH-IN | PIX entrando, entre recebimento e crédito |
| 12 | `ted_out_transit` | PASSIVO | 7 | TRANSITO TED CASH-OUT | TED saindo |
| 13 | `ted_in_transit` | PASSIVO | 7 | TRANSITO TED CASH-IN / CARGA | TED entrando e carga |
| 14 | `titulo_transit` | PASSIVO | 7 | TRANSITO PAGAMENTO DE TITULO/CONVENIO | pagamento de título e convênio |

Os nomes da coluna "referência" vêm do plano da Owem, que é de onde o motor foi
portado. **Não são para copiar**: servem para o contador entender a função de
cada rubrica e escolher o código e o nome corretos no plano da Monetarie.

**Uma rubrica do porte foi REMOVIDA e não deve ser pedida:** o
`expense_planner_scd` ("despesa Planner SCD, participante direto"). Ela existia
porque a AvivPay **não** é participante direto e pagava essa despesa à Planner
SCD. **A Monetarie é a própria SCD, com participação direta, e a tarifa é
integralmente dela** (decisão do dono, 27/07). Removida do código no mesmo dia;
o obrigatório passou de 21 para 20 rubricas com alias.

**As 7 que já estão prontas** (feitas pelo Bruno em 27/07, nada a pedir):

```
1.1.1.10.01.10.100  CAIXA INSTITUCIONAL       -> caixa_institucional
7.1.7.10.01.10.100  RECEITA TARIFA PIX        -> fee_pix
7.1.7.10.01.10.101  RECEITA TARIFA TED        -> fee_ted
7.1.7.10.01.10.102  RECEITA TARIFA TITULOS    -> fee_titulo
7.1.7.10.01.10.103  RECEITA TARIFA CONTA      -> fee_conta
7.1.7.10.01.10.104  RECEITA TARIFA MENSAL PF  -> revenue_pf_monthly
7.1.7.10.01.10.105  RECEITA TARIFA MENSAL PJ  -> revenue_mei_monthly
```

---

## 2. Contabilidade: quatro dúvidas menores, mas que mudam o resultado

**De quem:** contador, com o Bruno.

**2.1. MEI é o mesmo que PJ?** O alias do motor é `revenue_mei_monthly` e a conta
criada chama "RECEITA TARIFA MENSAL **PJ**". Se o contador precisar separar MEI de
PJ, são **duas** contas e o motor precisa de uma rubrica a mais. Se para ele MEI
entra em PJ, fica como está e é só confirmar.

**2.2. Quem escreve a coluna `alias`?** O ETL WEBCTB cria as contas mas **não
escreve `alias`** (conferido: zero ocorrências no módulo). Sem essa coluna o motor
não acha as contas, mesmo com todas criadas. Precisa decidir se a amarração vai
para dentro do ETL, ao lado da definição das contas-padrão, ou se fica num seed
separado nosso. **Minha recomendação: dentro do ETL**, junto de onde a conta é
declarada, para não haver duas fontes de verdade.

**2.3. Faltam 8 lançamentos.** O ensaio local carregou **8272** lançamentos. A
anotação do time da rodada de laboratório fala em **8280**. São 8 de diferença e
eu não sei explicar. Pode ser o `ajustes_conciliacao.csv`, pode ser recorte de
data, pode ser que o dump mudou entre as rodadas. **Não vou tratar como conferido
até fechar.** Preciso saber qual era o número correto e de qual dump ele saiu.

**2.4. IOF a Recolher: dois códigos diferentes para a mesma rubrica.** Achei um
defeito hoje, e ele é contábil:

| Módulo | PF | PJ |
|---|---|---|
| `loans.ex:51` | `4.9.1.10.10.01.001` | `4.9.1.10.10.01.002` |
| `overdraft_journal.ex:52` | `4.9.1.10.10.01.001` | `4.9.1.10.10.01.002` |
| `accounting_bridge.ex:112` | `4.9.1.10.02.10.001` | `4.9.1.10.02.10.002` |

Perguntei ao plano vivo de produção: **os códigos do `loans.ex` e do
`overdraft_journal.ex` NÃO EXISTEM.** Os do `accounting_bridge` existem, mas com
outro significado:

```
4.9.1.10.02.10.001  IOF a recolher - operacoes de credito
4.9.1.10.02.10.002  IOF adicional a recolher (0,38%)
4.9.1.10.02.10.003  IOF a recolher - complementar
```

Não é PF contra PJ: é **IOF principal contra o adicional de 0,38%**, que incide
nos dois. O código trata `.002` como "a conta de PJ", o que classifica errado.

E o desembolso de empréstimo faz assim:

```elixir
if iof_amount > 0 do
  with {:ok, iof_credit_id} <- AccountingBridge.account_id(iof_code) do
```

`with` **sem `else`**. Quando a conta não existe, o `with` cai fora **em
silêncio**: nenhum erro, nenhum log. **O lançamento de IOF simplesmente não é
criado.** Preciso do contador para dizer qual conta recebe o IOF de cada caso, e
se PF e PJ realmente vão para contas distintas.

Ressalva: provei o defeito no código e a ausência dos códigos no plano. **Não
medi volume**, então não afirmo que já houve lançamento perdido em produção.

---

## 3. Dados: os dumps do cliente

**De quem:** Gabriel.

Os dumps **não ficam no repositório** porque contêm PII, e essa regra continua.
O ETL espera um diretório com `diario2026.csv` e `placon2026.csv`.

**3.1.** Preciso do par de arquivos **a cada rodada**, por canal seguro. Os que
recebi hoje cobrem até maio de 2026.

**3.2.** O corte combinado foi legado contra vivo em **30/06**, com **maio
fechado nesta rodada** e junho em backup complementar. Se junho entrar, preciso do
dump correspondente.

**3.3.** Registrando um risco que corrigi hoje: os arquivos chegaram na **raiz do
repositório**, sem estar no `.gitignore`, aparecendo como `??` no `git status`. Um
`git add -A` os teria commitado com PII dentro. Já pus a regra no `.gitignore`
(`diario*.csv`, `placon*.csv` e o padrão do diretório de dump). Vale combinar um
diretório fora do repositório para as próximas.

---

## 4. Partner API: o que o Micael precisa saber, e o que preciso dele

**De quem:** Micael, e decisão de produto.

**4.1. A consulta ao DICT já aceita o pagador. Não é header, é query string.**

```
GET /api/partner/v1/pix/dict/{chave}?payerDocument=<CPF ou CNPJ do pagador>
GET /api/partner/v1/pix/dict/{chave}?accountId=<id da conta do parceiro>
```

**CORRIGIDO em 27/07, decisao do dono.** O codigo tinha um fallback: sem
parametro, mandava o documento do PROPRIO parceiro como PI-PayerId. Isso foi
removido e nao deve voltar. O parceiro nao tem conta e aqui nao se opera como
BaaS: dizer ao BACEN que quem paga e o parceiro e falso, e concentra o balde
antifraude (item 13, hoje em `enforce` nos dois ambientes, categoria G em
producao com 250 fichas) num documento que nao paga nada.

Como ficou:

- **`accountId` e obrigatorio.** Sem ele, 422 `payer_account_required` e o DICT
  nao chega a ser chamado.
- O PI-PayerId e **sempre** o documento do titular daquela conta.
- `payerDocument` deixou de ser fonte e virou **conferencia**: se vier e nao
  bater com o titular, 422 `payer_document_mismatch`.

**Mudanca de contrato para quem ja integra:** chamadas sem `accountId` passam a
receber 422. E intencional. O Micael precisa ajustar a chamada dele, que hoje e
`GET /pix/dict/{chave}` sem parametro nenhum.

**4.2. A tela de credenciais existe e está no menu**, em `ADMINISTRAÇÃO ->
Parceiros`. Cria parceiro, cunha chave com permissões e whitelist de IP, e mostra
`client_id` e `client_secret` uma única vez. Não falta tela.

**4.3. O que trava o cliente:** o backend exige a feature RBAC
**`admin.parceiros`**, e ela **não existe no catálogo de nenhum ambiente** (97
features em PRD e HML, só `admin.provedores`). Só `super_admin` passa. Qualquer
operador do cliente vê o menu, clica e toma **403**. Eu conserto isso, não é
pedido; está aqui para o time saber por que "não dava para cadastrar".

**4.4. Confirmar com o Gabriel o que ele precisa de verdade.** O relato foi que a
chave "não lista as contas já existentes". A causa é que a listagem filtra por
`users.partner_id`, e em produção há **0 usuários carimbados de 1607 contas**. A
decisão tomada foi **abrir o escopo por entidade, para leitura e para ação**.
Preciso que o time saiba o alcance disso, porque é grande: **uma chave de parceiro
com `transfer:write` passa a poder debitar qualquer uma das 1607 contas de
produção**, não só consultar. Se a intenção do Gabriel era apenas **consultar** a
base existente, vale rever antes de eu subir.

---

## 4-A. DICT: estamos ancorados em três versões ao mesmo tempo

**De quem:** decisão do dono mais trabalho nosso. **Não é pedido de dado.**

Conferi a fonte oficial hoje
(https://www.bcb.gov.br/content/estabilidadefinanceira/pix/API-DICT.html): a
versão publicada é **DICT API 2.12.1**. No repositório convivem três âncoras:

| Âncora | Onde | Situação |
|---|---|---|
| **v2.10** | fixtures oficiais em `apps/shared/test/fixtures/dict/v2.10/` | é contra elas que testamos |
| **2.11.0** | 48 arquivos, em comentários e moduledocs | é o que o código *afirma* seguir |
| **2.12.1** | `runtime.exs:140`, `funds_recovery_test.exs`, `entry_delete_reason_test.exs` | migração **parcial**, já feita em alguns pontos |

Ou seja, a migração para 2.12 **começou e não terminou**, e os comentários
ficaram para trás. A gap analysis de 26/07 já registrou o buraco concreto: o
modelo de `Refund` do legado tem `EffectiveRefundedAmount`, `FundsRecoveryId`,
`MonitorAccount` e um `RefundAccount` completo, e o nosso
`build_create_refund_xml/2` não tem nada disso. Aquele documento fecha dizendo
**"precisa do contrato 2.12.1 de devolução para fechar"**.

**O que eu NÃO vou fazer:** trocar em massa os 48 comentários de 2.11.0 para
2.12.1. Um comentário dizendo 2.11.0 é ao menos honesto sobre o que foi
verificado; trocá-lo sem auditar seria afirmar conformidade que não provamos, e
é exatamente o erro que a própria gap analysis se retratou de ter cometido.

**O que precisa ser feito, nesta ordem:** (1) gap analysis do delta 2.11.0 para
2.12.1 contra a página publicada, operação a operação; (2) atualizar as fixtures
de v2.10 para 2.12.1; (3) só então acertar as referências de versão no código.
Eu não sei hoje o que mudou entre as duas versões e não vou supor.

---

## 4-B. RESOLVIDO: a devolução recebida não liquidava pela pacs.002

**Estado: corrigido em 27/07, commit `5156f583`. Falta deploy.**

### O que foi relatado

Uma devolução aparecia como pendente na tela e só virava liquidada minutos
depois. A operação: `E46026562202607272219sc3w7ej6h6r` (envio de R$ 1,00) e a
devolução `D18236120202607272221s0681ba15b8`, MD06, da Nu Financeira.

### Duas afirmações minhas que estavam erradas, antes da correta

1. **"A devolução está parada e talvez não liquidou."** Errado. Ela liquidou. Eu
   concluí a partir de duas colunas do Core (`status = 0` e `tb_settlement_id`
   nulo) sem abrir a timeline da operação, que estava na tela e responde tudo.
2. **"Liquidou pela camt.054, que o BACEN exige."** Errado, e pior: eu não tinha
   e não tenho documento nenhum do BACEN dizendo isso. Li o rótulo `CAMT054` na
   coluna de origem da NOSSA tela e transformei em afirmação sobre o protocolo.

### A medição que resolveu

Contra o banco de produção, comparando **entrada com entrada**:

```
PIX recebido (pacs.008 inbound), 29 casos em julho:
    BACEN   | status 4 (ACSC) | pacs.002    <- liquida por pacs.002, em segundos
    SYSTEM  | status 4        | pacs.008

Devolucao recebida (pacs.004 inbound), 4 casos:
    CAMT054 | status 7 (STLD) | pacs.004    <- unica transicao, so por camt.054
```

Mesma direção: o PIX recebido liquida pela pacs.002 e a devolução não. Se fosse
característica do protocolo, os dois dependeriam da camt.054. **O defeito era
nosso.** No caso citado, 2m16s de janela contra 655ms do envio.

### Causa-raiz

A linha da devolução de entrada não era alcançável por estratégia **nenhuma** de
`find_correlated_transaction/2`:

```
find_tx_by_return_id(...)  ->  filtrava `direction == "OUTBOUND"`
find_tx_by_e2e(...)        ->  exclui `message_code != "pacs.004"`, de proposito
```

A exclusão no lookup por E2E está **certa** e continua: a pacs.004 não tem E2E
próprio, carrega o do pagamento original, e sem a exclusão a devolução roubaria o
pacs.002 do pagamento. O erro era o filtro de direção no lookup por RtrId.

Somados os dois, o pacs.002 da devolução caía na linha do pagamento **original**,
que tem o mesmo E2E e já está terminal, e a guarda de status terminal o
descartava como no-op silencioso.

### Correção

`find_tx_by_return_id/1` não filtra mais direção. É seguro porque o RtrId
identifica a devolução e não quem a emitiu: o RtrIdType do XSD carrega o ISPB do
emissor, então é único no SPI. Teste novo cobre a devolução de entrada e falhava
exatamente com o defeito. Suíte de workers do `spi_service`: **480/0**.

### O que fica pendente de validação, e o time precisa saber

1. **Deploy da cabine PIX: FEITO em 27/07.** Tag `*-7a77f2c3-devolucao-20260727`.
   Provado vivo em homologação contra dado real: a devolução INBOUND
   `D78632767202607201837TGSLECabrew` (msg 54749) passou a ser encontrada por
   `find_correlated_transaction`, com `dir=INBOUND`. Antes do fix aquela linha
   era inalcançável por qualquer estratégia.
2. **As 4 devoluções já liquidadas em produção não precisam de reparo** de saldo:
   elas liquidaram, só que tarde. Mas vale conferir se alguma ficou com status
   terminal divergente entre cabine e Core.
3. **`status_id = 7` (STLD) é marcado como NÃO terminal** no
   `operation_status_codes`, enquanto `4` (ACSC) é terminal. Depois do fix a
   devolução deve passar a terminar em ACSC como o resto. **Confirmar com o time
   se STLD ainda deve existir**: o catálogo o descreve como "representação
   legada" e a busca no `LegadoPIX` **não encontrou nenhum uso de STLD**.
4. **A linha do Core com `status = 0`: MEDIDO, e NÃO é anomalia.** Conferi 8 PIX
   de entrada dos últimos dias em produção e **todos** estão com `status = 0`,
   `payment_status = "completed"` e `tb_settlement_id` nulo. Essa coluna não é
   usada no caminho de entrada. Era pergunta; a resposta é que não é defeito.

### Verificação contábil: NÃO há erro de lançamento

Pedido direto do dono. Conferido contra `cosif_journal_entries` de produção,
todos os lançamentos de 27/07:

```
PIX | 16152                            |   37000 | 06:39:40
PIX | 16153                            | 5000000 | 18:53:10
PIX | 16154                            |  320000 | 20:46:28
PIX | PIXOUT-83f7949d99117009          |     100 | 22:20:58   <- o envio de R$ 1,00
PIX | PIXOUT-ca5d2b6dba137109          | 5000000 | 22:22:15
PIX | PIXRET120202607272221s0681ba15b8 |     100 | 22:23:14   <- a devolucao de R$ 1,00
```

**As duas pernas têm lançamento, com o valor certo.** O envio sob `PIXOUT-` e a
devolução sob `PIXRET`. O extrato do cliente bate com o razão.

Ressalva de método, porque quase virou um quarto falso alarme: os lançamentos de
PIX **não** referenciam a transação do Core pelo UUID dela, e sim pelo **id da
mensagem da cabine** (16152, 16153...) ou por uma chave própria (`PIXOUT-`,
`PIXRET`). Buscar por UUID devolve zero e parece buraco contábil. **Não é.**

**Efeito colateral positivo da correção:** o lançamento da devolução foi gravado
às 22:23:14, no instante da camt.054. Com o fix, passa a ser gravado quando a
pacs.002 chega, cerca de dois minutos antes. Mesmo dia, mesmo valor, só mais
cedo.

---

## 5. Decisões que faltam, sem dependência de terceiros

**De quem:** dono.

**5.1.** `pix_automatic` é cobrável de PF ou fica vedado? Hoje está vedado, na
leitura de que o PIX Automático debita o pagador, logo é PIX saindo de conta PF.

**5.2.** As vedações legais devem ser configuráveis por tela? Hoje `@pix_pf_vedado`
está cravado de propósito: configurável, um admin poderia habilitar cobrança
ilegal.

**5.3.** RBAC de `escrow_controller` e `coreproviders_parity_controller`. Os dois
estão apenas atrás de `:admin_only`, que aceita **qualquer** `platform_admin`,
inclusive `viewer`. O segundo é a tela que altera permissões e whitelist de IP de
chave de API. Precisa de decisão sobre qual papel alcança cada um.

**5.4.** Autorização de push. Tenho 39 commits locais.

---

## 6. O que eu faço sozinho, e não precisa ser pedido

Fica registrado para ninguém duplicar trabalho:

- Semear a feature `admin.parceiros` com view, create, edit e delete, e alinhar o
  `requiredRbac` do menu e da rota, que hoje aponta para `admin.provedores`.
- Abrir o `PartnerScope` conforme a decisão tomada, com o alcance travado por
  teste.
- Escrever a coluna `alias` sobre as 7 contas que já existem, assim que ficar
  decidido se isso vai para dentro do ETL ou para um seed separado.
- Corrigir o `with` sem `else` do IOF para falhar alto em vez de perder o
  lançamento em silêncio, assim que o contador disser qual é a conta certa.
- Documentar o `payerDocument` no portal do parceiro.

---

## 7. Estado, para quem for retomar

- Ensaio do ETL WEBCTB feito **somente no banco local**: 8272 lançamentos, 400
  contas criadas, 1 disponibilidade, snapshots de fevereiro a maio regenerados.
  **HML e PRD não foram tocados.**
- `cosif_accounts` com `alias`: **0** em local, HML e PRD. O bloqueio segue de pé.
- Flags `enable_fee_split` e `enable_caixa_institucional_mirror`: **`false`** nos
  dois ambientes. Nada foi ligado.
- Antes de afirmar qualquer estado de infraestrutura, rode
  `./scripts/estado-vivo.sh`.

---

## 8. REINCIDENTE: pagador e recebedor em branco no extrato

**De quem:** trabalho nosso. **Não é pedido, é defeito.** O dono já mandou
corrigir isso em definitivo antes, e voltou.

Print do extrato do coreadmin (conta GABRIEL CARDOSO, 099.183.589-12), em
27/07:

| Data | Descrição | Pagador | Recebedor |
|---|---|---|---|
| 24/07 | Estorno: PIX recebido (3 linhas) | GABRIEL CARDOSO | **em branco** |
| 25/07 | PIX recebido | **em branco** | GABRIEL CARDOSO |
| 27/07 | PIX enviado - Gustavo Franzoi Scroferneker | GABRIEL CARDOSO | Gustavo, 848.338.820-00 |
| 27/07 | **Devolução recebida** | **em branco** | GABRIEL CARDOSO |

O padrão é nítido: **a saída preenche a contraparte, a entrada não.** Estorno
perde o recebedor; PIX de entrada e devolução perdem o pagador.

**Causa, com evidência, e o dado NÃO está perdido.** A cabine **tem** o pagador.
A mesma operação, na tela do pixadmin, mostra "Gustavo Franzoi Scroferneker,
848.338.820-00, ISPB 18236120". O que chega ao Core é que vem capado:

```json
{"source": "pix_return_received", "payer_ispb": "18236120",
 "payer_name": null, "payer_document": null,
 "original_e2e_id": "E46026562202607272219sc3w7ej6h6r"}
```

O ISPB atravessou; **nome e documento chegaram nulos**. Então não é caso de
"informação indisponível": é informação que **existe na cabine e não cruza para
o Core** no evento de devolução.

E há ainda uma segunda fonte, redundante, também disponível: o pagador de uma
devolução é, por definição, o **recebedor da operação original**, e a
`E46026562...` carrega o Gustavo com nome e CPF. Os dois lados guardam o vínculo
(`original_end_to_end_id`). Nenhuma das duas fontes é usada.

Mesma família do que já foi corrigido em 15/07 e 22/07 para outros tipos
([[monetarie-extrato-contraparte-comprovante-0715]],
[[monetarie-extrato-pagador-recebedor-otp-0722]]). Ficou de fora: **devolução,
estorno e PIX de entrada sem identificação na mensagem**.

**Correção devida, e desta vez pela raiz, não por tipo:** um único ponto de
resolução de contraparte que, quando a mensagem não traz nome ou documento,
busca no vínculo que já existe (a operação original) e, só então, desiste. E um
teste por tipo de lançamento que reprove extrato com contraparte vazia quando a
informação é obtenível. Enquanto a correção for tipo a tipo, o próximo tipo
volta a nascer torto.

