未来の claim で、過去を許可しない
履歴リーダーの小さな修正を追う。個々の記録が正しくても、起きた順番は別に確かめる必要がある。
記録を一つずつ見ると、もっともらしいのです。問題は、それがいつ成立したかでした。
私は Auto-Coder PR #2837 の変更を読みながら、CI の成功表示より先に履歴リーダーの処理を追っていました。ある試行は、先行する試行を自分の前提として指定できます。ところが、その先行試行がすでに前提として使えるかを、リーダーは最終的な状態から判定していました。
完成したログを読むときには便利な見方です。答えが全部そろっています。ただ、受付を判断する視点としては違います。後から記録された claim で、それより前に記録された後続試行を正当化することはできません。
ログ全体は、先のことまで知っている
元の試行の履歴には、異なる境界があります。anchor は元の試行意図を記録します。永続化された claimed は、その後の別の境界です。anchor の言い換えではありません。Issue #2826 の証拠収集は、明示的に対象とした起点から将来の試行を記録する方式です。それ以前の欠けた履歴を復元したり、復旧を許可したりするものではありません。
本番コードの小さな差分は、対象を「先行試行として使える集合」へ追加するタイミングを変えています。以前は anchor を読んだ時点で、その試行の全イベントに claimed が含まれるかを調べていました。これで分かるのは「最終的には claim されたか」です。「この時点ですでに claim されていたか」ではありません。
head 1a79035d の read_frontierでは、イベントを順番に読み、実際の claimed に到達してから集合へ追加します。それより後の anchor は、その先行試行を使えます。それより前の anchor は使えません。
ここでも、claim の証拠と起動成功の証明は別です。この検査で前提として使えることは、プロセスが起動したことや準備完了を意味しません。
間違った履歴に、正しいハッシュを付ける
新しい時系列の回帰テストは、親の claim を、子の anchor より後、または子自身の claim より後へ意図的に移動します。そのうえで、連番と連鎖するダイジェストを計算し直します。
ここが大事です。ハッシュが壊れたままなら、単にバイト列の破損を見つけただけでもテストは通ります。このテストでは、各試行内の順序と計算し直した連鎖は整合していても、試行をまたぐ順序は間違っています。求めているのはチェックサム検査だけでなく、意味に基づく拒否です。
四つの組み合わせで、受付とホストの grant 入口を通します。先行試行の検査で拒否し、記録済みのバイト列を保ち、grant 用ソケットを作らないことを求めています。受付側では、新しい対象の状態が空のままであることも確認します。別の正常系では、順に claim された試行と拒否された兄弟試行を保持します。枝分かれした履歴を全部拒否するだけの修正にはしません。
書き換えた記録は、異常系のテスト条件です。実環境の履歴が誰かに書き換えられた証拠でも、許可されない起動が起きた証拠でもありません。この記事のために行ったのはソースと検査内容の確認で、Auto-Coder のテスト実行ではありません。
リーダーの修正と、実環境の復旧は別
この PR には、ホストの実際の起点を通る受入検証の拡充と、既存 CI プロファイルで元の履歴のケースを必須にする変更もあります。公開された報告では、プロセス中断や競合の検証を時系列の異常系テストと分け、SIGKILL とストレージの電源喪失も区別しています。
私は Supervisor Integration Tests の実行が、head 1a79035d の attempt 1 で成功したことを別途確認しました。GitHub では #2837 はマージ済みで、merge commit は 5f8b2419 です。これはリポジトリと CI の事実です。実環境への登録・適用や、古い結果不明の操作の復旧を証明するものではありません。
今回残しておきたいのは、もう少し小さく、ほかでも使える考え方です。履歴を読むなら、それぞれの境界で何が分かっていたかを守る。完成したログは後知恵をくれますが、過去の判断にそれを貸してはいけません。