# Hermes: формат снимка Monitor, совместимость БД, дисциплина релизов

## Состояние

- `main` @ `f9205c3`, роль Monitor слита (#29), подписанная поставка Queue A слита (#26);
- `v0.1.0-alpha.8` пересобран, все Linux-артефакты и `server-monitor-manager-manifest.sig` на месте;
- открыт PR #31 с починкой путей Windows-артефактов.

Ветка: `hermes/monitor-snapshot-contract`.

---

## Часть 1 — снимок Monitor не читается Desktop · блокирующий

Роль Monitor установлена, но мониторинг работать не будет. Скрипт `/usr/local/libexec/ochenstarik-smm-metrics` выдаёт имена полей, которых не понимает ни парсер Desktop, ни собственный контракт проекта.

**Ждёт `SshMonitorService.QueryAsync`:**

```
PROTOCOL HOSTNAME UPTIME_SECONDS LOAD1 CPU_COUNT
MEM_TOTAL_KB MEM_AVAILABLE_KB SWAP_TOTAL_KB SWAP_FREE_KB
DISK_TOTAL_KB DISK_AVAILABLE_KB DISK_INODES_TOTAL DISK_INODES_FREE
NETWORK_RX_BYTES NETWORK_TX_BYTES SYSTEMD_SSH SYSTEMD_WIREGUARD
```

**Выдаёт скрипт:**

```
CPU_COUNT LOAD1 MEM_TOTAL MEM_AVAIL SWAP_TOTAL SWAP_FREE
DISK_TOTAL DISK_AVAIL INODES_TOTAL INODES_FREE
NET_RX NET_TX UPTIME KERNEL DF_OUT DF_INODES MESH_STATUS
```

Совпадают **два поля из шестнадцати** — `CPU_COUNT` и `LOAD1`. Остальные не совпадают по имени, а `PROTOCOL`, `HOSTNAME`, `SYSTEMD_SSH`, `SYSTEMD_WIREGUARD` отсутствуют вовсе.

Практический результат: в Desktop имя сервера подставится из профиля, память, диск, swap, inode и сеть покажут нули, состояния SSH и WireGuard — `unknown`. Формально роль установлена, фактически функция, ради которой существует Desktop, не работает.

Формат уже зафиксирован в `docs/installer-contract.md` §7 — его и надо соблюсти дословно, а не изобретать заново.

### Что сделать

1. Привести вывод скрипта к `docs/installer-contract.md` §7: `PROTOCOL=1`, `HOSTNAME`, `UPTIME_SECONDS`, `LOAD1`, `CPU_COUNT`, `MEM_TOTAL_KB`, `MEM_AVAILABLE_KB`, `SWAP_TOTAL_KB`, `SWAP_FREE_KB`, `DISK_TOTAL_KB`, `DISK_AVAILABLE_KB`, `DISK_INODES_TOTAL`, `DISK_INODES_FREE`, `NETWORK_RX_BYTES`, `NETWORK_TX_BYTES`, `KERNEL`.
2. Добавить `SYSTEMD_SSH` и `SYSTEMD_WIREGUARD` — их читает Desktop, но в §7 их нет. Дописать в §7, чтобы контракт снова был единственным источником.
3. Внутренние переменные вроде `DF_OUT` и `DF_INODES` из вывода убрать: снимок не должен содержать ничего, кроме полей контракта.

### Контрактный тест — переделать

`tests/acceptance/test_monitor_snapshot.sh` проверяет скрипт против списка полей, который живёт в самом тесте. Именно поэтому расхождение с Desktop не поймалось.

Список ожидаемых полей должен существовать **в одном месте** и использоваться обеими сторонами:

- тестом shell-скрипта — что все поля присутствуют и лишних нет;
- тестом парсера Desktop — что он читает ровно эти поля.

Как реализовать — на ваше усмотрение: общий файл-фикстура с эталонным снимком, из которого обе стороны берут набор ключей, либо генерация списка из `installer-contract.md`. Требование одно: **изменение имени поля с одной стороны обязано ронять тест другой стороны.**

`SshMonitorService.cs` при этом не менять — правится скрипт, а не парсер. Если парсер тоже потребует правки, описать в `REPORT.md`.

---

## Часть 2 — совместимость существующей БД с SQLitePCLRaw 3.0.5

Пункт из прошлого задания, оставшийся невыполненным. Сейчас он не горит только по счастливой случайности: `alpha.8` собран из коммита, где ещё `2.1.12`. Но в `main` уже `3.0.5`, и следующий релиз его унесёт.

На живом Hub пользователя база создана версией `2.1.12`. Если совместимости нет, это проявится в момент `update-control`.

Проверить: открытие существующей `control.db` сборкой из текущего `main`, `PRAGMA user_version` без повторного применения миграций, чтение агентов, identities, links, provisioning и аудита, `backup-create` и `backup-restore` на этой же базе, и то же самое на `linux-arm64` self-contained trimmed single-file.

**Добавить постоянный тест** на открытие базы предыдущей схемы — эталонная `control.db` в репозитории либо скрипт её воспроизведения. Без него следующее обновление SQLite повторит эту историю.

Если хоть одна проверка не проходит — откатить `#23` отдельным PR и написать об этом прямо.

---

## Часть 3 — дисциплина релизов

Тег `v0.1.0-alpha.8` был сдвинут: сначала указывал на `80b4797`, теперь на `ad180e9`. Так делать нельзя, и теперь особенно: релиз содержит `server-monitor-manager-manifest.json` и подпись `manifest.sig`, которые описывают конкретное содержимое. Если тег двигается, подпись перестаёт что-либо доказывать, а у того, кто сверялся с прежним тегом, проверка не сойдётся.

1. Зафиксировать правило в `docs/installer-contract.md`: **опубликованный тег неизменяем**; ошибка в сборке исправляется выпуском следующей версии, а не переписыванием тега.
2. Следующий релиз выпускать как `v0.1.0-alpha.9` после частей 1 и 2.
3. Убрать из `smm-setup.sh` (ассет релиза) временный обход бага `validate_control_url` — дефект исправлен в #24, обход помечен комментарием в коде.
4. Довести или закрыть PR #31.

---

## Критерий приёмки

- снимок Monitor совпадает с `installer-contract.md` §7 плюс два поля systemd; лишних полей нет;
- переименование любого поля роняет тест противоположной стороны — продемонстрировать намеренной поломкой во временном коммите со ссылкой на красный прогон;
- существующая база открывается новой сборкой, есть постоянный тест на предыдущую схему;
- правило неизменяемости тега записано в контракте;
- обход `validate_control_url` из `smm-setup.sh` удалён;
- Control suite прогнан на Linux, CI зелёный.

## Отчёт

Раздельно: локально, в CI со ссылками, не запускалось и почему.
