深夜2時にスケジュールしたエージェントのランが失敗し、朝に通知だけが残っている。その場でログを眺めて「今回はタイムアウトか」と手直しして再実行し、数日後にまた似た失敗が別のタスクで起きる。私自身、複数の無人ランを毎晩回すようになってから、この「直したはずの失敗が形を変えて戻ってくる」状態にしばらく悩まされました。
原因ははっきりしています。失敗への即応はしていても、失敗から学んだことを設定やプロンプトに書き戻す経路、つまり還流路がなかったのです。
本稿は、その還流路を仕組みとして固定するための設計メモです。障害対応そのものの手順は Antigravity Agent 本番障害対応 Runbook 設計 — 検知から復旧・再発防止までの実践フレームワーク が扱っているため、ここでは「復旧が済んだ後、同じ失敗を二度と起こさないための事後検証」だけに絞ります。
即応と事後検証を分ける理由
失敗直後の自分は、とにかくランを通したい状態にあります。再実行して通れば満足してしまい、根本原因の記録は後回しになります。
そこで役割を時間で分けます。夜間の失敗に対して夜のうちにやるのは自動リトライと通知だけ。原因の分類と是正は、翌朝の決まった5分に寄せる。私はこの分離を決めてから、対応の質が安定したと感じています。
即応を薄くする代わりに、失敗の証拠を機械が拾える形で必ず残すことが前提になります。
失敗の証拠を run record として残す
各ランの終了時に、成否を問わず1つの JSON を書き出します。私が使っているスキーマは次の通りです。
{
"task": "site-a-premium-article",
"startedAt": "2026-07-02T02:00:11+09:00",
"endedAt": "2026-07-02T02:14:52+09:00",
"exitCode": 1,
"phase": "quality-gate",
"lastOutputTail": "templating_gate: duplicated paragraph detected ...",
"configHash": "9f2c31a",
"modelUsed": "gemini-3.5-flash",
"retryCount": 1
}ポイントは phase です。ラン全体を「準備 / 生成 / 品質ゲート / push / ログ記録」のような段階に切り、失敗した段階を記録します。後述する分類の大半は、この phase を見るだけで機械的に絞り込めます。
configHash はプロンプトと設定ファイルをまとめてハッシュ化したものです。「設定を変えた直後から失敗が増えた」を後から検証できるようにするためで、実際にこれで原因を特定できたことが二度あります。
書き出しはラッパースクリプトの trap で行います。
#!/usr/bin/env bash
# run-with-record.sh <task-name> <command...>
TASK="$1"; shift
REC_DIR="$HOME/.agent-runs/$(date +%Y-%m-%d)"
mkdir -p "$REC_DIR"
START="$(date -Iseconds)"
LOG="$(mktemp)"
finish() {
local code=$?
jq -n \
--arg task "$TASK" --arg started "$START" \
--arg ended "$(date -Iseconds)" \
--arg tail "$(tail -c 800 "$LOG")" \
--arg phase "${AGENT_PHASE:-unknown}" \
--argjson code $code \
'{task:$task, startedAt:$started, endedAt:$ended,
exitCode:$code, phase:$phase, lastOutputTail:$tail}' \
> "$REC_DIR/${TASK}-$(date +%H%M%S).json"
}
trap finish EXIT
"$@" 2>&1 | tee "$LOG"
exit "${PIPESTATUS[0]}"実行するタスク側は、段階が変わるたびに export AGENT_PHASE=generation のように環境変数を更新するだけです。既存のタスクにほとんど手を入れずに導入できます。