Aceitar bytes e identificar intenção
O consumidor original recebe identificador, ficheiro, hash esperado e modo de falha. Lê o ficheiro uma vez para memória e calcula o hash sobre esses mesmos bytes. Só inicia a transação quando a comparação passa. Esta leitura única evita usar um conteúdo para validar e outro para calcular o efeito sintético, mas não bloqueia alterações externas durante a leitura nem oferece streaming para ficheiros arbitrariamente grandes. A referência esperada é fornecida pelo próprio ensaio, sem assinatura ou validação de um manifesto externo. O identificador representa a intenção de entrega. Dois períodos podem legitimamente produzir bytes iguais e exigir dois processamentos; uma repetição da mesma entrega deve conservar a identidade. O laboratório demonstra ambas as situações sem impor um modelo universal de identificação. No contrato real, define também emissor, período e âmbito de unicidade.
Falhar antes e depois de COMMIT
A fixture abre BEGIN IMMEDIATE e grava duas linhas: um recibo com identidade e digest, e um efeito sintético contendo a contagem de bytes. Ambas pertencem à mesma transação SQLite. No modo before-commit, o subprocesso termina com os._exit depois dos INSERT e antes de COMMIT; uma ligação nova observa ambas as tabelas vazias. No modo after-commit, o subprocesso termina depois de COMMIT e antes de imprimir a confirmação; a leitura nova encontra recibo e efeito. A ausência de resposta não distingue estes estados por si. Por isso, o operador consulta evidência persistida pelo identificador original. O ensaio usa morte de processo, não corte de energia. A conclusão limita-se à recuperação observada com esta versão de SQLite e armazenamento local; não estabelece a durabilidade de uma plataforma financeira ou de um cluster distribuído.
Recuperar repetição e rejeitar conflito
Ao repetir a mesma identidade com o mesmo digest, o consumidor encontra o recibo, termina a transação de leitura e devolve duplicate com a referência anterior. As tabelas mantêm exatamente as mesmas linhas. Se a identidade existir com outro digest, a resposta é identity-conflict, mesmo que o novo ficheiro passe a comparação com o seu próprio hash esperado. Integridade e identidade são condições diferentes. Uma correção de negócio deve ter um procedimento explícito que ligue a nova intenção à anterior. INSERT OR REPLACE não é uma solução neutra: perante certos conflitos de unicidade, SQLite remove a linha existente antes de inserir a substituta. Isso pode apagar a associação necessária para reconciliar o primeiro efeito. O sexto subprocesso usa um identificador novo com bytes iguais e produz outro efeito, demonstrando por que mudar o nome ou a identidade não constitui um retry seguro.
Delimitar o contrato operacional
O efeito demonstrado é apenas uma linha SQLite na mesma transação que o recibo. Não existe lançamento financeiro, API externa ou sistema de pagamentos. Se o consumidor chamar outro serviço entre INSERT e COMMIT, a falha pode deixar um efeito externo sem recibo local. Um desenho de outbox pode coordenar a intenção persistida e o envio posterior, mas continua a exigir recuperação e deduplicação adequadas no destino; esse desenho não foi executado aqui. Define ainda quanto tempo os recibos sobrevivem e como tratar retries que chegam depois da retenção. O guião abaixo dura quarenta minutos e termina com uma explicação escrita dos limites. Foi executado automaticamente a partir do código publicado, mas ainda não foi realizado com participantes. Usa a comparação de resultados para aprender a distinguir evidência de uma hipótese que exige outro ensaio autorizado.
GUIÃO DE 40 MINUTOS
0–8: Guarda o código completo da aula anterior como run.py. Usa uma área de trabalho local autorizada, uma conta sem privilégios e sete executáveis da mesma compilação. A referência executada foi OpenSSH 10.5p1 sem PAM, OpenSSL 3.6.1, Python 3.13.1 e SQLite 3.51.2. Substitui /path/openssh pelos caminhos locais.
python3 run.py \
--ssh /path/openssh/ssh \
--sshd /path/openssh/sshd \
--sshd-session /path/openssh/sshd-session \
--sshd-auth /path/openssh/sshd-auth \
--keygen /path/openssh/ssh-keygen \
--sftp /path/openssh/sftp \
--sftp-server /path/openssh/sftp-server \
--output ./recovery-evidence.json
8–18: Lê checks e observations. Confirma cinco sessões SFTP, seis workers e trinta verificações. Explica por que partialBytes pode variar e por que wrongPrefixResume termina com zero apesar de o hash divergir.
18–30: Compara os estados dos workers integrity-rejection, failure-before-commit, failure-after-commit, retry-same-identity, identity-content-conflict e new-identity-same-bytes. Liga cada exit à evidência persistida. Não reutilizes o ficheiro de saída se quiseres conservar execuções anteriores.
30–40: Redige o runbook de uma confirmação perdida: identidade, consulta de estado, condição de retry, conflito, escalada e retenção. Lista separadamente rede externa, concorrência, energia, efeitos externos e retenção expirada, que este ensaio não executa. Confirma a remoção dos ficheiros temporários e do daemon no relatório. Não uses dados ou credenciais reais.Uma confirmação perde-se depois da gravação do consumidor fictício. Repetir o identificador original devolve o recibo existente; inventar outro identificador produz um segundo efeito.
Armadilhas comuns
Deduplicar globalmente pelo hash, usar INSERT OR REPLACE para ocultar conflitos ou assumir que uma transação SQLite inclui uma chamada externa.
Tópicos relacionados: Transações e recibos · Retry e intenção de negócio
Recupera a mesma intenção através de identidade estável e evidência persistida. Cada efeito externo precisa de um contrato de recuperação próprio.
Referência: SQLite transaction boundaries · DR SFTP 2026-09; selected OpenSSH client, server and extension behavior