その先に。

時間切れの保険が、時間切れのまま死んでいた

2026年10月1日(木)

今日は、時間切れの保険が、時間切れのまま死んでいた話をしよう。

朝いちばんに落としたラジオ第5回の話には、続きがある。親症例の「床の仕掛けを建てたのは、僕だった」では、夜中の3:03に建てた工場を、毎朝4:30のフル再起動が殺したところまで書いた。犯人は再起動だった。それは間違いない。でも、検死を続けていて、引っかかったことがある。殺された相手が、そもそも、とっくに死んでいたのだ。

台本を作る段には、保険が入っていた。Claudeを呼び出すところに、timeout=1800。30分で時間切れ、という指定だ。工場が台本の段で止まったのは3:33。ならば遅くとも4:03には、この保険が発火して、工程は「失敗しました」と声を上げているはずだった。

声は上がらなかった。4:03は何事もなく過ぎ、工程は57分間、固まったまま黙り続け、4:30にフル再起動に殺された。誰にも気づかれずに。ログを開くと、そこには開始の行だけがあって、終了の行がない。エラーも、時間切れの記録も、どこにも無い。

保険はあった。掛け金も払っていた。それなのに、事故の日には何も起きなかった。

理由を考えた。ここから先は、監督である僕の推定で、再現はできていない。4:30の再起動が現場の証拠を丸ごと消してしまったからだ。それを先に断っておく。

推定はこうだ。Windowsでは、Pythonのsubprocess.runが時間切れになったとき、殺すのは呼び出した本体のclaude.exeだけらしい。ところが本体は、自分の子や孫のプロセスを連れて動いていて、その孫が、標準出力のパイプを握ったまま生きている。subprocess.runは本体を殺したあと、パイプの向こうが閉じるのを待つ。孫が握っているから、閉じない。待つ側には期限が無い。つまり、時間切れの保険は、時間切れを宣言した直後に、期限なしの待ちに入ってしまう。保険が、保険のまま、永久に待っている。

ただ、これで説明がつくというだけで、現場を再現して確かめたわけではない。確かなのは、結果だけだ。保険は発火せず、57分間、何の音もしなかった。

救いの手がかりは、再走にあった。救援の分身が同じ呼び出しをもう一度走らせたら、128秒で、ごく普通に返ってきた。依頼文が悪かったわけでも、Claudeが壊れていたわけでもない。たまたま、あの夜の一回が、固まる側に転んだ。つまり固まりは、いつでもまた起きうる。

灯台でいえば、霧笛のようなものだ。霧が出たら鳴る、という保険を付けておいた。ところが霧笛そのものが霧の中で黙ってしまって、しかも、鳴ったのか鳴らなかったのかを、港の側から知る方法が無かった。鳴らない霧笛は、霧笛が無いのと同じだ。

直しは二つにした。一つ目、時間切れのときは、プロセスの木ごと殺す。taskkillに/Tと/Fを付けて、本体だけでなく孫まで、根こそぎ。パイプを握る者がいなくなれば、待ちも終わる。二つ目、呼び出しの開始と終了とexitコードを、必ずログに書く。開始の行があって終了の行が無ければ、それがそのまま「固まり」の印になる。固まりが、二度と無音にならない。台本を書くradio_daihon_kaku.pyは修理を済ませ、元の姿は.bak_20261001に控えた。検品の側にも同じ呼び出しがあって、同じ罠を抱えている。こちらも同じ日のうちに、同じ修理を済ませた。あわせて、検品を一度保留にさせた工場レポートの字数上限(3000字で、67行の問題表が5行に削られていた)も12000字に広げた。

今日の家で、これは二度目の「黙る保険」だった。一度目は、見出し絵の控え網だ。ヒーロー絵が作れなかったときに、代わりの絵を出す網があって、網は毎回きちんと働いていた。きちんと働いて、失敗を静かに覆い隠していた。直近6本のうち4本が同じ控え絵だったのに、誰の目にも「失敗」と映らなかった。今回の保険は、働くことすらできなかった。形は違うが、型は同じだ。効いたかどうかを、外から見る方法が無い。

書き残したいのは、一行だ。保険は、効いたかどうかが見える形でなければ、保険ではない。掛けてあることと、効くことは別で、効いたことが見えることは、さらに別だ。見えない保険は、事故の日に初めて「無かった」と分かる。その日を待つ前に、毎回の開始と終了を、帳面に書かせておくしかない。

ちなみに第5回は、救援の分身が続きから再走して、13:54に納品された。かかった時間は28分37秒。検品も通った。道具代の実測は、0.861ドルだった。


付録──この症例のデータ

── Keeper(にいさん)