# Handoff 2026-07-06 — Core surdo ao NATS (STR0008R2 + DICT), agrupamento eco ICOM, erro do Construtor

## Resumo executivo

Um único defeito nosso derrubou duas frentes ao mesmo tempo: o GenServer `Monetarie.Infra.Nats.Connection` do Core travou no boot do deploy `core-api:84` (2026-07-05 14:23 UTC) e deixou o Core surdo a TODO o NATS por ~24h. Consequências provadas: (1) a STR0008R2 recebida em 06/07 11:14 BRT não creditou o cliente; (2) toda consulta de chave PIX do IB devolvia `[DICT_INDISPONIVEL]`. Remediado vivo (crédito na conta, DICT funcionando) e corrigido em código com teste. Também corrigidos: agrupamento pibr.001↔pibr.002 no monitor ICOM e o erro cru de transporte no Construir Mensagem. Levantada a matriz completa de gaps do Construtor vs catálogo (implementação pendente).

## Incidente 1 — STR0008R2 sem crédito (RESOLVIDO vivo + fix commitado)

Fatos provados no ambiente vivo:

- Mensagem: `STR0008R2`, `NumCtrlSTR STR20260706033056377`, NUOp `00512839202607066557495`, CECRESA (Luiz Marcelo Penha) → MAURICIO GOMES DUTRA, conta pagamento `1176749` (IB `117674-9`), `VlrLanc 50000` (R$ 50.000,00), assinatura válida.
- Cabine SPB fez TUDO certo (o fix `79ae2077` de 30/06 do `CtPgtoCredtd` funcionou): classificou `credit_kind=client`, materializou e publicou `spb_inbound_credit` em `monetarie.spb.credits.inbound` (outbox `published` às 14:14 UTC).
- Core não tinha linha em `spb_inbound_credits`: consumer surdo. Logs: `[SPB Consumer] NATS not connected, retrying in 5s...` contínuo desde 2026-07-05 14:23 UTC (janela do deploy do :84).
- Prova de que era defeito NOSSO e não rede: do próprio nó do core-api, DNS resolvia (10.45.1.10), TCP conectava e `Gnat.start_link` direto funcionava; o GenServer estava preso em `{conn: nil, connecting?: true, attempts: 0}`.

Causa raiz (código): a task de conexão (`Task.start` linkada ao Gnat) pode morrer sem enviar `:connect_result` (link com o Gnat antes do `unlink`, ou raise não capturado — o `catch` só pegava `:exit`); `handle_info(:reconnect, %{connecting?: true})` é no-op, então o processo nunca mais tentava.

Remediação viva (ordem executada):

1. `Process.exit(pid, :kill)` no `Monetarie.Infra.Nats.Connection` via rpc → supervisor recriou → conectou na hora; todos os consumers reinscreveram às 14:28:03 UTC.
2. Replay pelo caminho real: re-enfileirado o evento no outbox do SPB (`BacenGateway.Outbox.Repository.enqueue/4`, payload STRING idêntico, metadata + `replay_of=core-nats-outage-20260705`).
3. Prova ponta a ponta no Core: `spb_inbound_credits` = `credited_member`/`client`/conta `1176749`/`amount_cents 5000000`/COSIF `created`; `account_entries` = depósito `confirmed` ref `STR20260706033056377` (subcentavos 500000000); `transactions` = `SPBCRSTR20260706033056377` (ted, inbound). TB-first executado pelo handler.

Fix definitivo: commit `66769931` — `spawn_monitor` na task de conexão (morte sem resultado = falha registrada + backoff + reagendamento), teto de vida da tentativa (`connect_timeout` de 15s mata task pendurada), opts injetáveis para teste. Testes: `core/backend/test/monetarie/infra/nats/connection_wedge_test.exs` (2 cenários RED→GREEN); suíte NATS do Core 166 testes 0 falhas.

