# Reparo R2 CA-026 executado em PRD + INCIDENTE NOVO: duplo-credito TB no settled de PIX-in (achado, remediado e corrigido em codigo)

Data: 2026-07-18 madrugada (~02:00-03:00 UTC). Mandato do dono: corrigir em definitivo o acervo COSIF mentiroso da Conta de Liquidacao (R2 CA-026), sem inferencia, deixando tudo 100% batido. Durante a verificacao empirica a sessao encontrou um INCIDENTE VIVO mais grave (dinheiro real) que tambem foi remediado. Tudo abaixo tem prova coletada de PRD por rpc; nada foi inferido.

## PARTE 1 — Reparo do acervo COSIF (R2 CA-026) EXECUTADO

Base: `docs/reports/2026-07-17-analise-cosif-conta-liquidacao-negativa-r2.md`. Forma escolhida: ESTORNO (rastreavel; preferencia declarada no proprio relatorio), nunca DELETE. Todo lancamento novo carrega `metadata.source = 'r2_ca026_repair'`; reversivel por consulta.

### Escopo real (maior que o relatorio): 21 lancamentos envenenados, nao 6

A releitura viva de PRD (todas as 48 linhas PIX da conta `1.1.2.10.01.10.001` + `PixReconciliation.reconcile(01..17/07)`) provou que alem dos 6 do relatorio havia mais 15 da mesma classe:

| Classe | Linhas | Defeito |
|---|---|---|
| Orfaos 10/07 (4x R$ 20.000,00) | `7ddfd0e4 6ad924f9 20548f60 29c3ad4c` | evento E000...451 (real R$ 2,00) a 10.000x, sem lastro, invertido |
| Orfaos 13/07 (4x R$ 13,7M) | `f729fa63 8ce75a87 af038966 0dc2e037` | evento E607...914 (real R$ 1.370,00) a 10.000x, sem lastro, invertido |
| E607...914 13/07 | `8d06d17d` | 100x + invertido (relancado: D 137.000c) |
| E000...451 13/07 | `7f8327c3` | 100x + invertido (relancado: D 200c) |
| E904...524 14/07 | `94096802` (100x) + `69f242bb` (10.000x) | invertidos (relancado: D 2.000.000c) |
| PIX-out 09 e 14/07 | `94a54680` `ac7ea420` | 100x (relancados: C 100c cada) |
| Devolucoes recebidas 15/07 | `dd9375f9` `991e2148` `db2474f3` | 100x + invertidas (relancadas: D 50/25/25c) |
| Duplicatas 17/07 (escritor vivo) | `2057bfb1` `ede17340` `416ee4b8` `7036f610` | segundo journal 100x por evento settled (gemeo correto preservado) |

Provas de nao-lastro dos orfaos: zero transacao PIX em 10/07; 13/07 tem exatamente E607 (13.700.000 bu) e E000 (20.000 bu). O trio da Wise (tentativa RJCT + estorno automatico do item 5 + tentativa ACSP) ja estava autoconsistente e NAO foi tocado; o proprio sistema ja usa o padrao estorno (`ref estorno-<RtrId>`).

### Execucao (transacao unica, guardas de contagem e soma; rollback automatico em qualquer divergencia)

1. **21 estornos** (`reference_type='PIX_ESTORNO'`, `reference_id = id do original`, mesma data contabil, D/C invertidos, mesmo valor).
2. **Anotacao dos 21 originais** (`metadata.estornado=true` + carimbo; valor/data/contas intactos).
3. **8 relancamentos corretos** (`reference_type='PIX'`, `reference_id = E2E`, valor real em centavos, direcao certa, data contabil original).
4. **Espelho da entrada da Wise**: a pacs.008 E595...PG2TJD (R$ 52,74, creditada na PI em 17/07 20:59 — fluxo auto-return nao journaliza a entrada) ganhou o journal D liquidacao / C obrigacoes 5.274c de 17/07. Corroborado por camt.054 do BACEN (CRDT 52.74, BookgDt 2026-07-17). Par RJCT+estorno anotado como autocancelado.
5. **Snapshots diarios 15/16/17-07 regenerados** (`SnapshotGenerator.generate_for_date`, idempotente, ETL preservado).

