@audit — Webhook MP classificando status normal como incidente
Data: 2026-05-07 Escopo: @audit — banner de incidentes do Dashboard Admin Severidade: baixa (ruído operacional — não afeta funcionalidade nem dados)
Sintoma
Após gerar um boleto via Mercado Pago, o banner do Dashboard Admin mostrava:
⚠ 1 incidente nas últimas 24h — último:
pagamento.webhook_validation_failed
Apenas a geração do boleto, sem nenhuma falha técnica real, disparava "incidente".
Causa raiz
supabase/functions/mercadopago-webhook/index.ts validava 4 condições no payload do MP (status_approved, external_reference_match, valor_match, moeda_correta) e, se qualquer uma falhasse, registrava pagamento.webhook_validation_failed.
O MP envia webhook imediatamente após a criação da preferência com status=pending (boleto aguardando pagamento). Isso é o estado normal do ciclo de vida — só vira approved quando o pagador efetivamente paga. Como status_approved=false, o log virava "validation failed" e a ação está no SSOT _shared/incident-actions.ts, alimentando o banner.
Correção
Split de classificação no webhook (L291–380):
- Se a única falha é
status_approved=falseE opayment.statusestá em{pending, in_process, cancelled, refunded}→ registrapagamento.webhook_status_recebido(informativo, fora do SSOT de incidentes). - Em qualquer outro cenário (referência adulterada, valor divergente, moeda errada, status
rejected/charged_back) → mantémpagamento.webhook_validation_failedcomo incidente legítimo.
- Se a única falha é
SSOT de log actions (
src/constants/log-actions.ts): nova entrada "Status de Pagamento Recebido (MP — informativo)" para o filtro do Admin → Logs.Política de incidentes (
docs/operations/INCIDENT_POLICY.md§3): linha explícita listando o ciclo de vida normal do MP como não-incidente.Comentário em
_shared/incident-actions.tsdocumentando a regra ao lado da exceção análoga delogin.falha_senha.
Visibilidade ao usuário
A informação de "boleto pendente / em processamento" continua disponível no histórico da fatura (drawer Admin → Financeiro), que consome logs_auditoria filtrando por pagamento.*. Não há perda de visibilidade — apenas deixa de poluir o banner de incidentes do Dashboard.
Arquivos tocados
supabase/functions/mercadopago-webhook/index.tssupabase/functions/_shared/incident-actions.tssrc/constants/log-actions.tsdocs/operations/INCIDENT_POLICY.mdmem://features/admin/dashboard-layout-v2
Não-objetivos
- UI do banner / dashboard inalterada.
- Webhook continua logando
webhook_status_recebidopara auditoria — só muda a classificação de incidente vs informativo.