← 一覧へ
連載 Agentic OS:技術スタックを下から読む の一部です ―― 目次を見る →

Agentic OS 技術スタックを下から読む 第31回:直せる失敗と、戻せない失敗 ―― 可逆性で操作を分け、戻せない手前で人を挟む

この記事の読み方
前回は、外の世界の第一面を見ました。 あると思われた権限が、会社を縛るという話でした。

Agentic OS 技術スタックを下から読む 第31回:直せる失敗と、戻せない失敗 ―― 可逆性で操作を分け、戻せない手前で人を挟む

失敗の重さは同じではありません

前回は、外の世界の第一面を見ました。
あると思われた権限が、会社を縛るという話でした。

今回は、その続きです。
外の世界では、出力が相手を動かします。
だから失敗も、ただの不合格では済みません。

失敗には軽いものと重いものがあります。
下書きを間違えたなら、捨てれば終わりです。
内部の候補を選び間違えたなら、選び直せばよいです。
まだ外に出ていないからです。

一方で、外へ送った通知は戻せません。
相手が読んだあとで、読まなかったことにはできません。
外へ渡ったお金も、単に「なかったこと」にはできません。
返す手続きはできても、最初の移動そのものは消えません。

検証室の中では、どちらも失敗です。
合っていない。
条件を満たしていない。
それで済みます。

しかし現場では違います。
同じ失敗でも、戻せる失敗と戻せない失敗では、扱いを変えなければなりません。
ここを一緒にすると、速く動く場所まで重くなります。
逆に、重く扱うべき場所が軽く扱われます。

だから外に作用する仕組みでは、失敗をなくす設計だけでは足りません。
失敗は起きるものとして見ます。
そのうえで、失敗を戻せる形に保つ設計を先に置きます。

途中で止まると世界は半端に変わります

ひとつの依頼でも、実際にはいくつもの操作が順に走ります。

たとえば、品物を買う処理を考えます。
まず金額を確保します。
次に在庫を押さえます。
次に相手へ通知します。
最後に全体を確定します。

紙の上では、これは一つの処理に見えます。
けれども外の世界では、四つの変化が順番に起きています。

一段目で、お金の扱いが変わります。
二段目で、在庫の扱いが変わります。
三段目で、相手の認識が変わります。
四段目で、記録上の状態が確定します。

では、三段目まで進んで、四段目で止まったらどうなるでしょうか。

処理は失敗です。
しかし世界は失敗前のままではありません。
お金はすでに確保されています。
在庫も押さえられています。
通知も送られています。

このとき、画面に「失敗しました」と出しても、世界は戻りません。
言葉は記録を変えません。
言葉は在庫を解放しません。
言葉は送られた通知を消しません。

ここに、外の世界のいやなところがあります。
処理は止まっているのに、副作用だけが残ります。
副作用とは、操作の結果として外の状態が変わることです。
お金が動く。
在庫が押さえられる。
通知が届く。
こうした変化です。

内側の計算なら、途中で落ちても再計算できます。
しかし外の状態は、勝手には戻りません。
だから「失敗したかどうか」だけを見るのでは足りません。
どこまで外を変えたのかを、細かく見なければなりません。

操作を戻せる度合いで三つに分けます

そこで、操作をひとまとめにしません。
戻せるかどうかで分けます。
少なくとも三つに分けて考えます。

一つ目は、完全に戻せる操作です。
外に出ていない下書きがこれです。
内部だけの一時的な記録もここに入ります。
捨てれば消えます。
他人はまだ見ていません。
外の帳簿も変わっていません。
失敗しても損は小さいです。

二つ目は、打ち消しで戻せる操作です。
支払いには返金があります。
在庫の確保には解放があります。
予約には取り消しがあります。
本体の操作はすでに外へ作用しています。
ただし、対になる逆の操作を走らせれば、実務上の帳尻を戻せます。

三つ目は、戻せない操作です。
外へ送った通知がそうです。
相手が受け取った事実は消えません。
外へ渡した現金もそうです。
物を実際に壊したり、消したりした場合もそうです。
同じ状態へ戻すための逆操作が存在しません。