Gotcha estrutural (follow-up): o durable JetStream do `SpbConsumer` é pull (sem `deliver_subject`) e nunca é puxado — consumo real é `Gnat.sub` plain, então mensagem publicada com o Core surdo NÃO reentrega sozinha. Crédito SPB não tem reconciliador (PIX tem Oban */15). Follow-up sugerido: consumir de verdade via JetStream ou criar reconciler de `spb_inbound_credits`.

## Incidente 2 — `[DICT_INDISPONIVEL]` no IB (RESOLVIDO, mesma causa)

Rota da consulta: IB → core `V2.PixController.dict_lookup` → `Provider.lookup_key` → NATS request/reply `dict.lookup.request` → cabine PIX. Com o Core surdo, tudo virava `:nats_disconnected` → "Serviço de mensageria indisponível" → o front (`usePix.ts:107`) mapeia qualquer "indispon" para `[DICT_INDISPONIVEL]`. Após a remediação, provado vivo pelo mesmo caminho: `lookup_key` de CNPJ `62188010000150` = `status: "found"` (PENHOTA / OWEM PAY, ISPB 37839059). Pedir ao time para repetir no IB.

## HSM RTM VOLTOU (06/07)

pibr.001 saiu ASSINADA e aceita (201) às 13:39 UTC e GEN0001/GEN0001R1 (eco SPB, "Teste Zili") trafegou às 13:52 UTC. O bloqueio de ENVIO desde 03/07 acabou; o alerta `stuck_outbound` deve limpar com o fluxo.

## Fix 3 — agrupamento pibr.001↔pibr.002 no monitor ICOM (commit `0a0a3375`)

Pedido reiterado do dono. Prova com o par real de 06/07 13:39 UTC: eco não tem E2E e o ÚNICO vínculo é `OrgnlData` (pibr.002) = `Data` (pibr.001) — `MONETARIE_HML_20260706133932`; as pernas gravavam `pi_resource_id` DIFERENTES (recurso do POST vs do long-poll), e a UI agrupa por `end_to_end_id || pi_resource_id || tx_id`. Fix: `MessageParser.echo_correlation_ref/2` (restrito a pibr.*, fail-closed) como fallback de E2E nos dois gravadores (`BacenLogger` SENT, `AckTracker` RECEIVED). Sem mudança de frontend; vale para mensagens novas após deploy (o acervo antigo continua desagrupado — backfill opcional).

## Fix 4 — Construir Mensagem: TransportError cru + sem retry (commit `43dfb161`)

`POST /api/v1/messages/send` (pacs.008) falhou às 11:35 BRT com `%Finch.TransportError{reason: :closed}` (conexão idle do pool fechada pelo BACEN). Dois defeitos: a cláusula de failover do `Bacen.Client` só casava ÁTOMOS (`:closed` etc.), nunca o STRUCT → sem retry; e o struct cru vazava no toast. Fix: `transient_transport_reason?/1` (átomos + structs Finch/Mint por `__struct__` — `Finch.TransportError` só existe no finch ≥0.23, o do runtime; lock local é 0.21) e `humanize_send_error/1` (reason humano pt-br, técnico em `detail`).

## Frente aberta — Construtor de Mensagens vs catálogo (mandato do dono, implementação PENDENTE)

Matriz exaustiva em `docs/reports/2026-07-06-construtor-mensagens-matriz-gaps-catalogo.md`. Resumo: catálogo de campos, whitelist `@known_params` e builders são 3 listas desacopladas; campos OBRIGATÓRIOS do XSD (CPF/CNPJ das partes, agência, tipo de conta no pacs.008; ISPBs do pacs.004; `execution_datetime` do trck.002) são descartados em silêncio; reda.016/017/041 expostos sem builder (422 na certa); pain.011/012 com rótulos trocados; nenhum SELECT (ISPB deveria vir do diretório de participantes já servido em `/api/v1/bacen/pix-participants`). Plano de correção no relatório.

## Deploy

