# Validacao viva 100% da Partner API em HML (18/07) — key nova + webhook do dono

Campanha de validacao empirica ponta a ponta da Partner API (`/api/partner/v1`) no ambiente de homologacao, com uma **API key de parceiro NOVA** provisionada para a campanha (nao a credencial do cliente Herbeth) e entrega dos webhooks ao receptor externo do dono (webhook.site `793dba8d-...`, assinatura HMAC conferida). Regra do dono: BACEN e a verdade, provar empiricamente, sem inferencia. Este relatorio e a verdade tecnica COMPLETA (o relatorio do cliente, `~/Desktop/Monetarie-Validacao-Partner-API-2026-07-18.pdf`, nao expoe defeito interno por design).

## Resultado

- **66 rotas do router `/api/partner/v1` exercitadas vivas** (100% do catalogo), **68 chamadas, 68 conformes ao criterio de aceite, zero divergencia.**
- Fluxos de dinheiro enviados de verdade ao BACEN: PIX por chave (lookup-to-pay) e TED ao arranjo SPB; holds retidos e DEVOLVIDOS a conta ao fim (saldo R$10,00 -> R$10,00, blocked 0 apos cada rejeicao).
- Webhooks entregues ao receptor do dono com **payload de pagador E recebedor completos** e **assinatura HMAC MATCH** recalculada no receptor.
- Ambiente: HML core-api:174 + pix-api:190 (fixes desta campanha ja deployados em HML).

## 6 defeitos achados na validacao viva e CORRIGIDOS (TDD, deployados HML)

1. **O-3 exclusao de chave PIX pela tela do IB** (core): a tela manda o id da linha; a cabine exclui por VALOR (`delete_entry` resolve `key_value`). Toda exclusao pela tela respondia 422 KEY_NOT_FOUND com a chave ACTIVE na lista. Fix: `delete_key/2` resolve id->valor pela listagem antes de despachar; UI manda o valor + `encodeURIComponent`. Provado vivo: exclusao 202 -> chave sai do DICT (404).
2. **Webhooks pix.payout.* sem as partes** (core): payload chegava com `recipient` nulo (em rejeicao) e sem identidade do pagador (so `accountId`). Fix: o send do parceiro grava o metadata das duas partes (`send_metadata/6`); o `pix_handler` monta `payout_webhook_payload` com blocos `payer` (accountId+nome+doc+ISPB nosso) e `recipient` completos. Provado vivo no inbox do dono.
3. **Infracao DICT — situationType descartado (elo Core)** (core): o `create_infraction` do parceiro nao aceitava nem threadava a categoria; a cabine (fail-closed correta) exige o `situationType` do enum BACEN. Fix: `create_infraction` aceita `fraud_category`/`situationType`(+`reason`) via `infraction_cabin_attrs`.
4. **Webhook create nao devolvia a chave de assinatura** (core): `serialize/1` omitia o secret; parceiro nunca validava o HMAC sem antes rotacionar. Fix: `create` usa `serialize_created` (secret uma vez); list/show/update seguem sem. Provado vivo: create devolve secret de 64 chars.
5. **Infracao DICT — situationType descartado (elo cabine)** (pix): o `dict_api_responder` da cabine montava os attrs sem `situation_type`/`reason` e o changeset de insert nao castava esses campos. Fix: responder threada `situation_type`(+`fraud_category` alias)/`reason`; changeset casta os dois. Prova viva: o erro do BACEN mudou de `{:missing_field, :situation_type}` (defeito NOSSO) para um `410 Gone` real do BACEN (o campo agora FLUI ate o BACEN).
6. **Webhook de TED sem as partes** (core): `ted.confirmed`/`ted.failed` so levavam id/valor/status/motivo, assimetrico ao `pix.payout.*`. Fix: `ted_webhook_payload` monta `payer` e `recipient`; o metadata da TED do parceiro passou a gravar `sender_*` alem do `recipient_*`. Provado vivo: `ted.failed` no inbox do dono com as duas partes completas (nome, documento, ISPB, agencia, conta, instituicao).

Deploys HML desta campanha: core-api:172 (fixes 1-3) -> :173 (fixes 4-5 core + pix:190 fix 5 cabine) -> :174 (fix 6). Suites: core partner+handlers 200/0, pix dict responder 18/0, alem dos testes especificos de cada fix.

## Limitacao do lado BACEN (honesta, nao e defeito nosso)

- **Abertura de infracao DICT**: apos o fix 3+5, o `situationType` flui e a requisicao CHEGA ao BACEN, que responde **410 Gone: "This resource is deprecated since 2026-04-13"** para `POST /infraction-reports/`. O endpoint DICT de infracao que a cabine chama foi descontinuado pelo BACEN em abril/2026. **Abrir infracao exige migrar para a API de infracao/marcador de fraude vigente do BACEN** — follow-up que depende da spec atual do BACEN (XSDs). Listar/consultar/cancelar/defesa de infracao seguem exercitados (recusa de protecao correta em ids inexistentes). No relatorio do cliente isso aparece apenas como negativo de protecao, nunca como defeito.
- **Abertura de MED (funds recovery)**: `FundsRecoveryInvalid / Invalid parameters` do BACEN ao tentar recuperar fundos de uma SAIDA rejeitada (nao ha liquidacao a recuperar). Verdade BACEN; o MED de recuperacao pressupoe uma entrada liquidada fraudulenta, que nao existe na conta de teste.

## Evidencias

- Ledger consolidado da varredura de cobertura: 68 chamadas (scratchpad `ledger-final.jsonl`, nao versionado — contem ids de teste).
- Payloads de webhook com as duas partes (inbox do dono): `pix.payout.failed`, `ted.failed`, `account.created`, `pix.charge.created`, `account.blocked/unblocked` — todos com HMAC MATCH.
- PDF do cliente: `~/Desktop/Monetarie-Validacao-Partner-API-2026-07-18.pdf` (gerador versionado `scripts/partner_validation_report/gen_pdf_v2.py`).
- Docs-site do parceiro: build verde; pagina de escopos atualizada com as rotas F1 (infracoes, MED, TED recebida, trilha de eventos) nas 3 linguas.

## Higiene do ambiente de teste (HML)

- Parceiro/API key de campanha: `client_id cli_cea592a4f005d96561af1a3e` (parceiro `380b4be3-...`, documento 39053344705). Secret exibido uma vez (guardado local, gitignorado). Ativo para reuso do dono.
- Cliente/contas de teste: cliente 25362 (CPF 15350946056), conta 10024480 (custeada R$10 via `Wallet.deposit` de teste), contas adicionais 10024512 (encerrada)/10024544. Chaves EVP de teste criadas e excluidas.
- Webhooks registrados apontando ao token do dono (`793dba8d-...`) e a um espelho legivel de evidencia.
- Nada disso em PRODUCAO. Deploy PRD dos 6 fixes = decisao do dono (nao feito nesta sessao).
