# Handoff 2026-07-13 — Contabilização PIX (Fase 1 + Fase 2) + merge da main + push

> Retomar via `/retomar`. Fecha a frente de **contabilização automática do PIX no Core** (Fases 1 e 2) e traz a branch a **100% de paridade com a main**. Tudo pushado COM autorização explícita do dono.

## Estado da branch (canônico)

- `origin/feat/monetarie_improviments` = **`7dfae726`** (pushado, branch 0/0 com o remoto).
- Commits desta sessão sobre a base:
  - `d28c796b` — **Fase 0**: reconciliador COSIF do PIX (read-only), endpoint + tela Tesouraria (pushado na sessão anterior).
  - `e4d1b380` — **Fase 1**: PIX-in materializa a perna PG num `Ecto.Multi` atômico.
  - `ccafc6eb` — **Fase 2**: reconciliação separa espelho COSIF pendente de falho no PIX-out.
  - `7dfae726` — **Merge da main** (45 commits) na branch.
- Ambiente local **no ar e validado** (core-api :4002 healthy, core-admin :5180 healthy, endpoint Fase 2 vivo).

## Princípio que guiou tudo (reforçado pelo dono)

**A contabilidade COSIF é a TERCEIRA/última perna, um espelho regulatório.** NUNCA bloqueia, atrasa ou desfaz o transacional (dinheiro no TigerBeetle, registro, hold, extrato do cliente) nem toca em saldo. O operacional (TB + transacional das cabines) segue exatamente como já funciona, performático; o COSIF vem por último só para refletir no balancete. Se o espelho falhar, o operacional segue e a falha vira **dado reconciliável**, não um freio.

## O que foi entregue

### 1. Fase 1 — PIX-in atômico (`e4d1b380`, TDD)

O crédito PIX-in no Core deixou de ser "3 escritas PG soltas" (journal + transação + extrato, as duas últimas fire-and-forget) e passou a nascer num **único `Ecto.Multi`** (`persist_pix_in_pg` em `core/backend/lib/monetarie/infra/nats/handlers/pix_handler.ex`), no padrão SPB `InboundCredits`:
- **TB primeiro e FORA do Multi** (money-first, id determinístico, fail-closed — inalterado). Quando o COSIF entra, o cliente **já está creditado no TB**.
- `:cosif_je` **FAIL-SOFT** (nunca segura o crédito; falha vira desfecho registrado, exposto pela reconciliação da Fase 0).
- `:transaction_record` e `:statement_entry` — pernas do cliente: falha genuína faz rollback de TODAS (WAL fica em `tb_done`, o `PixInCreditRecoveryWorker` reexecuta, idempotente).
- Antes desse fix, o journal estava DENTRO do `with` que porteava a transação/extrato — um erro de COSIF **bloqueava** o registro do cliente (violação do princípio). Agora o journal é fail-soft categoricamente.
- Recovery `replay_pg_leg` passou a usar o MESMO `persist_pix_in_pg` (fonte única). Monitor PLD e fee movidos p/ post-commit.
- Teste: `test/monetarie/infra/nats/handlers/pix_handler_atomic_pg_test.exs` (5/5: sucesso, atomicidade transação/extrato, fail-soft, idempotência).
- **Saldo do cliente vem do TB** (`Wallet.get_balance` = credits−debits), então rollback do Multi nunca esconde o dinheiro (só a projeção PG, que o recovery refaz).
- Caminho vivo confirmado: `two_phase_pix_in_enabled` = OFF (default, PROIBIDO ON), então o path `tb_first`/`PixInPgWriteJob` está DORMENTE e não sobrepõe o Multi.

### 2. Fase 2 — reconciliação distingue espelho pendente de falho (`ccafc6eb`, TDD)

