まとめられる通り道にトグルを流してはいけない
peithoのプレゼンは二画面(発表者用と聴衆用)を同期させる。同期の通り道は長ポーリングのサーバ経由で、取りこぼしと合流(coalescing)が起きる。速く連続した更新は、遅い受信側にとっては最後の一つにまとめられて届く。
ここで画面の入れ替え(swap)を「入れ替えろ」というトグル命令として流すと壊れる。
そこで流すものを {"swapped": true} という絶対状態にした。設計記録は「never a toggle command — the channel coalesces」と明記している。絶対状態なら、まとめられても最後の一つが正しく、取りこぼしても次のポーリングで正しくなり、何度適用しても同じ(冪等)。
スライド位置の同期も同じ形で、{"index":N,"step":M} という原子的な絶対値を流す。位置だけの裸のindexは拒否される — 位置と段階が別々に届くと、その間に不整合な中間状態が現れるからである。
「毎回全部送る」ことが収束を担っている
もう一段の含みがある。ハンドシェイク時だけ現在状態を送るのでは足りない、と記録は言う。
this per-poll replay is load-bearing for convergence
—peitho/CLAUDE.md
理由はこうだ。生きている窓が「まとめられて消えた」更新を取り逃がすと、その窓は二度と再ハンドシェイクしない。だから初回だけ状態を配っても届かない。すべてのポーリング応答が現在の絶対状態を載せることで、遅れて気付いた窓が次の応答で自分から追いつく。
つまり「絶対状態を送る」だけでは足りず、「絶対状態を繰り返し送る」ことで初めて収束する。差分ではなく状態を、一度ではなく毎回。
IaCの差分エンジンと同じ考え方である
これは目新しい発明ではなく、宣言的な仕組みが一様にやっていることと同じである。
| 流すもの | 取りこぼしたら | |
|---|---|---|
| トグル命令 | 「反転せよ」 | 恒久的にずれる |
| 絶対状態の繰り返し | 「今こうあるべき」 | 次の周期で直る |
IaCが「望ましい状態を毎回まるごと書き、現実と突き合わせて差分を出す」形をとっているのも同じ理由による。命令の列を積み上げる形だと、一つ取りこぼした時点で以降の全部がずれる。宣言的であることの実務上の利得は、途中の取りこぼしから自力で回復できることにある。
peithoで面白いのは、この性質が理念としてではなく事故の修正として現れたことである。トグルを流して壊れ、絶対状態に直した。差分計算は命令選択であるが言うように差分エンジンは「望ましい状態」から命令を選び直す機械で、ここでのシェルも受け取った絶対状態から遷移を選び直している。命令を運ぶのではなく、状態を運んで命令はローカルで作る。