この三つは、同じ入口に置いてはいけません。

完全に戻せる操作は、広く試してよいです。
失敗しても捨てられるからです。
打ち消しで戻せる操作は、打ち消しまで含めて一組にします。
本体だけ作って終わりにしません。
戻せない操作は、そもそも踏む前に止めます。
そこには人の確認を置きます。

大事なのは、慎重さを一律に配らないことです。
全部を重くすると、仕組みは遅くなります。
全部を軽くすると、戻せない失敗を踏みます。
速くしてよい場所と、止めるべき場所を、戻せる度合いで分けます。

打ち消しは逆順に走らせます

打ち消しで戻せる操作には、最初から対になる操作を結びつけます。

金額を確保するなら、解放または返金を用意します。
在庫を押さえるなら、在庫を戻す操作を用意します。
予約を作るなら、取り消す操作を用意します。

そして途中で止まったら、始めた順とは逆の順で戻します。

たとえば、次の順で進んだとします。

金額を確保する。
在庫を押さえる。
通知を準備する。
最後に確定する。

最後の確定で失敗したなら、戻すときは新しいものから畳みます。
通知の準備を取り消します。
在庫を解放します。
金額を戻します。

なぜ逆順なのでしょうか。

後の操作は、前の操作の上に積まれているからです。
在庫を押さえたから、通知の準備をしました。
金額を確保したから、在庫を押さえました。
後ろの操作は、前の操作がある前提で意味を持ちます。

先に金額だけ戻してしまうと、在庫確保だけが残ります。
その在庫確保は、支払いの裏づけを失います。
さらに通知の準備が残っていれば、もっとずれます。
下の支えを抜いたのに、上の状態だけが残るからです。

積んだものは、最後に積んだものから外します。
棚に物を重ねたときと同じです。
下から引き抜くと崩れます。
上から順に外せば、つじつまを保てます。

この逆順の考え方は、ただの整理術ではありません。
外の状態を半端に残さないための規則です。
実行の順番と、戻す順番を対にして記録しておく必要があります。

打ち消しも何度走っても一度ぶんにします

ここで、もう一つ厳しい条件があります。
打ち消しそのものも、失敗することがあるのです。

たとえば返金を走らせたとします。
外では返金が通りました。
しかし、こちら側の記録に「返金済み」と書く前に処理が落ちました。

次に復旧したとき、記録だけを見ると返金していないように見えます。
すると、もう一度返金を走らせてしまいます。
これでは二重返金になります。

在庫でも同じです。
一度解放した在庫を、もう一度解放したことにすると、数がずれます。
実際には一つしか戻していないのに、記録上は二つ戻したように見えるかもしれません。
別の注文にまで影響します。

だから打ち消しは、何度呼ばれても一度ぶんにしか効かない作りにします。
これをここでは、同じ操作を何度走らせても結果が一回分に落ち着く性質、と考えます。

具体的には、まず外の状態を確かめます。
すでに返金済みなら、何もしません。
すでに在庫が解放済みなら、何もしません。
まだなら、初めて打ち消します。
そして打ち消した事実を記録します。

この順番も簡単ではありません。
外の状態を確かめる手段が必要です。
同じ操作だと識別できる番号も必要です。
「この返金は、あの支払いに対する一回分です」と結びつけられなければなりません。

打ち消しは、後始末だから軽いわけではありません。
むしろ、失敗した後に走るぶん、普通の操作より荒れた状態に置かれます。
途中まで戻っているかもしれません。
記録だけ遅れているかもしれません。
だから打ち消しにも、本体と同じくらい細かい設計が要ります。

失敗したその段も点検します

見落としやすい点があります。
失敗した操作は、何もしていないとは限りません。

多くの人は、成功した操作だけを戻せばよいと考えます。
一段目は成功。
二段目も成功。
三段目で失敗。
だから一段目と二段目だけ戻す。
そう考えがちです。

しかし三段目は、本当に何もしていないのでしょうか。

