# ACEITE do operador na transferência judicial (money-path) - design

Decisão do dono (19/07, brainstorm): **escalação em 2 níveis** - sem aceite no prazo interno, notifica supervisor; sem ação até o cutoff BACEN, responde não cumprida ao BCB. A transferência NUNCA executa sozinha.

## Evidência do estado atual (file:line)

- `core/backend/lib/monetarie/use_cases/judicial/processor.ex:169` despacha `order_type: "TRANSFER"` direto para `process_transfer/1` (:303) → `process_outbound_transfer/1` (:592) → `settle_blocks_and_respond/3` (:659) → `settle_one_block/2` (:765) que trava o bloco e chama `Transaction.collect_funds/1` (:769) movendo dinheiro no TigerBeetle SEM nenhum gate humano.
- Resposta 5302 código 01 montada em :686-696 + `file_processor.ex:875-985`.
- O bloco de atendimento do F3 (`judicial_order.ex:124-136`, `sisbajud_controller.ex:134`, rota :960, `SisbajudView.vue:172`) é descritivo e NÃO gateia.
- Perna externa (cnpj_destino não-Monetarie) está diferida (`processor.ex:279-289`) - o desenho cobre o gate para a liquidação interna atual e vale para a perna externa futura.

## Desenho

1. **Estado novo da ordem**: `awaiting_acceptance` entra na máquina (`judicial_order.ex:53`) entre o processamento e a liquidação. `process_transfer` passa a: validar + localizar blocos + gravar a ordem em `awaiting_acceptance` com snapshot do que será liquidado (valores por bloco), SEM tocar TB e SEM responder 01 ao BCB.
2. **Aceite**: endpoint novo `POST /v1/regulatory/sisbajud/orders/:id/accept-transfer` (gate admin + permissão dedicada `judicial:transfer:accept`), grava `aceite_por_id/nome`, `aceite_em`, auditoria, e SÓ ENTÃO chama o trilho existente `settle_blocks_and_respond/3` (inalterado; o money-path provado continua o único). Recusa: `POST .../reject-transfer` com justificativa obrigatória → ordem `not_fulfilled_by_operator`, resposta ao BCB com código de não cumprimento e a justificativa na trilha.
3. **Escalação nível 1**: worker Oban `JudicialTransferEscalationWorker` (cron 5 min): ordens `awaiting_acceptance` há mais de `JUDICIAL_ACCEPT_ESCALATION_MINUTES` (default 60) notificam supervisor (alerta operacional `Alerts.Operational.raise` + e-mail quando transporte existir) uma única vez (flag `escalated_at`).
4. **Escalação nível 2 (cutoff)**: ordens `awaiting_acceptance` além de `JUDICIAL_ACCEPT_CUTOFF_MINUTES` antes da janela de resposta BACEN respondem ao BCB como não cumprida (mesmo trilho da recusa, justificativa "sem aceite do operador no prazo"), status `not_fulfilled_timeout`. NUNCA auto-executa.
5. **Tela**: a SisbajudView ganha o botão Aceitar/Recusar transferência quando a ordem está `awaiting_acceptance` (reusa o padrão do atendimento editável); lista com destaque de pendentes de aceite + relógio do prazo.
6. **Compatibilidade**: flag `JUDICIAL_TRANSFER_ACCEPT_ENABLED` default OFF no deploy inicial (comportamento atual preservado até o dono ligar); com a flag ON, nenhum caminho executa transferência sem aceite.

## Erros e invariantes

- O aceite é idempotente (segunda chamada em ordem já liquidada → 409 legível).
- Crash entre aceite e liquidação: o aceite persiste; retry do worker de liquidação reprocessa pelo estado (mesma disciplina de claim dos blocos, `lock_and_mark_block_transferred`).
- Reapresentação BCB (teimosinha) de ordem `awaiting_acceptance`: re-emite a situação atual sem duplicar snapshot.
- COSIF/extrato: inalterados (a liquidação continua no trilho existente).

## Testes (TDD)

RED: transfer NÃO move TB sem aceite; aceite move e responde 01; recusa responde não cumprida com justificativa; escalação 1 notifica uma vez; cutoff responde e nunca executa; flag OFF preserva o atual; idempotência do aceite; reapresentação. Validação viva em HML com remessa de teste (AJUD5301) antes de PRD.
