Задания, отчёты и патчи, лежавшие в C:\Users\Ochenstarik\projects и в домашней папке, перенесены в agents/. Разложено по агентам там, где имя файла позволяло определить автора; остальное — в _salvage-2026-08-18/ и разбирается вручную. Патчи в notes/salvage-2026-08-18/ — незакоммиченная работа из брошенных рабочих копий: она существовала только на диске. Тяжёлое (релизные архивы, инсталляторы, наборы данных) в репозиторий не попало: оно лежит рядом, в Agent_projects/_archive и Agent_projects/_data. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
20 KiB
План доделывания Server Monitor Manager — для облачного исполнителя (Gemini)
Составлен 2026-08-04. Заменяет собой полосовое разделение: Codex приостановлен, Gemini ведёт весь объём.
Базовая ревизия на GitHub: main @ b11c277.
0. Передача работ — сделать до постановки первой задачи
0.1. B-3R существует только локально
Незавершённая работа по блоку B-3R — 24 изменённых файла, около 1276 добавленных строк — лежит незакоммиченной в C:\Users\Ochenstarik\projects\server-monitor-manager-task3-b3. На GitHub этой ветки нет: последняя ветка серии на remote — hermes/task2-b-link-reconciliation (1580ec7), это ещё блок B-2.
Облачный исполнитель этого не видит. Возможные решения:
| Вариант | Последствия |
|---|---|
Закоммитить и запушить ветку hermes/task3-b3-fact-reconciliation как есть, с честной пометкой «незавершено, см. B3R_SPEC» |
Работа сохранена, Gemini продолжает с неё. Рекомендуемый вариант |
| Выгрузить патчем и передать файлом | Работает, но патч быстро протухнет и его придётся накатывать вручную |
Отбросить и переделать с b11c277 |
Потеря корректной работы: R3 закрыт полностью, R1 закрыт на уровне отдельной мутации — я это проверял по коду |
Пока решение не принято, ставить задачу по B-3R облачному исполнителю нельзя: он либо не найдёт контекст, либо начнёт вторую параллельную реализацию.
0.2. Нормативные документы тоже локальны
Коммит 4de849e (docs/product-horizons.md, docs/approval-policies.md, docs/integration-kagent.md, правки roadmap.md и security-model.md) находится на локальной ветке docs/product-horizons-and-integration и не запушен. Пока он не в репозитории, план ниже ссылается на документы, которых исполнитель не увидит.
Запушить до выдачи первой задачи.
1. Что облачный исполнитель проверить не может
Это самый важный раздел. Дисциплина честной отчётности была сильной стороной предыдущих пакетов — её надо сохранить, а список ограничений изменился.
| Проверка | Доступно в облаке | Что делать |
|---|---|---|
| Control test suite на Linux | Да | Запускать обязательно. Именно Linux-прогон в блоке B-3 выявил, что integration-тест остался на старом протоколе: на Windows он молча пропускался по OperatingSystem.IsLinux() |
| Тесты helper, nftables, bash-контракты | Да | Запускать; это естественная среда для них |
| Сборка Desktop (WinUI 3) | Нет | Требует Windows и Windows App SDK. Полагаться на windows-build.yml в CI. Никогда не заявлять локальную сборку Desktop |
Test-DesktopContracts.ps1 |
Частично | Это сопоставление строк в XAML, идёт под pwsh на Linux. Указывать, что запущено под pwsh, а не на Windows |
| Физический acceptance | Нет ни у кого | Требует HUB_SSH_HOST, HUB_SSH_USER, SOURCE_SSH_HOST, SOURCE_SSH_USER, HOME_WG_IP, SECOND_WG_IP, SSH_IDENTITY_FILE. Не выдавать mock- и contract-тесты за него |
| Trimmed linux-x64 publish | Да | Полезно: проверка source-generated сериализации на реальном опубликованном артефакте |
Правило. В TEST_EVIDENCE.md раздельно перечисляются: что запущено локально, что запущено в CI, что не запускалось и почему. Отсутствие проверки — не дефект отчёта; выдача непроверенного за проверенное — дефект.
2. Формат сдачи для облака
Прежние пакеты складывались в локальную папку. Для облачного исполнителя:
- Основной артефакт — Pull Request. Якорь целостности — SHA коммита, а не
SHA256SUMS. В отчёте указывать точный SHA, который ревьюился, и SHA, который смержен, если они различаются. REPORT.mdиTEST_EVIDENCE.md— в описании PR либо отдельным коммитом в PR; содержание прежнее.CI_CHECKS.txtзаменяется ссылкой на прогон checks в PR.INDEPENDENT_REVIEW.md— обязателен по-прежнему, и ревьюеру передаётся полный текст задачи, а не только диф. Три блока из четырёх дали находки класса «пропущенное требование», которые при diff-only ревью не ищутся вовсе.- Один PR — одна тема. Смешанные PR не принимаются.
- Статус после merge —
merged / verified, а не «выполнено», если критерий сформулирован через фактическое поведение и не измерялся на реальной топологии.
3. Первая задача — калибровочная
Дешёвая, быстрая, с нулевым риском для существующего кода, и результат проверяется объективно. Даёт понять, справляется ли исполнитель, до того как ему доверят control plane.
Задача A — гигиена репозитория и цепочки поставки · до одного дня
Только новые файлы и .github/**. Ни одного файла, который трогает ветка B-3R.
- Запинить все GitHub Actions по commit SHA. Сейчас плавающие
@v6,@v5,@v2— содержимое шага может измениться без нашего ведома. .github/dependabot.ymlдляgithub-actionsиnuget.- Сузить
permissions: contents: writeвlinux-release.ymlиwindows-release.ymlдо job'а публикации. SECURITY.md— куда сообщать об уязвимости, ожидаемое время ответа, что считается уязвимостью. Для инструмента безопасности его отсутствие — само по себе дефект.CHANGELOG.mdв формате Keep a Changelog, заполнить по существующим тегамv0.1.0-alpha.1…5.CONTRIBUTING.md,CODEOWNERS, шаблоны issue и PR.- SBOM (
dotnet CycloneDX) как артефакт релиза. - Удалить слитые ветки
agent/remove-lightweight-server-referencesиcodex/ttl-backup-acceptance.
Как я буду проверять результат: ни одна ссылка на action не содержит плавающего тега; permissions сужены именно в job'ах публикации, а не глобально; SECURITY.md содержит адрес и процедуру, а не заглушку; CHANGELOG соответствует реальным тегам, а не выдуман; CI зелёный; в TEST_EVIDENCE.md честно разделено локальное и CI; ревью получило текст задачи.
Если задача выполнена аккуратно и отчёт не приукрашен — переходим к содержательным задачам. Если в отчёте появятся непроверенные утверждения, это будет видно сразу и дёшево.
4. Дальнейшая очередь — Горизонт 0
Порядок обязательный. Горизонт закрывается целиком, Горизонт 1 не начинается до этого.
Задача B — завершить B-3R · зависит от решения по п. 0.1
Контракт: B3R_SPEC.md (выдан ранее, принят исполнителем как authoritative).
По состоянию на 04.08 закрыто: R3 полностью (lookup_node_ip читает статус, reserved → exit 80, active с битым IP → 78) и R1 на уровне отдельной мутации (VerifyExactFactualCountAsync считает записи через link-list, условие if (persisted) вокруг верификации снято).
Осталось:
- пакетная финальная верификация: сейчас
1 + kвызововlink-list, требуется ровно два — стартовый и один финальный на все затронутые ключи; - класс
Deferredи инвариантConverged + Failed + Deferred == Examined;PendingActivation— этоDeferred, а неFailed, и он не блокирует потребление marker, иначе один зарезервированный Node вернёт бесконечный цикл проходов; - R4: именованный DTO в source-generated контексте вместо анонимного типа для orphan audit, с проверкой на опубликованном trimmed-артефакте;
- R5: Linux integration test на fact-first протокол, с обязательным прогоном на Linux;
- R6: убрать fail-open default у
ILinkPolicyApplier.ListRulesAsync; - R7: форматирование вложенных lock-scope;
- дополнительно: мусор в поле статуса
nodes.tsvдолжен давать 78, а не 80 — повреждённое состояние не то же самое, что ожидаемое.
Готово, когда: PR создан, Linux CI зелёный впервые для этой ветки, merge выполнен.
Задача C — жизненный цикл сертификатов
CertificateAuthority.cs:55 выдаёт клиентские сертификаты на год, автопродления нет. Через год после развёртывания парк отваливается одновременно, и восстановление потребует ручной перерегистрации каждого Node.
- срок клиентского сертификата 30–90 дней, значение в конфигурации с валидацией;
- автопродление Agent за треть срока до истечения через существующий mTLS-канал: новый CSR, выдача, атомарная замена
agent.pfx, откат при неудаче; - продление Operator-сертификата Desktop с уведомлением пользователя;
- событие
certificate.expiringв поток событий; - документированная процедура ротации Control CA и повторной регистрации парка — сейчас её нет;
- тесты: продление до истечения, недоступный Hub в момент продления, отказ при отозванном сертификате.
Файлы CertificateAuthority.cs, CertificateLifecycleService.cs, AgentClient.cs веткой B-3R не затронуты — задачу можно вести параллельно задаче B.
Задача D — роль Monitor в bootstrap
SSH-мониторинг — функция, ради которой существует Desktop, — не имеет серверной части. В bootstrap нет install-monitor, forced-command скрипт не поставляется, а парсер SshMonitorService.QueryAsync ожидает ключи PROTOCOL, CPU_COUNT, MEM_AVAILABLE_KB, DISK_INODES_TOTAL, которых в репозитории никто не производит.
- действия
install-monitor PUBLIC_KEYиuninstall-monitor; - пользователь
ochenstarik-monitor: nologin, без пароля, без sudo; /usr/local/libexec/ochenstarik-smm-metrics, root-owned0755, выдающий ровно снимок изdocs/installer-contract.md§7 и read-onlymesh status;authorized_keysсcommand="…",restrict,no-pty,no-agent-forwarding,no-port-forwarding,no-X11-forwarding;- идемпотентность повторного запуска и корректное удаление;
- контрактный тест формата снимка, общий для скрипта и парсера Desktop.
Bootstrap-скрипт затронут веткой B-3R — делать после merge задачи B.
Задача E — подписанная поставка
Bootstrap сверяет ARCHIVE.sha256, лежащий рядом с архивом в том же релизе, а manifest не подписан и содержит только хэш самого bootstrap. Кто может опубликовать релиз — ставит произвольный root-код на весь парк через update-agent.
- manifest v2: хэши всех артефактов, версии Control/Agent/helper/Desktop, минимальные совместимые версии,
helper_protocol; - подпись
cosign sign-blobkeyless либоminisign; публичный ключ или issuer вшит константой в bootstrap и Desktop, а не скачивается вместе с релизом; - действие
verify-manifest;verify_archiveсверяет хэш с manifest, а не с соседним файлом; старый путь только подSMM_ALLOW_UNSIGNED=1; - отказ
update-controlиupdate-agentпри несовместимых версиях — требованиеdocs/installer-contract.md§6, не выполненное до сих пор; PROGRAM_VERSIONиз тега вместо0.2.0-dev;- отсутствие инструмента проверки подписи — отказ, не предупреждение;
- негативные тесты в CI: изменённый байт архива, подменённый хэш в manifest, manifest без подписи.
Задача F — инженерная оснастка
Directory.Build.props:Nullable,TreatWarningsAsErrors,EnableNETAnalyzers,AnalysisLevel latest-recommended, детерминированная сборка;Directory.Packages.propsиRestorePackagesWithLockFileс коммитом lock-файлов — сейчас сборки невоспроизводимы, что противоречит требованию закреплённой поставки;- разделить тесты на
Core.Tests,Control.Tests,Agent.Tests,Helper.Tests: сегодняLinuxMetricsTests,MetricBufferTestsиProvisioningHelperTestsлежат в проекте Control; - тесты round-trip сериализации контрактов: при
PublishTrimmed=trueмолчаливая потеря поля не ловится ничем.
TreatWarningsAsErrors включать после merge задачи B, иначе сломает незавершённую ветку.
Гейт Горизонта 0
Чистый сервер ставится из подписанного релиза одной командой, регистрируется одноразовым кодом, попадает под мониторинг без ручной правки authorized_keys, и после перезагрузки Hub и Node фактическое состояние Links совпадает с желаемым — измеренное связностью на реальной топологии.
Последнее не может закрыть ни один исполнитель. Это единственное, что зависит только от выдачи доступов, и оно дешевле любой задачи в этом плане.
5. Горизонт 1 и далее
Не выдавать до закрытия гейта Горизонта 0. Состав и порядок — по docs/product-horizons.md и разделу «Горизонт 1» документа smm-codex-plan-2026-08-04.md: каркас IProvisioningModule первым, затем модули по одному, политики подтверждения, миграция SSH, alert engine, Telegram только на чтение, наблюдение Docker и systemd, Backup Manager.
Ключевое правило переноса: не добавлять второй provisioning-модуль копированием timezone-исполнителя. Сначала каркас, иначе шесть копий логики backup → mutate → verify → rollback.
6. Как оценивать исполнителя
По задаче A смотреть на четыре вещи, в порядке важности:
- Честность отчёта. Разделены ли локальные проверки, CI и то, что не запускалось. Появление в отчёте непроверенных утверждений — худший признак из возможных, потому что обесценивает все последующие отчёты.
- Соответствие постановке, а не её пересказ. Выполнены ли все восемь пунктов, а не пять удобных.
- Отсутствие расползания. Не тронуты ли файлы вне области задачи.
- Качество ревью. Получил ли независимый ревьюер полный текст задачи и нашёл ли что-нибудь, кроме опечаток.
Если задача A пройдена — давать задачу C (сертификаты): она содержательная, файлы свободны, и результат тоже проверяется объективно. Задачу B (завершение B-3R) давать только после того, как решён вопрос 0.1 и подтверждено, что исполнитель понимает контракт: это самая тонкая часть системы, там уже дважды находили блокирующие дефекты.