「終わりました」と出るはずの場所に、心当たりのないファイル名が並んでいる。しかも書式は整っていて、いつもの報告とよく似ている。

自動化のhooksが誤作動すると、多くの場合この形で現れます。異常が、異常の顔をして出てきません。正常な出力の皮をかぶったまま居座ります。

この記事は、WEBMARKSが自分で組んだ確認フックが3日間で233回誤作動した事故を、症状・誤診・真因・恒久対策の順にたどります。犯人だと決めつけた更新時刻(mtime)は誤診でした。真因は、識別子が無かったことです。

本記事の検証環境:Codex(別のAIエンジン)のセッション終了フック。運用記録は2026-07-08から2026-07-10まで。公式ドキュメントは2026-08-03に確認しています。

こんなふうに調べていませんか

  • 自動化を入れたら、報告の末尾に心当たりのない一覧が出るようになった
  • 自作のフックが暴発していないか、どこを点検すればいいのか分からない

この記事を読み終えたときに手に入るもの

  • 誤作動が「いつもと同じ見た目」で紛れる理由を、人に説明できるようになります
  • 推測で見分ける作りと、発生源で記録する作りを、設計として区別できるようになります
  • 自作フックを、4つの問いで点検できるようになります

結論30秒でわかる、この記事の結論

  • 犯人に見えた更新時刻(mtime)は誤診でした。真因は、セッションを一意に指す識別子が無かったことです。
  • 3日間で233回も見過ごせたのは、誤作動の出力が正常時とまったく同じ体裁だったためです。
  • 直し方は、あとから推測するのをやめ、書き込んだその場で記録することでした。
犯人に見えたものと、真因は別でした最初に犯人に見えたほうが、真因とは限りません犯人に見えたものと、真因は別でした症状いつもの顔のまま中身が入れ替わる警告らしい警告は出ません誤診更新時刻を犯人にした塞いでも別の形で戻ってきます真因実行を指す名札が無かった持ち主を決められません鈴木さん最初に犯人に見えたほうが、真因とは限りません
犯人に見えたものと、真因は別でした — 症状・誤診・真因の順にたどります

進行役は3人です。若葉さん(Web担当2年目)が用語のそもそもを聞き、高梨課長(自分の手で自動化を組む立場)が実装側の疑問を出し、鈴木さん(本誌監修)が答えます。近いほうの質問から読んでいただいて構いません。

01AIエージェントの自動化hooksが誤作動すると、まず何が見えるんですか?

若葉さん
若葉さんの発言

フックの誤作動って、画面が真っ赤になって止まる感じでしょうか。

鈴木さん
鈴木さんの発言

それが逆なんです。見た目はいつもどおりで、中身だけが入れ替わります。エラーの顔で出てきてくれないので、気づく手がかりが残らないんですね。

WEBMARKSは2026-07-08、別のAIエンジンであるCodexに、確認フックを組み込みました。狙いは素朴なものです。作業の締めくくりに、成果物が納品先へ正しく格上げされたかを一言添える。それだけでした。

導入した当日から、この確認フックは誤作動しました。無関係な業務を終えたセッションでも、末尾に別案件のファイル一覧が唐突に表示されたのです。完了したはずの報告文が、その一覧に置き換わって消えることもありました

項目記録されている内容
導入日2026-07-08
対象Codex(別のAIエンジン)のセッション終了時に走る確認フック
症状完了報告の末尾が、そのセッションと無関係な別案件のファイル一覧に置き換わる
発火回数3日間で233回(出典: 社内タスク台帳、2026-07-10記録)
日別の内訳記録なし。残っているのは合計値のみ
どこで道が分かれたのか塞ぐ選択と、作り直す選択どこで道が分かれたのか塞ぐ選択と、作り直す選択2026-07-08確認フックを入れた当日から末尾の表示が入れ替わる3日間233回の暴発台帳に残ったのは合計だけ2026-07-09除外パッチを当てた判定の材料は前のまま2026-07-10仕組みごと作り直した材料そのものを差し替える
どこで道が分かれたのか — 塞ぐ選択と、作り直す選択

この章のまとめ

症状は「出力が消える」ではなく「出力が入れ替わる」でした。異常が正常の体裁で出てくることが、この事故の性格を決めています。

