つまずきの型
共有クローンにそのまま bundle install するとロックが汚れ、Webhook 戻し先のトークンがプロキシで欠落すると 401 が再現しにくいまま本番だけ失敗します。イベントごとに空に近い沙箱へ浅い git clone から入るのが再現性の鍵です。
判断表:直列・沙箱・戻し
| 観点 | 推奨 | 避ける |
|---|---|---|
| 直列 | check → outdated →(任意)lock --check | install だけで成功扱い |
| 沙箱 | ビルド ID ごとの TMP 配下 | 恒久ワークスペース共有 |
| 差分 | lock の git diff 冒頭を文字列化 | 巨大 diff をそのまま POST |
| 戻し | JSON+Bearer+指数バックオフ | 成功ログのみで失敗を隠す |
ミラー・並列・キャッシュ鍵の網羅は Bundler×Git 決定表 を参照してください。
ステップ 1:インストール・daemon・トークンとヘルス
Node 22.16 以上または 24 系を対話シェルと LaunchAgent の PATH で一致させ、公式ドキュメントに沿って CLI を入れて openclaw doctor を通します。Dashboard 用トークンはキーチェーン等に閉じ、外向き公開はリバースプロキシ+トンネルに限定します。daemon は LaunchAgent 健康診断 のパターンで curl -fsS http://127.0.0.1:<port>/health を定期取得し、落ちたら launchctl kickstart で再起動します。
ステップ 2:作業ディレクトリ沙箱
ハンドラ内でビルド ID またはコミット SHA ごとに専用ディレクトリを切り、毎回クリーンに近い状態から開始します。
umask と所有者を CI ユーザーに揃え、失敗時はこのツリーごと削除できるようにします。
ステップ 3:スキル雛形で bundle check/outdated を走らせる
まずロック整合を bundle check で確認し、続けて更新候補一覧を bundle outdated --parseable で取得します。厳格モードでは bundle lock --check を追加し、差分本文は git diff -- Gemfile.lock | head -c 4000 のように上限付きで文字列化して JSON に載せます。終了コードと標準エラー末尾はそのまま要約フィールドへ写します。
ステップ 4:失敗リトライとログ退避
ネットワーク揺らぎは 失敗リカバリ の考え方に合わせ、指数バックオフで最大三回まで再試行します。各試行の標準出力末尾を ~/Logs/oc-bundle/$(date +%Y%m%d-%H%M%S).log へ追記し、ディスク圧迫時は find … -mtime +7 -delete でローテーションします。
ステップ 5:汎用 HTTP Webhook へ JSON で要約回帰
status(success/failed)・elapsed_ms・bundler_exit・lock_diff_excerpt・outdated_lines を 1 つの JSON にまとめ、社内ゲートウェイやサーバーレス受口へ POST します。CircleCI/Jenkins 固有の署名がある場合は各記事の HMAC 節を流用し、本稿のペイロードは自前の Bearerで足りる想定です。
FAQ:切り分け短答
bundle check が常に失敗する
ロックと Gemfile の不整合、または企業プロキシ経由で gem メタデータが欠けるケースがあります。BUNDLE_MIRROR__HTTPS://RUBYGEMS__ORG/ 等を決定表どおり固定し、沙箱を毎回新規にします。
jq が無い
ハンドラ言語側で辞書を組み立てても構いません。重要なのは UTF-8 とペイロード上限、およびタイムアウト付き HTTP クライアントです。
Webhook は 204 だが CI が拾えない
受口側が本文を読まずステータスだけ見ている場合、本文キーを合わせるか、受口のサンプル JSON をこの雛形に合わせてください。