### Batimento provado (pos-reparo)

- Conta `1.1.2.10.01.10.001`: snapshot 17/07 de **-25.384.534.462** para **+320.342.417 centavos (R$ 3.203.371,43)**; liquido por journals = +319.262.677c.
- **Batimento por E2E 12/12 EXATO** (tx_cents == journal vivo, sinal correto) em todos os E2E antes divergentes.
- `amount_mismatch` na reconciliacao: 7 -> **0**.
- Decomposicao final: PIX 56 linhas (D 138.157.103 / C 25.735.440.004) + PIX_ESTORNO 21 (D 25.701.750.000 / C 134.662.900) + account_entry/etl inalterados.
- Diferenca snapshot x soma-de-journals (1.079.740c) = acervo de junho embutido no snapshot 30/06; fechada ao centavo.
- Residual da tela (12 `duplicate_e2e`) = originais estornados que o codigo DEPLOYADO ainda conta; a peca 3 do fix de codigo (abaixo) faz a tela ignorar `estornado=true` — pos-deploy a janela 01..18/07 zera (exceto orphan honesto do espelho Wise, sem tx core por design do auto-return).

Nota honesta: o saldo espelhado (~R$ 3,2M) ainda nao e o retrato da liquidez real — restam GAPS documentados de espelho (B8: perna de saida do STR0008 manual sem journal; base ETL) que sao lacunas, nao mentiras. Fechamento fino = trabalho mensal com o contador.

## PARTE 2 — INCIDENTE NOVO (P0): duplo-credito REAL no TigerBeetle pelo settled de PIX-in

### Mecanica (provada por log + codigo + saldo)

O evento `monetarie.spi.transaction.settled` da cabine carrega `transaction_id` PROPRIO da settlement-service (`UEkBn*`) e `amount` em **CENTAVOS** (contrato do `settled_event_payload` do StatusUpdater). No Core:

1. `pix_handler.ex` (branch "PROD 2026-07-17", payload autossuficiente) RE-RODAVA `handle_transaction_ledger` para PIX-in JA RASTREADO confiando em "idempotencia por transfer_id deterministico" — FALSO: o transfer_id deriva do `transaction_id`, que e OUTRO no settled -> o TigerBeetle aceitou um SEGUNDO deposito real;
2. a fronteira convertia os centavos como reais (x10.000) -> o segundo deposito saiu **100x**.

Log de PRD (17:50:09-11 UTC, conta 2949): deposito correto 130.596.000 bu (R$ 13.059,60) pelo created; 1s depois "TB deposit ok: account=2949 amount=13059600000" (R$ 1.305.960,00) pelo settled `UEkBn3...`.

### Estrago e remediacao (executada 02:4x UTC, provada ao subcentavo)

Extrato PG estava CORRETO (1 linha por evento); o excesso existia so no TB. `Wallet.withdraw` com transfer_id deterministico (idempotente), apos assercao TB-extrato == excesso esperado:

| Conta | Excesso removido | TB antes | TB depois | Residual |
|---|---|---|---|---|
| 2949 | R$ 1.345.960,00 (40.000,00 + 1.305.960,00) | 13.608.595.500 | 148.995.500 == extrato | 0 |
| 1644 | R$ 500,00 | 5.070.000 | 70.000 == extrato | 0 |
| 2031 | R$ 169,00 | 2.896.900 | 1.206.900 | -10.000 = drift PRE-EXISTENTE conhecido de R$ 1,00 (saga 14/07), preservado |

Ninguem gastou o excesso (saidas do 1644 foram ANTES do credito indevido; 2949/2031 sem saidas). Conta 2867 (E904 14/07) conferida EXATA — o duplo-deposito TB e comportamento que so se manifestou em 17/07; em 14/07 o settled so gerava journal (reparado na Parte 1).

### Fix de codigo (commit LOCAL `f890906d`, TDD RED->GREEN, aguarda OK para push/deploy core-api)