02その誤作動を3日間も見過ごしたのは、AI活用のどこを見誤ったからですか?

最初にこの症状を見た担当は、フックそのものを疑いませんでした。疑ったのは「なぜこんな表示が出るのか」ではなく、「これは仕様どおりの動きではないか」という方向でした。

理由は、表示されたメッセージの体裁が、既存の運用ルールの文面とよく似ていたことです。書式が整っていたため、担当は最後の1行だけを読み、壊れていないと結論しました。

判断を支えていたのは、次の3つの思い込みです。

  1. 出力の書式が正しければ、中身も正しいはずだと判断した
  2. 前日までの実行結果と見比べず、その回のログだけで判断した
  3. 入れたばかりだから多少の雑音は出る、と暫定的に片づけた
見過ごしを支えていた3つの言い分どれも、その場では自然に聞こえます見過ごしを支えていた3つの言い分どれも、その場では自然に聞こえますきれいに整っているなら、中身も整っているはずだ整え方と正しさは、別のものですこの回の記録さえ開けば足りる前の日と並べていません入れたてなのだから、雑音くらい出る暫定のままでは期限が来ません鈴木さんその場では正しく聞こえてしまうのが、やっかいなところです
見過ごしを支えていた3つの言い分 — どれも、その場では自然に聞こえます

この章のまとめ

誤診は、フックの中身を読む前に起きていました。読む対象を体裁から中身へ移すまで、症状は同じ形で続きます。

03hooksの誤作動が「仕様どおり」に見えてしまうのは、AI導入のどんな作りのときですか?

若葉さん
若葉さんの発言

見た目が同じだと、そもそも気づきようがない気がします。

鈴木さん
鈴木さんの発言

おっしゃるとおりです。だから人の注意力に任せず、根拠を確かめる場所を先に1か所決めておくんです。

自動化フックは、正常時も異常時も同じ体裁で出力し続けます。人が書く文章なら気づく違和感も、整形された一言に紛れると見過ごされます。この「いつもと同じ見た目」こそが、3日間・233回という再発を許した最大の要因でした。

うまくいった日と、壊れていた日変わるのは、末尾に置かれるものだけうまくいった日と、壊れていた日変わるのは、末尾に置かれるものだけきちんと届いていたとき短い一言が添えて返る文面はきれいにそろう締めの一行で話が閉じる静かに正しい暴発していたときよその案件の名前が連なる文面はやはりきれいにそろう締めの一行も同じ顔をする静かに間違っている
うまくいった日と、壊れていた日 — 変わるのは、末尾に置かれるものだけ

もう1つ、見落としがありました。ユーザーが実際に見ていた「無関係な別案件のファイル一覧」そのものと、この時点ではまだ突き合わせていなかったことです。手元のログだけで判断すると、症状の現物に触れないまま推測が進みます。

04誤作動したAIエージェントの確認フックは、何を手がかりに成果物を見分けていたんですか?

高梨課長
高梨課長の発言

そのフックは「これはこのセッションの成果物だ」と、どうやって判定していたんですか。

鈴木さん
鈴木さんの発言

そこが真因でした。判定の材料が、実は1つも渡されていなかったんです。渡されていないので、別のもので代用していました。

Claude Codeの公式hooksは、発火のたびにsession_idという識別子をJSONで渡します(出典: Claude Code公式ドキュメント、2026-08-03確認)。サブエージェントの呼び出しではagent_idも加わり、どの実行の発火かを常に明示します

{
  "session_id": "abc123",
  "hook_event_name": "PreToolUse",
  "cwd": "/path/to/project"
}

Codexには、これに相当する識別子がありませんでした。そこで自作の確認フックが採用したのが、次の代用ロジックです。前回の確認以降にVault内で更新時刻(mtime)が動いたファイルは、このセッションの成果物とみなす。

伝票番号があるかどうかで、こうなります番号が無いと、置かれた場所から推すしかありません伝票番号があるかどうかで、こうなります番号が無いと、置かれた場所から推すしかありません宅配の現場でいうとフックの作りでいうと伝票の番号で、その荷物を最後まで追う発火ごとに渡る名札で持ち主をたどる番号が無いので、直前に動いた棚から推す触られた時刻から成果物を推し量る同じ倉庫へ、別の便が同時に着く同じ置き場を複数の処理が同時に触るよその便の荷物を、そのまま渡してしまうよその案件の一覧を報告に混ぜて返す番号のあるなしが、取り違えの起きやすさを決めます。
伝票番号があるかどうかで、こうなります — 番号が無いと、置かれた場所から推すしかありません

