Cenário construído para estudo, não o incidente de uma empresa específica. A forma se repete o suficiente pra valer como exercício, e a causa raiz é sempre mais interessante que o sintoma.
O sintoma
O relatório diário de conciliação acusa diferença de R$ 0,01 entre o total do gateway e o total interno. Todo dia útil. Às vezes um centavo, às vezes três.
Alguém do financeiro fazia o ajuste manual e seguia. Virou rotina, e depois de um tempo ninguém mais achava estranho.
Catorze meses assim.
Por que ninguém investigou
Três razões que se combinam, e todas são humanas.
O valor é irrelevante. Ninguém pede prioridade pra um centavo.
Existe um jeito de contornar. O ajuste manual leva dois minutos, e o problema fica resolvido todo dia.
E o alerta perdeu significado. Como ele disparava sempre, virou ruído. Um alerta que dispara todo dia deixa de ser alerta e vira parte da paisagem.
Esse terceiro ponto é o que realmente custa. Não é o centavo: é que o mecanismo criado pra detectar problema financeiro tinha sido desligado na prática.
A investigação
Quando alguém finalmente olha, a hipótese óbvia é arredondamento em split de pagamento. Dividir R$ 100 entre três vendedores gera 33,33 três vezes e sobra um centavo.
Só que a diferença aparecia também em dias sem nenhum pagamento dividido.
O que se descobre olhando as transações uma a uma: a diferença aparecia sempre em transações com estorno parcial.
O fluxo era este. O cliente compra por R$ 149,90, com taxa de 3,49%, que dá R$ 5,23 depois de arredondar. Líquido de R$ 144,67.
O cliente pede estorno de metade. O sistema calculava a taxa proporcional sobre o valor estornado: 3,49% de R$ 74,95, arredondado, R$ 2,62.
E o gateway calculava diferente: ele estornava a diferença entre a taxa total e a taxa da parte que permaneceu. R$ 5,23 menos R$ 2,61, que dá R$ 2,62 em alguns casos e R$ 2,61 em outros, dependendo de qual metade caía com o centavo.
Duas fórmulas defensáveis. Resultados que divergem em um centavo, de forma imprevisível.
O erro estrutural
O bug não é a fórmula. É que existiam duas fórmulas.
O sistema recalculava a taxa em vez de usar o valor que o gateway informava. Isso significa que ele estava mantendo uma opinião própria sobre um número que não era dele.
Toda vez que dois sistemas calculam independentemente o mesmo valor a partir de regras parecidas, eles vão divergir. Não é questão de se: é questão de quando e de quanto.
A regra que evita a categoria inteira: quem é dono do número informa, quem consome registra. Nunca recalcula.
A correção
Três mudanças.
Usar o valor informado. O campo de taxa passou a vir do payload do gateway, gravado como recebido. O cálculo interno continuou existindo, e virou estimativa antes da confirmação, claramente marcada como tal.
Separar estimado de realizado.
alter table payment
add column fee_estimated_minor bigint,
add column fee_actual_minor bigint;
Duas colunas, e o relatório usa a segunda. A primeira serve pra mostrar ao vendedor antes da liquidação, e a diferença entre elas virou uma métrica útil por si só.
Uma conta de ajuste no ledger. Diferenças residuais legítimas passaram a ter destino explícito, com lançamento próprio, em vez de sumirem. Como escrevi em ledger imutável, o resto nunca desaparece por arredondamento: ele vai pra algum lugar nomeado.
O que se descobre no meio
Ao investigar os catorze meses, aparece o que sempre aparece: outra coisa.
Duas transações com divergência de valor cheio, não de centavo. Cobranças que existiam no gateway e não no sistema, de clientes que pagaram e nunca receberam o produto.
Elas estavam escondidas no meio do ruído. Como o alerta disparava todo dia por causa do centavo, ninguém olhava a lista de divergências, e as duas grandes tinham entrado na mesma lista.
Esse é o custo real do alerta que vira paisagem. Não é o centavo: é o que ele estava escondendo.
O que fica
Alerta que dispara sempre não é alerta. Se algo dispara todo dia e a resposta padrão é ignorar, ou o limiar está errado ou existe um problema real não resolvido. Não existe terceira opção.
Divergência pequena e persistente é sinal de premissa divergente, não de erro de cálculo. Erro de cálculo dá diferença grande e óbvia. Premissa divergente dá diferença pequena e teimosa.
E “a gente ajusta na mão” é uma decisão. Ela precisa ter dono e prazo, senão vira o processo permanente que ninguém lembra por que existe.
Sobre o desenho de uma conciliação que separa ruído de sinal, escrevi em conciliação financeira automatizada.