0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ディレクトリを1つ移した日、無人運転パイプラインは「エラーを出さずに」止まった — 3週間で4回、同じ原因が形を変えて再発した記録

0
Posted at

ディレクトリを1つ移しただけで、無人運転のパイプラインが何のエラーも出さずに止まっていた——そんなことが自社では3週間で最低4回、形を変えて起きていた。今日この記事を書きながら実際に確認したところ、そのうち3件はすでに直っていたが、残り1件はいま現在も直っていないことが分かった。この記事は、その4件を実測ベースで並べ、読者が自分のcron/launchdジョブに同じ罠がないかを確認するための手順をまとめたものである。

起きたこと(結論)

自社ではブログ記事の生成・反応測定・取材依頼のやり取りをClaude Codeの無人運転(cron/launchd経由のheadless実行)で回している。2026年8月、部門ディレクトリの整理・移設を2回行った(8月中旬と8月下旬)。そのたびに、ディレクトリを跨いで参照している側のスクリプトが「移設に気づかないまま動き続け、エラーを出さずに沈黙する」という同じ壊れ方をした。

発生日症状の型気づくまで2026-09-05時点

2026-08-24完走判定が別ディレクトリを見ていた即日修正済み(実測)
2026-08-27依存先ディレクトリの参照が切れていた即日(応急対応)修正済み(実測)
2026-08-31(発覚)本体が失敗しても終了コード0で「成功」に見えた4日間(8/27発生相当〜8/31発覚・同日修正)修正済み(実測)
2026-09-05ドキュメントと実装の記載が食い違ったまま未検知(今回発見)未修正

パターンA: 終了コード0で死ぬ

何がズレたのか

部門ディレクトリの移設(8月下旬)を境に、反応測定処理が「移設前の(もう存在しない)パス」を複数箇所にハードコードで持ったままになっていた。実行するたびに例外を出して異常終了していたが、この処理をヒアドキュメント形式のPythonスクリプトとして書き、その出力をtailにパイプする形で手動実行していたため、シェルが最終的に返す終了コードは本体の失敗ではなくtailの終了コード(=0)になっていた。

# 起きていたことの型
python3 <<'PY'
...本体が例外を出して落ちる...
PY
| tail -n 20
# シェルが見るのは最後のコマンド(tail)の終了コードだけ
# → 本体が例外で落ちていても $? は 0 になる

なぜ検知できなかったのか

移設直後の8月27日ごろから反応データが1行も増えなくなっていたが、終了コードが0のため実行ログ上は「成功」にしか見えず、4日間気づかれなかった。8月31日、台帳の最終更新行の日付が古いまま止まっていることに気づいて発覚している。

修正内容

発覚した8月31日のうちに該当パスを4箇所修正し、142件を再取得して復旧した。パイプの終了コードは「最後のコマンドの終了コード」であって「パイプ全体が成功したか」ではない、という基本的な性質が、無人運転では"検知できない失敗"に直結する。読者が自分の環境で確認するなら、パイプでつないだ処理の異常終了を検知したい場合は、パイプ全体の失敗を拾う設定(各シェルにある同種のオプション)を使っているか、あるいは中間ファイルに書き出して件数を突き合わせているかを見直す価値がある。

パターンB: 完走判定が「空のディレクトリ」を見て成功と誤読する

何がズレたのか

2026-08-24の一次記録では、無人運転の完走判定ロジックが「特定のファイルが新しく作られたかどうか」で成功・失敗を見ていたが、その判定が見ているディレクトリと、実際に出力が書き込まれるディレクトリが、前日までの移設によって分岐していた。

なぜ検知できなかったのか

判定側は「ファイルが無い」と正しく検知したが、その原因は「処理が失敗した」のではなく「見る場所を間違えている」ことだった。判定ロジック自体はバグなく動いていたため、ログだけを見ると「未完了」という誤報にしか見えなかった。

修正内容

今日(2026-09-05)、このロジックの参照先を実装のソースでgrepして確認したところ、現在は実体のディレクトリと一致するよう修正済みであることを確認できた。この型の危うさは、判定ロジック自体は「正しく動いている」ことだ。バグはロジックの中ではなく、ロジックが見ている場所と実体が指す場所の間の「暗黙の一致」が崩れた瞬間に発生する。ファイルの有無で完走を判定する設計を採る場合、参照先のディレクトリをハードコードで持つのではなく、生成側と判定側が同じ変数・同じ設定から参照先を導出しているかを点検する必要がある。

パターンC: 一時しのぎの参照でつないだ後、気づかれない

何がズレたのか

2026-08-27の一次記録では、取材依頼を読み込む処理が参照していたディレクトリが、前日の移設で消えていた。

なぜ検知できなかったのか

