Forma 1: Reparo de Estado. Forma 2: Relatório Desperdiçado.
Um Coração Medido bate no relógio. Não no necessidade. Não na mudança. No cronômetro.
Dois formatos, uma causa raiz: um trabalho agendado substituindo o design correto.
Forma 1: Reparo de Estado
Uma transição de estado falha para ser concluída atomicamente. Em vez de corrigir a transição, um trabalho de fundo é executado com atraso & reconcilia. Os usuários veem estado quebrado durante a janela de reconciliação.
Exemplo do GitHub (2026-04-08): Uma solicitação de pull do repositório upstream tornou-se privada. O GitHub tentou uma transição de estado: fechar o PR, atualizar o status do branch, limpar o status de fusão. A transição não concluiu atomicamente. O status do PR mostrou 'branch-forced-closed' & 'Não é possível carregar o status de fusão' simultaneamente. Um trabalho de fundo Sidekiq correu minutos depois & concluiu a reconciliação. Observadores viram estado quebrado durante a duração da janela.
O Coração Medido: o trabalho Sidekiq foi executado conforme o agendado. Ele não foi executado porque o GitHub detectou estado quebrado; ele foi executado porque o relógio disparou. Um usuário assistindo o PR em tempo real viu um PR que contradizia-se até a próxima execução do trabalho.
Forma 2: Relatório Desperdiçado
Um relatório ou agregação recalcula do zero em um intervalo fixo. Nenhuma verificação de cache. Nenhuma guarda de idempotência. Nenhuma atualização incremental. Cada execução: um escaneamento completo.
Exemplos: um trabalho de cron noturno que recalcula o total de compras de cada usuário escaneando todas as ordens desde o início do tempo. Um trabalho de análise diário que regenera um painel do dashboard a partir de logs de eventos brutos. Um e-mail semanal de resumo que consulta todas as linhas na tabela de atividades.
Cada um dispara independentemente de haver dados alterados desde a última execução. Cada um escaneia a história completa mesmo quando apenas os últimos 24 horas contêm novos dados. Cada um substitui a repetição agendada por um design incremental.
A Raiz Compartilhada
Um Coração Medido não pode dizer a verdade sobre seu próprio estado. Ele só sabe do relógio. Forma 1: o trabalho de reparo de estado é executado às 5 minutos após T independentemente de o estado estar quebrado em T+0. Forma 2: o trabalho de relatório é executado às 2 da madrugada independentemente de haver dados alterados desde ontem.
O relógio não carrega informações sobre o que precisa ser feito. Um evento carrega essa informação: 'uma transição de estado acabou de falhar', 'novas ordens acabaram de chegar'. Um Coração Medido joga essa informação no lixo & a substitui por um agendamento.
Drenagem de Capital
O Coração Medido drena capital vivo: engenheiros em chamada para incidentes de estado quebrado. Erode a confiança social: usuários veem dados inconsistentes e relatam defeitos que se resolvem sozinhos. Amplifica outros MOADs: um trabalho de reparo de estado que escaneia todos os registros para encontrar estado quebrado frequentemente contém MOAD-0001 (escaneamento O(N²)). Um trabalho de relatório que recalcula dados frios pode disparar MOAD-0005 (estampide de cache). O MOAD-0009 agrava outros defeitos.
A Raiz Compartilhada
Forma 1 e Forma 2 parecem diferentes na superfície: uma reparo estado, a outra recalcula dados. A causa raiz os conecta.
Queime Mudança, Não Relógio
Design baseado em eventos dispara quando algo muda. A transição de estado é o evento. O evento é o gatilho.
Forma 1: a transição atômica substitui o trabalho de reparo.
Se uma transição de estado pode deixar o sistema em um estado quebrado intermediário, o defeito vive na transição, não na ausência de um trabalho de reparo. Corrija a transição para ser completada atomaticamente (ou transacionalmente). Quando a transição for completada atomaticamente, o estado quebrado nunca existirá. O trabalho de reparo não terá nada para reparar.
# DEFECT: transição não-atômica deixa estado quebrado
def close_pr_on_repo_private(pr_id):
pr = PR.get(pr_id)
pr.status = 'branch-forced-closed' # etapa 1: estado parcial
pr.save() # visível aos usuários AGORA
# ... outras etapas podem falhar ...
pr.merge_status = 'not_applicable'
pr.save() # etapa 2: agora consistente
# Job Sidekiq de reconciliação se a etapa 2 falhar
# CORREÇÃO: transição atômica; nenhum estado intermediário visível
def close_pr_on_repo_private(pr_id):
with db.transaction():
pr = PR.get(pr_id)
pr.status = 'branch-forced-closed'
pr.merge_status = 'not_applicable'
pr.save() # ambos os campos se comprometem atomicamente; nunca escrito pela metade
Forma 2: a atualização incremental substitui o cálculo completo.
Um relatório que recalcula do zero dispara porque dados antigos + novos dados = novo resultado. Mas os dados antigos + delta = mesmo novo resultado, calculado incrementalmente. O evento: dados novos chegaram. O gatilho: atualize o agregado apenas para os novos dados.
# DEFICIÊNCIA: cálculo completo agendado
def nightly_totals_job():
for user in all_users():
total = sum(o.amount for o in user.orders) # analisar todos os tempos
user.total_purchases = total
user.save()
# CORREÇÃO: atualização incremental baseada em eventos
def on_order_placed(order):
order.user.total_purchases += order.amount # apenas delta
order.user.save()
A atualização incremental dispara quando uma compra é feita, não às 2 da madrugada. Ele atualiza apenas o usuário afetado. Ele lê apenas a nova compra, não todas as compras de todos os tempos. O job noturno desaparece.
Por que a Forma 1 Revela uma Transição Quebrada
Um Medidor de Corrente da Forma 1 Revela que uma transição de estado foi deixada incompleta. O job de reparo existe porque um engenheiro notou um estado quebrado e adicionou um mecanismo de reconciliação em vez de corrigir a transição. O job de reparo: uma correção sobre uma decisão arquitetural quebrada.
MOAD-0009 como Amplificador
O MOAD-0009 amplifica outros MOADs. Um job de reparo do estado que varre todos os registros para encontrar o estado quebrado: MOAD-0001 (O(N) ou O(N²) scan por execução do job). Um job de relatório que recalcula tudo em frio: MOAD-0005 (estampide de cache quando o job começa e atinge uma fonte upstream quente). O MOAD-0009 não machuca apenas por si só; ele entrega outros MOADs em um cronograma.
Diagnose & Redesign
Um time executa um job cron noturno às 2 da madrugada. O job escaneia todos os pedidos de todos os usuários e recomputea o total de compras de cada usuário do zero. O job leva 4 horas. Às 6 da manhã, o painel mostra totais atualizados. Entre às 2 da madrugada e às 6 da manhã, o painel mostra totais do dia anterior.