miniに実装を任せた結果 マージまで4秒、壊れたmainが49分残った

公開: 2026-10-04
AIエージェントOpenClawMac miniCodex自動マージ

決算書類のPDF2本を、Mac miniの常駐エージェントに任せた。仕様書を書いて渡し、実装から修正までminiの仕組みで回した結果をまとめる。

結果から書く。仕様書を入れてから1時間25分で、実装のPRが出た。そのPRは、型エラーとテスト失敗5件を持ったまま、作成から4秒でmainに入った。 直ったのは49分後。ただ、直ったあとのPDFを開いたら、欄の番号がすべて「☒」だった。

任せたもの

次の2本をminiに渡した。どちらも、仕様書を先にaccounting-app/docs/02_detail_design/へ置いてある。

Issue中身仕様書
#1801別表十四の値出力PDFと、画面のボタン、API25番
#1802勘定科目内訳明細書PDFを表形式にする26番

仕様書の末尾に、完了条件をコマンドで書いた。

miniの経路は、実装→合図のファイルを1枚置く→ホストの固定スクリプトがpush・PR作成・squashマージ、という形だ。鍵を渡さない作りは前に書いた。

その日の時系列

mainに型エラー 49分12:2613:1014:3515:1315:2515:3515:46Issue起票仕様書をマージPR #18154秒でmainへ型エラーを検知修正 #1816マージ#1817マージPDFを開いて「☒」を発見仕様書から1時間25分2026-10-03(JST)。時刻はGitHubのPR・Issueの作成・マージ時刻から換算
赤い帯が、mainに型エラーが残っていた時間。時間の目盛りは等間隔ではない。デプロイは手動のまま止めてあったので、この間にビルドは走っていない。

4秒でmainに入った

14時35分にPR #1815が出た。451行の追加、5ファイル、コミット1つ。PR本文には「マージは人が判断します。 内容を確認してください。」と書いてある。マージされたのは、その4秒後だった。

人が判断する前に入った理由は、ホスト側のスクリプトの作りにある。合図を検知すると、push・PR作成のあとにそのままgh pr merge --squashまで進む。止めるスイッチ(AUTO_MERGE=0)はあるが、既定は有効だ。

高い岸から、水門が全開の支流と、本流へ広がる濁りの筋を見下ろす浪人

支流(PR)の水門が開けっぱなしだと、濁りは、誰も見ないうちに本流(main)へ入る。ホスト側の検査が見ているのも、次の4つだけだった。

コードが動くか(tscとテスト)は、どこでも見ていない。 仕様書に完了条件を書いても、実行する役が誰もいなかった。

mainに入っていたもの

15時13分、mainでtscと指定テストを実行した。#1815の変更ファイル4つに型エラーがあり、テストは5件落ちた。

場所起きていたこと
PDF生成createDocWriter()は非同期で値を返すのに、待たずに使っている
PDF生成DocWriterに存在しないdrawTableを呼んでいる
APIrequireCapabilityに渡す引数の型が違う(NextRequestではなくRequest)
API存在しないプロパティ(capital・companyName)を読んでいる
APIUint8Arrayを、そのままNextResponseへ渡している
テスト存在しない入力項目(enterpriseTax)を渡している
テストviとbeforeEachをimportしていない

2行目のdrawTableは、仕様書に「#1802で追加する」と書いた関数だった。別のIssueで作る予定の関数を、#1801の実装が先に呼んでいた。 仕様書に書いてあった情報が、「この回では使うな」ではなく「あとでできる」としてだけ読まれたことになる。

next.configに型エラーを無視する設定は入れていないので、この状態でデプロイすればnext buildが落ちる。ただ、Vercelの自動デプロイは止めてあって、デプロイはこちらが明示的に起動する。mainは49分間壊れていたが、本番には何も出なかった。 守ってくれたのは、miniの検査ではなく、デプロイが手動だったことだ。

修正も、mini上で回った

直したのは15時25分の#1816(7ファイル、+464/−384)と、15時35分の#1817(#1802の実装、5ファイル、+289/−20)だ。どちらも同じ合図の仕組みを通って、PR作成から数秒でmainに入った。

ただし、直したのはminiのローカルLLM(qwen3-coder:30b)ではない。mini上でCodexが引き継いだ。 ローカルLLMのモデル自体は動いていて、短い応答は返る。一方、OpenClawからのエージェント要求は、会話の圧縮のあとで失敗した。原因は特定できていない。

つまり今回の「修正を任せた」は、正確には「修正を戻す回路(worktree→合図→PR)は使えた。ただし、戻した先は別のモデルだった」だった。

Codexの報告には、通したものと、通していないものが分けて書いてあった。