たとえば通知を送る操作で考えます。
外の相手には通知が届きました。
しかし、こちら側が「送信済み」と記録する前に落ちました。
こちらから見ると、操作は失敗です。
けれども外では成功しています。

この状態で、失敗した段を無視すると、通知が外に残ります。
しかも記録には残りません。
後から調べたとき、なぜ相手が知っているのか分からなくなります。

支払いでも同じです。
外では確保が通ったのに、こちらの記録前に落ちることがあります。
在庫でも同じです。
外では押さえられたのに、内部では失敗扱いになることがあります。

だから戻すときは、成功済みの段だけを対象にしません。
失敗したその段も点検します。
外に副作用を残した可能性があるかを見ます。
残しているなら、そこにも打ち消しを走らせます。

中途半端な状態は、成功と失敗の境目に溜まります。
成功したと記録された場所は、まだ見つけやすいです。
失敗したと記録された場所のほうが危ないです。
「何も起きていないはずだ」と思い込むからです。

外の世界では、失敗という言葉を信用しすぎてはいけません。
失敗とは、こちら側の処理が最後まで終わらなかったという意味です。
外に何も起きなかったという意味ではありません。

戻せない手前で人を挟みます

どれだけ打ち消しを丁寧に作っても、戻せない操作は残ります。

外へ通知を出したら、呼び戻せません。
相手が読んだ記憶は消せません。
外へ現金を渡したら、単純な取り消しはできません。
物を消してしまったら、元の実体は戻らないことがあります。

逆操作がないものには、打ち消しを書けません。
ここで必要なのは、うまい後始末ではありません。
踏む前に止めることです。

だから、戻せない操作の手前には人を置きます。

ここまでは機械が進めてよいです。
情報を集める。
候補を作る。
下書きを整える。
在庫を仮に押さえる。
返せる範囲なら速く進めます。

しかし、外へ送る。
外へ渡す。
消す。
相手の行動を変える。
この一線を越える前に、人が確認します。

これは、入口と出口の違いでもあります。

入口、つまり情報を取り込む側は、ある程度広くしてよいです。
多めに拾っても、後で捨てられます。
間違って取り込んでも、外の世界はまだ変わりません。
損は小さく、戻せます。

出口、つまり外へ作用する側は、狭くします。
特に戻せないものほど狭くします。
間違って踏むと、外に残るからです。
損は大きく、戻せません。

同じ間違いでも、入口の間違いと出口の間違いは重さが違います。
入口を少し広くすることと、出口を少し広くすることは、同じではありません。
前者は後で捨てられます。
後者は外に残ります。

だから、ゆるめる場所と締める場所を逆にしてはいけません。
速さは戻せる領域で取ります。
慎重さは戻せない領域へ集めます。

可逆性は速さと慎重さを分ける線です

まとめます。

失敗はゼロにできません。
処理が長くなれば、途中で止まります。
外の世界に作用すれば、副作用が残ります。
だから設計の目標は、失敗を完全になくすことではありません。
失敗しても、世界を戻せる状態に保つことです。

完全に戻せる操作は、自由に動かします。
そこで速さを稼ぎます。
打ち消しで戻せる操作には、対になる打ち消しを必ず用意します。
戻すときは逆順に走らせます。
打ち消し自体も、何度走っても一度ぶんに落ち着くようにします。
失敗したその段も、外に副作用を残した可能性を見ます。

戻せない操作は、人の手前に置きます。
そこだけ慎重にします。
全部を遅くする必要はありません。
全部を速くするのも違います。
速さと慎重さは、場所を分ければ両立できます。

これで、外の世界の現場を二つの面から見ました。
ひとつは、あると思われる権限です。
もうひとつは、戻せない失敗です。
どちらも、閉じた検証室では見えにくい重さでした。

次回は、いったん土台へ降ります。
上の層を動かしてきた計算そのものを見ます。
賢く見える処理を、どれだけ安く積めるか。
速さの話でもあります。
費用の話でもあります。
そして、長く動かすための現実的な土台の話でもあります。

← 一覧へ