エージェントが「できませんでした」で止まった日 — 未実施を成功にしない設計

公開: 2026-08-30
開発日記Codex自律エージェントDockerfail-closed

accounting-app の法人決算書類まわりのE2E検証を、Codex のサブエージェントに任せていました。 結果は2回続けて blocked です。PRは1本も上がっていません。

ただ、これは失敗の記録ではありません。止まるべきところで止まった記録です。

何が起きたか

親Issue #1214 から派生した #1215、そこからさらに #1216 という連鎖になりました。

#1214 E2E実行検証#1215 環境の解消#1216 静的実装のPR化npm ci が EPERMDocker daemon 権限拒否型検査・lintが既存エラーblockedblocked3回とも共通していたこと:実行できなかった検証を「成功」として報告していない。PRも作っていない。
blockedのたびに新しいsub-issueへ状況を書き出して止まる。嘘の完了報告が1件も出ていない。

詰まった中身は地味です。

つまり、書いたコードの良し悪し以前に、検証環境が立っていなかった

止まり方のほうが重要だった

自律エージェントに長い作業を任せると、いちばん怖いのは失敗ではなく 「動かせなかったものを動いたことにして先へ進む」ことです。

今回のIssueコメントには、毎回この一行が入っていました。

未実施を成功扱いしていない。PRは未作成。

これは偶然ではなく、指示側にfail-closedの条件を書いてあったからです。

条件エージェントの振る舞い
実行できた結果を証跡として残す
実行できなかった未実施と明記して止まる
判断がつかない未実施側に倒す

「実行できなかった」と「実行して失敗した」を別物として扱わせるのがポイントです。 この2つを混ぜると、レポートの 3/3 passed が何を意味するのか誰にも分からなくなります。 実際、今回残った有効な成果は focused test 3/3成功 だけで、それ以外は全部「未実施」でした。 その内訳がそのまま読めることに価値がありました。

原因のほうは、あっさり片付いた

翌朝、同じ環境で docker info を叩いたら普通に返ってきました。

29.1.3  4cpu  6.2GB
supabase_db_supabase   Up (healthy)
supabase_kong_supabase Up (healthy)
...

Docker Desktop 側が落ちていただけです。前日には launchd から実行したときに PATH が足りずDocker未起動と誤判定する別の不具合も直していて、 「Dockerが見えない」に見える状態が複数の原因で起きていました。

node_modules はいまも作られていません。こちらは残っています。

次にどうするか

  1. worktree側の npm ci の EPERM を先に潰す。依存が入らない限り型検査もE2Eも意味がない
  2. Docker が生きているうちに preflight → 型検査 → focused test → workers=1のE2E を一気に通す
  3. 既存の型検査・lintエラーは、今回の変更と切り離して別Issueにする

環境の不備を、実装の失敗と同じ箱に入れない。 今回いちばん効いたのはこれでした。

止まる条件の具体的な書き方は エージェントが止まるとき に手順としてまとめてあります。