参照が切れた結果、依頼ファイルが1件も検出されなくなっていたことで発覚した。その日はディレクトリへのシンボリックリンクを張って応急対応し、処理が依頼ファイルを認識できることをその場で確認している。

修正内容

今日、この参照が定義されている箇所を実装のソースでgrepして確認したところ、現在はリンク経由ではなく、実体のディレクトリを直接指すよう恒久修正されていることが分かった。応急リンクそのものは悪くない——動かなくなった無人運転を即座に復旧させる手段として妥当である。ただし応急リンクは「動く」を作るのであって「直った」の証拠にはならない。応急対応と恒久対応を別のタスクとして区別して残しておかないと、リンクが残ったまま何年も気づかれない、という別の負債になる。

パターンD: 今日、書きながら見つけた4件目

何がズレたのか

この記事の一次情報を集めている最中に、もう1つの同型の問題を見つけた。自社では機械的な作業(翻訳・要約・分類など)をローカルLLMのラッパースクリプト経由で実行しているが、そのラッパーが実際に呼び出しているバックエンドと、全プロジェクト共通のルール文書に書かれている「既定のバックエンド」が食い違っていた。ラッパー側のソースには「8月30日にポート8080から8083へ切り替えた」というコメントが残っているが、ルール文書側はいまも旧ポート(8080、フォールバックは11434)を既定として記載したままだった。

なぜ検知できなかったのか

ディレクトリ移設のような明確な「イベント」が無いため、これまでの3件のように障害として表面化しなかった。ドキュメントを読んで動かす側が、実装より遅れた前提のまま使い続けても、誰もエラーを出さない。

修正内容(未修正)

この記事を書いている時点(2026-09-05)で、ポート8083(新)・8080(旧)・11434(もう一つの旧バックエンド)のいずれも実際には応答しないことを、タイムアウト付きのヘルスチェックで確認した(3ポートともhttp_code=000)。11434番の旧バックエンドについては実行バイナリ自体・モデル保存先ディレクトリのいずれも存在しなかった。原因(手動でアンインストールしたのか、別の要因かなど)はこの記事の範囲では特定していない——単一の「無い」という観測から原因を断定しないためである。

この4件目は、これまでの3件と違って今日時点でも直っていない。実装が先に進み、ドキュメントが取り残される、という順序で起きるドリフトは、ディレクトリ移設のような「イベント」がなくても静かに進行する。

4パターンに共通する1つの原因

パターン何が正本か何が参照側かズレが発覚した経緯

A: 終了コード0本体処理の成否パイプ経由でシェルが見る終了コード4日間データが増えていないことに気づいた
B: 完走判定の誤読出力の実体ディレクトリ完走判定ロジックが見るディレクトリ「未完了」の誤報で気づいた
C: 参照切れ依存先ディレクトリの実体読み込み処理のディレクトリ参照依頼が1件も検出されないことに気づいた
D: ドキュメントドリフトラッパー実装の現状ルール文書の記載この記事を書く過程でgrepして気づいた

4件とも、根は同じ1つの構造——「何かが移動・変更されたとき、それを直接参照している側は追随するが、間接的に前提として置いている側(判定ロジック・ドキュメント・パイプの終了コード)は追随しない」——に行き着く。しかも4件とも、失敗時に人間へ知らせる仕組み(エラー出力・戻り値)のどこかが「正常」の顔をして通過してしまっていた。

読者が自分の環境で確認する方法

無人運転のジョブを持っているなら、次の4つを一度確認する価値がある。

# 1. パイプでつないだ処理の終了コードを、パイプ全体の失敗として扱っているか
#    (最後のコマンドの終了コードしか見ていない実装が無いか)

# 2. 「完走したか」を判定するロジックが見ているパスと、
#    実際に生成側が書き込んでいるパスが、同じ設定・同じ変数から来ているか

# 3. シンボリックリンクや一時しのぎの参照が、
#    「応急」のまま棚卸しされずに残っていないか

# 4. 実装のコメント・変更履歴と、
#    ドキュメントに書かれている「既定値」が、実際に一致しているか
grep -rn "既定" ドキュメント側の設定ファイル
grep -rn "既定\|BACKEND\|PORT" 実装側のラッパースクリプト

まとめ — 直った数と、まだ残っている数

4件のうち3件はすでに修正済みであることを、今日この記事のために再確認できた。修正の速さ自体は良い兆候である。ただし残り1件は今日時点でも直っておらず、しかも調べている最中に「バックエンド候補が3つとも応答しない」という、記録には無かった新しい事実まで見つかった。

「エラーが出ていない」は「正常に動いている」の証拠にはならない——これは今回の4件すべてに共通する、実測に基づく結論である。無人運転を長く回すつもりなら、正常に見える状態そのものを定期的に疑う仕組みが要る。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?