- Commits em `origin/main`: `66769931` (core), `0a0a3375`+`9bdfd23a` (pix eco), `43dfb161` (pix transporte/erro humano).
- Imagens tag imutável `homolog-9bdfd23a-fixes-20260706`; **deploy COMPLETED e validado vivo**: `pix-api:117` (health 200; eco real pós-deploy provou o agrupamento: pibr.001 SENT e pibr.002 RECEIVED ambos com `end_to_end_id=MONETARIE_HML_20260706150354`) e `core-api:85` (health 200; boot logou `[NATS] Connected` 15:03:18Z + `[SPB Consumer] Subscribed to monetarie.spb.credits.inbound`).
- Auditoria da janela de surdez (05/07 14:23 → 06/07 14:28 UTC): SPB publicou SÓ o crédito da STR (replayado); PIX completou 1.420 jobs `nats_publish` porém ZERO em `monetarie.spi.*` (HSM fora, sem eventos de dinheiro). Perda total do incidente = 1 evento, recuperado.
- Rollback: `core-api:84`, `pix-api:116`.

## Gotchas novos

- `.gitignore` linha `audit/` engole `apps/shared/{lib,test}/shared/audit/` — arquivo novo ali exige `git add -f`.
- Runtime HML usa finch 0.23 (`Finch.TransportError` existe); lock local 0.21 (NÃO existe) — nunca expandir o struct em pattern; casar por `__struct__`.
- `spi_service` não roda `mix test` sem `priv/repo/migrations/` (adicionado `.gitkeep`).
- Suíte local do `shared` tem 4 falhas PRÉ-existentes (3 namespaces reda no `message_builder_test` + 1 `client_dict_headers_test`) — não são regressão destes fixes.
- PG local de teste: container `monetarie-pg` porta 15432, `DB_PASS=monetarie` (não o default `MonetarieDB@2026` do `config/test.exs`).

## Adendo (tarde de 06/07) — dinheiro, comprovante e Construtor completo

### Saldo 100x menor + Entradas do mês zeradas (RESOLVIDO vivo, `core-api:86`)

- Bug de unidade: `post_member_credit` depositava CENTAVOS no TigerBeetle (que é SUBCENTAVO): os R$ 50.000 da STR viraram R$ 500 no saldo do IB (TB vivo: `credits_posted 5.223.700`). Fix `a7db5a66` (os testes CONGELAVAM o bug esperando centavos e foram corrigidos juntos); saldo vivo complementado com depósito de ajuste idempotente de 495.000.000 subcentavos → TB `500.223.700` = R$ 50.022,37. ATENÇÃO follow-up: `PixHandler`/`AccountResolver` passam `amount_cents` cru ao `Wallet.deposit` nos fluxos de estorno de devolução; auditar unidade.
- "Entradas do mês R$ 0,00": `sum()` do Postgres volta Decimal e o `build_summary` somava Decimal+integer (ArithmeticError → rescue → 500 `analytics_unavailable` SEMPRE que havia transação). Fix `6e8306ff` com teste de regressão no endpoint; validado vivo: `income=5000000` centavos.

### Comprovante (RESOLVIDO vivo, `core-api:86`)

- Instituição do pagador "ISPB 00512839" cru → `InstitutionDirectory.name_by_ispb` (nova tabela `institution_directory`, semeada com as 437 instituições do `bacen_ispbs` do SPB via rpc; `banks` não serve: check de 3 chars no code). Fixes `a74729a8` + `e0b3a430`. Validado vivo: payer.institution = "COOPERATIVA DE CREDITO DOS SERVIDORES DO MUNICIPI". Gotcha: a primeira carga levou `\r` do terminal nos 437 nomes (limpo com regexp_replace).
- Data/Hora 05/07 21:00 em crédito de 06/07: receipt de lançamento serializava `entry_date` date-only (front lia como UTC-midnight). Agora emite `inserted_at` com fuso; validado vivo `2026-07-06T14:29:46Z`.

### Construtor de Mensagens vs catálogo v5.12.1 (MANDATO CUMPRIDO, 12/12 tasks)

