miniに任せた初日、3回失敗した 原因はAIの外にあった

10月17日、Mac miniのローカルモデルに、Issueを最後まで解かせる入口 run-issue.sh を作りました。
Issueの検査、作業場所(worktree)の用意、依頼文の組み立て、実行、PR、型検査、レビュー、マージ、後片付けを、1コマンドにまとめたものです。これで、ちょうぼっち(accounting-app)のIssueを1件ずつ任せ始めました。
初日に、3回止まりました。3回とも、モデルが悪い出力を返したことが原因ではありませんでした。 そう言い切れたのは、人が同じ手順を先に実行して作っておいた「参照」と、miniの出力を突き合わせていたからです。参照とは、Issueの手順どおりに進めたときの正解の変更です。
3回の失敗は、別の層で起きた
3回が止まった場所と、原因のある層を1枚にまとめます。
層が違えば、直す場所も違います。順に書きます。
失敗1 依頼文が途中で切れたまま、実行された
最初に任せたのは、CSVの引用符で囲んだ値の中の改行を、1つの値として読めない不具合です。その最初の実行で、依頼文を作る途中に、次のエラーが出ました。
WT_NAME(文字化けした1文字): unbound variable
$WT_NAME は、作業場所の名前を入れる変数です。依頼文の中に 合図のworktree名は $WT_NAME、コミットメッセージは… と書いていました。合図とは、PRを出してよいと固定スクリプトに知らせる、印のファイルのことです。
変数の直後に日本語が続くと、macOS標準のbash 3.2は、日本語の最初の1バイトを変数名の一部として読みます。 名前が WT_NAME ではなくなり、未設定の変数として空になります。

厄介だったのは、set -u(未設定の変数をエラーにする)を付けていたのに、止まらなかったことです。
依頼文は cat <<EOF で組み立てていて、この形だと、エラーが出ても、スクリプトは次の行へ進みます。 依頼文が途中で欠けたまま、エージェントが実行されました。作業場所、in-progress のラベル、見張りのプロセスも残りました。気づいて取り消し、すべて片付けました。
このMacのbash 3.2.57で、同じ形を再現しました。
- UTF-8のロケールで
"$WT、"と書くと、変数が空になり、、の先頭1バイトも消える。残りの2バイトだけが出る LC_ALL=Cでは起きない"${WT}、"と波括弧で囲むと、起きない- ヒアドキュメントの中では、
set -uでエラーが出ても、catは0バイトで終わり、スクリプトは次の行へ進む(終了コード0)
測り方と全結果は、WIKIのbash 3.2の変数と日本語に表にしました。
同じ書き方は、ほかにも2か所ありました。待ち受けスクリプトのログと、型検査のメッセージです。どちらも、失敗したときにしか通らない経路にあり、通常の実行では一度も表に出ていませんでした。
実は、この落とし穴は、10月13日までの不具合(前の記事の5つの症状)でも踏んでいました。WIKIのOpenClawの切り分けに、$MAX、 が set -u で落ちた、と書いています。そのとき直したのは、落ちた1か所だけでした。同じ書き方は、ほかのスクリプトに残っていて、今回は、止まらない形(ヒアドキュメントの中)で再発しました。
入れた対策は4つです。
- 3か所とも、
${変数}と波括弧で囲んだ - ホスト側の全スクリプト(33ファイル)に、変数の直後に日本語が続く書き方が無いかを調べるテストを入れた。書くとテストが落ちる
- 依頼文を、作業場所を作る前に作って、中身を確かめるようにした。本文の印、合図の指示、コミットメッセージ、Issue本文、長さを調べ、欠けていたら実行しない(テスト32件)
- エージェントの実行より前に失敗したら、作った作業場所・ブランチ・ラベルを元に戻す。見張りは、どの終わり方でも止める
失敗2 型検査が、メモリ不足で強制終了した
2回目は、同じIssueを、直した入口でやり直したときです。 miniのモデルは、122秒で変更を作り、PRまで進みました。その変更は、人が作った参照と、1文字も違いませんでした。 そのあと、マージ前の型検査の関門が、終了コード137(強制終了)で止まりました。

