⌂ все дашборды/Инфраструктура и рутины← Waiting-Sessions · _Relink-AutoApplied →
Watchdog Door Audit

Аудит дверей сторожей — узел ZBOOKG8-2023PaloAlto

29.08.2026 · сид root5 (перезапуск сида 14.08; одобрение Антона «+» 14.08 01:46) · два вопроса к каждому сторожу: (1) пингует ли он ТУ ЖЕ дверь, что дёргает потребитель? (2) сторожит ли ВОЗРАСТ и СОДЕРЖИМОЕ выхода, а не порт, exit-код или факт запуска?
1сторож врал — найден и починен
31ложных «restarted» за 28–29.08
0тревог ушло наружу до починки
+0новых сторожей (правило «+1 = −1»)
3 / 5находок панели подтвердил, 2 отбил
3/15выходов протухли по output_freshness
СторожQ1 — та ли дверь?Q2 — что сторожит?ВердиктУлика
MCP Daemons Watchdog
mcp_daemons_watchdog_ZBOOKG8-2023PAL.cmd
БЫЛО: нет. Одна TCP-проба; дверь потребителя (реальный MCP-вызов) не трогаласьБЫЛО: факт запуска. Результат перезапуска не проверялся вообщеВРАЛ / починеноВРАЛ. Починено 29.08. ЗАМЕР: 31 строка «restarted» подряд за 28-29.08, порт 8765 не поднялся НИ РАЗУ, наружу ушло 0 тревог. Корень: шардирование 05.08 заморозило узел за день до общей починки 06.08. Настоящая причина смерти демона — мёртвая авторизация Telegram-сессии, её сторож не лечит в принципе. СТАЛО: две пробы + HTTP-проба + проверка перезапуска через 10с + счётчик подряд-неудач + эскалация в 03 после третьей. Break-тест пройден, эскалация доставлена (message_id 63137).
Claude Git Daemon Serve Watchdog
git_daemon_serve_watchdog.cmd
ДА. Делает настоящий git ls-remote — ту же операцию, что и потребительСодержимое ответа (readiness), а не занятость портачестныйЭТАЛОН. В шапке прямым текстом: «порт-only = false-green», поэтому пробует реальный fetch и убивает залипшего держателя порта. Класс «слушает, но не обслуживает» закрыт 29.06.
output_freshness
output_freshness.py (через housekeeping_daily)
ДА. Смотрит артефакт у ПОТРЕБИТЕЛЯ, а не факт запуска писателяВОЗРАСТ ВЫХОДА, ровно по §5.5честныйЭТАЛОН и сейчас честно КРАСНЫЙ: 3 из 15 выходов протухли (search-catalog-weekly — 20 суток; у fb-diary-writer и content-drain-writer нет stamp-файлов). Прибор работает; неразобранное красное — долг владельцев, не дефект сторожа.
TG Channels Check Hourly
tg_channels_check.py
ЧАСТИЧНО и ЧЕСТНО: Telethon-рельса пробуется настоящим вызовом; MCP скриптом непробиваем в принципе, и это написано в шапкеСвежесть FATAL в логе MCP (окно 48ч) + живой процессграница методаНе врёт: сам объявляет границу («настоящий вердикт MCP даёт только скилл /tg-check в сессии»). НО побочно от находки №1: mcp_errors.log не менялся с 14.08 при мёртвом демоне — «нет свежих фаталов» здесь значит «демон не доживает до ошибки», а не «всё хорошо». Дыру закрывает починенный сторож MCP.
Claude-Desktop-Watchdog
claude_desktop_watchdog.ps1
ДА (после починки 26.08)Возраст выхода + state-файл; есть тормоз MAX_REVIVES_6HчестныйКласс «сторож судит прокси, а не предмет» разобран 26.08 (Breakage-Journal), тест _test_desktop_watchdog_freshness.py 13/13 + два мутанта. Именно отсюда взят образец счётчика подряд-неудач, применённый теперь к MCP-сторожу.
watchdog_ping.py → n8n dead-man
n8n.palo-alto.ai/webhook/watchdog-hb
ДА, живая проверка внешнего приёмникаМолчание источника (dead-man switch)честныйПроверено живым запросом 29.08: HTTP 200. Гипотеза «эндпоинт умер и все пинги тонут молча» — не подтвердилась.
ack-watchdog
_shared/ack_watchdog.py (+ шим в scripts/)
ДА, после разбора 31.07Возраст неотвеченного ACKчестныйКласс «писатель и читатель на РАЗНЫХ файлах» закрыт шимом; ценой были 354 записи с nudged:0. Шим оставлен намеренно: удаление вернуло бы копию синком.
Session Wait Watchdog
session_wait_watchdog.py
ДА, читает сами транскрипты сессийВозраст последней активности + тип ожиданиячестныйЧестно объявляет свой false positive (долгий Bash неотличим от ожидания разрешения) и гасит его порогом 15 мин + капом в 3 пинга.
Quarantine-Watch
quarantine_watch.py
ДА, идёт через approval.py, а не в пустотуНовые held-пакетычестныйОстаточный корень «немой аск без id» закрыт 26.07: без id вопрос невидим для approval.py due/check.
Syncthing Watchdog Periodic
syncthing_watchdog.ps1
ДА, живой REST /rest/system/ping и /rest/system/connectionsЧисло реально подключённых пиров, а не факт процессачестныйСчитает connected-пиров через API — это предмет, а не прокси. Ровно то, чего не хватало в инциденте «стоял с 0 пиров 4 часа».
TG Heartbeat
tg_heartbeat.py
ДА, шлёт через ту же Telethon-рельсу, что и шинаСтатус двух каналов от tg_channels_checkграница методаТранспорт настоящий. Наследует ограничение строки выше: MCP-половина статуса — прокси. Это граница метода, а не дефект сторожа.
Прочие 20+ гардов узла
cron_watchdog, revert_guard, memory_guard, dupgen_guardian, proc_patrol, orphan_engines, browser_rail_watch, oauth_probe, robot_watchdog, session_approvals_doctor и др.
поштучно живым прогоном НЕ проверялосьпо тексту: у 19 из 23 есть работа с возрастом или выходомне доказаноЧестная граница аудита: это ТЕКСТОВЫЙ разбор — он ищет слова, а не понимает логику; та же оговорка, что в Watchdog-Symmetry-Audit 06.08. Зелёное по тексту слабее красного по замеру. Не-нулевые коды прошлых прогонов (Revert Guard=5, Fleet Manifest=1, Orphan Engines=1, Regress Grid=1, Token Audit=1) НЕ разбирались — кандидаты в следующий заход.