Executado por subagentes com TDD e revisão dupla (plano `docs/plans/2026-07-06-construtor-mensagens-catalogo-plano.md`). Commits `7a44efb1..22537e8e`:

- Task 1 `7a44efb1`: `SettlementServiceWeb.MessageFormCatalog` fonte única; `@known_params` DERIVADO do catálogo (4 campos eram descartados em silêncio, incl. `execution_datetime` obrigatório do trck.002).
- Tasks 2-4 `28ff7259`/`6b59db87`/`adc84874`: pacs.008 (11 required, era 3; CPF/CNPJ, contas, tipos, finalidade; `creditor_name` removido por não existir no XSD), pacs.004 (ISPBs + `SttlmPrty`), trck.002.
- Task 5 `6e8aa6a8`: builders reda.016/017/041 (antes: raise → 422); campos corrigidos pelo XSD (`report_id`→`confirmation_deadline`; `activity_status`/`effective_at`→`field_name`/`old_value`/`new_value`).
- Task 6 `15335eb5`: pain.009-014; RÓTULOS TROCADOS corrigidos (pain.011=MndtCxlReq, pain.012=MndtAccptncRpt); defeito real de builder achado pelo RED: elementos opcionais VAZIOS quebravam facets (fix `opt_el/2`, beneficia Recorrências em produção).
- Task 7 `07ee6757`: camt.014/025/029/052/053/054/055/060; decisões: camt.053 sem from/to_date (não existe no XSD 1.4), camt.060 aceita `balance_type` com compat `prtry`.
- Task 8 `78d3f951`: pibr/admi/reda.022 (10 campos de contato/diretor agora fluem: `reda022_modifications/1` público; eco leva `echo_data` do operador no envio; admi.002 renomeado MessageReject).
- Task 9 `32c6b82c`: `field_meta` por tipo (domínios REAIS por XSD, ex.: purpose difere entre pacs.008 e pain.013); endpoint types devolve.
- Task 10 `74975a1b`: front renderiza selects (ISPB = diretório BACEN via participants store, ~901; date/datetime/number).
- Task 11 `22537e8e`: guarda de completude (27 tipos constroem sem raise).
- Task 12: DEPLOY `pix-api:118` + `pix-admin-ui:30` (tag `homolog-22537e8e-construtor-20260706`), COMPLETED, health 200; evidência regra 11 em `docs/reports/screenshots/2026-07-06-construtor-DEPOIS/` (pacs.008 com 11 obrigatórios e selects populados, validado logado no admin vivo).
- XSDs do repo provados IDÊNTICOS (cmp, 28/28) à fonte autorizada `/Users/luizpenha/mwbank/md/v5.12.1/xsd/`.
- Pré-existentes NÃO tocados: 3 falhas de namespace reda.014/022/031 no `message_builder_test` local e 14 de cert/AWS no settlement_web (ambiente).

### Estado final de deploys do dia

| Serviço | Task-def | Tag |
|---|---|---|
| core-api | :86 | homolog-30517571-fixes2-20260706 (rollback :85/:84) |
| pix-api | :118 | homolog-22537e8e-construtor-20260706 (rollback :117/:116) |
| pix-admin-ui | :30 | homolog-22537e8e-construtor-20260706 (rollback :29) |

## Adendo 2 (noite de 06/07) — rodada de negócio pós-revisão do dono

Deploys finais (tag `homolog-ee5fd6cd-final-20260706`, todos COMPLETED, health 200): **core-api:88**, **pix-api:119**, **pix-admin-ui:31**. Rollbacks: :87/:86, :118/:117, :30/:29.

