# Handoff — ETL do Core (concluído) + Conta Escrow (a implementar) — 2026-07-08

> Sessão longa. Duas frentes: (1) **ETL do Core do backup `monbank_backup_2026-07-08.sql` — CONCLUÍDO e reconciliado ao centavo em HML**; (2) **Produto Conta Escrow — decidido, desenhado, a implementar (Fase 0 + 8 PRs) antes de produção**. Este handoff é a fonte única para a próxima sessão terminar.

## 1. O que ESTÁ FEITO (não refazer)

### 1.1 ETL do Core (backup 2026-07-08) — concluído, ao centavo, em HML
- Matriz de>para 100% (262 colunas, 10 tabelas, 694.162 linhas): `docs/plans/2026-07-08-etl-core-monbank-de-para-matriz.md`.
- **Re-migração destrutiva rodada no `mon_core` vivo de HML** (Aurora `monetarie-core-homolog-45`; **prod `-prod-50` intocada**). Snapshot de rollback: `moncore-pre-etl-0708`.
- Relatório `Remigrate.run(reset: true)`: **to_the_cent=TRUE, 0 erro, 0 mismatch, 1606 contas, 1542 usuários, total R$ 719.303,44** (= relatório oficial `~/Desktop/SALDO CONTAS GERAL.csv`, conta a conta por `accounts.number||accounts.digit`).
- Verificado no vivo: cadastro no fill-rate exato (bairro via `line3` 1592, RG 584, nascimento 781, estado civil 424, nome do pai 399, faturamento 538, renda 949, mãe 426, ocupação 145, PEP 0); IBAN 1606/1606 + número legado preservado (000000003…, agência 0001); extrato 216.471/231.415 com contraparte; BLQ→7 contas `blocked`.
- Partner API keys re-provisionadas do Secrets Manager: **Herbeth** `cli_716d68efa0b3156deaf799dc` (TOKEN_OK http=200) + time-integração `cli_55f88194faef042781d5f3f6`.
- Código em `origin/main`: **PR #5** (ETL + matriz + população cadastro + numeração/IBAN + extrato + tela admin 4 campos), **PR #6** (fix do IBAN, abaixo), **PR #7** (doc do resultado).
- Bug latente CORRIGIDO (PR #6): `AccountNumberGenerator.generate_iban` estourava `String.to_integer` porque não convertia a letra do tipo de conta ("C") no mod-97; só disparava porque o ETL passou a gerar IBAN. Fix: converter TODAS as letras.

### 1.2 Escrow — decidido e desenhado (docs versionados)
- `docs/research/2026-06-28-escrow-legal-research.md` (pesquisa jurídica), `docs/plans/2026-06-28-conta-escrow-implementacao.md` (guia técnico, 8 PRs), `docs/plans/2026-07-08-conta-escrow-brainstorm-validacao.md` (brainstorm, PR #8).
- **Decisões do dono (08/07):** implementar o **produto completo (PR1-8) + Fase 0 ANTES de produção**; **Monetarie TEM autorização de Moeda Eletrônica** (modelagem A viável); COSIF `4.1.1.85.00-1` DEPÓSITOS VINCULADOS; ledger TB `1_004` (`Ledgers.operational_escrow/0`, já existe).

## 2. O que FALTA FAZER (a próxima sessão)

### 2.1 Fase 0 — reconciliar os fundos vinculados legados (deixa o "100% batido" contábil)
A re-migração trouxe **R$ 523.174,21 de bloqueado real em 5 contas** (KAY CASS = CTA ESCROW VINCULADA 373k; LIDER TRATORES 136k; RJ RICK 12k; CARGOPAY 210; CATAN 92). Hoje estão no saldo total como conta de pagamento 4.9.8, **não** segregados nem indisponíveis. Fase 0:
1. Seed COSIF `4.1.1.85.00-1` (DEPÓSITOS VINCULADOS) no plano de contas.
2. No `Remigrate`, para cada conta com `blocked_amount > 0` (fonte: `autbank_src.account_wallets.blocked_amount`): criar **hold PENDING** no TB.
3. Reclassificar a parcela vinculada no COSIF: sai de 4.9.8, entra em 4.1.1.85.00-1.
4. **Fix do display** (bug hoje): endpoint de saldo mostra `available = saldo − pending` e `blocked = pending`.
5. Reconciliar: postado total = R$ 719.303,44 (inalterado); `debits_pending` por conta = blocked; disponível exibido = 719.303,44 − 523.174,21.

### 2.2 Desenho técnico do hold + display (PROVADO contra o código — não re-descobrir)
- **Wallet.get_balance = credits_posted − debits_posted (só postado)**; não há `get_available`.
- O endpoint de saldo `lib/monetarie_web/controllers/v2/account_controller.ex` (`balance`/`balance_self`, linhas ~194-200 e `fetch_tigerbeetle_balance` ~1069-1084) HOJE crava `blocked: 0` e `available = balance` — **bug**. Idem base `lib/monetarie_web/controllers/account_controller.ex` (~349-356, ~487-499).
- **O caminho de autorização de gasto SUBTRAI debits_pending** (`use_cases/payments/balance_guard.ex:238`, `balance_check.ex:28-31`, `transaction_pipeline.ex:233`) → **hold pending bloqueia o gasto de verdade**.
- **Reconciliação mira o POSTADO** (`remigrate.ex` reconcile) → usar **hold PENDING** (`flags.pending: true`), NÃO transfer posted→pool (isso reduziria o postado e quebraria a reconciliação).
- Como criar o hold (padrão `use_cases/payments/pending_transfers.ex`): `TigerBeetlex.Transfer` com `debit_account_id = conta cliente` (client_liability, code 30), `credit_account_id = cash_asset` (id do config `cash_asset_account_id` default **1**, code 10) OU settlement_pool (code 20), `ledger = ledger do cliente` (ler de `Tigerbeetle.lookup_account(client_id).ledger`), `amount = blocked subcentavos`, `flags: %{pending: true}`, e NUNCA post/void. `Wallet.deposit`/`create` usam esse cash_asset e o ledger do cliente — reusar.
- Caveat: hold pending "cru" aparece como `orphan_holds` no `use_cases/accounts/blocked_breakdown.ex` (só categoriza MED/pix-out/judicial). Aceitar por ora OU, no produto escrow, categorizar via o domínio.

### 2.3 Produto Escrow completo (guia 8 PRs — `docs/plans/2026-06-28-conta-escrow-implementacao.md`)
PR1 Contábil (accounting_bridge + COSIF) · PR2 Domínio (`escrow_agreements/parties/conditions/releases` + state machine) · PR3 Execução TB 1_004+COSIF (Σ fecha) · PR4 KYC dual+PLD/FT gating · PR5 APIs cliente+admin (maker-checker) · PR6 Painel admin · PR7 Eventos NATS+cabines PIX/SPB (Core não assina) · PR8 Go-live gating (`ESCROW_ENABLED=false` até checklist §1.3).

**PR1 — pontos exatos (já mapeados):** em `lib/monetarie/use_cases/accounts/accounting_bridge.ex`: adicionar `@deposito_vinculado_code` (código canônico interno de `4.1.1.85.00-1`; confirmar formato seeded em `cosif_contas`, ex.: `"4.1.1.85.00.10.001"`); estender `@mapped_categories` (linha ~113) com `escrow_deposit escrow_release escrow_refund escrow_fee`; adicionar cláusulas em `resolve_debit_credit/2` (D/C conforme §8.3 do guia); seed da conta no plano de contas (`use_cases/cosif/plano_contas.ex` + seed). Em `AccountType` (`use_cases/model/relational/account_type.ex`): add kind `escrow (5)`; em `account_kind.ex` mapear `"escrow" => escrow()` FORA de `partner_account_types/0`. **NÃO** reusar aliases `bet/win/loss` de `transaction.ex` (deprecados).

**account_type válidos hoje** (`account_kind.ex`): payment/checking/savings/salary/client/client_external. **Não existe "escrow"/"dep_vista"** — por isso a modalidade legada do CSV NÃO virou account_type (seria inválido); ficou em metadata. Escrow vira o novo kind.

## 3. Operacional pendente (produção)
- **2 TEDs órfãs em PRD**: chegaram antes do restore do legado, não acharam conta destino. Precondição: o **restore de produção do Core subir** (as contas passam a existir). Aí: validar cada TED (E2E/valor/beneficiário), **creditar** na conta certa com lançamento + extrato, idempotente (sem duplicar).
- **Acesso ruim ao coreadmin em PRD** (tela em branco no print do dono): diagnosticar deploy/roteamento/UI admin de produção.

## 4. Como rodar o ETL do Core em HML (reproduzível — para a Fase 0 exigir novo run)
Estado vivo: core-api HML na task-def `:92` (imagem `main-c04e0c39`, tem meu código+fix); base local `docker monbank-etl-0708` (porta 5545, backup + CSV carregados, schema `autbank_src` pronto); `autbank_src` ainda no `mon_core` vivo. AWS: `AWS_PROFILE=vulcimonetarie`, `AWS_REGION=sa-east-1`, conta `990933657879`.

Mecanismo (o que funcionou):
1. **Build**: worktree de `origin/main` → `docker buildx build --builder avivfe --platform linux/arm64 -t <ecr>/monetarie/core-api:<tag> --push core/backend` (deps cacheadas, rápido).
2. **Task-def**: derivar de `:89`/atual (strip campos read-only), trocar `image`, `register-task-definition`; `update-service --task-definition ... --enable-execute-command --force-new-deployment`; esperar `rolloutState=COMPLETED`.
3. **Carga autbank_src**: local, `CREATE SCHEMA autbank_src` + 5 tabelas (account_information, accounts, account_wallets, account_information_addresses, autbank_legacy_transactions SEM raw_payload/metadata) → `pg_dump -n autbank_src | gzip` → S3 presigned → na task: `curl -s <url> | gunzip | sed -e '/^\\restrict /d' -e '/^\\unrestrict/d' -e '/transaction_timeout/d' | psql "$DB"` (DB de `/proc/1/environ` `DATABASE_URL`, `ecto://`→`postgresql://`; psql da task = 15.18 rejeita `\restrict` do pg18).
4. **Snapshot Aurora** ANTES do reset: `rds create-db-cluster-snapshot --db-cluster-identifier monetarie-core-homolog-45`.
5. **Migration** (se houver): via rpc SQL (`ALTER ... ADD COLUMN IF NOT EXISTS` + `INSERT INTO schema_migrations`), NÃO `eval`.
6. **Remigrate**: `bin/monetarie rpc 'Code.eval_string(Base.decode64!("<b64>"))'` onde o Elixir faz `spawn(fn -> System.put_env("ALLOW_ENTITY_RESET","true"); ...Remigrate.run(reset: true)... File.write!("/tmp/remig.out", ...) end)` (async, sobrevive à queda da sessão SSM). Monitorar `/tmp/remig.out`.
7. **execute-command**: precisa de PTY. Wrapper python `pty.spawn` do `aws ecs execute-command --interactive --command "/bin/sh -c \"echo <b64> | base64 -d | sh\""` (base64 evita inferno de aspas). session-manager-plugin em `~/.local/bin`.
8. **Reconciliar** vs CSV; **re-provisionar Partner keys** (`scripts/partner_api_reprovision.sh` ou manual via `ApiKey.changeset` com sha256 do secret).

**GOTCHA GRAVE:** o ETL roda como `spawn` no BEAM da task do SERVIÇO. Se **outra sessão faz deploy do core-api**, o ECS mata a task e o ETL morre no meio (aconteceu: interrompeu na Fase 1 com 1511 contas). Para a Fase 0: rodar em **task DEDICADA one-off** OU pedir para segurar deploys paralelos do core-api por ~20 min. O reset é idempotente (re-run limpa o parcial). ETL ~20 min a 0,5 vCPU (1606 contas uma a uma).

## 5. Regras absolutas a respeitar
- Core NUNCA assina mensagens BACEN (saídas PIX/TED → cabines PIX/SPB via NATS). Escrow segue isso.
- Escrow = DEPÓSITOS VINCULADOS 4.1.1.85.00-1, ledger 1_004, `escrow_agreement` obrigatório (anti-bolsão), maker-checker, sem garantia (SCD não garante). `ESCROW_ENABLED=false` até checklist regulatório.
- pt-br sem travessão de IA; zero inferência, provar empiricamente; segredo real só no Secrets Manager.
- Checkout compartilhado com outras sessões (PIX/SPB) — usar worktree isolado, commitar só o próprio escopo (`core/**` + docs), não tocar `pix/**`/`spb/**`.

## 6. Ponteiros
Memória: `monetarie-escrow-produto`, `monetarie-etl-core-monbank-0708`. Docs: matriz de>para, guia escrow (8 PRs), brainstorm, este handoff.