Что именно починено — по одному, с break-тестом

MCP Daemons Watchdog — класс «сторож лечит вслепую и рапортует успех»

Корень (доказан, не гипотеза): 05.08 файл сторожа отшардировали по хостам после клоббера синка. Общая починка сторожа приехала 06.08 — на день позже. Узел остался на старой слепой версии: одна TCP-проба → перезапуск → строка «restarted» → выход 0. Проверки «а поднялся ли демон» не было вообще.

Замер: 17 строк 28.08 плюс 14 строк 29.08, каждые 30 минут; порт 8765 не поднялся ни разу. Настоящая причина смерти демона — Telegram client 'default' is not authorized, мёртвая сессия. Такое сторож вылечить не может в принципе, а значит обязан был кричать, а не лечить.

Починка (правим дверь существующего, новых сущностей 0): обёртка узла теперь зовёт общий закалённый mcp_daemons_watchdog.ps1 от 06.08 — две пробы вместо одной, HTTP-проба поверх TCP (виден зомби «слушает, но не обслуживает»), перезапуск проверяется через 10 секунд. Добавлено сверху: счётчик подряд-неудач на диске (отдельный на порт) и эскалация в чат 03 после третьей подряд, не чаще раза в 12 часов. Образец счётчика взят у desktop-сторожа (MAX_REVIVES_6H), а не изобретён заново.

Break-тест — убил предмет, сторож обязан покраснеть: живой порт 8768 → молчит, exit 0. Мёртвый порт 9999 → вердикт с уликами. Три подряд неудачных оживления → эскалация ушла и доставлена в 03, message_id 63137. Выздоровление обнуляет счётчик (проверено: 7 → 0). Синтаксис ps1 чист.

