# Estudo: contabilização instantânea das cabines PIX/SPB no Core

**Data:** 2026-07-10. **Método:** 4 trilhas de leitura de código com evidência arquivo:linha + prova viva E2E no ambiente local (PIX simulado de R$ 1,00 rastreado da cabine ao razão do Core). **Pergunta do dono:** quando um PIX acontece, além do saldo do cliente (TigerBeetle), o Core gera os lançamentos COSIF corretos (trânsito de PIX, conta SPI, 4.9.x de clientes)? Existe esse mapeamento hoje?

## Veredito em uma linha

**SIM, o mapeamento existe e roda hoje (PIX-in e PIX-out geram lançamento COSIF automático no Core), mas ele é raso (2 contas, sem trânsito PIX nem Conta PI) e tem defeito grave provado vivo: o PIX-in REAL contabiliza INVERTIDO (registra um envio para cada recebimento) e as pernas PIX gravam o razão em SUBCENTAVOS (100x inflado vs a convenção do módulo).**

## 1. O que existe hoje (mapa)

### 1.1 O módulo contábil do Core (mon_core)

- Tabelas: `cosif_accounts` (plano vivo, 364 contas), `cosif_journal_entries` (particionada por mês; índice único PARCIAL `(reference_type, reference_id, entry_date) WHERE NOT NULL`), `cosif_posting_templates` (60 ativas), `cosif_account_balances`, `accounting_periods`, `spb_cosif_mirror`.
- Escrita única: `Monetarie.UseCases.Cosif.create_journal_entry/2` (`use_cases/cosif.ex:284-301`).
- **Três motores** geram lançamentos:
  1. **`Cosif.Mapper`** (`use_cases/cosif/mapper.ex:63-181`): mapa HARDCODED transfer code TB → par D/C (code 1 deposit, 6 pix out, 8 ted, 5/401/403/406 tarifas). Usado pelos handlers NATS de PIX/SPB e pelo `JournalEntryWorker`.
  2. **`Cosif.PostingEngine`** (`use_cases/cosif/posting_engine.ex`): evento→template em DADOS (`cosif_posting_templates`). Usado em runtime SÓ pelo SISBAJUD (`SBJ_BLOCK`/`SBJ_UNBLOCK`, provado vivo com 4 JEs locais). Templates `PIX_SEND`/`PIX_RECEIVE` EXISTEM no banco mas estão MORTOS (sem caller) e apontam contas inexistentes/vedadas p/ SCD (ex.: `2.1.1.10.00-9` Depósitos).
  3. **`Accounts.AccountingBridge`** (`use_cases/accounts/accounting_bridge.ex`): categoria de account_entry → par COSIF (com `accounts.cosif_account_code`, fallback `4.9.8.10.01.10.002`). Usado pelo crédito STR do SPB, back-office e crédito.

### 1.2 O caminho PIX no Core (existe, mas genérico)

- **PIX-in**: `PixConsumer` (`monetarie.spi.transaction.*`) → `MoneyBoundary` (reais→subcentavos) → `PixHandler.handle_transaction_ledger` → `create_pix_journal_entry` (`pix_handler.ex:933-991`) via Mapper code 1 = **D `1.1.2.10.01.10.001` (Conta de liquidação/banco liquidante) / C `4.9.8.10.01.10.002` (Obrigações por prestação de serviços de pagamento)** → depois crédito TB + extrato + tarifa.
- **PIX-out**: liquidação → `AtomicPaymentHandler.post_and_settle` → `move_to_transactions` enfileira `JournalEntryWorker` (Oban `:cosif`) NA MESMA transação PG (`use_cases/payments/outbound_requests.ex:192-195`) → code 6 = D 4.9.8 / C 1.1.2.
- Devolução e devolução-rejeitada também contabilizam (com JE espelho); tarifa PIX contabiliza via `FeeCharger.record_cosif_entry` (fail-soft).

### 1.3 O que NÃO existe no plano vivo

Sob `1.1.x` há somente Caixa, Depósitos Bancários e Reservas Livres. **Não existe** conta "Relações com o SPI"/"Conta PI"/"Pagamentos Instantâneos" **nem conta transitória de PIX**. Todo PIX liquida contra a MESMA `1.1.2.10.01.10.001` usada pelo banco liquidante — o balancete não distingue o que está na Conta PI no BACEN do que está no liquidante, e um PIX-in tem o mesmo lançamento de um depósito genérico.