1. **Descritivos oficiais nos selects** (`622e1ffa`): todas as options do construtor viraram código + descrição OFICIAL do catálogo v5.12.1 (extraídas dos xlsx; inclui os 43 reason codes da pacs.002). Pegadinhas confirmadas na fonte: OTHR de conta = Conta PI de participante direto; DICT = inserção manual de CHAVE; GSCB = Pix Troco; OTHR finalidade = Pix Saque; IPRT = devolução MED 2.0. ISPB virou input pesquisável (datalist, diretório completo), default do próprio ISPB por contexto (ispb/from_ispb/debtor_ispb/party_ispb), separador sem travessão (`16e820b5`).
2. **camt.060 por MODO** (`6e304f8d`): paridade 1:1 com os 7 exemplos oficiais do legado (SALDO_MOMENTO, SALDO_DATA_ANTERIOR, SOLIC_REL_LANCAMENTO com FrToDt/FrToTm, SOLIC_ARQUIVO_TRD, SOLIC_REMUNERACAO_CONTA_PI, SOLIC_LANCAMENTO por E2E, SOLIC_LANCAMENTO_STR). A "consulta de operação" cobrada pelo dono = camt.054 + RptgReq/Id, sem ReqdBalTp (suprimido como nos exemplos). Builder ganhou RptgPrd completo.
3. **Vínculo DICT na timeline** (`cc9e88f0`): linhas DICT herdam o PI-EndToEndId no end_to_end_id (restrito a DICT, fail-closed); **backfill executado vivo: 70 linhas** do acervo. Script: docs/operator/scripts/2026-07-06-backfill-dict-e2e.exs.
4. **Dois eixos de status no monitor** (`9bad0915`), paridade com o legado (enumStatusOperacao vs enumTransactionStatus): coluna "Status de negócio" (Validado ACSP / Concluído ACSC/ACCC / Rejeitado RJCT / Aguardando retorno) extraída do TxSts da pacs.002 do fluxo; cor da linha segue o NEGÓCIO (RJCT = vermelha mesmo com ACK 2xx); tooltip do ACK: "código HTTP da transmissão, não é o resultado do pagamento".
5. **PIX liquidado sem extrato no Core** (`ee5fd6cd`, achado do dono com o PIX OUT de R$ 1,00): nem OUT nem IN gravavam account_entries (só transactions + TB) — extrato do admin descolava da wallet. Novo `Monetarie.UseCases.Pix.StatementEntries` com hooks nos 3 caminhos (OUT settled, IN legado, IN TB-first), idempotente por (reference, source), fail-soft + backfill público. **Backfill executado vivo**: débito de R$ 1,00 "PIX enviado - Bruno Cardoso" ref E46026562202607061857mevnaa6pihq no extrato da conta 117674-9; acumulado do extrato agora fecha com a wallet (R$ 50.021,37).
6. **Timestamp da lista de transações do IB** (`40e6cfec`): lançamentos legados emitem inserted_at com fuso (era date-only, mostrava "há 20 horas" para crédito de 8h).

Evidências: docs/reports/screenshots/2026-07-06-construtor-DEPOIS/ (pacs.008 com selects, camt.060 com modo "Consulta de operação", monitor com "Status de negócio") + docs/reports/screenshots/2026-07-06-validacao-dono/ (telas enviadas pelo dono: extrato do admin ao centavo e dashboard do IB com Entradas R$ 50.000,00).

Follow-ups novos: restringir ISPB "próprio" a nós + participantes indiretos nossos (hoje default preenchido, lista completa disponível); revisão de fluxo de NEGÓCIO ponta a ponta vs LegadoPIX segue como frente aberta (a rodada de hoje cobriu construtor, monitor, camt.060, vínculo DICT e extrato).

## Adendo 3 (madrugada) — sincronização 100% dos retornos do DICT + monitor sem eco duplo

Deploys: **pix-api:120** e **pix-admin-ui:32** (tag `homolog-a94dba8b-sync-20260706`); migration `20260706150000` (dict_sync_cursors + colunas espelho, aditiva) aplicada via rpc.

