hermes-hub/agents/inbox/2026-08-21-B-codex-ui-redesign.md
Hermes Team 93883f9ce4 docs(task): split Plan A and UI redesign into two non-overlapping assignments
The UI redesign draft duplicated eight Plan A phases on the same files
(accounts_view, routing_view, hermes_hub_app, unified_health), which would have
put two agents into the same merge conflicts. Ownership is now split by file
path, with docs/UI_STATE_CONTRACT.md as the interface between them.

Four draft items were already implemented at 50fde5f and are marked as such
rather than reassigned: OAuth URL copy-before-open, keyed account card reuse,
the no-fake-metrics rule, and the importorskip guard.

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

17 KiB
Raw Blame History

Задание B (Codex): переработка интерфейса Hermes Hub

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

2026-08-21

База

Проверочный HEAD на момент выдачи: 50fde5f. Перед началом выполнить git fetch, зафиксировать фактический BASE_SHA, изучить существующий UI по коду, не по названиям файлов.

Ветка

codex/ui-redesign

Зависимость

Работа ведётся против контракта docs/UI_STATE_CONTRACT.md, который публикует Antigravity в рамках Задания A. Дождаться публикации контракта перед PHASE 2. PHASE 1 (токены, компоненты) можно начинать сразу — она от контракта не зависит.


ГРАНИЦА РАБОТ — читать первым

Параллельно выполняется Задание A (Antigravity) — слой состояния и данных. Разделение проходит по файлам.

Ваша зона (можно менять):