### 1.4 A contabilidade da cabine PIX (espelho operacional, não a contabilidade da instituição)

- 2 contas (CosifSeeder, ancoradas VERBATIM no `scd_cosif_plan.exs` do Core), journal fail-fast P11.
- Único produtor automático: `SettlementObligationWorker` sobre `transaction.settled` — que no modelo canônico do PIX-in real NUNCA acontece (crédito vai pelo `created`). Na prática a contabilidade da cabine só roda para OUTBOUND liquidado; **PIX-in orgânico não gera lançamento nenhum na cabine** (journal_entries=0 no local com fluxo rodando).
- Balance sheet/Circular 4010 da cabine operam sobre 2 contas — não servem como demonstração contábil da instituição. **A arquitetura correta é a contabilidade oficial viver no Core** (como já vive); a cabine é espelho de liquidação.

### 1.5 O padrão-ouro (SPB novo + SISBAJUD)

O caminho `monetarie.spb.credits.inbound` → `InboundCredits.post_member_credit` é o modelo a seguir (`use_cases/spb/inbound_credits.ex`): **TigerBeetle primeiro** (id determinístico/idempotente por `num_ctrl_str`) → **Ecto.Multi ATÔMICO** com AccountEntry + transaction `SPBCR...` + **JE COSIF em CENTAVOS** via AccountingBridge → desfecho auditado em `resolution["cosif_je"]` p/ repair do contador. O SISBAJUD adiciona o padrão evento→template em dados (PostingEngine, fail-closed no Multi). A cabine SPB ainda mantém contabilidade própria standalone (roteiro do legado, 303 eventos) + espelho `spb_cosif_mirror` para conciliação (flag `cosif_to_core` OFF por design, sem duplicar).

## 2. Defeitos encontrados (com prova)

### P0 — INVERSÃO CONTÁBIL NO PIX-IN REAL (afeta produção)

`pix_transfer_code/1` (`pix_handler.ex:993-1007`) faz match EXATO minúsculo de direction. O evento real da cabine sai com `direction: "INBOUND"` (maiúsculo, `inbound_processor.ex:2882`). O fix case-insensitive de 09/07 (`944cbde2`) corrigiu a perna TB (`AccountResolver.inbound_direction?`), **mas não a perna COSIF**: o PIX-in real cai no code 6 (envio) e o razão registra **D 4.9.8 / C 1.1.2 — um PIX ENVIADO para cada PIX RECEBIDO**. Provado vivo no local (journal invertido com TB creditando certo, +R$1,00 conta 1774). **Este código está em produção (`core-api:9`)**: se nenhum PIX-in orgânico aconteceu ainda, o acervo está limpo; conferir antes que o primeiro chegue.

### P0 — UNIDADE 100x NAS PERNAS PIX

`create_pix_journal_entry` e `JournalEntryWorker` gravam o journal em SUBCENTAVOS (o MoneyBoundary converte antes do handler), enquanto a convenção canônica de `cosif_journal_entries` é CENTAVOS (`money_unit.ex:33-37`; SPB/judicial convertem com `to_cents`). Razão/balancete somando origens mistas distorce as pernas PIX em 100x. Mesma suspeita nos JEs de tarifa (`fee_charger.ex:173` declara centavos, recebe base units).

### P1 — JOURNAL ÓRFÃO E DUPLICADO (sem atomicidade nem dedup)

O JE do PIX-in é criado ANTES do crédito TB, fora de transação (`pix_handler.ex:449-451`). Se o TB falha e o NATS redelivera, cada entrega recria o lançamento quando `reference_id` é NULL (o índice único parcial não deduplica NULL). Provado vivo: 4 JEs duplicados de um mesmo disparo, SEM nenhum crédito correspondente (contabilidade sem dinheiro). PIX-out é fail-silent após 5 tentativas do Oban (JE perdido com só log, sem desfecho auditado nem reconciliação journal×transactions).

### P1 — Cobertura e contratos mortos