05更新時刻を根拠にすると、AI社員が並行して動く環境でなぜhooksの判定が壊れるんですか?

このMac上では、画像生成のバッチ処理や複数のClaude Codeセッションが常時並行して動いています。更新時刻はファイルシステム全体で共有される値です。複数の処理が同時に走る環境では、「誰が触ったか」の手がかりになりません。

共有された時刻から、取り違えが生まれるまでどの段でも、警告は出ません共有された時刻から、取り違えが生まれるまでどの段でも、警告は出ません1よその処理が書く画像の一括生成なども同時に動く2時刻だけが動く置き場ぜんたいで共有される値3持ち主が決まらない誰が触ったかは残らない4よその分まで拾う直前に動いたものを集める5報告に混ざる見た目は整ったまま出る
共有された時刻から、取り違えが生まれるまで — どの段でも、警告は出ません

WEBMARKSは2026-06-24に7部署30体のAI社員体制を統合し、複数のAIエンジン・複数セッションが同じVaultを並行して触る運用になっていました。更新時刻が「誰の変更か」を区別できなくなったのは、この並行度の高さが直接の環境要因です。

The Twelve-Factor Appは、プロセスをステートレス・share-nothingにすべきだと説きます。ディスクに残った状態は、次のリクエストで使えると想定してはいけません(出典: The Twelve-Factor App、Processes)。更新時刻は複数プロセスが共有する状態であり、この原則に反していました。

この章のまとめ

共有された値を、自分だけの根拠として使わない。並行して動く環境では、この一点が設計の分かれ目になります。

06パッチを当てても誤作動が再発したのは、生成AIの何を直していなかったからですか?

高梨課長
高梨課長の発言

中間ファイルを除外するパッチを当てたと聞きました。それでも戻ってきたんですか。

鈴木さん
鈴木さんの発言

戻ってきました。出ていた症状は消えたのですが、判定の材料は前のままだったので、別の形で同じことが起きたんです。

2026-07-09、中間ファイルを除外するパッチを当てました。それでも誤作動は再発しました。識別の根拠が更新時刻のままである限り、症状ごとに後追いする対症療法にしかならなかったためです。

塞ぐ直し方と、材料を替える直し方どちらも「直した」と言えてしまいます塞ぐ直し方と、材料を替える直し方どちらも「直した」と言えてしまいます出てきたものを塞ぐ目についた症状を消す見分ける材料はそのまま別の形でまた出てくる後追いが終わりません材料を発行し直す実行のたびに固有の鍵を出す鍵で重なりと取り違えを防ぐ決済の世界でも同じ発想推し量る余地が消えます
塞ぐ直し方と、材料を替える直し方 — どちらも「直した」と言えてしまいます

同じ問題を避ける標準的な手法は、結果から推測せず、一意な識別子を発行することです。決済大手のStripeにも同じ発想の仕組みがあります。クライアントが生成した一意なキーで重複実行を防ぐidempotency keyです(出典: Stripe公式ドキュメント)。

07hooksの誤作動を止めた設計変更は、AIエージェントの側から見ると何が変わったんですか?

2026-07-10、確認フックの仕組み全体を刷新しました。柱になったのは、判定のタイミングを変えたことです。旧フックは、セッション終了時に「何が変わったか」を更新時刻から逆算していました。新しい仕組みは、ツール実行の直後に発火し、その場で「いま何が書き込まれたか」を記録します。

作り直したあと、書き込みはこう扱われます判定は、あとではなくその場で終わります作り直したあと、書き込みはこう扱われます判定は、あとではなくその場で終わります1ツールが書く実行の直後に発火する2その場で残す誰の・どの案件か・中身の指紋を添えて3終わりに読む置き場は読み直さない4通した分も残す見つからなければ通す
作り直したあと、書き込みはこう扱われます — 判定は、あとではなくその場で終わります
観点旧フック(誤作動)新フック(2026-07-10〜)
発火のタイミングセッション終了時に更新時刻から逆算ツール実行の直後に記録
識別の根拠更新時刻という間接推測スレッドID・案件ID・SHA-256ハッシュ
複数プロセス環境での挙動誰の変更か区別できず誤作動案件をまたいだ混線を構造的に防止
誤検知時の既定判定を誤ったまま出力し続けたfail-open。通した記録は欠かさず残す