Канарейка поймала дефект в самой починке: первый прогон боевой обёртки выплюнул мусор — cmd.exe читает .cmd в OEM-кодировке, и кириллица в комментариях превращалась в команды, которые он пытался выполнить. Переписано ASCII-only, код возврата внутреннего сторожа проброшен наружу. Повторный прогон чист: exit 1 при мёртвом 8765, тишина по 8768.

Сторонние глаза: панель вернула BLOCK — и это окупилось

Панель ломателей (3 из 3 headless-рельс ответили за 62с) нашла 5 дефектов. Проверил каждый по коду, а не на слово: два оказались неверны — «состояние пишется в System32» (все пути абсолютные через $env:USERPROFILE) и «сторож 8765 убьёт обёртку живого 8768» (mcp_wrapper_cleanup.ps1 фильтрует строго по *telegram_mcp_sse.cmd*).

Одна находка оказалась настоящей и попала ровно в тот класс, который я чинил: если демон ФЛАПАЕТ, живая проба обнуляет счётчик, но штамп «уже кричали» остаётся — и следующая, уже настоящая, смерть молчит до конца 12-часового окна. Сторож снова замолкает, только изящнее. Починено: выздоровление снимает И счётчик, И штамп, поэтому окно тишины живёт только на НЕПРЕРЫВНОЙ беде. Break-тест: счётчик 3 + штамп → демон ожил → 0 и штампа нет (PASS).

Две оставшиеся находки — латентные, не текущий отказ, записаны честно: (1) осиротевший дочерний процесс может удерживать сокет после убийства cmd-родителя (сейчас не наш случай: замер показал 0 процессов сервера и 0 слушателей порта); (2) теоретическая гонка двух копий задачи за файл счётчика — прогон ~25с против интервала 30 мин, и оба порта идут последовательно в одной обёртке.

Что НЕ починено и почему — говорю прямо

Сам Telegram-MCP на этом узле мёртв (мёртвая авторизация сессии). Это не дефект сторожа, а отдельная работа: нужен новый session string. Теперь об этом будет громко — починенный сторож доложит в 03 на третьем подряд провале, то есть в ближайшие полтора часа. До сегодня об этом не знал никто.

Красное у output_freshness не разбиралось: search-catalog-weekly протух 20 суток, у fb-diary-writer и content-drain-writer нет stamp-файлов. Прибор честен, долг за владельцами — вне рамок этого сида.

Не-нулевые коды прошлых прогонов (Revert Guard = 5, Fleet Manifest = 1, Orphan Engines = 1, Regress Grid = 1, Token Audit = 1) не разбирались. На Mac16 ровно такой exit 1 оказался легальным сигналом, а не поломкой, поэтому гадать не буду — это следующий заход.

Граница метода: поштучно живым прогоном проверены 11 сторожей. Остальные разобраны по тексту, а текст ищет слова, а не понимает логику. Зелёное по тексту слабее красного по замеру.

🧒 Простыми словами

У нас есть сторожа — маленькие программы, которые проверяют, живы ли другие программы. Я проверял не «работает ли сторож», а в ту ли дверь он стучит. Потому что сторож может бодро стучать в стену и всем докладывать, что дома всё хорошо.

Одного такого поймал. Он каждые полчаса «чинил» телеграмного помощника: выключал и включал заново и писал в тетрадку «починил». Тридцать один раз подряд за два дня. А помощник ни разу не включился — у него просроченный пропуск, и выключением-включением это не лечится вообще никак. Сторож этого не проверял: включил и ушёл, довольный собой.

Теперь он считает свои неудачи. Три раза подряд не вышло — кричит в общий чат: «я не справляюсь, нужен человек». Я это специально сломал и проверил, что крик доходит — дошёл. Новых сторожей не заводил: починил дверь у старого.

Ещё пригодилась канарейка — правило проверять на одной машине, прежде чем раздавать всем. Моя же починка с первого раза выдала мусор, потому что Windows не понял русские буквы в служебном файле. Переписал латиницей — стало чисто.