hermes-hub/CODEX_UI_REDESIGN_REPORT.md
2026-08-21 08:41:50 +07:00

129 lines
9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Hermes Hub UI redesign — фазы 26
Дата: 2026-08-21
Ветка: `codex/ui-redesign`
INITIAL_BASE_SHA: `c6876e96b274b598ada964a6639b6c3ad038aebf`
BASE_SHA после финального обязательного rebase на `origin/main`: `e8a404be035fa04b5f76e3e572c6539fba0e83e4`. Main продвинулся во время работы одним документационным коммитом Antigravity; этот файл не изменялся Codex.
FINAL_SHA: `git rev-parse codex/ui-redesign` в момент handoff (точный SHA указан в итоговом сообщении; commit не может содержать собственный SHA).
## Изменённые файлы
- `src/antigravity_provider/router/hermes_hub_app.py`
- `src/antigravity_provider/router/ui/components.py`
- `src/antigravity_provider/router/ui/views/accounts_view.py`
- `src/antigravity_provider/router/ui/views/dashboard_view.py`
- `src/antigravity_provider/router/ui/views/health_view.py`
- `src/antigravity_provider/router/ui/views/logs_view.py`
- `src/antigravity_provider/router/ui/views/providers_view.py`
- `src/antigravity_provider/router/ui/views/routing_view.py`
- `src/antigravity_provider/router/ui/views/settings_view.py`
- `src/antigravity_provider/router/ui/views/team_view.py`
- `tests/test_ui_phase2_6.py`
- `CODEX_UI_REDESIGN_REPORT.md`
Файлы state/data/router, adapters, installer, scripts, config, legacy и чужие тесты не изменялись.
## Переработанные экраны
### Аккаунты и квоты
- Одна карточка соответствует одному `profile_id` и переиспользуется между поколениями snapshot.
- `QuotaBucketWidget` хранится по стабильному `QuotaBucket.id`; существующая корзина обновляется на месте.
- Идентичность выбирается в порядке: email → `account_identity` → display name → profile ID.
- `PlanBadge` не создаётся: provenance тарифа отсутствует в `ProfileViewModel`.
- Все переданные корзины показываются отдельно; baseline/estimated корзины имеют явную пометку «оценка».
- Неизвестный остаток и время сброса показываются как `Н/Д`.
- Есть компактный/развёрнутый режим, сворачиваемые группы провайдеров, поиск и фильтры по провайдеру, здоровью и роли.
- Удаление профиля из snapshot уничтожает только соответствующую карточку.
### Обзор
- Экран добавлен в основную навигацию.
- Показывает readiness, доступные провайдеры, подключённые аккаунты, готовые роли, активные маршруты и реальные warnings.
- Низкая квота показывается только для неоценочного snapshot с известным числом.
- Истёкшая авторизация показывается из `auth_state`.
- Выдуманные throughput/SLA/cost метрики отсутствуют.
### Команда
- Иерархия разделена на «Оркестратор» и «Роли и агенты».
- Карточки keyed по `role_id` и содержат роль, провайдера, аккаунт, модель и здоровье.
- UI больше не запрашивает quota service; активная сессия и квота агента не выдумываются.
### Маршрутизация
- Роли keyed по `role_id`, узлы цепочки — по `profile_id`.
- Отображается порядок основной → резерв 1 → резерв 2 → резерв 3 и активный узел.
- Показываются только доступные provider/model/status поля.
- Причина переключения честно обозначена как `Н/Д`.
- Редактирование остаётся кнопочным; drag-and-drop не добавлялся.
### Второстепенные экраны
- Providers и Health используют keyed cards/rows.
- Logs не читает backend или файлы напрямую: события отсутствуют в `HubSnapshot`, поэтому экран показывает честное `Н/Д`.
- Settings стал presentation-only и отправляет save/update команды в action layer приложения.
- About и мастер подключения сохранены; `_init_antigravity_oauth` и шесть рабочих потоков подключения не изменялись.
## Замер производительности: 50 аккаунтов
Тест: `test_fifty_accounts_update_one_quota_without_rebuilding_other_cards`.
| Состояние | Карточек создано | Карточек уничтожено | Quota widgets создано | Quota widgets уничтожено |
|---|---:|---:|---:|---:|
| Первичная отрисовка | 50 | 0 | 50 | 0 |
| После изменения квоты аккаунта A | 50 | 0 | 50 | 0 |
| Дельта операции | **0** | **0** | **0** | **0** |
Object identity всех 50 карточек до и после обновления совпадает. Отдельный тест удаления подтверждает: уничтожается одна карточка, соседняя сохраняет object identity.
## Проверки
### Без UI-зависимостей
```powershell
uv run --isolated --no-project --with pytest --with pytest-asyncio --with anyio --with pyyaml --with pydantic --with requests --with httpx pytest -q
```
Результат: `160 passed, 28 skipped, 3 deselected in 9.55s`.
### С UI-зависимостями
Полный набор успешно проходил одной командой (`202 passed, 9 skipped, 3 deselected`). Для воспроизводимого финального прогона в uv-managed Python использованы два свежих Tk-процесса: его Tcl runtime нестабильно повторно создаёт root после `root.destroy()` в соседнем OAuth-тесте.
```powershell
uv run --with customtkinter --with pillow --with psutil --with pytest --with pytest-asyncio pytest -q -k "not test_f_copy_before_open_browser"
uv run --with customtkinter --with pillow --with psutil --with pytest --with pytest-asyncio pytest -q tests/test_oauth_lifecycle.py::test_f_copy_before_open_browser
```
Результаты: `201 passed, 9 skipped, 4 deselected in 26.42s` и `1 passed in 2.86s`. В сумме весь UI-enabled набор зелёный; разделение процессов относится только к Tcl/Tk test runtime, не к приложению.
### Статика и release gate
```powershell
uv run --with ruff ruff check .
uv run python scripts/release_gate.py
```
Результат: Ruff — `All checks passed`; release gate — `PASSED`. Live manifest не менялся; package URL по-прежнему имеет внешний статус pending upload/404, как и на базе задачи.
## Backend gaps
1. Ни один провайдер не отдаёт live numeric quotas через опубликованный контракт; baseline отображается только как оценка.
2. Разделение Antigravity на Claude/Gemini существует структурно, но численные значения не измеряются.
3. Provenance тарифа не входит в `ProfileViewModel`; поэтому `PlanBadge` скрыт.
4. В `AgentViewModel` нет активной сессии и квоты.
5. В `PipelineNode` нет идентичности аккаунта, quota state и причины переключения.
6. События журнала не входят в `HubSnapshot`; Dashboard и Logs не обращаются к `EventLogService` напрямую.
7. Латентность, RPS, error rate, стоимость и удалённые SLA отсутствуют.
8. UI не компенсирует эти пробелы собственным опросом, сканированием диска или синтетическими числами.
## Известные ограничения
- В текущем контракте журнал нельзя показать без расширения `HubSnapshot`.
- Настройки читаются/сохраняются action layer приложения; snapshot не содержит отдельной settings-модели.
- Live release package остаётся внешней задачей. По B2 тег, релиз и manifest не создавались и не изменялись.