← Notas
Um registro que ninguém reescreve em silêncio
architecture·audit·security

Um registro que ninguém reescreve em silêncio

Cada movimento de capital, cada aprovação e cada troca de modo cai num log de auditoria com cadeia de hash. Por que isso importa em software de trading e como verificar a integridade em menos de um minuto.

· Mikhail Savchenko

Existe uma classe de bug em software financeiro que é pior do que as outras: não é um crash, é uma quebra silenciosa. O algoritmo continua operando, o dashboard segue desenhando a curva, e em segundo plano algo — um bug, uma race condition, um erro de serialização — reescreveu uma linha do passado in-place. Pegar uma quebra dessas uma semana depois não dá: você não sabe quais números eram reais e quais eram a reescrita.

O log de auditoria do inite.fund foi feito justo para descartar essa classe de falha. Não pra sinalizar depois do fato, mas pra tornar reescrever o passado estruturalmente impossível.

Append-only por construção

Toda tabela de auditoria — audit_log, capital_flows, mode_history, hil_decisions — funciona em modo append-only. UPDATEs estão bloqueados em nível de trigger do banco. DELETE só é permitido na linha mais recente, e só enquanto ela está marcada como pending. Qualquer coisa mais antiga que um dia não pode ser modificada por ninguém — incluindo admin.

Parece restrição; é alívio. Uma vez que uma linha está no log, está lá pra sempre. Sem “a gente ajustou o valor de ontem porque viu um erro de digitação”. O erro fica do lado da correção, e os dois ficam visíveis.

A cadeia de hash

Cada linha do log carrega, além dos dados, dois campos extras: prev_hash e row_hash. row_hash é o SHA-256 de todos os campos significativos da linha atual concatenados com prev_hash da linha anterior. Cada registro assina não só ele mesmo mas tudo que veio antes no mesmo log.

A aritmética dali em diante é simples. Muda uma linha no meio e o row_hash dela quebra. Pra esconder isso, é preciso recalcular todo row_hash depois dela. Pra recalcular, é preciso desativar os triggers do banco. Pra desativar os triggers, é preciso superusuário postgres. E cada elevação dessas cai no audit nativo do postgres, que a gente também guarda.

A cadeia dá pra verificar por qualquer ferramenta externa em uma passada. Pega a primeira linha, recalcula row_hash na mão, compara com o que está gravado. Pega a próxima, recalcula com prev_hash, compara. Até o fim. Se uma só não bater — o log foi mexido. O script cabe em vinte linhas; a gente roda em todo backup noturno.

Idempotência via audit_ref

Toda operação de capital — move_to_long, move_to_trading, approve_trade, set_mode — exige um audit_ref. É uma string única que quem chama gera antes do request. O banco checa que ainda não existe linha com esse ref, e só então aplica a operação.

Por que isso importa. Falha de rede no meio de uma chamada é coisa rotineira. Cliente manda o request, o banco aplica, a resposta se perde, o cliente tenta de novo. Sem audit_ref a segunda chamada passa, e o mesmo rebalanceamento acontece duas vezes. Com audit_ref a segunda chamada volta como “já aplicado” com o mesmo row_hash da primeira, e o cliente vê que não tem nada novo a fazer.

Na prática isso significa que operações de capital no inite.fund são seguras para retries em qualquer camada. Dá pra retentar do stack de rede, do cliente MCP, de um script manual do operador — o log permanece consistente.

O que isso dá ao operador

Três coisas. Primeiro, um histórico completo do movimento de capital quebrado por causa e por iniciador. Pra qualquer número do dashboard dá pra voltar até a linha de auditoria que o produziu — quando, por quem, com que justificativa.

Segundo, verificabilidade externa. Se um dia for preciso mostrar pra um regulador, um auditor ou um parceiro que os dados não foram maquiados depois do fato, a gente tem script e formato de export pra isso. Não é “confia na gente, somos os mocinhos”. É uma propriedade matemática do log que pode ser checada de fora.

Terceiro, e pra gente o mais importante, alívio psicológico. Quando você sabe que toda operação deixou rastro e o rastro não pode ser forjado, uma classe inteira de ansiedade some. Não precisa pensar se o sistema decidiu por você em silêncio e escondeu a decisão. Se o log está vazio, a ação não aconteceu. Se o log tem linha, ela é exatamente a linha que foi escrita no momento.

Quanto custa

Cada gravação no log é um INSERT a mais, um SHA-256 a mais, uma checagem de unicidade de audit_ref a mais. Nas nossas medições isso dá 40-60 microssegundos por operação. Pra uma engine de trading com tick a cada 200 milissegundos, é ruído. Pra uma API de corretora com tráfego alto seria crítico, mas a gente não é corretora.

O armazenamento cresce uns 4-6 KB por trade. Um ano de uma estratégia de trading rodando ao vivo dá 20-40 MB de log. Pro lado de portfólio é uma ordem de grandeza menor, porque o rebalanceamento roda uma vez por semana. De graça em qualquer escala de disco moderno.

No total: o custo operacional é quase zero, e o que se ganha é a impossibilidade de reescrever o passado em silêncio. É um dos raros momentos de arquitetura em que não dá pra trocar uma coisa pela outra.

— inite team

Notas relacionadas
Todas as notas →