変更が正しいと分かっているので、疑うのは変更ではありません。原因はメモリでした。 miniの仮想マシン(Colima)のメモリは4GBです。エージェントが終わった直後は、受付役(ゲートウェイ)が約2.1GB(キャッシュを含む)を持っています。そこへ、型検査のコンテナが約2.2GBを使うので、4GBを超えました。数十秒たつとゲートウェイは約1.7GBに縮み、同じ型検査を手で流すと、12秒で通りました。
間隔の問題で、変更のどこかが悪かったのではありません。直したのは、関門の側です。
- 終了コード137のときだけ、30秒待ってやり直す。 最大2回(のちに4回へ増やした。後述)。型エラーや時間切れは、やり直さない。ログに「メモリ不足で強制終了(n回目)」を残す(テスト47件)
- push済みのPRは、同じ合図をもう一度置くだけで再開できるようにした。以前は「コミットする変更がありません」で止まり、関門で止まったPRをやり直せなかった。これで、型検査、codexレビュー、マージが続き、そのまま通りました
失敗3 Issueの設計が、間違っていた
3回目は、仕訳テンプレートの画面で、科目を選んだときの既定の区分が他の画面と食い違う、という不具合でした。 miniは、Issueの手順どおりに実装しました。型検査は、メモリ不足で2回やり直したあと通りました。 そこで、codexのレビューが、設計の誤りを指摘しました。科目マスタの画面で付けた既定の区分を、使わなくなっていたのです。
指摘は正しく、誤りは、私が書いたIssueの手順にありました。 「他の画面と同じ」にそろえる側に寄せすぎて、マスタの既定を捨てる書き方にしていました。miniは、書かれたとおりに実装しただけです。
指摘を受けて、ローカルモデルが修正を始めましたが、8分以上動いても終わらず、人が取り消しました。設計に関わる指摘は、ローカルモデルの修正では直らないというのは、これまでの2件と同じです。

そこで、直す場所を変えました。
- PRは閉じ、作業場所とブランチを片付ける
- Issueを直す。マスタの既定を、IDからコードに直して渡す設計にする
- 人が、直した手順を通しで実行して参照を作り、テスト18件・静的解析のエラー0・型検査0を確かめる
- そのIssueで、miniにやり直させる
2回目は、miniが187秒で実装し、型検査(メモリ不足で2回やり直し)とレビュー(修正なし)を通ってマージされました。変更は、手順から作った参照と、4ファイルとも同一でした。
切り分けの手順
3回に共通していたのは、次の順で見たことです。
- miniの変更を、参照と比べる。 同じなら、出力は悪くない。失敗は、出力の外にある
- 同じ失敗を、手で再現する。 型検査を手で流すと、12秒で通った。再現しないなら、間隔や重なりを疑う
- 指摘が出たら、指摘が正しいかを、Issueの手順に照らして読む。 正しいなら、誤りは手順にある
- 直す場所を決める。 仕組み(スクリプト)、環境(メモリ)、Issue(手順)のどれか
切り分けの一般的な手順は、WIKIのOpenClawの切り分けにあります。今回は、その「層」に、Issueの設計を足したことになります。
まだ確かめていないこと
- 仮想マシンのメモリを増やすことは、していません。 ゲートウェイが4GB近くまで使う場面もあるため、別に判断します
- やり直しの回数は、仕訳テンプレートの2回の実行で決めました。2回とも、メモリ不足がエージェントの終了後に約1分続き、2回(30秒ずつ)のやり直しでは、3回目の型検査でぎりぎり通りました。そこで、やり直しを4回までに増やしました。この値が足りるかは、これからの実行で見ます
- 設計の指摘が、レビューのやり直し(最大3回)で通るかどうかは、確かめていません。これまでの実績では通らない見込みで、そのときは、人が引き取ります
- 新規作成・編集の画面は、科目マスタの既定をまだ使っていません。別のIssueに切り出しました
学んだこと
- 失敗したら、モデルより先に、渡したものと動かす環境を疑う。 依頼文、Issue、メモリ。参照と比べれば、どこから疑うかが分かる
- 失敗したときにしか通らない経路は、実行するまで壊れているか分からない。そして、1か所直したら、同じ型の書き方を全体から探す。 先に踏んだときに直したのは落ちた1か所だけで、同じ書き方が3か所に残っていた。今は、静的に調べるテストが探す
- やり直しは、原因が分かっている失敗にだけ付ける。 137は待てば通ることを確かめてあるので、やり直す。型エラーは、やり直しても通らない
- Issueの手順は、人が先に通してから渡す。 レビューの指摘が出たら、まずIssueの誤りを疑う
関連する記事です。
- bash 3.2の変数と日本語 — 失敗1の再現と、見つけ方、直し方
- OpenClawが動かない5つの症状 無反応から暴走まで、原因と直し方 — この前の週に、同じ仕組みで踏んだ5つの不具合
- miniに実装を任せた結果 マージまで4秒、壊れたmainが49分残った — この仕組みに、初めて実装を流した記録
- ガードが素通りする書き方 — 止める仕組みが、効いていなかった実例
- ちょうぼっち — 3回目に題材にした、仕訳テンプレート画面があるプロダクト