もう1つ、小さな手戻りがあった。最初の合図は、空のファイルだった。ウォッチャーは1行目をコミットメッセージとして読むので、空の合図は破棄される。1行目にコミットメッセージを書いて、置き直した。

テストは通ったが、PDFの欄番号は「☒」だった

行灯の下で、文字が欠けた巻物を指でなぞる浪人

Codexが「未実施」と書いた、PDFの目視をこちらでやった。別表十四を実際に出力して開くと、欄の番号(①〜⑥)が「☒」になっていた。

原因は、PDFに埋め込んでいるフォントに丸数字の字形がないことだった。無い文字を描くと、エラーも警告も出ず、「☒」になる。 tscも、vitestも、ESLintも通る。通ったのは、PDFの「見た目」を何も見ていない検査だったからだ。

PDFを作るソース33ファイルの文字列を、フォントの字形と照合した。

ファイル文字出力
別表十四のPDF①〜⑥欄の番号が「☒」(今回の出力)
請求書PDF※注記の印と凡例が「☒」(既存のコード)
貸借対照表PDF※警告の頭が「☒」(既存のコード)
手入力確認PDF 2本□チェックリストの印が「☒」(既存のコード)

最初の1個は今回のものだが、残りは前からあるコードだった。 miniに任せたことで見つかったのではなく、出力を開いたことで見つかった。置き換えと再発防止のテスト(pdfGlyphCoverage.test.ts)をPR #1818で入れた。仕組みと対処はWIKIにまとめた。

全体レビューで出た指摘は、どちらの側にもあった

翌日、#1800配下の全体レビューをした。確認できた指摘9件のうち、6件を#1821で直した。

区分件数例
miniの経路で作った別表十四のAPI(Codexの修正を含む)2件PDF生成の失敗でHTMLのエラーを返す。標準と異なる税率の登録のまま計算していた
同じ日にClaude Codeで書いた様式転記・概況説明書4件PDF画像の取り出しで処理時間が2乗で増える。認証より先に本文をメモリへ読む

任せたほうだけが穴だらけだった、という結果ではない。 任せなかった側にも、同じくらい出た。

違ったのは、マージの前に人の目が入ったかどうかだ。Claude Codeで書いた#1810〜#1814は、マージの前にCodexの静的レビューを通し、重大な指摘が3件出たので直してから入れた。miniの#1815は、そのレビューの前にmainへ入っていた。それでも、レビューを通した側に4件残った。レビューは穴を減らすが、ゼロにはしない。 だからこそ、通る関門は多いほうがいい。

結論: どこまで任せられたか

工程結果
仕様書つきの小さなIssueから、動く骨格のPRまで任せられた(1時間25分。値の組み立ては、修正後に昨年度の提出書類と一致)
失敗の差し戻しと修正のPR化任せられた(検知の12分後と22分後にmainへ。ただし戻し先はCodex)
「完了」の判定任せられなかった(完了条件を実行する役がいない)
マージ任せられなかった(4秒。人の判断の前に入った)
出力物の検品任せられなかった(通ったのに「☒」)

実装は任せられる。任せられないのは、「できた」を決める工程だ。

次の手(まだ実装していない)

次のIssueを任せる前に、次の3つを入れる。どれも未実装で、効くかは実測してから書く。

いまの経路合図のファイルpush・PR作成squashマージmain見る検査: mainへのpush・ブランチ名・秘密情報・変更の有無(コードが動くかは見ない)合図から数秒入れる検査(未実装)合図のファイルtsc・指定テスト・eslintを実行通過 → PR・マージ失敗 → PR作成で止め、報告
上がいまの経路。下が、次に入れる検査の設計。完了条件を実行する役を、通す側に置く。
  1. マージの前に、完了条件を実行する。 合図を受けたホスト側のスクリプトが、worktreeでtscと指定のテストを実行し、落ちたらPR作成で止める。仕様書に書いた条件を、書いた側ではなく、通す側が実行する
  2. 自動マージを切る。 9/24に直した導入手順を、mini側にまだ入れ直していない。10/4時点のウォッチャーの設定にはAUTO_MERGEが書かれておらず、既定の自動マージのままだ。止める手段は、止まるところまで通して確かめる
  3. 出力物は、人が開く工程を残す。 PDFは生成して目視する。見つかった「☒」は、再発防止のテストへ落とす

仕様書にも1行足す。「ほかのIssueで作る予定の関数は、この回では呼ばない」。 書いていなかったから、先取りされた。

手順と挙動はWIKIに置いた。

この経路が実装を任せる先は、ちょうぼっちを含むこのリポジトリのコードだ。前の記事はAIに鍵を渡さず、合図1枚でmainへ、同じ「できたと言われたら生成物を見る」の話はMCPのツールが見えていなかった日にある。