15 KiB
Инварианты: вопросы владельцу
Проход по репозиторию сверху вниз, 2026-10-05. 120 .nix, ~8.5k строк.
Структура:
- Сводный ответ, ядро и ловушки →
AGENTS.md(корень репозитория). - Подробная карта архитектуры с per-host деталями и инвентарём сервисов →
docs/arch/map.md. - Этот файл → открытые вопросы (слои 0–8) + ещё непрочитанные слои 9–11 (home-manager, deploy, формат).
Пометки: [!] — найденный дефект, не вопрос. [?] — не смог определить по коду.
[✓] — отвечено владельцем 2026-10-05.
Статус ответов (2026-10-05)
Отвечено: 2.1, 5.2, 6.1, 6.3, 6.5, 7.1, 7.2 (7 пунктов). Остальные ждут ответа (таблица ниже).
Ключевое из ответов, что меняет картину:
- 6.5 — моя ошибка.
100.64.0.0не «сетевой адрес вместо интерфейса»: это Tailscale-адрес sapphira, назначенный вручную. - 6.3 — это не дыра, а осознанное решение. Граница держится на роутере:
на сервер пробрасываются ровно 5 портов — 443, 80, 22000 (syncthing),
8443 (xray), 22 (ssh).
firewall.enable = falseна sapphira — следствие, а не недосмотр. Проблема в другом: список пробросов нигде не записан в репозитории, и именно его агент обязан уважать (D1 вtodo.md). - 7.2 — 3x-ui рабочий. Откат сделан осознанно: панель последняя, ядро Xray осталось на 26.7.28, миграция на 26.9 провалена, лишний код закомментирован. Состояние — «заморожено», а не «сломано».
- 5.2 — подтверждённая дыра в защите данных. Guard для несмонтированного носителя не был продуман → задача B1.
Сводка подтверждённых инвариантов
| # | Пункт | Краткая формулировка | См. |
|---|---|---|---|
| 1 | Все outputs флейка вычисляются |
A1: правка lib/xlib.nix → lib/xlib; закрепить через nix flake check |
todo A1 |
| 2 | External-диск монтируется до сервисов | mkServiceStorage + bind без guard'а → сервис стартует на пустой БД | todo B1 |
| 3 | Сетевая граница sapphira = роутер | 5 портов: 22, 80, 443, 8443, 22000; firewall.enable = false намеренно |
todo D1 |
| 4 | 100.64.0.0 = Tailscale sapphira |
Назначен вручную; в 4 файлах | AGENTS.md §5 |
| 5 | 3x-ui заморожен | Панель на latest; ядро Xray на 26.7.x; миграция 26.9 провалена | todo C1–C5 |
| 6 | nftables на VDS — явная финальная политика | Сейчас ruleset без финального правила + конфликт с firewall.* |
todo A3 |
Сводка по ловушкам
Полная таблица (10 пунктов) в AGENTS.md → раздел «Ловушки». Кратко:
firewall.enable=false намеренно · uid=1001 на sapphira · image = …:latest
намеренно для 3x-ui · reality443Forwarding=true — следствие отката ·
15 закомментированных модулей в server/default.nix · serviceConfig vs Service
в home-manager · nftables без финального правила · 100.64.0.0 не сеть ·
/mnt/services mode 0777 · stateVersion разный между хостами.
Неотвеченные вопросы (слои 0–8)
Самые важные — выделены.
| ID | Вопрос | Что блокирует |
|---|---|---|
| 0.1 | Восстанавливать ли migration notes, удалённые в 22a19be? |
C1: реконструкция заметки 3x-ui |
| 0.2 | Комментарий-density 38/120 файлов без комментариев — нормально? | Стиль модулей |
| 0.3 | 15 закомментированных модулей: удалить или хранить как референс? | E3: чистота кода |
| 0.4 | README пустой, todo.md нет — норма? | E1: AGENTS.md/README |
| 1.3 | Лишние inputs в flake (justray, nix-minecraft, proxy-suite)? |
Чистота flake |
| 1.5 | nix-systems через follows — оптимизация размера lock |
Документация |
| 2.2 | vetymae / lamet / therima / soptur — те же машины или хосты вне реестра? |
DNS/nginx/identity |
| 2.3 | sapphira uid=1001: блокер ли использование /mnt/archive//mnt/mobile? |
Миграция ФС |
| 2.5 | stateVersion 24.05 / 24.11 / 25.05 / 26.05 — намеренный дрейф? | Миграции |
| 2.6 | Есть ли escape hatch для per-host отличий в xlib? | Архитектура |
| 2.7 | devices.termux без NixOS-хоста — закрытый список |
Документация |
| 3.2 | any.nix (minimal) нужны home-manager + sops + disko? |
Минималка |
| 4.1 | Как root получает доступ по SSH — authorizedKeys в коде нет | deploy, безопасность |
| 4.2 | Как разрешается цикл «ключ в секрете, а нужен для расшифровки»? | bootstrap, recovery |
| 4.3 | Все файлы в secrets/ покрыты path_regex? |
sops |
| 4.4 | Как подключается вторая машина / второй человек при одном age-ключе? | sops, scale |
| 4.5 | users.nix:87 — личный ключ или общий «ключ от деплоя»? |
Безопасность |
| 5.1 | /mnt/services mode 0777 — осознанно? |
Безопасность |
| 5.3 | NFS выключен, Samba работает — миграция? | Сетевые сервисы |
| 5.4 | NTFS-том lamet-drive mask=0000 — что на нём? |
Семантика |
| 5.5 | therima / vetymae / soptur в dirs.nix — реально смонтированы? |
Семантика |
| 5.6 | Где бэкапы БД и 3x-ui? | B2 |
| 6.6 | 192.168.1.20 зашит в 30 мест — константа? |
Рефакторинг |
| 6.7 | DNS ↔ сервисы — как ловим рассинхрон? | Документация, CI |
| 6.8 | Публичные IP + SSH-алиасы в home/termux.nix — карта «хост → адреса» нужна? |
Архитектура |
| 6.9 | Какой путь REALITY правильный сейчас? | C5 |
| 7.4 | Почему не публиковать весь диапазон 14380-15379? | 3x-ui |
| 8.2 | lamet.opencodes → :6061 (порт miniflux) — ошибка? |
nginx |
| 8.4 | onlyoffice после трёх регрессов — работает? |
Статус сервиса |
| 8.5 | Что слушает :3002 (/whiteboard nextcloud)? |
Карта сервисов |
| 8.6 | Бэкапы вне Nix — записать | Документация |
Где это раньше лежало
До переноса в AGENTS.md / map.md здесь был подробный Q&A по слоям 0–8
с разделами «Вопрос», «Факт», «Риск», «Кандидат». Этот текст сохранён в
git-истории файла (последний коммит, где Q&A был полным). Восстановить:
git log -p docs/arch/invariants.md | less.
Слой 9. home-manager
9.1 home/home.nix:52-57 — для пользователя импортируется
home/${xlib.device.type}.nix; для root — без профиля (строка 51).
Вопрос: почему у root нет home-профиля — сознательно?
Кандидат: home/<type>.nix = единственный источник «что есть на этом хосте»
для пользователя; добавление пакета в новый тип = правильный файл, а не
home/default.nix.
9.2 [!] home/home.nix:28-43 для headless-хостов: xdg.userDirs.* = null и
createDirectories = false, при этом lib/xlib/dirs.nix:26 обещает
music-library = "${user-home}/Music".
Вопрос: кто создаёт ~/Music и ~/Storage? createDirectories = false
означает, что home-manager их не создаст, а dirs.nix на них ссылается.
Риск: на headless-хосте путь в конфиге есть, а каталога нет → тихий сбой
сервиса, который туда пишет.
9.3 [!] home/modules/opencode.nix:339-350 (c73a698): в home-manager нельзя
писать serviceConfig = { ... } — рендерится литеральная секция [serviceConfig],
которую systemd молча игнорирует («Unknown section 'serviceConfig'. Ignoring.»).
Правильно: systemd.user.services.opencode-web.Service = { ... }.
Кандидат (готовый инвариант, стоит закрепить буквально в AGENTS.md):
в home-manager cgroup-опции (MemoryHigh, OOMScoreAdjust, …) пишутся
в systemd.user.services.<name>.Service, не в serviceConfig. Ошибка
не диагностируется — она просто не применяется.
9.4 linger = true добавлен ради opencode-web (users.nix:71-75) и включён
для всех хостов.
Кандидат: «user-сервисы переживают logout на всех хостах» — закрепить, потому
что это неочевидное поведение, влияющее на ресурсы и на безопасность.
9.5 home/modules/opencode.nix:286-303 — opencode.web слушает 0.0.0.0:4096
(комментарий: nginx проксирует 127.0.0.1:4096), и nginx на sapphira ходит туда
же по Tailscale у двух других хостов (см. 8.3).
Кандидат: 0.0.0.0 в opencode.web — обязательное условие для внешнего
доступа через opencodes.*; пароль приходит из sops-секрета opencode_server.
9.6 Секреты opencode приходят в ~/.config/opencode/server.env (dotenv),
~/.local/share/opencode/auth.json и account.json (json, key = "").
Кандидат: эти три файла перезаписываются sops при каждой активации — ручные
правки в них теряются. Уже отражено в комментарии users.nix:120-131, стоит
закрепить как инвариант.
Слой 10. deploy и проверка
10.1 deploy/default.nix:20-24 — цели: sapphira (server), otrecа (vds),
rydiwo (ноутбук). Нет atoridu (основной десктоп), wsl, epral.
Вопрос: почему не деплоится десктоп? И безопасно ли пересобирать ноутбук
rydiwo по SSH (он может быть выключен/на другом Wi-Fi)?
Кандидат: deploy-rs = только серверы + ноутбук; десктоп и WSL обновляются
вручную. Инвариант: не добавлять в deploy.nodes хост, который нельзя
пересобрать в любой момент без риска потерять доступ.
10.2 deploy/default.nix:18-19 — sshUser = "oqyude", user = "root".
См. 4.1: root-доход по SSH не описан в конфигурации.
Кандидат: деплой требует ручной настройки root-доступа на каждом из 3 хостов —
это скрытая зависимость, которую агент не выведет.
10.3 deploy/default.nix:27-29 — checks = builtins.mapAttrs (... deployChecks).
Вопрос: nix flake check реально проходит сейчас? Учитывая 2.1 (lib/xlib.nix)
он должен падать на nixOnDroidConfigurations. Падает или checks покрывают
не всё дерево outputs?
Кандидат (первое, что стоит сделать): добиться, чтобы
nix flake check был зелёным — это единственная автоматическая защита от
подобных breakage'ов.
10.4 CI нет, flake check не запускается автоматически.
Кандидат: минимальный локальный набор перед коммитом:
nix flake check && nix build .#nixosConfigurations.<хост>.config.system.build.toplevel --dry-run.
Слой 11. Формат (то, что я предлагаю зафиксировать как процесс)
11.1 Где будет жить итог: AGENTS.md в корне (читается агентом всегда),
docs/arch/map.md (карта хостов/сервисов), docs/arch/invariants.md (этот файл).
Кандидат: этот файл после ответов превращается в docs/arch/invariants.md
с колонкой «ответ» и становится источником для AGENTS.md; AGENTS.md — краткая
выжимка, без подробностей.
11.2 Какие инварианты можно превратить в автоматическую проверку (тогда они перестанут «забываться»):
- ни одного
:latestв образах (grep поimage =); nix flake checkзелёный;- каждый домен из
coredns.nixимеет vhost вnginx.nixи наоборот; - каждый сервис в
mkServiceStorageимеет каталог в/mnt/servicesнаExternal-диске; - в самописном nftables-ruleset последнее правило цепочки явное;
- каждый
listen.addr— реально назначенный адрес, а не сеть; - все файлы в
secrets/матчатpath_regexиз.sops.yaml.
Вопрос: какие из этих проверок ты хочешь, а какие — лишний CI?