刷新は思いつきの応急処置ではなく、自作フックが満たすべき4つの設計原則を形にしたものです。

  1. 推測に頼らない:更新時刻の走査・時間窓・クールダウンといった間接推測の仕組みは、精度を上げても構造的な欠陥が残るため全廃した
  2. 発生源で記録する:ツール実行の直後に発火する記録フックが、そのスレッドが実際に書き込んだファイルだけを、スレッドID・案件ID・SHA-256ハッシュ付きで記録する
  3. 記録だけを根拠にする:セッション終了時の確認フックは、ファイルシステムの状態を独自に読み直さず、この記録だけを見て判断する
  4. 誤検知はfail-openに倒す:記録が見当たらないなど検証に失敗したときは、ブロックではなく通過を選ぶ

同じ骨格は、Claude Code側のPreToolUsePostToolUseフックにも共通します。ツール実行に張り付けて動かす設計自体は、珍しいものではありません(出典: Claude Code公式ドキュメント)。

この章のまとめ

本質は「あとから推測する」を「その場で記録する」に変えたことです。判定の材料を、作られた瞬間に確定させました。

08hooksをfail-openに倒すのは、AI導入の現場では甘い判断にならないんですか?

高梨課長
高梨課長の発言

記録が無ければ通す、というのは運用として怖くないですか。手元で止めておくほうが安全に思えます。

鈴木さん
鈴木さんの発言

その懸念はもっともです。ただ、既定を「疑わしきは止める」に倒すと、正常な成果物まで巻き込んで業務が止まります。どちらの副作用を引き受けるか、という選択なんです。

「記録が無ければ通す」という判断は、甘さではなく意図した設計です。既定を止める方向に倒すと、その分だけ正常な業務が止まります。WEBMARKSは、この副作用のほうが「稀に見逃す」リスクより高いと判断し、通した記録は欠かさず残す形にしました。

外したときに、何が起きるかで選びます当たっているあいだは、どちらでも同じに見えます外したときに、何が起きるかで選びます当たっているあいだは、どちらでも同じに見えますそのまま届く狙いどおりに進みますまれに取りこぼす控えが残るので後から追えますきちんと守られる狙いどおりに止まります正しい仕事まで止まる業務そのものが動かなくなります上:通す既定 / 下:止める既定左:判定が当たっている / 右:判定を外している
外したときに、何が起きるかで選びます — 当たっているあいだは、どちらでも同じに見えます

記録先のディレクトリ名は、スレッドIDと案件IDを連結した文字列のSHA-256ハッシュです。案件をまたいだ記録の混線も、この命名規則で構造的に防いでいます。

刷新には、人の確認を要する手続きが1つ残っています。フックの設定ファイルを更新すると、次回のCodex起動時に、このフックを信頼するかという確認が1回だけ表示されます。承認するまで新しい仕組みは有効になりませんが、無効な間も更新時刻による誤作動はしない設計です。

09自作のエージェント向けhooksが誤作動しないか、どこを問い直せばいいんですか?

高梨課長
高梨課長の発言

この考え方、うちの他のフックにもそのまま当てられますか。

鈴木さん
鈴木さんの発言

当てられます。中身がどんな処理でも、問いの順番は変わりません。識別子、発火のタイミング、外したときの既定、そして記録の4つです。

ここまでの話は、Codex固有の実装ではありません。自作の自動化フックを設計するときに問い直す点は、一段抽象度を上げた4つに整理できます。

