Читайте вместе с канареечными долями и skill-паками, поэтапным апгрейдом и peer deps, multi-AZ webhook шлюза и merge фрагментов workflow: там — математика балансировщика и semver-срезы; здесь — чтобы инвентаризация сервисов macOS не врала после копирования plist между AZ и merged readiness не «зеленела» на чужом PID.
Три боли, которые не поймать только doctor --json
- Дубликаты Label: два plist с одним
Labelи разными бинарниками —launchctlоставляет тот юнит, что загрузился первым; пробы остаются зелёными. - Пересечение портов: канарейка и stable слушают
127.0.0.1:9099; merged readiness после ручного копирования plist цепляет неверный PID. - Шум webhook: сырые логи скрывают короткий дайджест, который должен заморозить наращивание весов LB.
После merge шаблонов или клонов «золотого» образа запускайте openclaw doctor --deep --json и сравнивайте блок инвентаризации между AZ. Если путь отличается от эталонного узла, а поверхностный doctor зелёный — стоп: до widen канарейки вас отделяет один гоночный сценарий launchctl.
Матрица: поверхностный doctor и doctor --deep на узлах clustervps
Выберите глубину доказательств до правок launchd на арендованных Mac.
| Сигнал | doctor --json |
doctor --deep --json |
Заметка оператору |
|---|---|---|---|
| Скорость | Секунды; безопасно в tight loop. | Медленнее; обходит discovery из plist. | --deep после правок plist или AMI-клонов. |
| Дубликаты Label | Часто невидимы. | Показывает конфликтующие юниты. | Дифф deep JSON эталон vs канарейка до сдвига LB. |
| Канареечный гейт | Ежедневный смоук. | Обязателен после launchd. | Связка с merged-пробами из гайда по rolling upgrade. |
Храните shallow и deep JSON рядом с openclaw.lock и снимками весов LB: откат — это tarball плюс восстановление весов, а не расследование в чате. В таблице промоушена — одна строка на узел с именами файлов и id тикета.
Минимально воспроизводимый чек-лист (у каждого шага — откат)
Сначала один канареечный хост; рядом эталонный witness для диффа JSON.
- Заморозка: tarball LaunchAgents с OpenClaw и JSON весов LB. Откат: только восстановление tarball.
- База:
doctor --jsonиdoctor --deep --jsonв/tmp. Откат: прервать до правок plist. - Дедуп Label:
launchctl list,plutil -pпо каждому plist; один Label — один plist. Откат:bootoutтестового юнита,bootstrapархивного plist. - Срез порта: stable
9099, канарейка — высокий блок (напр.19199+) черезEnvironmentVariablesв plist; обновите фаервол хоста и заметки по security group региона. Откат: прежние ключи окружения,bootout/bootstrapстарого plist. - Перезагрузка и deep doctor: один цикл
bootout/bootstrap; deep JSON должен совпасть с эталоном по путям и портам. Откат: связка прежнего semver и plist. - Резюме по дайджесту: когда merged readiness и дайджест пересекают порог — POST однострочного резюме (см. tenant split и merge webhook). Откат: выключить notifier, вернуть окно дайджеста.
- Расширение: только если SHA256 пробы совпадает с пирами по гайду по канарейке. Откат: снимок LB из шага заморозки.
/usr/bin/find ~/Library/LaunchAgents /Library/LaunchAgents -name '*openclaw*' -maxdepth 1 -print /usr/local/bin/openclaw doctor --deep --json | /usr/bin/tee "/tmp/$(/bin/hostname -s).doctor.deep.json"
Канареечные срезы портов и stable-слушатели
Оставьте stable-шлюзы на loopback 9099, чтобы привычные curl-проверки не менялись. Админку, очередь и вспомогательный endpoint дайджеста для канарейки привяжите к задокументированному высокому блоку портов — тогда merged readiness и резюме webhook всегда цепляют PID канарейки, даже если при инциденте продублировали plist. Зафиксируйте срез в той же таблице, что и строки merge фрагментов, чтобы люди и автоматизация смотрели на одну матрицу.
hostname, AZ, счётчик классов ошибок дайджеста, merged SHA256 — не трогайте доли LB, пока deep JSON не совпадёт с эталоном.Сохраняем merged-пробы; после успешного deep doctor добавляем контекст дайджеста
Повторите паттерн хэша из гайда по rolling upgrade; curl направляйте на канареечный loopback-порт из вашего среза.
#!/usr/bin/env bash
set -euo pipefail
CANARY_PORT="${CANARY_PORT:-19199}"
/usr/local/bin/openclaw doctor --deep --json >/tmp/doctor.deep.json
/usr/bin/curl -fsS --max-time 3 "http://127.0.0.1:${CANARY_PORT}/v1/queue-snapshot" -o /tmp/queue.json
/usr/bin/curl -fsS --max-time 3 "http://127.0.0.1:${CANARY_PORT}/v1/webhook-digest" -o /tmp/digest.json
/usr/bin/python3 - <<'PY'
import hashlib, json, pathlib
parts = [pathlib.Path(p).read_bytes() for p in ("/tmp/doctor.deep.json","/tmp/queue.json","/tmp/digest.json")]
print(json.dumps({"ready_probe_sha256": hashlib.sha256(b"".join(parts)).hexdigest(),"canary_port": __import__("os").environ.get("CANARY_PORT","19199")}))
PY
Если SHA256 расходится, а счётчики дайджеста растут, сначала широковещание и заморозка долей — как в сценариях multi-AZ gateway webhook.
Лестница отката
- LB: обнулить вес канарейки.
- Plists: восстановить tarball;
bootout/bootstrap. - Бинарник: переустановить semver, проверенный на witness.
- Доказательство: shallow и deep doctor совпадают с эталоном до возврата долей.
FAQ
bootout или delete? bootout выгружает юнит; tarball plist оставьте для восстановления.
Пропустить --deep? Рискованно после любой ручной правки plist или клонированного образа.
Batch на хосте? См. Nomad, аффинити и build lock.
openclaw.lock.
Арендуйте Mac mini M4, чтобы безопасно репетировать doctor --deep
Тарифы и покупка на сайте доступны без обязательного входа в аккаунт; в помощи — SSH и доступ. Связанные материалы: канарейка, rolling upgrade, webhook шлюза.