---
name: mini_ext_disk_dropout_disksleep
description: "mac mini — внешний диск /Volumes/Ext полностью пропадал с USB-шины (не TCC-зависание); фикс pmset + детектор причины авто-рестарта + автоматика uhubctl (только для мягкого отвала, не для зависшего моста)"
metadata: 
  node_type: memory
  type: project
  originSessionId: b11e39bd-4f6f-47c9-ba7b-680ccf041a5b
---

**Инцидент 2026-07-12:** Механт-Postgres (`mehant_pg`) слал одинаковые `♻️ Auto-restart` в TG раз в ~5 минут часами. Корень — `/Volumes/Ext` пропал **целиком с USB-шины**: не в `diskutil list`, `system_profiler SPThunderboltDataType` → «No device connected». Юзер подтвердил: кабель физически не трогали (это НЕ [[mini_launchd_ext_tcc_fda]] — там процесс висит на `open()` при живом смонтированном диске; здесь диска на шине вообще нет).

**Диагностика:** `ioreg -p IOUSB` показал диск («Ugreen Storage Device») за **цепочкой из 3 каскадных USB-хабов**. `pmset -g custom`: `disksleep=10`, `powernap=1`. Гипотеза (без sudo по SSH не подтвердить ядерными логами наверняка): macOS усыпляет простаивающий внешний диск, дешёвый USB-мост за каскадом хабов не переживает пробуждение — отваливается с шины целиком, нужен физический реконнект.

**Фикс:** `sudo pmset -a disksleep 0; sudo pmset -a powernap 0` — сервер 24/7 с живыми БД, сон дисков не нужен вообще, только риск. Выполнено юзером.

**Восстановление после реконнекта:** `mehant_pg` (`com.cebers.gaechkin-pg`) и TecDoc MariaDB (`com.cebers.mariadb`, тоже на Ext) — `launchctl kickstart -k`; оба чисто восстановились (WAL redo / `Crash table recovery finished`), данные целы.

**Побочная находка:** `com.cebers.delor-sport` и `com.cebers.onec-build-agent` вообще не забутстрапены в launchd — не связано с этим инцидентом, не трогал.

**Улучшение алертинга (ops_dashboard `server.py`):** добавлен `detect_known_restart_cause(log_paths)` — сканирует хвост логов сервиса на известные сигнатуры (`_KNOWN_RESTART_CAUSES`), при совпадении дописывает причину в текст `♻️ Auto-restart`. Работающая сигнатура — `waiting for /Volumes/Ext` (пишет `start-postgres.sh` в цикле ожидания). **Грабля:** первая версия матчила `FATAL: внешний SSD не примонтирован` — эта строка **никогда не пишется в реальности**, т.к. цикл ожидания скрипта (10 мин) длиннее интервала авто-рестарта дашборда (cooldown 5 мин) — launchd убивает процесс раньше, чем тот доходит до FATAL. Сигнатуру проверял на реальном логе с реального инцидента, не на «что скрипт должен написать по логике». `mehant_pg.log_paths` в конфиге были пустые — заполнены. Детали: Obsidian `Projects/ops_dashboard/Decisions.md#D9`, `Changelog.md` 2026-07-12.

**Инцидент 2026-07-19 — автоматика uhubctl, найден жёсткий предел.** Диск отвалился снова, юзер переткнул физически и попросил: «сделай так, чтобы mini сам мог перетыкать». Разведка (без покупок): `uhubctl` встал через brew, хаб `GenesysLogic` на порту диска заявляет `ppps` (per-port power switching) — программный power-cycle именно этого порта в принципе возможен. Собран `~/Services/ops_dashboard/scripts/ext_disk_recover.sh`: детект пропажи тома → находит хаб/порт через парсинг `uhubctl` → чистый unmount+cycle → ждёт ремонт → kickstart зависимых launchd-агентов (mariadb, gaechkin-pg и др.). Вшит в `server.py` (`detect_ext_disk_drop`+`maybe_trigger_ext_disk_recovery`, fire-and-forget с `pgrep`-дедупом), TG-алерт для этой сигнатуры теперь говорит «пробую авто-восстановить», а не «переподключи физически».

**Тест 1 (контролируемый, --force, БД остановлены чисто):** диск вернулся за 20с, mariadb+gaechkin-pg подняты **без crash recovery** — полный успех.

**Тест 2 (диск отвалился САМ, спонтанно, во время тестирования):** нашёл и починил баг матчинга (порт в «половинчатом» состоянии `[0bda:9210]` без строки продукта — старая эвристика по строке "Ugreen" не находила его; фикс — матч по vendor:product ID). Но дальше cycle (3с), cycle с 30с разрядом и `uhubctl -a reset` **не смогли** вернуть диск — порт держит линк 5гбит (U0), но мост в боксе не отвечает на дескрипторы; `system_profiler`/`ioreg` начали зависать целиком (весь USB-стек встал, не один девайс). Юзер физически переткнул — диск вернулся, оба сервиса поднялись автоматически (crash recovery/WAL redo), данные целы.

**Вывод/предел:** `uhubctl` реально чинит **мягкий** отвал с шины (частый, основной сценарий, как 12 июля) — но НЕ чинит «зависший мост» в самом боксе: заявленный `ppps` на дешёвом хабе, похоже, не режет VBUS до конца на SuperSpeed-стороне; реальный физический реконнект дополнительно рвёт дифференциальные пары, чего софт-тумблер не делает. Единственный оставшийся программный рычаг для этого случая — сон/пробуждение mini целиком (реально снимает питание с портов), но это остановит ВСЕ сервисы mini на время сна — сознательно не сделано без отдельного явного запроса (blast radius не соразмерен). Умная розетка (реальное AC-питание) остаётся валидным следующим шагом, если «зависший мост» станет частым, а не разовым. Детали: Obsidian `Projects/ops_dashboard/Decisions.md#D11`, `Changelog.md` 2026-07-19.