- Caminho legado `SpbHandler.handle_transaction_ledger` repete os defeitos do PIX (journal antes do TB, subcents, codes genéricos) — só o caminho novo `credits.inbound` é correto.
- Handshake morto duplo: cabine publica `monetarie.settlement.transaction.credited` (money_path) que ninguém consome; Core tem handler de `monetarie.settlement.session.credit` que ninguém publica.
- Evento `created` INBOUND real sai com `amount=0` no payload da cabine (tx.amount virtual nunca setado) — o Core lê `payload["amount"]`; risco de crédito zero se o caminho ICOM→NatsBridge for o produtor.
- Extrato do PIX-out não é escrito pelo caminho principal de liquidação (`move_to_transactions` não insere account_entry).

### P2 — Ambiente/local e higiene

- Rota realista pacs.008→InboundProcessor morta no LOCAL: o req/reply `monetarie.core.pix.validate_account` cai DENTRO do stream JetStream `MONETARIE_CORE` (`monetarie.core.>`) e o PubAck chega antes da resposta → poison DLQ. **Investigar se HML/prod têm a mesma sobreposição** (o E2E de HML de 09/07 validou o `created` direto, não este req/reply).
- Simulador local: `default_account_id "201"` hardcoded (`scenario_runner.ex:43`) não existe na base local → inject-inbound suja COSIF+DLQ sem creditar.
- Codes 607/608 (compulsório) do Mapper apontam contas em formato legado que não existem no plano (fail-closed se emitidos).
- Resíduos do teste E2E no LOCAL (documentados; sem impacto fora do dev): +R$1,00 no TB da conta 1774, 5 JEs de teste (4 dup + 1 invertido), 1 linha em transactions/account_entries/WAL, DLQ entries.

## 3. Recomendações (ordem sugerida)

1. **P0 imediato**: fix case-insensitive em `pix_transfer_code/1` (mesma classe do `944cbde2`) + conversão `to_cents` nas pernas PIX (journal e fee). Verificar acervo de `cosif_journal_entries` reference_type='PIX' em PROD antes do 1º PIX orgânico; estornar/ajustar se houver.
2. **P1 — padrão SPB no PIX**: mover o JE do PIX-in para DEPOIS do TB, dentro do Multi com extrato/transactions (como `InboundCredits`), `reference_id` SEMPRE preenchido (e2e/tx id) para o dedup do índice funcionar; desfecho auditado tipo `resolution["cosif_je"]` no PIX-out.
3. **P1 — plano de contas com o contador**: criar folhas próprias (ids >= 50_300 no `scd_cosif_plan`): conta "Relações com o SPI / Conta PI" (1.1.x ou 1.8.x conforme orientação) e transitória de PIX se o desenho contábil exigir; então migrar o mapeamento do Mapper (ou ativar os templates `PIX_SEND`/`PIX_RECEIVE` do PostingEngine com as contas corrigidas — a infraestrutura evento→template já está pronta e é o desenho mais governável).
4. **P2**: limpar contratos NATS mortos; `amount` no payload do `created` INBOUND; extrato no caminho principal do PIX-out; simulador local com conta default válida; investigar overlap req/reply×stream em HML/prod; limpar resíduos do teste no local.

## 4. Matriz fluxo × tratamento contábil (estado atual)

| Fluxo | Saldo cliente (TB) | Extrato | Contab. cabine | COSIF Core | Qualidade |
|---|---|---|---|---|---|
| PIX-in real (created INBOUND) | OK (fix 09/07) | OK | NÃO roda | **INVERTIDO**, subcents, sem atomicidade/dedup | P0 |
| PIX-out liquidado | OK | só via handle_tracked_status | OK (obrigação netting) | OK direção; subcents; fail-silent | P0 unidade |
| Devolução PIX | OK | OK | não | OK (espelho no rejeitado) | subcents |
| Tarifa PIX | OK | — | não | fail-soft | suspeita 100x |
| STR crédito (credits.inbound) | OK (TB-first) | OK (Multi) | roteiro próprio + mirror | OK, CENTAVOS, auditado | padrão-ouro |
| TED settled genérica (SpbHandler legado) | OK | — | — | codes genéricos, subcents, pré-TB | igual PIX |
| SISBAJUD block/unblock | hold TB | — | — | PostingEngine template, fail-closed, idempotente | padrão-ouro |

**Fontes:** workflow `wf_de54de0e-ab1` (5 agentes, resultados integrais em `journal.jsonl` do transcript da sessão); evidências arquivo:linha citadas ao longo do texto; prova viva executada em 2026-07-10 no ambiente local.