1. **Pollers descartavam TUDO** (mandato do dono: 100% dos retornos de MED/reivindicação/portabilidade/infração no banco). Causas provadas: client embrulhava XML como `%{raw: body}` e claims/infrações nunca parseavam; infrações nem parser tinham e o changeset exigia campos que a listagem 2.11 não devolve (insert falhava mudo); refunds parseava e não persistia nada (`route_inbound_refund` nem casava a chave do id). Fix `8dcdac45`+`af3c7148`: parsers com XML REAL do acervo como fixture, upsert idempotente por Id BACEN, claims em OWNERSHIP e PORTABILITY nos DOIS papéis com ciclo de vida completo (antes: só IsDonor+Status=OPEN e status hardcoded), erro sempre logado.
2. **Controle de estado espelhado do LegadoPIX** (exigência do dono para não detonar o link BACEN): `ModifiedAfter` incremental com sobreposição de 5 min, avanço só em ciclo bem-sucedido, paginação pelo LastModified (+1s), Limit + teto de 50 páginas logado, cursores PERSISTIDOS em `monetarie_dict.dict_sync_cursors` (melhoria sobre o `static DateTime` em memória do legado, que repuxava 1 dia a cada restart). Referências .NET no relatório do implementador (ReceiveService.cs:175-326, BuscarReivindicacaoUseCase.cs:113-150, FactoryUnitOfWorkDevolucao.cs:467-597).
3. **Carga inicial provada viva**: refunds 0→**67**, infraction_reports 0→**312** (4 páginas), claims 3→**446** (344 buscadas no papel reivindicador + doador; 220 materializadas no 1º ciclo). Ciclos seguintes (21:57/21:58Z) buscaram SÓ o delta (2 refunds, 1 claim) = watermark funcionando, link preservado. `resync_all()`/`resync(tipo)` disponíveis para recarga explícita.
4. **Monitor** (`d24072a7`+`2c7ce78c`): dupla auditoria do mesmo inbound ICOM corrigida na origem (eram DOIS espelhos: AckTracker pré-ACK com path `/in` errado + InboundProcessor via BacenLogger com path `/out`; 60ms entre eles, md5 idêntico); **46 duplicados do acervo removidos** pelo script (0 restantes); direção agora segue a natureza do path (long-poll ICOM = Recebido; consultas nossas /api/v2/* = Enviado); labels traduzidos (Reivindicações/Portabilidade, Relatos de infração, Sincronização CID, Consulta de chave) e recurso ICOM não é mais rotulado como E2E.

Pré-existentes intocadas: 1 falha dict_service (prefixo dict- vs UUID do fix Vulci) + 15 do shared (reda namespace, CnpjAlfa, CERTQRC/JWS) — provadas no baseline.

## Adendo 4 (2026-07-07) — bateria de paridade DICT v2.11.0 + ICOM/SPI + telas MED/DICT

Deploys: **pix-api:122** (tag `homolog-8712b30e-final-20260707`) e **pix-admin-ui:33** (tag `homolog-36520e4b-paridade-20260707`); core-api:88 inalterado (bateria 100% PIX). `origin/main` = `8712b30e`. Migrations aplicadas via rpc: `20260706230000` (refund cancel fields), `20260706233000` (fraud_markers).

### Duas matrizes de auditoria (3 colunas: spec/LegadoPIX/nossa cabine, evidência file:line)
- `docs/reports/2026-07-07-paridade-dict-v2110-matriz.md` e `...-icom-spi-fluxos-matriz.md`. Nota de honestidade: não há manual DICT v2.11.0 oficial em texto em mwbank/md (só .xls binário) — itens SEM-FONTE marcados, não inventados.

### Gaps corrigidos com TDD
- Construtor: **8 caminhos ficticios `/pix/v2/*` eliminados** (send_payment do pacs.008 inclusive), envio pelo endpoint real assinado com canal por tipo; tabela-verdade dos 27 tipos (`docs/reports/2026-07-07-construtor-tabela-verdade-envio.md`) + guard test que quebra o build se um tipo cair em caminho não mapeado; tipos SPI-only recusados 422 (camt.014/025/052/053/054, admi.004, reda.016/017/041) por dupla prova (exemplo oficial AppHdr/Fr + montador legado).
- camt.060 do Construtor: era o fallback ficticio no canal secundario (icom-sec morto) sem assinar → agora endpoint real primario assinado (`681cf9df`).
- claimer_opening_date (`dc33cc28`), reason/situation_type (`aabdcd2b`), @operation_types + idempotencia (`fec1a26b`), CloseRefund emite RefundRejectionReason (`a924985b`), validacoes de envio GSCB/saque/DICT/prioridade no send gate (`73b2b61f`), mapa erro-credito→ISO no pacs.002 que destravou devolucao automatica (`37093d3e`), 13 motivos → 4 oficiais do XSD pacs.004 + guard (`4b82f9a5`).
- Cancel de devolucao (501→real fail-closed, `df51c680`), menu lateral active unico (`6fcb4b3c`).

### Telas religadas em paridade com o LegadoPIX
- Reivindicacoes/Portabilidade (`0954fd7b`/`df20fa33`): estava vazia por BUG DE CONTRATO (service lia data.data de {claims,total_count}); agora papeis doador/reivindicador, prazos D+7/14/30 com badge, acoes por estado espelhando o Monitor de Reivindicacao. Gap real fechado: claims SINCRONIZADAS nao agendavam timers de quarentena (so as criadas por nos) — agora agendam.
- DICT Relatorios (`fd99216c`): 4 abas religadas (mesmo bug Array.isArray sobre {returns/claims}); colunas/filtros do legado.
- Indicadores (`59863633`): "20.926ms" era duracao de LIQUIDACAO (com espera do recebedor), nao latencia; religado a response_time_ms real por request; P50/95/99 reais; sincronismo em paridade com ListaUltimoHistSincronismo.
- Infracoes (`a2fe3bc6`/`743df5d2`): campos 2.11 (relator/contraparte/motivo/situacao) JA gravados e nao exibidos → agora na tela com rotulos honestos; enriquecimento local por E2E + camt.060 de consulta de operacao para o acervo antigo.
- Tracking graph via GET (`43585d19`): POST era deprecated; bug real era guard de status + inserts duplicados.

### Achados de validacao viva (honestos, nao mascarados)
1. **Fraud markers: 5a perna do poll era arquiteturalmente ERRADA** — BACEN deu 400 FraudMarkerInvalid (fraude nao e recurso inbound; legado consulta por Id e lista da base local). Removida do ciclo automatico (`8712b30e`) para parar o desperdicio de link; schema/parser/create-cancel local mantidos. Tela vazia e CORRETA (0 marcadores porque nao criamos nenhum).
2. **Enriquecimento das 302 infracoes: 0 local** — sao dados de TESTE do ISPB 27302181 (nos somos so a contraparte), nunca transacionaram pela cabine; sem transacao local para casar. Codigo correto (provado por teste); enriquece quando chegar infracao de operacao real nossa.
3. Backfill timers claims: 4 agendados / 41 ja terminais. 20 camt.060 de operacao disparadas (E2Es de teste + HSM, fail-closed).

### Falso alarme da matriz (provado, nao gap)
FraudType enum (confusao entre submissao singular 5 valores e contadores plurais de estatistica), devolucao parcial ≤ original (ja implementada spi_validator.ex:62), prazo de devolucao (validate_return_window), person-statistics path (ja usa /persons/{TaxId}/statistics v2.11), CID sync desligado (HML tem env=true, roda).

### Evidencia (regra 11)
`docs/reports/screenshots/2026-07-07-paridade-DEPOIS/`: reivindicacoes-portabilidade (papeis+prazos+linhas reais), dict-relatorio-devolucoes (67 refunds, colunas legado), med-infractions-relator (RELATOR/CONTRAPARTE ISPB + menu active unico).

### Pendencias
Manual DICT v2.11.0 oficial + planilhas Dom/Erros legiveis para fechar SEM-FONTE contra o BACEN; T1-T5 vivo dependem do HSM RTM e trafego homolog.
