Webhook-дайджесты про доставку; канареечные доли и semver skill про то, какой путь кода в проде. На Mac clustervps: веса LB, деревья skill и одна merge-проба (Doctor, очередь, поле дайджеста).

Боли: дайджест зелёный при расколе версий; разные skills/current; нет строки аудита — нет отката. Ещё: webhook и multi-AZ, тенанты и Doctor, rsync-матрица, блог.

Матрица: широковещательный webhook против канареечного среза

Статья про webhook и шлюзы ставит нотификации в центр; здесь главный рычаг — доля трафика и версионный срез skill, а дайджест лишь сигнал внутри пробы. Так вы снижаете риск ложноположительного зелёного статуса при расколе версий между AZ.

Угол Главный рычаг Что даёт Риск
Webhook-first Дайджесты, overlap токенов Видимость ретраев. Не доказывает semver на диске.
Канарея Веса LB, шаги долей Малый blast-radius. Без снимка весов нет отката.
Срез skill /var/db/openclaw/skills/<semver> + lock Граница тень/прод. Расход skills.d ломает тенантов.
Merge проб Один /readyz: Doctor, очередь, дайджест Один JSON для LB. Пять URL скрывают частичный деград.

Многоузловая публикация OpenClaw до сдвига долей

Публикация — контракт шлюзов: openclaw.lock, фрагменты из гайда по тенантам, дерево skill по semver, маршрут merge-пробы. Цепочка: тень → зелёный Doctor/проба → вес LB → зеркало → аудит. Порядок: тег на writer, pull канареи, стабильные после гейта; воркеры не опережают шлюз. На трёх узлах clustervps сценарий честно воспроизводится без «одного ноутбука с правами sudo».

#!/usr/bin/env bash
set -euo pipefail
cd /usr/local/share/openclaw-infra
/usr/bin/git fetch --tags origin
/usr/bin/git checkout "refs/tags/${PROMOTE_TAG}"
/usr/bin/shasum -a 256 openclaw.lock | /usr/bin/tee /tmp/lock.sha
/usr/local/bin/openclaw version --json | /usr/bin/tee /tmp/version.json
/usr/bin/diff -q openclaw.lock <(ssh canary-gw "cat /usr/local/share/openclaw-infra/openclaw.lock")

Пустой diff разрешает трогать веса; непустой — стоп: вы на пороге раскола AZ.

Доли трафика: канареечные гейты на multi-AZ шлюзах

Старт ~5% сессий на шлюз с skills/next; держите ≥двух интервалов пробы; смотрите p95 и очередь вне шума webhook. Шаг 10–20% только при зелёном Doctor и приемлемом дайджесте.

Строка на шаг: время, веса, semver, тикет — компас отката.

Фрагменты конфигурации по тенантам и граница среза

Зеркалируйте /etc/openclaw/tenants/<t>/skills.d/ до смены next; фрагменты — границы инструментов и квот, секреты — в /var/db/openclaw/secrets/<t> с ACL.

# На каждом шлюзе после checkout тега
sudo install -d -o root -g wheel /etc/openclaw/tenants/acme/skills.d
sudo /usr/local/bin/openclaw config lint --tenant acme
sudo /bin/ln -sfn "/var/db/openclaw/skills/1.4.2" /var/db/openclaw/skills/next
sudo launchctl kickstart -k system/com.openclaw.gateway

Канареечный YAML на next, прод на current до аудита.

Объединение проб: Doctor, очереди, дайджест и semver skill

Один URL: semver на диске = lock, Doctor тенантов с трафиком, очередь в SLO; дайджест webhook — поле JSON, не главный рычаг промоушена (в отличие от broadcast-only).

#!/usr/bin/env bash
set -euo pipefail
TENANT_CANARY="${TENANT_CANARY:-acme}"
SKILL_PATH="/var/db/openclaw/skills/current"
/usr/bin/readlink "${SKILL_PATH}" | /usr/bin/tee /tmp/skill_path.txt
/usr/local/bin/openclaw doctor --tenant "${TENANT_CANARY}" --json >/tmp/doctor.json
/usr/bin/curl -fsS --max-time 3 "http://127.0.0.1:9099/v1/webhook-digest" -o /tmp/digest.json
/usr/bin/python3 - <<'PY'
import hashlib, json, pathlib
blob = pathlib.Path("/tmp/doctor.json").read_bytes() + pathlib.Path("/tmp/digest.json").read_bytes()
print(json.dumps({"probe_sha256": hashlib.sha256(blob).hexdigest(),"skill_resolved": pathlib.Path("/tmp/skill_path.txt").read_text().strip()}))
PY

degraded при жёлтом Doctor приемлемом semver; hard fail при расхождении с lock — не промоутить по webhook.

Откат: веса, symlink и launchd одним дыханием

Вместе: снимок весов LB + symlink current на старый semver; иначе раскол. Затем kickstart и сверка JSON с архивом аудита. См. rsync-матрицу под артефакты.

#!/usr/bin/env bash
set -euo pipefail
/usr/bin/scp stable-gw:/var/db/openclaw/audit/last_good_weights.json /tmp/weights.json
./lb_restore_weights.sh /tmp/weights.json
sudo /bin/ln -sfn "/var/db/openclaw/skills/${ROLLBACK_SEMVER}" /var/db/openclaw/skills/current
sudo launchctl kickstart -k system/com.openclaw.gateway
/usr/bin/curl -fsS http://127.0.0.1:8088/readyz | /usr/bin/jq .

Аудит: append-only JSONL для grep и комплаенса

На шаг доли — строка в promotions.jsonl: actor, ticket, from/to semver, веса, probe_sha256; реплика в объектное хранилище.

/usr/bin/printf '%s\n' \
  "{"ts":"$(date -u +%Y-%m-%dT%H:%M:%SZ)","actor":"${USER}","ticket":"${TICKET}","from":"1.4.1","to":"1.4.2","weights":"${WEIGHT_BLOB}","probe_sha256":"${PROBE_SHA}"}" \
  | /usr/bin/tee -a /var/db/openclaw/audit/promotions.jsonl

Ответы по jq, не по Slack.

Коротко

Дайджест — поле пробы, не единственный гейт. Один тенант — sticky на канареечный пул. Минимум три Mac: два стабильных AZ + канарея до зеркала.

Ориентир. Флаги и API LB — по вашему релизу и вендору; примеры — шаблоны.
Параллельный кластер

Шлюз на каждую AZ

Добавьте Mac mini M4 под канарею и merge-пробу: тарифы, справка SSH, покупка.

Добавить параллельный шлюз Mac Тарифы