docs(task): reissue the UI redesign assignment against the published contract
Codex was handed Task A by mistake and duplicated the state-layer work that
Antigravity had already merged. This reissues its own scope, rebased on the
facts at 39b1f92: PHASE 1 is merged, docs/UI_STATE_CONTRACT.md now exists, and
the twelve backend gaps it declares are mapped to what the UI may and may not
render.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
39b1f928f4
commit
c6876e96b2
1 changed files with 149 additions and 0 deletions
149
agents/inbox/2026-08-21-B2-codex-ui-redesign-phase2.md
Normal file
149
agents/inbox/2026-08-21-B2-codex-ui-redesign-phase2.md
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
# Задание B2 (Codex): переработка интерфейса, фазы 2–6
|
||||
|
||||
## Дата поступления
|
||||
2026-08-21
|
||||
|
||||
## База
|
||||
Проверочный HEAD на момент выдачи: **`39b1f92`**, `origin/main` = `39b1f92`.
|
||||
Перед началом: `git fetch`, зафиксировать фактический `BASE_SHA`, **обязательно подтянуть `main`** — с момента вашей PHASE 1 в него вошло 8 коммитов.
|
||||
|
||||
## Ветка
|
||||
`codex/ui-redesign` — она отстала, начните с `git rebase origin/main` либо создайте новую от `origin/main`.
|
||||
|
||||
---
|
||||
|
||||
## Это заменяет предыдущее задание
|
||||
|
||||
Предыдущая выдача была ошибочной: вам передали Задание A (слой состояния), предназначенное Antigravity. Ту работу Antigravity уже выполнил и она влита в `main`. **Всё, что вы делали по слою состояния, не нужно** — не пытайтесь это дослать или смержить, оно конфликтует с влитым. Возьмите чистый `origin/main` и работайте только по этому документу.
|
||||
|
||||
---
|
||||
|
||||
## ГРАНИЦА РАБОТ
|
||||
|
||||
Antigravity продолжает Задание A (реальный сбор квот, релизная инфраструктура, остатки долгов). Разделение по файлам прежнее.
|
||||
|
||||
**Ваша зона:**
|
||||
```
|
||||
src/antigravity_provider/router/ui/**
|
||||
src/antigravity_provider/router/hermes_hub_app.py
|
||||
tests/test_ui_*.py
|
||||
```
|
||||
|
||||
**Чужая зона (НЕ трогать):**
|
||||
```
|
||||
src/antigravity_provider/router/*.py (state_store, unified_health, scheduler,
|
||||
event_bus, quota_collector, model_registry,
|
||||
router_engine, profile_manager, *_oauth, …)
|
||||
src/antigravity_provider/router/adapters/**
|
||||
src/antigravity_provider/*.py
|
||||
scripts/**, installer/**, config/**, legacy/**
|
||||
tests/** кроме tests/test_ui_*.py
|
||||
```
|
||||
|
||||
Не хватает данных для отрисовки — **не добавляйте сбор в UI**. Зафиксируйте в отчёте разделом «Backend gaps» и покажите честное отсутствие данных.
|
||||
|
||||
---
|
||||
|
||||
## Что уже сделано — не переделывать
|
||||
|
||||
**Ваша PHASE 1 влита** (`a7027b4`): дизайн-токены с семантическими ролями, уплотнённая типографика, библиотека компонентов (`PlanBadge`, `QuotaBar`, `QuotaBucketWidget`, `AccountCardWidget`, `AgentCardWidget`, `RouteTargetWidget`, `EmptyState`, `SearchField`, `FilterButton`, `ActionButton`, `IconButton`, `ConfirmDialog`, `Toast`, `ellipsize_text`, `Tooltip`). Стройте на них.
|
||||
|
||||
Одна правка в вашем тесте: `test_unknown_quota_is_supported_explicitly` сравнивал объект аннотации со строкой и не мог пройти — переписан через `typing.get_args`. Причина в том, что вы прогоняли тесты без `customtkinter`, где ваши UI-тесты **пропускаются**. Поставьте зависимости локально, иначе снова будете отчитываться о непроверенном.
|
||||
|
||||
**Сделано другими, не откатывать:**
|
||||
|
||||
- `hermes_hub_app.py` больше не передаёт `app_state` в `update_data`; все view защищены проверкой `isinstance(snapshot, HubSnapshot)` — это чинило краш при старте `'dict' object has no attribute 'readiness'`;
|
||||
- `add_account_wizard.py` — распаковка `start_profile_oauth` приведена к 3-кортежу `(session_id, auth_url, port)` и добавлено поле `self.oauth_port`. **Без этого подключение Antigravity-аккаунта не работает вовсе.** Если ваша ветка содержит старый двухэлементный вариант — при rebase возьмите версию из `main`;
|
||||
- `conftest.py` пропускает GUI-тесты только по маркеру `ui`, не по имени; модули с GUI-импортом обязаны иметь `pytest.importorskip("customtkinter")` на уровне модуля — это проверяется `tests/test_import_invariants.py`;
|
||||
- `scan_all()` из UI убран: все view уже принимают `snapshot` и не ходят в backend сами. Сохраните это свойство.
|
||||
|
||||
---
|
||||
|
||||
## Контракт данных
|
||||
|
||||
**`docs/UI_STATE_CONTRACT.md` опубликован** — это единственный источник правды о том, какие поля существуют. Раздел 7 «Backend gaps» перечисляет 12 пробелов; из них прямо влияют на вас:
|
||||
|
||||
| Пробел | Следствие для UI |
|
||||
|---|---|
|
||||
| Живых числовых квот **нет ни у одного провайдера**, все корзины `baseline` | Показывать как оценку; точные проценты не выдавать за измерение |
|
||||
| Разделение корзин Antigravity есть структурно, значения не измеряются | Отрисовать структуру, значения — с пометкой оценки |
|
||||
| Происхождение тарифа не доходит до `ProfileViewModel` | `PlanBadge` не показывать, пока поле не появится |
|
||||
| `AgentViewModel` не содержит активной сессии и квоты | В карточке агента эти строки — `Н/Д` либо отсутствуют |
|
||||
| `PipelineNode` не содержит идентичности аккаунта, состояния квоты и причины переключения | В цепочке маршрута показать то, что есть; остальное не выдумывать |
|
||||
| Большинство точечных событий объявлены, но никто их не публикует | Не рассчитывать на дельта-события; обновление по снапшоту |
|
||||
| Латентность, RPS, проценты ошибок, стоимость отсутствуют | Только `Н/Д` либо блок скрыт |
|
||||
|
||||
Если поле нужно, а его нет — это строка в вашем отчёте, а не повод достать данные самому.
|
||||
|
||||
---
|
||||
|
||||
## Область задачи
|
||||
|
||||
### PHASE 2 — Аккаунты и квоты (приоритет)
|
||||
|
||||
Экран уже на keyed-дельте (`self._cards[profile_id].update_from_model(...)`) — сохранить и достроить:
|
||||
|
||||
- **внутренний `quota_box` всё ещё пересоздаётся целиком** — перевести на `QuotaBucketWidget` со стабильным ключом и обновлением на месте;
|
||||
- идентичность аккаунта по контракту: email → username → provider user ID → внятный fallback; «Google account #1» недопустимо, если реальная идентичность есть;
|
||||
- мульти-корзинные квоты: сколько корзин отдал `QuotaSnapshot`, столько и показать, со своими метками и временем сброса; признак `is_estimated` — визуально явный;
|
||||
- компактный и развёрнутый режим карточки;
|
||||
- группировка по провайдерам со сворачиванием, поиск, фильтры по провайдеру/здоровью/роли;
|
||||
- удаление аккаунта затрагивает только его карточку.
|
||||
|
||||
### PHASE 3 — Обзор
|
||||
|
||||
Dashboard: состояние системы, число доступных провайдеров, подключённых аккаунтов, готовых ролей, предупреждения и ошибки, компактное представление активного маршрута, аккаунты с низкой квотой и с истёкшей авторизацией, последние реальные события журнала.
|
||||
|
||||
Всё, чего нет в контракте, — `Н/Д` или блок скрыт. Никаких «842 rps» и «99.98 %» из макетов.
|
||||
|
||||
### PHASE 4 — Команда
|
||||
|
||||
Иерархия «оркестратор → роли → агенты». Для агента: имя, роль, провайдер, аккаунт, модель, здоровье. Активная сессия и квота — по контракту отсутствуют, поэтому либо `Н/Д`, либо не показывать вовсе.
|
||||
|
||||
### PHASE 5 — Маршрутизация
|
||||
|
||||
Цепочка отказоустойчивости по ролям: основной → резерв 1 → 2 → 3, с активным узлом. Провайдер и модель есть; идентичность аккаунта, состояние квоты и причина переключения в `PipelineNode` отсутствуют — не выдумывать. Редактор оставить кнопочным/селекторным, drag-and-drop не делать.
|
||||
|
||||
### PHASE 6 — Второстепенные экраны
|
||||
|
||||
Единый стиль для состояния, журнала, настроек, «о программе», мастера и диалогов. `health_view`, `providers_view`, `routing_view`, `logs_view` пересоздают виджеты через `winfo_children()` + `destroy()` — перевести на обновление по ключу там, где список стабилен.
|
||||
|
||||
**Мастер подключения не ломать.** Работающие потоки: Antigravity OAuth, Codex OAuth, Codex API, OpenCode, Claude, Grok, вставка из буфера. Особенно бережно с `_init_antigravity_oauth` — он только что чинился.
|
||||
|
||||
---
|
||||
|
||||
## Ограничения
|
||||
|
||||
- Не переписывать на Tauri/React. Готовить архитектуру к разделению — да, мигрировать — нет.
|
||||
- Не удалять `router/ui` целиком ради переписывания заново; после каждой фазы приложение запускается.
|
||||
- Сеть, опрос OAuth, subprocess, сканирование диска — только в фоне, никогда в UI-потоке.
|
||||
- Секреты: не логировать токены и коды, ключи показывать маскированно.
|
||||
- Тег `v0.1.1` не создавать, релиз не публиковать, манифест не трогать.
|
||||
|
||||
---
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
1. Ни один файл чужой зоны не изменён: `git diff --name-only BASE_SHA..HEAD` не содержит путей из списка.
|
||||
2. Приложение запускается после каждой фазы; экран «Команда» открывается без ошибок.
|
||||
3. `quota_box` обновляется по ключу; изменение аккаунта A не перерисовывает карточку B; удаление затрагивает одну карточку.
|
||||
4. Идентичность аккаунта берётся по приоритету из контракта.
|
||||
5. Оценочные квоты визуально помечены; ни одно значение не подано как измерение провайдера.
|
||||
6. `PlanBadge` не отображается, пока происхождение тарифа не приходит в модель.
|
||||
7. Отсутствующие данные — `Н/Д` или скрытый блок; выдуманных метрик нет.
|
||||
8. Мастер: URL авторизации доступен и копируется до открытия браузера; все шесть потоков подключения работают; вставка из буфера работает.
|
||||
9. Ни один view не обращается к backend напрямую — только к переданному снапшоту.
|
||||
10. UI-тесты начинаются с `pytest.importorskip("customtkinter")`.
|
||||
11. Прогон **в обоих окружениях**: без UI-зависимостей и с установленными `customtkinter`, `pillow`, `psutil`. Оба зелёные. Отчёт содержит обе команды и оба результата.
|
||||
12. `ruff check .` чисто; release gate не ухудшен.
|
||||
|
||||
## Проверка производительности
|
||||
На 50 аккаунтах изменить квоту одного и зафиксировать в отчёте число уничтоженных и созданных виджетов до и после. Ожидается обновление одной карточки.
|
||||
|
||||
## Отчёт
|
||||
`CODEX_UI_REDESIGN_REPORT.md`: `BASE_SHA`, `FINAL_SHA`, ветка, изменённые файлы, переработанные экраны, что реально поддержано по идентичности/тарифам/квотам, замер производительности, точные команды и результаты **обоих** прогонов, известные ограничения и раздел «Backend gaps».
|
||||
|
||||
---
|
||||
|
||||
## Главное
|
||||
Интерфейс должен за несколько секунд отвечать: кто выполняет задачу, через какого провайдера, аккаунт и модель, сколько лимита осталось, кто подхватит при недоступности. Там, где данных нет, — честное «Н/Д». Пустое место лучше выдуманного числа.
|
||||
Loading…
Reference in a new issue