hermes-hub/agents/inbox/2026-08-22-A8-antigravity-deployment-and-doctor.md
Hermes Team 20078f5ff6 docs(task): A8 and B7 — defects found during the first live run
The owner used the product and the router proved itself: the log shows a real
failover chain codex-orch -> ag-orch-fallback -> opengo-3 driven by actual quota
errors. Everything around that core failed.

Hub stopped launching because customtkinter vanished from the Hermes venv, most
likely wiped by that app's repair-install; pythonw swallows the traceback, so it
looks like the window never opens. The wizard offers five providers while the
router config defines profiles for three, so find_free_slot returns a
non-existent claude-orch. The test action still reaches the agy subprocess, which
opens a browser on expired credentials. The routing "configure" button only
raises a toast about drag-and-drop.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 20:13:01 +07:00

12 KiB
Raw Blame History

Задание A8 (Antigravity): запуск, развёртывание, самопроверка

Дата поступления

2026-08-22

База

Проверочный HEAD: 8cddc9f, origin/main = 8cddc9f. git fetch, зафиксировать BASE_SHA.

Ветка

antigravity/deployment-doctor


Что принято по A7

Проверено исполнением: лизы объединены (engine.leases is LeaseManager.get()True, снапшот показывает {'codex-orch': 1}), CPU прогревается (первое измерение 25.0 вместо нуля), сеть стала скоростью net_speed_mbps. Прогон: headless 195, с UI-зависимостями 249, ruff чисто, гейт PASSED.


Контекст: владелец впервые эксплуатировал Hub

Вчера и сегодня продукт запускали вживую. Результат: роутер работает, оболочка — нет. В журнале зафиксирован настоящий каскад отказоустойчивости:

20:07:10 Переключение роли 'orchestrator': сбой 'codex-orch'      — Insufficient quota
20:07:10 Успешное переключение: резервный профиль 'ag-orch-fallback'
20:07:10 Переключение: сбой 'ag-orch-fallback'                    — Individual quota reached
20:07:10 Успешное переключение: резервный профиль 'opengo-3'

Это первое доказательство, что ядро делает то, ради чего создавалось. Всё остальное, о чём сообщил владелец, — дефекты вокруг ядра.

P0-1. Hub перестал запускаться: зависимость живёт в чужом окружении

Симптом: «программа запускается и сразу закрывается». Причина воспроизведена:

ModuleNotFoundError: No module named 'customtkinter'

Лаунчер запускает pythonw.exe — без консоли, поэтому трейсбек уходит в никуда и окно просто не появляется. Ещё в 09:41 Hub стартовал нормально; пакет исчез между 09:41 и вечером. Наиболее вероятная причина — кнопка «Repair install» в диалоге ошибки Hermes: она пересоздаёт venv агента и стирает всё доустановленное.

Я вернул пакет вручную, Hub снова импортируется. Но проблема архитектурная: Hub держит свои зависимости в venv чужого приложения, которое их периодически сносит.

Требуется:

  1. Самолечение при запуске. Перед созданием окна проверять импорт customtkinter, PIL, psutil, yaml. Если чего-то нет — доустановить в venv Hermes и повторить, либо показать понятное окно с одной кнопкой «Установить зависимости».
  2. Ошибка запуска должна быть видимой. Сейчас любой сбой до создания окна = тишина. Писать трейсбек в logs/startup.log до импорта UI и, при падении, показывать нативное окно с текстом ошибки и путём к логу. Файл уже есть, но пишется слишком поздно.
  3. Оценить переход на собственный venv Hub рядом с %LOCALAPPDATA%\Programs\HermesHub\, чтобы обслуживание Hermes не ломало Hub. Если решение — остаться в venv Hermes, записать это как осознанный выбор с обоснованием.

P0-2. Мастер предлагает провайдеров, для которых нет профилей

Симптом владельца: «завершить не нажимается, пишет что всё исчерпано, но нет».

Причина: мастер предлагает пять провайдеров, а в конфигурации роутера профили есть только для трёх.

antigravity   10 профилей
openai-codex   3 профиля
opencode-go    3 профиля
claude         НЕТ НИ ОДНОГО
grok           НЕТ НИ ОДНОГО