O journal COSIF do PIX-**out** nasce ASSÍNCRONO (`JournalEntryWorker`, fila `:cosif`, enfileirado atômico com a transação em `OutboundRequests.move_to_transactions`) — o espelho é a última perna e NÃO segura a saída. A reconciliação da Fase 0 gritava `missing_journal` para QUALQUER transação sem journal, incluindo as que só ainda não rodaram. Agora (`core/backend/lib/monetarie/use_cases/cosif/pix_reconciliation.ex`) ela consulta o ciclo de vida do job Oban (READ-ONLY, SELECT em `oban_jobs`) e separa:
- `:journal_pending` — job em estado não-terminal E **fresco** (`inserted_at` na janela de 30 min) → async lag normal, NÃO é divergência (sai em `summary.pending`, card âmbar).
- `:missing_journal` — job descartado (falhou 5x), inexistente (podado/nunca enfileirado) OU **travado** (executing órfão > janela) → falha real.
- **Achados do code review adversarial (corrigidos):** (a) job `executing` órfão (node morre/OOM antes do commit; não há `Oban.Plugins.Lifeline`) mascararia um journal ausente para sempre → **janela de frescor** (`@pending_max_age_seconds 30*60`); (b) TOCTOU journals↔oban → leio o **Oban ANTES dos journals**.
- Teste: `test/monetarie/use_cases/cosif/pix_reconciliation_test.exs` (13/13, incl. executing-órfão). Provado empiricamente contra `mon_core`: string do worker Oban (`Monetarie.Workers.Cosif.JournalEntryWorker`, sem `Elixir.`) e gating OFF do `PixInProjectionWorker`.
- 100% espelho: zero escrita, zero toque no transacional. **NÃO incluído (é transacional, não COSIF):** o gap do extrato do PIX-out (`account_entries`) — item separado, exige estudo próprio.

### 3. GARANTIA verificada: COSIF em CENTAVOS nos 3 caminhos regulatórios

Verificado no código (não só na doc):
- **Tabela de decisão do `Monetarie.Util.MoneyUnit`**: `cosif_journal_entries` = centavos; `judicial_blocks/orders` = centavos; `account_entries` (extrato), `transactions`, holds TB = base units (subcentavos).
- **PIX**: `MoneyUnit.to_cents(amount)` (`journal_entry_worker.ex:45`, `pix_handler.ex:803/1085`).
- **SPB**: `AccountingBridge.journal_attrs_for_create` → `MoneyUnit.to_cents(abs(entry.amount))` (`accounting_bridge.ex:264`).
- **SISBAJUD**: `post_cosif_entry(..., amount_to_block, ...)` onde `amount_to_block = block_amount_cents` (`processor.ex:1572/1596`); `from_cents` só na fronteira do hold TB.
- **Guardião contínuo**: a Reconciliação Contábil PIX (Fase 0) checa `transaction.amount ÷ 100 == journal.amount` → grita `amount_mismatch` (100x) se algum caminho escrever COSIF em subcentavos.

### 4. Merge da main (45 commits) — `7dfae726`

Paridade com a main (simuladores PIX/SPB completos, TED-in duplo JE, webhooks canônicos, escala centavos/subcentavos, pagador/recebedor SPB/PIX-admin, 26 telas de path `/v1`, ETL AutBank). **Fase 1 e Fase 2 preservadas** (não conflitaram; `pix_handler.ex` auto-mergeou limpo — main mexeu só no path OUTBOUND de webhooks). Análise dos 7 conflitos por workflow de agentes + verificação de money-path + testes:

| Arquivo | Resolução |
|---|---|
| `judicial/processor.ex` + `SisbajudView.vue` | **OURS (centavos)** — decisão do dono (ver abaixo) |
| `reports/accounts_balance.ex` + `checking_account_reports.ex` (+teste) | **THEIRS** — a main evoluiu o mesmo fix de fan-out p/ superset money-EQUIVALENTE (group_by conta, sem duplicar) que cobre onboarding + KPI `members_with_balance_count`; testes de fan-out nossos mantidos (combine) |
| `dashboard/aggregator.ex` | **COMBINE** guiado pelo nosso teste (def pública, filtro status-aceito-OU-payment_status-liquidado, janela BRT) + `ted_in/ted_out`/`meds_abertos` reais da main |
| `AccountSearch.vue` | **COMBINE** (nosso refetch + `forbidden` da main, usado fora do bloco) |
| `CLAUDE.md` | combine cronológico (07-11 canônico, 07-10 anterior) |

**Verificação do merge:** compile limpo; reports 52/0, cosif+dashboard 132/0, judicial 0 falhas, aggregator 2/0, Fase 1 5/0, Fase 2 13/0.

### 5. Push + rebuild + gotcha do seccomp

- Push feito: `a5ebe3bd..7dfae726`.
- Rebuild das 2 imagens locais + recreate dos containers preservando env/rede/porta.
- **GOTCHA (já documentado no `dev_commands` do Serena, mas eu esqueci no 1º run):** o container local do core-api PRECISA de `--security-opt seccomp=unconfined` (io_uring do NIF TigerBeetle) senão crash-loop (exit 133, `PermissionDenied` no `tb_client_context`). Recriado com seccomp → subiu limpo.
- core-api reassumiu IP **192.168.155.4**; `CORE_API_UPSTREAM` do core-admin religado a ele.