1. `pix_handler.ex`: PIX-in RASTREADO + settled = materializa status e NUNCA re-roda o ledger (created perdido segue coberto pelo ramo untracked).
2. Guarda WAL de defesa em profundidade: `pix_in_credit_wal` em `tb_done/pg_done` = credito ja aplicado -> settled/redelivery nao re-deposita (janela de crash entre TB e commit PG fechada; dono da perna PG pendente e o PixInCreditRecoveryWorker).
3. `pix_consumer.ex`: `monetarie.spi.transaction.settled` convertido como CENTAVOS (`convert_inbound_cents`) — o unico publisher com amount nesse subject e o `settled_event_payload` (centavos); o `publish_status_updated` do SPI nao carrega amount.
4. `pix_reconciliation.ex`: ignora journals `metadata.estornado=true` (tela reflete acervo reparado; estornos `PIX_ESTORNO` ja eram invisiveis).

Suites: nats 396/0, cosif 22/0, payments 165/0, workers 205/0, focados novos 4/0 + 9/0.

**ATENCAO OPERACIONAL: enquanto core-api PROD estiver em :66, TODO PIX-in liquidado pela cabine re-deposita 100x.** A remediacao acima limpou o acervo ate 02:4x UTC; qualquer PIX-in novo antes do deploy do fix recria o excesso (varrer com a mesma receita: TB-extrato por conta). Deploy do fix e prioridade antes das sequencias do cliente de segunda 21/07.

## PARTE 3 — Wise: DBIT de R$ 52,74 (item 8 do retomar)

- pacs.004 `D46026562202607180128pxhdxps4eww` ACSP 01:28:52 UTC (prova de liquidacao BACEN ja obtida na sessao anterior).
- camt.054 de 01:30:30 UTC confirma o CRDT da ENTRADA original (52.74 CRDT BOOK, BookgDt 2026-07-17) — valida tambem a data contabil do espelho da Parte 1.
- O DBIT da devolucao ainda NAO apareceu em camt.054 ate 02:55 UTC; camt.060 detalha-lancto enviada as 02:43 (`M46026562e2fd43fb4ce2086f257cdf6`) segue `sent` sem resposta. VIGIAR: proxima camt.054/extrato da PI deve trazer o DBIT 52.74; se a camt.060 responder, correlacionar.

## PARTE 4 — Varredura total do sistema (manha de 18/07, ordem do dono) e deploys

**Deploys executados (ordem do dono "sobe essa merda logo"):**
- `f890906d` (settled fix): HML core:164 -> **PROD core:67** (rollback :66). ZERO PIX-in na janela de exposicao (02:40->09:45 UTC) — nenhum poison novo.
- `9425f281` (OperationQuery InstrId + reconcile D%/L%): HML core:165 pix:186 -> **PROD core:68 pix:61** (rollbacks :67/:60). ICOM handover limpo (locks 10:13:21 -> lider novo 10:13:22, CPM 3 + CSM 4 sessoes reassumidas, zero janela surda).
- `376afdd6` (espelho simetrico do auto-return): em deploy na sequencia.

**Varredura dinheiro real (TODAS as contas, desde o go-live):**
- `StatementBackfill.reconcile()` completo: 1 unico drift no sistema = conta 2031, R$1,00 (o conhecido da saga 14/07). Decomposto ao subcentavo: devolucoes de 14-15/07 nunca creditaram TB (+R$1,00 devido) e o PIX-out bi5io de 09/07 (settled no BACEN, era zumbi) nunca debitou NEM TB NEM extrato (-R$1,00 devido) — TB liquido CORRETO; faltava so a linha de extrato do bi5io. **Backfill executado; reconcile final = `[]` (ZERO drifts em todas as contas).**
- Sweep global de tx liquidada sem linha de extrato: **PIX 0, TED 0.**
- Espelho account_entry<->journal COSIF: **0 mismatch, 0 orfao.**
- Reconciliacao COSIF PIX 01-18/07 (pos-fixes): mismatch/duplicata/orfao/direcao = **0**; os 3 missing_statement eram alarme FALSO (loader filtrava like 'E%' e nao via referencias D-RtrId — corrigido em 9425f281).