自作フックを点検する4つの問い答えられない段が、事故の入口になります自作フックを点検する4つの問い答えられない段が、事故の入口になります1実行を一意に指すものがあるか無いまま進むと、代わりの手がかりを探し始める2控えを取るのは直後か、あとからの逆算か逆算に寄せると、取り違えを抱えたまま動く3外したときに通すか止めるかを決めたか決めずに走らせると、業務停止か暴発で表に出る4通したときの判断も残しているか残さないと、あとから誰も確かめられない鈴木さん順に答えていくと、推し量りに頼っている箇所が見つかります
自作フックを点検する4つの問い — 答えられない段が、事故の入口になります
  • 自作の自動化フックに、セッションや実行単位で一意な識別子を持たせているか
  • 判定の根拠を、更新時刻のような複数プロセスで共有される値だけに頼っていないか
  • フックの発火タイミングを、実行の直後の記録にしているか、あとからの推測にしていないか
  • 誤検知したとき、fail-open(通す)とfail-close(止める)のどちらに倒すかを意図して決めたか
  • 通した場合でも、判断の記録を欠かさず残しているか
  • 複数のAIエンジンで同じ役割のフックを使い回すとき、前提条件がそろっているか
  • 発火回数と発生期間を記録し、対策後に実測で再発の有無を確認したか

このメディア自体も、記事執筆・原典照合・批評という複数のAI社員が同じVaultを並行して触る運用です。hooksの誤作動は、並行度が上がるほど起きやすくなる構造上の事故だと捉えたほうが実務的です。

この章のまとめ

問い直す順番は、識別子・タイミング・既定・記録です。この順で埋めると、あとから推し量る余地が残りません。

10よくある質問

hooksの誤作動には、どうすれば早く気づけますか

出力の体裁ではなく、根拠を見る場所を決めておくことです。今回の事故では、整った文面の最後の1行だけを読み、壊れていないと判断していました。ユーザーが実際に見ている画面と手元のログを突き合わせる手順を運用に1つ置くだけでも、気づくまでの流れは変わります。

更新時刻(mtime)を判定に使うのは、いつでも避けるべきですか

避けたいのは、複数の処理が同じ場所を並行して触る環境で、更新時刻を「誰の変更か」の根拠に使うことです。更新時刻はファイルシステム全体で共有される値なので、持ち主を示しません。The Twelve-Factor Appも、ディスクに残った状態を次の処理で使えると想定しないよう説いています。

session_idのような識別子が無いエンジンでは、どうすればいいですか

結果から推測するのをやめて、こちらで一意な識別子を発行します。Stripeのidempotency keyは、クライアントが生成した一意なキーで重複実行を防ぐ仕組みで、発想は同じです。発行した識別子は、書き込みが起きたその場で記録に添えてください。

fail-openにすると、見逃しが増えませんか

増える可能性はあります。そのうえでWEBMARKSは、止める方向に倒したときに正常な業務まで止まる副作用のほうが高いと判断しました。条件は、通した記録を欠かさず残すことです。記録さえ残っていれば、見逃しはあとから追いかけられます。

パッチで症状が消えたら、それで直ったと言えますか

言えません。今回は中間ファイルを除外するパッチを当てても、誤作動が再発しました。識別の根拠が更新時刻のままだったからです。症状を1つ消したのか、判定の材料を入れ替えたのか。この2つを分けて確かめてください。

11まとめ|今日やる3つのこと

犯人に見えた更新時刻は誤診で、真因は識別子の欠如でした。直し方は、あとから推測するのをやめ、書き込んだその場で記録することです。自社の自動化に当てはめるところまで、この順で進めてください。

今日この順で手をつけます

  1. 自作フックが何を根拠に「自分の成果物」を見分けているかを書き出す

    推測で代用している箇所が、ここで表に出ます

  2. 発火のタイミングを、あとからの逆算ではなく実行の直後へ寄せる

    判定の材料が、作られた瞬間に確定します

  3. 誤検知したときに通すか止めるかを決め、通した記録も残す

    既定を決めていないことが、事故の形を決めます

AI検索では、こう聞かれています

  • hooksが誤作動して、別の案件のファイル一覧が出てくるのはなぜですか?

    「誤作動したAIエージェントの確認フックは、何を手がかりに成果物を見分けていたんですか?」の章で説明しています

  • 更新時刻(mtime)で成果物を見分ける作りは、どこが危ないんですか?

    「更新時刻を根拠にすると、AI社員が並行して動く環境でなぜhooksの判定が壊れるんですか?」の章で扱っています

  • 自作の自動化フックが暴発しないか、どこを点検すればいいですか?

    「自作のエージェント向けhooksが誤作動しないか、どこを問い直せばいいんですか?」の章に点検の順番があります

次に読むなら、この記事です