src/antigravity_provider/router/ui/**        ← theme, components, assets, views, wizard
src/antigravity_provider/router/hermes_hub_app.py
tests/test_ui_*.py

Чужая зона (НЕ трогать):

src/antigravity_provider/router/state_store.py
src/antigravity_provider/router/unified_health.py
src/antigravity_provider/router/scheduler.py
src/antigravity_provider/router/event_bus.py
src/antigravity_provider/router/quota_collector.py
src/antigravity_provider/router/model_registry.py
src/antigravity_provider/router/router_engine.py
src/antigravity_provider/router/router_config.py
src/antigravity_provider/router/adapters/**
src/antigravity_provider/router/*_oauth.py
src/antigravity_provider/router/profile_manager.py
scripts/**, installer/**, config/**

Если для отрисовки не хватает данных — не добавлять сбор данных в UI. Зафиксировать пробел в разделе «Backend gaps» отчёта и отрисовать честное отсутствие данных.


УЖЕ СДЕЛАНО — не переделывать

Проверено по коду на 50fde5f. Эти пункты из исходного черновика закрыты:

Пункт черновика Факт
§14 OAuth URL копируется до нажатия «Открыть браузер» Реализовано: _init_antigravity_oauth() вызывается при входе в шаг 2, поля oauth_url_entry и copy_url_btn уже есть
§22 AccountsView пересоздаёт все карточки Уже keyed-дельта: if p.profile_id in self._cards: card.update_from_model(...). Осталась пересборка внутреннего quota_box — только её и чинить
§36 запрет выдуманных метрик Обеспечен, есть 7 регрессионных тестов (test_data_truthfulness_and_oauth_security.py)
§37.14 importorskip для UI-тестов Сделано и закреплено CI-job headless + tests/test_import_invariants.py

Изъято из задания как чужой scope (передано Antigravity): §23 RoutingView-перестройка на уровне данных, §24 удаление scan_all из сервиса, §25 stale-политика, §27 планировщик обновлений, §28 событийная модель, §9/§10 сбор мульти-корзинных квот, §17 логика выбора модели.

Вам остаётся отрисовка того, что отдаёт контракт.


Область задачи

PHASE 1 — Фундамент (не зависит от контракта)

Design tokens. Единый набор: цвета, отступы, радиусы, типографика, высоты контролов, паддинги карточек. Никаких случайных padx=7/padx=11 по коду. Тема остаётся тёмной (Hermes), но константы централизованы так, чтобы светлая тема later не требовала переписывания views.

Библиотека компонентов. Нормализовать и достроить: HubCard, SectionHeader, StatusBadge, PlanBadge, ProviderBadge, QuotaBar, QuotaBucketWidget, AccountCardWidget, AgentCardWidget, RouteTargetWidget, EmptyState, SearchField, FilterButton, ActionButton, IconButton, ConfirmDialog, Toast. Одинаковая разметка не должна дублироваться по views.

Семантика цвета. Зелёный — работает; янтарный — предупреждение, резерв, приближение к лимиту; красный — ошибка, недоступен, исчерпан; серый — отключён, неизвестно. Золото — только брендинг и акцент, не статус «всё хорошо».

Плотность и типографика. Уменьшить заголовки и пустоты, унифицировать паддинги, высоты кнопок, радиусы. Длинные email — многоточие с полным текстом в подсказке. Карточки аккаунтов одинаковой геометрии.

Иконки. Один стиль, на существующей инфраструктуре ассетов. Не менять всё на emoji и не тянуть тяжёлую зависимость. Логотип Hermes Hub и символика H остаются главным идентификатором.

PHASE 2 — Аккаунты и квоты (приоритетная страница)

По контракту отрисовать так, чтобы за секунды читалось: провайдер, идентичность аккаунта, тариф, способ авторизации, здоровье, назначенная роль.

Идентичность обязательна. Порядок предпочтения: email → username → provider user ID → внятный fallback. Не показывать «Google account #1», если реальная идентичность доступна в ProfileViewModel.

Тариф показывать только когда провайдер его реально отдаёт (см. контракт), иначе не показывать бейдж вовсе.

Мульти-корзинные квоты. Отрисовать столько корзин, сколько отдаёт QuotaSnapshot, с их собственными метками, остатками и временем сброса. Не сводить к одному проценту. Если снапшот помечен is_estimated — показать это явно, признак уже есть в модели.

Компактный режим. Свёрнутая карточка: провайдер, идентичность, тариф, роль/статус, полосы квот, время сброса, действия. Развёрнутая: подробные корзины, доступные модели, роли, авторизация, приоритет в маршруте, отметки времени.

Группировка по провайдерам со сворачиванием, плюс поиск и фильтры по провайдеру, здоровью, роли, тарифу — насколько это не усложняет код чрезмерно.

Дельта-отрисовка. Внутренний quota_box не пересоздавать целиком: корзины обновлять по стабильному ключу. Удаление аккаунта уничтожает только его карточку.

PHASE 3 — Обзор

Dashboard как обзорный центр управления, только реальные данные: состояние системы, доступные провайдеры, активные аккаунты, доступные агенты, предупреждения и ошибки; компактное представление активного маршрута; аккаунты с низкой квотой, приближающимся сбросом, исчерпанные, недоступные, с истёкшей авторизацией; последние реальные события журнала.

Если backend не собирает величину — «Н/Д» или скрыть блок. Никаких «842 rps», «99.98 %», «1.23 % ошибок» из макетов, пока таких данных нет.

Пункты навигации без функциональности — скрыть либо честный «Позже», но не пустые страницы и не выдуманные метрики.

PHASE 4 — Команда

Иерархия «оркестратор → роли → агенты». Для агента: имя, роль, провайдер, аккаунт, модель, здоровье, индикатор квоты, активная сессия — там, где данные есть в контракте. Существующее переиспользование виджетов в TeamView не ломать.

PHASE 5 — Маршрутизация

Понятная цепочка отказоустойчивости для каждой роли: основной → резерв 1 → резерв 2 → резерв 3. Для каждого узла: провайдер, аккаунт, модель, статус квоты, здоровье. Показывать активный узел и, если причина есть в состоянии маршрута, — почему произошло переключение (квота, авторизация, таймаут, недоступность, ручное).

Сложный drag-and-drop не делать: редактор оставить кнопочным/селекторным, подготовив модель состояния под будущий React-фронтенд.

PHASE 6 — Второстепенные экраны

Привести к единому стилю: состояние, журнал, настройки, «о программе», мастер подключения, диалоги. Мастер должен визуально соответствовать новому интерфейсу; не ломать уже работающие потоки Antigravity OAuth, Codex OAuth, Codex API, OpenCode, Claude, Grok и вставку из буфера.


Ограничения

Не переписывать приложение на Tauri/React. Архитектура UI готовится к будущему разделению «состояние → ViewModel → компоненты», но миграция в этот scope не входит.

Не делать слепую переработку. Запрещено «удалить router/ui целиком и написать заново». Итеративно, после каждой фазы приложение запускается.

Не блокировать UI-поток. Сетевые запросы, опрос OAuth, получение квот, subprocess, сканирование диска — только в фоне, на существующей инфраструктуре потоков.

Секреты. Не логировать access/refresh-токены и коды авторизации, не показывать API-ключи в открытом виде, не сохранять учётные данные в состоянии UI. Показ — только маскированный.

Тег v0.1.1 не создавать, релиз не публиковать, манифест не менять.


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

  1. Ни один файл из чужой зоны не изменён (проверяется git diff --name-only).
  2. Приложение запускается после каждой фазы.
  3. Аккаунты показывают реальную идентичность; тариф — только когда он известен.
  4. Отрисовывается несколько квотных корзин; ни одна не сведена к единому проценту; оценочные данные помечены.
  5. quota_box обновляется по ключу, а не пересоздаётся; удаление аккаунта затрагивает только его карточку.
  6. Изменение аккаунта A не перерисовывает карточку аккаунта B.
  7. Маршрутизация показывает цепочку основной/резервы со статусами.
  8. Команда показывает провайдера, аккаунт и модель там, где данные доступны.
  9. OAuth URL копируется до открытия браузера; вставка из буфера работает; ни один из существующих потоков подключения не сломан.
  10. Нет выдуманных метрик: отсутствующие данные показаны как «Н/Д» либо скрыты.
  11. Секреты не попадают в UI и логи.
  12. Проверено на 1280×720, 1366×768, 1920×1080 при масштабировании Windows 100 %, 125 %, 150 % — критичные элементы управления не уходят за экран.
  13. Тесты: отрисовка идентичности, бейджа тарифа, нескольких корзин, отсутствующих полей квоты, неизвестного провайдера, неизвестного тарифа, длинного email, копирования OAuth URL, работы буфера обмена, цепочки маршрутизации, удаления одной карточки, независимости обновления A и B. Все UI-модули начинаются с pytest.importorskip("customtkinter").
  14. Полный pytest без новых падений; прогон в окружении без UI-зависимостей тоже зелёный; ruff check . чисто; release gate не ухудшен.

Проверка производительности

На тестовых данных из 50 аккаунтов изменить квоту одного и зафиксировать в отчёте количество уничтоженных и созданных виджетов до и после изменений. Ожидается обновление одной карточки, а не пересоздание пятидесяти.

Отчёт

CODEX_UI_REDESIGN_REPORT.md: BASE_SHA, FINAL_SHA, ветка, изменённые файлы, что переработано по экранам, что реально поддержано по идентичности/тарифам/квотам, результат замера производительности, точные команды и результат тестов (X passed / Y skipped / Z failed), известные ограничения и обязательный раздел «Backend gaps» — чего нельзя сделать одними изменениями UI.

Скриншоты основных экранов приложить, если возможно.


Главное

Интерфейс должен за несколько секунд отвечать на четыре вопроса: кто сейчас выполняет задачу, через какого провайдера, аккаунт и модель, сколько реального лимита осталось, и кто подхватит работу при недоступности исполнителя. Оптимизировать под ежедневное управление десятками аккаунтов, а не под красивый скриншот.