**camt.060 das 02:43 — RETRATACAO e verdade final:** minha conclusao de "mensagem ACKada e perdida" estava ERRADA. O `icom_received` (fonte primaria pre-ACK da cabine) prova: tudo que o ICOM entregou foi persistido e publicado; o rid `UEkBn3Mc...` era pibr.002 (heartbeat) legitimo — eco nao vai a bacen_inbound por design. O invariante pre-ACK do CPM SEGUROU mesmo com o banco estrangulado pelas minhas queries de investigacao (licao registrada: NUNCA rodar LIKE full-scan em tabela de XML no banco vivo). A resposta das 02:43 nao foi entregue pelo BACEN (nem camt.054 nem admi.002 no periodo) — mesma classe do dossie das 2 pacs.002 de 16/07 (lado SPI; chamado ao BACEN pendente de OK). As reemissoes das 09:52 e 10:1x responderam em segundos, e a segunda, ja com o fix, fechou **`STATUS=ok AMOUNT=52.74 INSTR=D46026562202607180128pxhdxps4eww` VIVO EM PRD** — consulta por RtrId funcionando ponta a ponta.

**DLQ PROD (25 msgs) — triagem completa, nada purgado (decisao do dono):**
- Historico ja resolvido por remediacoes anteriores + reparo desta sessao: auto-returns 10-13/07 mortos por ACENTO no XML da pacs.004 (fix ja em producao), eventos E904/E607/E000 pre-fix, thin-payloads 17/07, RETURN_CREATED da Wise (seq 41/42 — NAO redespachar: o espelho ja foi reparado a mao; redespacho duplicaria a perna de entrada).
- Os 3 spb.failed (TED-in `amount_exceeds_limit` da era 100x): TODOS creditados na remediacao de 13/07 (conta 2627 R$292.836,91; conta 2630 R$163.287,50 + R$154.983,15) — conferido vivo, TB==extrato.
- Poison de netting (10 msgs, ate 00:30 de HOJE): whack-a-mole de schema — 20260717171000 alinhou colunas mas sobraram NOT NULLs legados sem default (`operation_id` etc., 23502). **DDL corretiva aplicada HML+PROD via rpc (probe de INSERT com rollback passou); migration `20260718100000` no repo.** Proxima janela 00:30 deve registrar em vez de envenenar — VIGIAR.
- Recomendacao: purge da DLQ inteira (tudo triado e resolvido) — aguarda decisao do dono.

**Fix do espelho simetrico do auto-return (`376afdd6`):** rota dedicada no handle_return para auto-return de entrada nao materializada — journaliza ENTRADA + SAIDA (idempotente por referencia em qualquer data), zero TB, ack fail-soft. Mata a classe do buraco -R$52,74 e a classe de DLQ dos seq 41/42 para sempre.

## Follow-ups registrados

- Deploy core-api do fix (`f890906d`) — pendente OK do dono; depois validar tela Reconciliacao Contabil PIX 01..18/07 (esperado: zero divergencia real) e card DISPONIBILIDADES (~R$ 3,2M).
- Varredura pos-deploy: TB-extrato das contas com PIX-in entre 02:4x UTC e o deploy (excesso novo possivel).
- Journal de devolucao criado no DESPACHO (nao no desfecho): a tentativa RJCT gera journal que depende do estorno automatico do item 5; considerar journal so no desfecho terminal.
- I-1: `do_handle_transaction_ledger` publica `ledger.balance.updated` fora de transacao (RuntimeGuard loga violacao em prod) — pre-existente, tratar na frente do outbox.
- Snapshot mensal 2026-07-31 segue = ETL puro; sera regenerado no fechamento do mes (contador).
- Cabine: dupla personalidade de unidade no MESMO subject familia transaction.* (created=reais, settled=centavos) — normalizar na fonte quando houver janela (mudanca de contrato, coordenar).
- 42P10 do ReturnProcessor (item 7 do retomar): nao recorreu no re-despacho nem no auto-return seguinte ate o fecho; segue em vigilancia.