## DECISÃO do dono (money-path) — registrar

**Unidade do judicial (SISBAJUD) = CENTAVOS.** As duas branches escolheram convenções OPOSTAS para `blocked_amount`/`total_blocked` (nossa=centavos, fix `e8f48c0b` validado vivo + schema `judicial_block.ex` documentado "NÃO assuma base_units"; main=base_units) e o git auto-mergeou inconsistente. O dono decidiu **manter CENTAVOS**. A main não tinha migração nem a doc de unidade → o judicial-centavos é 100% obra da nossa branch.

## PENDÊNCIAS / FOLLOW-UPS (priorizados)

0. **PRÓXIMO GRANDE MANDATO — backup contábil (chega nos próximos dias, confirmado pelo dono em 2026-07-13):** o dono vai disponibilizar o backup com TODO o contábil + o plano de contas OFICIAL da Monetarie. A MECÂNICA da contabilização já está pronta (Fase 1/2 + garantia centavos + reconciliador) esperando o CONTEÚDO real. Com o backup: (a) **MIGRAÇÃO** dos dados contábeis + plano de contas real; (b) **BATIMENTO CONTÁBIL** contra o balancete oficial assinado (Maio/2026), ao centavo; (c) **DEFINIÇÃO DAS CONTAS CORRETAS** — validar/substituir os mapeamentos (`Cosif.Mapper`/templates/34 folhas propostas) pelas contas reais (trânsito PIX, Conta SPI/PI, 4.9.x clientes, disponibilidades). Isso destrava a Camada B (contas segregadas) e a Fase 3, e encerra a dependência do CONTADOR. AGUARDAR o backup.

1. **PRÉ-CONDIÇÃO DE DEPLOY (crítico):** produção roda o judicial em **base_units**; a branch mesclada está em **centavos**. Antes de QUALQUER deploy, reconciliar os dados judiciais de prod (já era pré-condição documentada). NÃO deployar sem isso.
2. **Migrations da main no `mon_core` local:** o merge trouxe migrations novas da main (45 commits); o core-api subiu healthy, mas verificar se há migration pendente (`mix ecto.migrate` local) antes de confiar em telas que dependem de colunas novas.
3. **Avisar Bruno:** os relatórios CC (`accounts_balance`/`checking_account_reports`) passaram a usar a versão da MAIN (superset money-equivalente), substituindo a implementação de join exato dele — mesmo dinheiro, cobertura melhor. Falhas de teste pré-existentes seguem (fees packages, webhook stats, GeneratorAuditWire).
4. **Fase 3 — motor de templates COSIF:** trocar o `Cosif.Mapper` hardcoded pelo `PostingEngine` (evento→template), como o SISBAJUD já usa. Camada B: 34 folhas segregadas (ids 50_305–50_338) pendentes do CONTADOR.
5. **Follow-up de INFRA (Oban):** adicionar `Oban.Plugins.Lifeline` ressuscita jobs `executing` órfãos de TODOS os workers — decisão separada (fora do escopo COSIF; a janela de frescor da Fase 2 já mitiga no reconciliador).
6. **Gap transacional (não-COSIF):** o extrato do PIX-out (`account_entries`) pode faltar no caminho `move_to_transactions` — item transacional, exige estudo próprio, NÃO tocar sem validar.
7. **HML `validate_account` × stream:** RESERVADO para sessão exclusiva do dono em HML (`docs/reports/2026-07-10-validate-account-stream-overlap-PENDENTE-HML.md`). Não implementar sem validar em HML.

## Fontes de verdade

- Este handoff (mais recente).
- Design: `docs/plans/2026-07-13-design-contabilizacao-pix-core.md` (Camadas A/B, Fases 0-3).
- Fase 0: `docs/reports/2026-07-10-estudo-contabilizacao-cabines-core.md`, `docs/reports/2026-07-10-balancete-oficial-vs-plano-vivo.md`.
- Memórias Serena (projeto `monetarie`): `contabilizacao_pix_estado`, `conventions_money_units`, `dev_commands`, `cabines_pix_spb_local`, `sisbajud_estado_atual`, `admin_paginas_estado_atual`, `project_overview`, `retomada_de_sessao`.
