doctor --deep でサービス発見を掃き、重複を bootout してから カナリア用ポート帯と Webhook 失敗要約を同じ検証テーブルに載せると、再現ドリルが短くなります。
比率ゲートと切片の本編はカナリア・スキル切片・探針合算(マルチ AZ)、ワークフロー隔離はフラグメントマージとカナリア分流、テナント分割と合成プローブはテナント分割・doctor・Webhook 要約、網関配線はマルチ AZ 網関と Webhook。索引はブログ一覧。
本稿の位置づけ(カナリア稿との役割分担)
既稿は「LB 重み・semver ディレクトリ・合算 readiness」に軸足があります。本稿はその前段として、plist のコピペや退避用 LaunchAgent が残した重複 Label、ListenURL の衝突、環境変数の漂流を doctor --deep の JSON に落とし込み、ノード横断で突き合わせる手順です。掃除が終わって初めて、カナリア用のポート切片と失敗要約のドリルが意味を持ちます。
doctor --deep と重複 launchd Label
各 Mac で openclaw doctor --deep --json を取得し、同一 Label が複数 plist に現れていないか、ThrottleInterval や RunAtLoad の食い違いがないかを一覧化します。手早い機械チェックとして grep -R '<key>Label</key>' ~/Library/LaunchAgents /Library/LaunchAgents /Library/LaunchDaemons の値をソートし、重複キーを潰します。正規化の順序は非 canonical を bootout → 単一 plist を bootstrap。退避フォルダに置いた複製が再読込されないよう、拡張子を .disabled に寄せるかパスから外します。
#!/usr/bin/env bash
set -euo pipefail
TENANT="${TENANT:-demo}"
/usr/bin/openclaw doctor --tenant "${TENANT}" --deep --json >"/tmp/oc-deep-${TENANT}.json"
/usr/bin/plutil -lint /Library/LaunchDaemons/com.example.openclaw*.plist 2>/dev/null || true
/usr/bin/printf "deep written: /tmp/oc-deep-%s.json\n" "${TENANT}"
深い巡検のフラグ名は版で揺れ得るため、ヘルプの CLI 節と突き合わせてください。合成プローブに doctor サブチェックを載せる構成はテナント分割稿と同型です。
カナリアポート切片(LB 重みとは別軸)
テナントごとに 8820–8839 のような連番ブロックを予約表に書き、カナリア切片だけ OPENCLAW_GATEWAY_LISTEN や sidecar の --bind をその帯へ載せ替えます。LB が 5% でも、ローカルで別ポートのプロセス束が生きているとヘルス JSON だけが錯覚を起こすため、doctor --deep のポート行と lsof -nP -iTCP の突合を同じ runbook に印刷しておきます。台数と拠点は料金で先に合意すると予約表がブレません。
Webhook 失敗要約のブロードキャスト
通知器ノードが 5 分窓でイベントを畳み、テナント ID・相関 ID・代表 HTTP ステータスを 1 件に要約して送ります。launchd 掃除のあと意図的に 4xx を流し、重複排除が効いているか、degraded が長引くときに要約に理由コードが載るかを確認します。詳細トレースは JSONL、チャットは要約のみ、という二層にすると運用が持ちます。
最小再現ステップ(チェックリスト)
- 観測:全ノードで
doctor --deep --jsonを保存し、ホスト名付きで git かオブジェクトストアに集約。 - 重複検出:
Labelのソートuniq、ListenURLの衝突表を作る。 - 正規化:非 canonical を
launchctl bootout、単一 plist のみbootstrap。plist は事前にcpで退避。 - 合成ヘルス:
/healthz/compositeが緑になるまで待機し、合算 readiness と整合。 - ポート切片:カナリア帯へ環境変数を載せ替え、
curlでローカル疎通。 - Webhook ドリル:意図的 4xx→要約 1 件・相関 ID 記載を確認。
- 昇格:問題なければ LB 重みを戻すか全ノードへ展開(手順はローリング昇格稿参照)。
- 記録:runbook に deep JSON のパスと時刻を残す。
ロールバック(最短)
- LB/重み:直前のブックマーク比率へ戻す(カナリア稿の手順と同型)。
- ポート:予約表の旧値へ環境変数を戻し、プロセスを再起動。
- launchd:退避した plist を元パスへ戻し、誤って二重 bootstrap していないか
launchctl listで確認。 - 検証:
doctor --deepを再取得し、掃除前と差分が意図どおりか比較。 - 連絡:Webhook 要約チャネルに「巻き戻し完了」と相関 ID を 1 行で投稿。
FAQ(要点)
deep が遅い:メンテ窓・低トラフィック AZ から。タイムアウトは合成プローブで degraded に落とす。要約が二通:窓境界のズレを疑い、通知器の時計と NTP を揃える。