AutoAssigner.find_free_slot перебирает claude-orch, claude-worker-1… не находит их в конфиге, пропускает все и возвращает candidates[0] — то есть несуществующий claude-orch. Дальше мастер сохраняет авторизацию в слот, которого нет, назначение роли отвечает «профиль не найден», завершение не проходит.

Требуется: профили для claude и grok во встроенной конфигурации и в шаблоне router_profiles.example.yaml, по образцу существующих, с ролями в цепочках. И find_free_slot не должен возвращать идентификатор, отсутствующий в конфиге, — при отсутствии свободных слотов возвращать None с внятной причиной.

Тест: для каждого провайдера, который предлагает мастер, find_free_slot возвращает либо существующий профиль, либо None.

P0-3. Кнопка «Тест» открывает окно авторизации

Симптом: «при тесте открывается опять окно авторизации и ничего».

В журнале: Ошибка теста ag-orch-fallback (gemini-3.7-flash): Antigravity error: agy error: authentication failed or timed out.

Проверка учётных данных в do_test_profile выполняется, но затем вызывается адаптер, а он запускает agy — и этот подпроцесс сам открывает браузер, когда токен просрочен. Требование «тест никогда не запускает OAuth» стоит в проекте с первого аудита и нарушено на уровне подпроцесса.

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

Тест: просроченные учётные данные дают ошибку авторизации без попытки интерактивного входа.

P0-4. Установка должна быть зеркалом, а не наслоением

HermesHubSetup.cs:279 делает CopyDirectoryRecursive — только копирует, никогда не удаляет. Развёрнуто у владельца 51 файл от 19 августа против 70 в репозитории, и среди них четыре модуля, удалённых нами как мёртвый код:

router/capability/
router/skills/skill_registry.py
router/supervisor/lifecycle_supervisor.py
router/gui_server.py

Сами по себе инертны, но однажды уже ввели в заблуждение: тесты подхватывали runtime.py из развёрнутой копии.

Требуется точное зеркало источника: удалять файлы, которых нет в источнике, исключать __pycache__. Тест: развернуть, удалить файл из источника, развернуть снова, убедиться, что в цели его нет.

P0-5. Команда самопроверки

Расширить print_diagnostics_cli до проверки, отвечающей на вопрос «работает ли Hub» без запуска десктопа Hermes:

  • зависимости в venv с указанием, чего не хватает;
  • свежесть развёрнутого плагина против версии приложения (для этого при установке писать манифест: версия, дата, коммит);
  • валидность router_profiles.yaml, число профилей и ролей;
  • по каждому профилю: провайдер, идентичность, авторизация, квота, источник данных;
  • реальный тестовый вызов по одному профилю на провайдера;
  • итог одной строкой: готов / частично / не готов, с причинами.

Секреты в выводе маскируются.

P1-6. Остаток по YAML

Внутренние комментарии router_profiles.yaml теряются (7 → 2). Либо полный round-trip, либо статус «частично» с перечнем теряемого — в контракте и отчёте.


Ограничения

  • Граница прежняя: зона Codex (router/ui/**, hermes_hub_app.py, tests/test_ui_*.py) — не трогать. Исключение по P0-1: проверка зависимостей до создания окна лежит в точке входа; согласовать минимальную правку, остальное — данными.
  • Тег v0.1.1 не создавать.

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

  1. Hub запускается на машине без customtkinter: либо доустанавливает, либо показывает окно с понятной ошибкой. Проверено на изолированном venv.
  2. Любой сбой до создания окна попадает в startup.log с трейсбеком.
  3. Для всех пяти провайдеров мастера find_free_slot возвращает существующий профиль или None.
  4. Тест профиля с просроченной авторизацией не открывает браузер.
  5. Повторное развёртывание удаляет исчезнувшие файлы.
  6. Самопроверка работает без запущенного Hermes и печатает связный вердикт без секретов.
  7. Прогон в обоих окружениях; обе команды и оба результата в отчёте.
  8. ruff check . чисто; release gate PASSED на финальном коммите.
  9. Отчёт: START_HEAD, FINAL_HEAD, origin/main, git status, точный X passed / Y skipped / Z failed.

Порядок сдачи

Передать точный FINAL_COMMIT_SHA.