docs(tasks): A11 и A12 — разделение работ между двумя исполнителями
A11 (Pro, тяжёлая ветка): интеграция с Hermes — перехват без роли, граница между учётными системами Hub и Hermes, токены Codex и безопасное переключение аккаунта, замена зонда обнаружения моделей на agy models, устранение выдуманного запасного списка в адаптере. A12 (Flash, быстрая ветка): компактные карточки аккаунтов, разбор дублирующих разделов «Провайдеры»/«Квоты», причина у каждого Н/Д, тест на достижимость службы обнаружения моделей, живое подключение Grok. Заданы строгие непересекающиеся списки файлов, чтобы параллельная работа не дала конфликтов. В A12 порядок работы с git расписан пошагово: pull в начале, push ветки сразу после первого коммита, обязательная проверка финального push через git log origin/<ветка>. A10 удалено — заменено этой парой. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
cdfd9f1c8d
commit
78cd826624
3 changed files with 472 additions and 178 deletions
|
|
@ -1,178 +0,0 @@
|
||||||
# Задание A10 (Antigravity): всё оставшееся — backend и интерфейс
|
|
||||||
|
|
||||||
## Дата поступления
|
|
||||||
2026-08-23
|
|
||||||
|
|
||||||
## База
|
|
||||||
Проверочный HEAD на момент выдачи: **`0165434`**. Обязательно обновить локальную копию — см. следующий раздел.
|
|
||||||
|
|
||||||
## Ветка
|
|
||||||
`antigravity/all-remaining`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Главное изменение: границы зон больше нет
|
|
||||||
|
|
||||||
У Codex закончились лимиты. **Вся работа переходит к вам, включая интерфейс.** Прежнее ограничение «зона Codex — `router/ui/**`, не трогать» **снимается**: теперь `src/antigravity_provider/router/ui/**` и `tests/test_ui_*.py` ваши.
|
|
||||||
|
|
||||||
Из этого следует требование, которого раньше не было: вы отвечаете и за то, чтобы интерфейс не врал. Правило честности распространяется на экран целиком — ни одного числа, идентификатора или названия модели без измерения.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Перед началом: обновить локальную копию
|
|
||||||
|
|
||||||
Ваш отчёт по A9 назвал базой `6494c51`. С тех пор в `main` вошли: исправление плагина (`2d62d39`), дополнение задания A9 и **влитая частичная работа Codex по B8** (`0165434`).
|
|
||||||
|
|
||||||
```
|
|
||||||
cd <каталог репозитория>; git fetch origin --prune; git status
|
|
||||||
git checkout main; git reset --hard origin/main
|
|
||||||
```
|
|
||||||
|
|
||||||
Зафиксировать фактический `BASE_SHA` через `git rev-parse --short HEAD`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## О статусе A9
|
|
||||||
|
|
||||||
Отчёт по A9 получен и прочитан. **Ни одной строки этой работы в репозитории нет.** Проверено: ветки `antigravity/quotas-models-migration` на `origin` не существует, ни в одной ветке нет ни `model_discovery_service.py`, ни `test_a9_migration_quotas_models.py`, ни миграции в `router_config.py`.
|
|
||||||
|
|
||||||
Работа осталась на вашей машине. Это уже второй такой случай в проекте: ветка Codex сутки лежала только локально, пока её не отправили в git.
|
|
||||||
|
|
||||||
**Первое действие по этому заданию — отправить готовую работу A9 в `origin`**, до всякой новой правки:
|
|
||||||
|
|
||||||
```
|
|
||||||
git push origin antigravity/quotas-models-migration
|
|
||||||
```
|
|
||||||
|
|
||||||
Ветка в `origin` ничего не ломает и никого не обязывает. Несохранённая работа теряется вместе с диском.
|
|
||||||
|
|
||||||
Пока код не в репозитории, приёмки быть не может: проверка идёт **исполнением, а не по отчёту**, и это не формальность. По A8 отчёт назвал сделанными четыре вещи, из которых ни одна у владельца не работала: профили claude/grok не дошли до существующего конфига, проверка просрочки была написана с опечаткой в имени ключа и не срабатывала ни разу, пересобранный установщик остался на вашей машине из-за `.gitignore`, флаг `/reinstall` не использовался в коде вообще.
|
|
||||||
|
|
||||||
Два числа из отчёта A9, которые нужно объяснить при сдаче:
|
|
||||||
|
|
||||||
- **«218 passed, 29 skipped»**. На `main` в venv Hermes набор даёт **290 passed, 2 skipped**. Двадцать девять пропусков означают, что UI-тесты в вашем окружении не выполнялись — то есть прогон не был полным. Требуется прогон в окружении **с** `customtkinter`, `pillow`, `psutil`.
|
|
||||||
- **«Release Gate 7/7 PASSED»**. Замер на чистом `main` даёт **FAILED**: проверка 4 (полный офлайн-прогон pytest) падает. Если у вас гейт зелёный — покажите, чем отличается окружение, либо приложите правку, которая его чинит.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## P0-1. Довести A9 до репозитория и проверяемого состояния
|
|
||||||
|
|
||||||
Всё содержание задания A9 остаётся в силе без изменений — миграция конфигурации, квоты остальных провайдеров, служба обнаружения моделей, отказ от выдуманных моделей, устойчивый порядок провайдеров, флаги установщика, доставка установщика. Читайте A9 как часть этого задания.
|
|
||||||
|
|
||||||
Добавляются два пункта из дополненного A9, которые ваш отчёт не покрывает, потому что писался до них:
|
|
||||||
|
|
||||||
- **P0-00 — Hub перехватывает каждый вызов Hermes как `orchestrator`.** Следствие устранено ревьюером; от вас — причина: не претендовать на вызов, если роль не определена достоверно; описать границу между учётными системами Hub и Hermes в контракте; подготовить варианты связывания профилей с ценой каждого.
|
|
||||||
- **P0-01 — обновление токена Codex и безопасное переключение аккаунта** по образцу Cockpit Tools: раздельная проверка `access_token` и `id_token`, обновление по `refresh_token`, остановка клиента **до** подмены учётных данных.
|
|
||||||
|
|
||||||
## P0-2. Обязательный контракт службы обнаружения моделей
|
|
||||||
|
|
||||||
Расхождение, которое сломает выбор моделей молча, и оно уже в коде.
|
|
||||||
|
|
||||||
Codex в `ui/model_catalog.py` импортирует:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from antigravity_provider.router.model_discovery import ModelDiscoveryService
|
|
||||||
```
|
|
||||||
|
|
||||||
Ваш отчёт называет модуль `model_discovery_service.py`. Импорт обёрнут в `except (ImportError, AttributeError, TypeError): return None`, поэтому при несовпадении имени **ошибки не будет** — интерфейс просто всегда покажет «Список моделей ещё не получен».
|
|
||||||
|
|
||||||
Проверено на текущем `main`: каталог возвращает `models=()`, `is_stale=True`, причина «Список моделей ещё не получен». Выбор модели подключён и пуст.
|
|
||||||
|
|
||||||
**Контракт фиксируется:**
|
|
||||||
|
|
||||||
- модуль: `src/antigravity_provider/router/model_discovery.py`
|
|
||||||
- класс: `ModelDiscoveryService`
|
|
||||||
- получение экземпляра: classmethod `get()`
|
|
||||||
- чтение для интерфейса: поля `models`, `fetched_at`, `is_stale`, `unavailable_reason`
|
|
||||||
|
|
||||||
Если у вас модуль назван иначе — переименовать либо добавить `model_discovery.py` точкой входа.
|
|
||||||
|
|
||||||
**Тест обязателен, и он должен падать при несовпадении пути.** Защитный `except ImportError` уместен в бою, но он же прячет несобранную интеграцию: тест обязан отличать «службы нет» от «служба есть, но импорт не тот».
|
|
||||||
|
|
||||||
## P0-3. Компактные карточки аккаунтов
|
|
||||||
|
|
||||||
Codex до этого не дошёл — `accounts_view.py` не менялся.
|
|
||||||
|
|
||||||
Жалобы владельца: **«аккаунты должны выглядеть как у кокпит тулс, компактно»**, **«вид не тот, не надо делать раскрывающееся окно»**, **«в аккаунтах квота так и не отображается»**.
|
|
||||||
|
|
||||||
Требуется:
|
|
||||||
|
|
||||||
- плотный список фиксированной высоты: провайдер, идентичность, роль, состояние авторизации, квота — одной строкой, без раскрытия;
|
|
||||||
- квота видна сразу, числом и полосой, **с указанием пула и периода**: у Antigravity четыре пула, и «просто процент» вводит в заблуждение. Данные уже есть и настоящие — на живых аккаунтах владельца приходят измеренные значения от провайдера (`ag-w2` — 37.4% остатка недельного пула Claude/GPT, `source=provider_api`);
|
|
||||||
- шестнадцать аккаунтов читаются без прокрутки внутрь карточек;
|
|
||||||
- **дельта-отрисовку по стабильным ключам не терять** — изменение одного аккаунта не должно перерисовывать остальные. Это главное преимущество текущей версии, и в `COCKPIT_TOOLS_ARCHITECTURE_COMPARISON.md` описано, почему: при пересборке всех карточек на 50 аккаунтах выходит больше тысячи операций с виджетами в UI-потоке.
|
|
||||||
|
|
||||||
Документ в корне репозитория — архитектурное сравнение, а не макет. Берите из него принцип обновления и плотность, не буквальную вёрстку.
|
|
||||||
|
|
||||||
## P0-4. Разобрать дублирующие разделы
|
|
||||||
|
|
||||||
Codex до этого не дошёл — `quotas_view.py` не менялся.
|
|
||||||
|
|
||||||
Жалоба: **«провайдеры и квоты и лимиты вообще не понятно для чего нужны, там всё то же, что и в аккаунты»**.
|
|
||||||
|
|
||||||
Владелец прав: после появления квот в карточках аккаунтов отдельный раздел квот потерял смысл. Нужно решение, а не сохранение обоих на всякий случай.
|
|
||||||
|
|
||||||
- **«Квоты и лимиты»** — убрать из навигации либо оставить только то, чего нет в «Аккаунтах»: сводка по провайдеру целиком, история расхода, ближайшие сбросы.
|
|
||||||
- **«Провайдеры»** — оставить относящееся к провайдеру, а не к аккаунту: доступность runtime, обнаруженные модели, версия CLI, состояние авторизации в целом.
|
|
||||||
|
|
||||||
В отчёте перечислить перенесённое и удалённое. Пустой раздел не оставлять.
|
|
||||||
|
|
||||||
## P0-5. Причина у каждого Н/Д
|
|
||||||
|
|
||||||
Жалоба: **«что означает н/д в маршрутизация запросов»**.
|
|
||||||
|
|
||||||
Codex закрыл это частично: `unavailable_reason` используется в `components.py` и на «Обзоре», но не везде.
|
|
||||||
|
|
||||||
Везде, где стоит `Н/Д`, должна быть доступна причина — подсказкой при наведении и текстом рядом, если место позволяет. Формулировки конкретные: «нет телеметрии: роль ещё не вызывалась», «провайдер не отдаёт лимиты», «аккаунт не подключён». Данные для этого есть.
|
|
||||||
|
|
||||||
## P1-6. Подключение Grok и Claude довести до конца
|
|
||||||
|
|
||||||
После миграции конфигурации (A9 P0-0.1) слоты для Grok и Claude появятся, и мастер перестанет упираться в «свободный слот не найден». Но проверить нужно весь путь целиком, а не только `find_free_slot`: подключение, назначение роли, появление в маршрутизации, тест профиля.
|
|
||||||
|
|
||||||
Жалоба владельца была **«при подключении грока ошибка»** — принимается только пройденный вживую сценарий со скриншотами.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Что уже принято и не подлежит переделке
|
|
||||||
|
|
||||||
Проверено исполнением, работает — не откатывать при слиянии:
|
|
||||||
|
|
||||||
- **живые квоты Antigravity**: настоящий опрос `retrieveUserQuotaSummary` с обновлением OAuth-токена при 401, шесть аккаунтов владельца отдают разные измеренные числа;
|
|
||||||
- **правка плагина `2d62d39`**: при `router_error` вызов уходит вниз по цепочке, а не подменяет ответ модели; закрыта тестом `tests/test_plugin_passthrough.py`;
|
|
||||||
- **`_finish` мастера**: `destroy()` выполняется всегда, ранние `return` показывают ошибку в самом окне;
|
|
||||||
- **из работы Codex по B8**: выбор модели (`model_catalog.py`), кликабельная карточка целиком, окно настроек роли `_open_agent_settings_modal`, снятая правая панель, устранённые срезы `providers[:3]` и `agents[:5]`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Ограничения
|
|
||||||
|
|
||||||
- Границы зон нет — весь репозиторий ваш. Ответственность за честность интерфейса теперь тоже ваша.
|
|
||||||
- Не выдумывать числа, идентификаторы и названия моделей. Нет данных — `None` в модели, `Н/Д` с причиной на экране.
|
|
||||||
- Три темы сохранить, дельта-отрисовку не терять.
|
|
||||||
- Мастер не ломать: шесть потоков подключения, трёхэлементная распаковка `start_profile_oauth`, `destroy()` в `_finish` всегда.
|
|
||||||
- Сеть и подпроцессы — не в UI-потоке. Замерено: `agy models` в одном прогоне отвечает за 40 секунд, в следующем висит больше двух минут.
|
|
||||||
- Тег `v0.1.1` не создавать.
|
|
||||||
- **Ветку пушить сразу после первого коммита.**
|
|
||||||
|
|
||||||
## Критерии приёмки
|
|
||||||
|
|
||||||
1. Работа A9 находится в `origin` и проверяема исполнением.
|
|
||||||
2. Прогон в окружении **с** UI-зависимостями; число пропусков объяснено; обе команды и оба результата в отчёте.
|
|
||||||
3. Состояние релизного гейта названо до и после; расхождение с замером ревьюера объяснено.
|
|
||||||
4. Служба обнаружения моделей доступна по согласованному пути; тест падает при несовпадении импорта; выбор модели в интерфейсе показывает настоящий список.
|
|
||||||
5. Карточка аккаунта компактна, фиксированной высоты, без раскрытия; квота видна сразу с указанием пула и периода; шестнадцать аккаунтов без внутренней прокрутки; дельта-отрисовка сохранена и проверена тестом.
|
|
||||||
6. Принято решение по «Провайдерам» и «Квотам»; перенесённое и удалённое перечислено.
|
|
||||||
7. У каждого `Н/Д` доступна причина.
|
|
||||||
8. Вызов без достоверной роли уходит вниз, не тратя попыток роутера; правка `2d62d39` сохранена.
|
|
||||||
9. Граница между учётными системами Hub и Hermes описана в контракте; варианты связывания профилей — с ценой каждого, без односторонней реализации.
|
|
||||||
10. Grok и Claude подключаются вживую: подключение, роль, маршрутизация, тест профиля — со скриншотами.
|
|
||||||
11. `ruff check .` чисто.
|
|
||||||
12. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, точный `X passed / Y skipped / Z failed`.
|
|
||||||
13. **Скриншоты живого сценария с настоящими данными.** Пустых состояний не присылать.
|
|
||||||
|
|
||||||
## Главное
|
|
||||||
|
|
||||||
Владелец сказал: «надо чтобы хаб уже заработал». Ядро работает, квоты Antigravity настоящие, интерфейс наполовину доведён. Осталось закрыть остаток и, что важнее всего, **довести сделанное до репозитория** — работа, лежащая на одной машине, для продукта не существует.
|
|
||||||
|
|
||||||
## Порядок сдачи
|
|
||||||
Передать точный `FINAL_COMMIT_SHA`.
|
|
||||||
252
agents/inbox/2026-08-23-A11-antigravity-pro-integration.md
Normal file
252
agents/inbox/2026-08-23-A11-antigravity-pro-integration.md
Normal file
|
|
@ -0,0 +1,252 @@
|
||||||
|
# Задание A11 (Antigravity Pro, этот ПК): интеграция с Hermes и учётные данные
|
||||||
|
|
||||||
|
## Дата поступления
|
||||||
|
2026-08-23
|
||||||
|
|
||||||
|
## База
|
||||||
|
Проверочный HEAD на момент выдачи: **`cdfd9f1`**.
|
||||||
|
|
||||||
|
## Ветка
|
||||||
|
`antigravity/hermes-integration`
|
||||||
|
|
||||||
|
## Кому
|
||||||
|
Тяжёлая ветка работ: разбор чужого кода, обратная разработка эндпоинтов, проектные решения. Механических правок здесь нет.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Порядок работы с git
|
||||||
|
|
||||||
|
**В начале — обновить локальную копию:**
|
||||||
|
|
||||||
|
```
|
||||||
|
cd <каталог репозитория>; git fetch origin --prune; git status
|
||||||
|
git checkout main; git pull --ff-only origin main
|
||||||
|
git checkout -b antigravity/hermes-integration
|
||||||
|
```
|
||||||
|
|
||||||
|
Зафиксировать фактический `BASE_SHA` через `git rev-parse --short HEAD`. Не считать `cdfd9f1` актуальным автоматически — параллельно идёт задание A12.
|
||||||
|
|
||||||
|
**Ветку отправить в `origin` сразу после первого коммита**, не дожидаясь готовности:
|
||||||
|
|
||||||
|
```
|
||||||
|
git push -u origin antigravity/hermes-integration
|
||||||
|
```
|
||||||
|
|
||||||
|
**В конце — обязательный push:**
|
||||||
|
|
||||||
|
```
|
||||||
|
git push origin antigravity/hermes-integration
|
||||||
|
```
|
||||||
|
|
||||||
|
Работа, которой нет в `origin`, для проекта не существует: проверка идёт исполнением, а не по отчёту.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Параллельная работа: строгая граница по файлам
|
||||||
|
|
||||||
|
Одновременно выполняется **A12** вторым исполнителем.
|
||||||
|
|
||||||
|
**Ваши файлы:**
|
||||||
|
|
||||||
|
```
|
||||||
|
src/antigravity_provider/hermes_plugin.py
|
||||||
|
src/antigravity_provider/router/router_engine.py
|
||||||
|
src/antigravity_provider/router/codex_oauth.py
|
||||||
|
src/antigravity_provider/router/profile_manager.py
|
||||||
|
src/antigravity_provider/router/quota_collector.py
|
||||||
|
src/antigravity_provider/router/adapters/**
|
||||||
|
src/antigravity_provider/agy_subprocess.py
|
||||||
|
docs/UI_STATE_CONTRACT.md
|
||||||
|
tests/test_integration_*.py (новые файлы)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Не ваши** (зона A12): `router/ui/**`, `router/model_discovery.py`, `router/model_discovery_service.py`, `router/router_config.py`, `installer/**`, `tests/test_ui_*.py`.
|
||||||
|
|
||||||
|
Понадобился чужой файл — скажите, будет заказан. Молча не трогать: в проекте уже был случай, когда два исполнителя переписали один файл и слияние дало конфликт в двух местах.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Что принято по A9
|
||||||
|
|
||||||
|
Проверено исполнением на живой машине владельца — работа хорошая:
|
||||||
|
|
||||||
|
- **миграция конфигурации работает**: 16 → 22 профиля, `claude` и `grok` получили по три слота, `find_free_slot` возвращает существующие профили по всем пяти провайдерам. Это снимает корень жалобы «при подключении грока ошибка»;
|
||||||
|
- резервная копия `router_profiles.yaml.bak_<ts>` создаётся, **десять профилей antigravity не изменены ни в одном поле**, комментарии не потеряны;
|
||||||
|
- квоты `grok` и `opencode-go` честно отдают `None` с причиной вместо правдоподобных чисел;
|
||||||
|
- флаг `/repair` и `/reinstall` задействован, предупреждение CS0219 исчезло;
|
||||||
|
- граница зоны Codex не нарушена, правка плагина `2d62d39` сохранена.
|
||||||
|
|
||||||
|
**Исправлено ревьюером при слиянии** — переделывать не нужно, но знать полезно:
|
||||||
|
|
||||||
|
1. Служба обнаружения моделей была **недостижима**. Создан `model_discovery_service.py`, а интерфейс импортирует `model_discovery`. Импорт обёрнут в `except ImportError`, поэтому расхождение не давало ошибки — выбор моделей просто оставался пустым навсегда. Добавлена согласованная точка входа.
|
||||||
|
2. Служба отдаёт `discovered_at`, каталог искал `fetched_at`. Сведено.
|
||||||
|
3. Тест `test_ui_routing_graph.py` закреплял выдуманный список `grok-3`; вы верно убрали литералы, и тест начал падать. Приведён к честному поведению.
|
||||||
|
|
||||||
|
Урок на будущее: **защитный `except ImportError` прячет несобранную интеграцию.** Когда пишете модуль для чужого потребителя — согласуйте путь и проверьте импорт исполнением, а не глазами.
|
||||||
|
|
||||||
|
Два числа из отчёта A9, которые не сошлись: «218 passed, 29 skipped» против **307 passed, 2 skipped** на слитом `main`, и «Release Gate 7/7 PASSED» против **FAILED** в моём замере. Двадцать девять пропусков означают, что UI-тесты у вас не выполнялись. Прогон обязателен в окружении **с** `customtkinter`, `pillow`, `psutil`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## P0-1. Hub перехватывает каждый вызов Hermes и назначает ему роль `orchestrator`
|
||||||
|
|
||||||
|
Самое важное в задании.
|
||||||
|
|
||||||
|
Владелец сообщил: «зашёл в Гермеса, а там наш хаб не работает, основной оркестратор не выбрался», и заключил, что Hub к Hermes не привязан. Заключение неверное, положение хуже: **Hub привязан и активно ломал Hermes.**
|
||||||
|
|
||||||
|
Установлено разбором кода Hermes и его журналов:
|
||||||
|
|
||||||
|
1. Плагин регистрируется штатно. `hermes_cli/plugins.py:4789` берёт `register` у модуля, корневой `__init__.py` его экспортирует, `ctx.register_middleware("llm_execution", …)` — допустимое имя (`hermes_cli/middleware.py:23`). Перехватчик **срабатывает на каждом обращении к модели**, это видно в трейсбеке `agent.log`.
|
||||||
|
|
||||||
|
2. **Hermes не передаёт роль.** `agent/conversation_loop.py:2950` передаёт `task_id`, `turn_id`, `api_request_id`, `session_id`, `platform`, `model`, `provider`, `base_url`, `api_mode`, `api_call_count`. Ключа `role` нет.
|
||||||
|
|
||||||
|
3. `resolve_role` доходит до последней строки и возвращает `config.default_role`. **Каждый вызов Hermes идёт как `orchestrator`.**
|
||||||
|
|
||||||
|
4. Цепочка `orchestrator` у владельца исчерпана целиком:
|
||||||
|
|
||||||
|
```
|
||||||
|
ag-orch-fallback skipped_unhealthy
|
||||||
|
codex-orch 429: Your account is not active, please check your billing details
|
||||||
|
opengo-3 No API key found for OpenCode Go profile 'opengo-3'
|
||||||
|
ag-w1, ag-w3 Antigravity error: agy error: authentication failed or timed out
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Роутер возвращал «⚠️ Hermes Router Failover Exhausted» **как ответ ассистента**, и Hermes показывал это вместо ответа модели, хотя его собственный провайдер работал.
|
||||||
|
|
||||||
|
Следствие устранено ревьюером (`2d62d39`): при `router_error` вызов уходит вниз через `next_call`, отказ пишется в журнал уровнем `warning`. Закрыто тестом `tests/test_plugin_passthrough.py`. **Правку не откатывать.**
|
||||||
|
|
||||||
|
Принцип, который она закрепляет: **плагин может улучшить маршрутизацию, но не имеет права сделать Hermes хуже, чем без него.**
|
||||||
|
|
||||||
|
**От вас — причина.** Сейчас Hub на каждом вызове Hermes сначала пробует цепочку `orchestrator`: лишняя задержка и расход квоты не той роли даже там, где пропуск сработал верно.
|
||||||
|
|
||||||
|
1. **Определить роль честно.** Разобрать, что из переданного Hermes пригодно как признак: `task_id`, `session_id`, `platform`, `model`, `provider`. Надёжного признака нет — **не угадывать**. Эвристика в `resolve_role`, ищущая в системном сообщении подстроки «developer», «coding agent», «review agent», — это гадание по тексту промпта, и оно тоже подлежит пересмотру.
|
||||||
|
|
||||||
|
2. **Не претендовать на вызов без роли.** Роль не определена достоверно — пропускать вниз сразу, не тратя попыток. Роль по умолчанию для внешнего перехвата — неверная модель поведения.
|
||||||
|
|
||||||
|
**Тесты:** вызов без определяемой роли уходит вниз, не тратя попыток роутера; вызов с определённой ролью маршрутизируется; отказ цепочки никогда не возвращается как ответ ассистента.
|
||||||
|
|
||||||
|
## P0-2. Граница между учётными системами Hub и Hermes
|
||||||
|
|
||||||
|
Владелец прав по существу: Hub профилями Hermes не управляет.
|
||||||
|
|
||||||
|
Hermes ведёт собственные профили в каталоге `profiles` своего домашнего каталога:
|
||||||
|
|
||||||
|
```
|
||||||
|
agy-01 … agy-06, worker-fast, worker-research, worker-review,
|
||||||
|
worker-code, worker-code-2, deepseek
|
||||||
|
```
|
||||||
|
|
||||||
|
и настраивает `delegate_task` отдельно (`max_concurrent_children=3`, `provider=opencode-go`, `model=kimi-k2.7-code`).
|
||||||
|
|
||||||
|
Профили Hub — `ag-w1`, `ag-orch-fallback`, `codex-orch`, `opengo-*` — **другое множество идентификаторов**. Один и тот же аккаунт Google живёт в двух учётных системах под разными именами.
|
||||||
|
|
||||||
|
**Требуется:**
|
||||||
|
|
||||||
|
1. Раздел в `docs/UI_STATE_CONTRACT.md`: что Hub видит от Hermes, чего не видит, чем управляет и чем не управляет. Без этого интерфейс, показывающий «команду агентов», вводит владельца в заблуждение — он видит роли, которых Hermes не спрашивает.
|
||||||
|
|
||||||
|
2. **Варианты связывания профилей с оценкой цены каждого:** сопоставление по идентичности аккаунта (email из `id_token`), чтение профилей Hermes как источника, либо явная таблица соответствия. **Решение принимает владелец — вам подготовить варианты, не реализовывать молча.**
|
||||||
|
|
||||||
|
## P0-3. Codex: обновление токена и безопасное переключение аккаунта
|
||||||
|
|
||||||
|
Владелец прислал, как это делает Cockpit Tools, и просит так же:
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Прочитать данные аккаунта access_token · id_token · refresh_token
|
||||||
|
2. Проверить access_token действителен до 28.08, обновление не требуется
|
||||||
|
3. Проверить id_token истёк 5 дней назад — нужно обновление
|
||||||
|
4. Обновить данные входа полный набор обновлён и сохранён
|
||||||
|
5. Остановить прежний процесс безопасная остановка ChatGPT/Codex и app-server
|
||||||
|
6. Записать данные клиента
|
||||||
|
7. Синхронизировать настройки
|
||||||
|
8. Запустить клиент Codex
|
||||||
|
```
|
||||||
|
|
||||||
|
Ключевое: токены проверяются **по отдельности**, и клиент останавливается **до** подмены учётных данных.
|
||||||
|
|
||||||
|
В отчёте A9 упомянуты токены Codex, но проверить это исполнением не удалось: у профилей Codex на машине владельца нет авторизации. Поэтому пункт остаётся открытым и должен быть закрыт **тестами**, а не только кодом:
|
||||||
|
|
||||||
|
1. Обновление токена по `refresh_token` с сохранением полного набора и понятной ошибкой, когда `refresh_token` отсутствует или отвергнут.
|
||||||
|
2. Раздельная проверка срока `access_token` и `id_token` с запасом по времени; в статусе профиля видно, что именно просрочено.
|
||||||
|
3. Переключение аккаунта как наблюдаемая последовательность: остановка клиента → запись учётных данных → синхронизация → запуск. Каждый шаг сообщает о себе, чтобы интерфейс (зона A12) показал прогресс.
|
||||||
|
4. Сбой на любом шаге не оставляет промежуточного состояния: либо переключено полностью, либо возврат к прежнему.
|
||||||
|
|
||||||
|
**Тесты:** просроченный `access_token` при живом `refresh_token` обновляется без повторного входа; отсутствие `refresh_token` даёт понятную ошибку, а не молчаливый провал; прерывание на середине не оставляет смешанных учётных данных.
|
||||||
|
|
||||||
|
## P0-4. Обнаружение моделей Antigravity устроено неверно
|
||||||
|
|
||||||
|
Служба кэширования из A9 работает, но зонд для Antigravity не возвращает ничего. Проверено:
|
||||||
|
|
||||||
|
```
|
||||||
|
discover_models failed: agy.exe -p x --model __invalid_probe__ ... timed out after 20 seconds
|
||||||
|
обнаружено моделей: 0
|
||||||
|
```
|
||||||
|
|
||||||
|
`agy_subprocess.py:122` запускает `agy` с **заведомо неверной моделью** и разбирает текст ошибки, надеясь выудить из неё список. Это отказало: команда просто виснет на 20 секунд.
|
||||||
|
|
||||||
|
При этом у CLI есть штатная команда. Проверено вручную — `agy models` возвращает четырнадцать настоящих моделей, разделитель табуляция:
|
||||||
|
|
||||||
|
```
|
||||||
|
gemini-3.7-flash-high Gemini 3.7 Flash (High)
|
||||||
|
gemini-3.1-pro-high Gemini 3.1 Pro (High)
|
||||||
|
claude-sonnet-4-6 Claude Sonnet 4.6 (Thinking)
|
||||||
|
gpt-oss-120b-medium GPT-OSS 120B (Medium)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Требуется** заменить зонд на `agy models` с разбором табулированного вывода.
|
||||||
|
|
||||||
|
Осторожно с таймаутом: **та же команда в одном прогоне отвечает за 40 секунд, а в следующем висит больше двух минут.** Это замерено, не предположение. Жёсткий таймаут обязателен, при его срабатывании прежний кэш сохраняется.
|
||||||
|
|
||||||
|
Заодно убрать выдуманный запасной список в `antigravity_adapter.py:144`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
return list(profile.preferred_models or ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.5-flash-thinking"])
|
||||||
|
```
|
||||||
|
|
||||||
|
Моделей `gemini-2.5-*` у провайдера **не существует** — настоящие начинаются с `gemini-3`. Это тот же класс дефекта, из-за которого в конфигурацию владельца попал несуществующий `gemini-3.7-flash`, стоящий сейчас у роли `orchestrator` как `default_model`. Нет обнаруженного списка — возвращать пустой.
|
||||||
|
|
||||||
|
**Тест:** зонд возвращает непустой список на подготовленном выводе `agy models`; при таймауте прежний кэш не затирается; запасного литерала в адаптере нет.
|
||||||
|
|
||||||
|
## P1-5. Квоты: `source` не должен опережать данные
|
||||||
|
|
||||||
|
Мелочь, но она из того же семейства, с которым боремся весь проект:
|
||||||
|
|
||||||
|
```
|
||||||
|
opencode-go:opengo-1 source=provider_api
|
||||||
|
Общий 5 часов / Недельный / Месячный: remaining=None
|
||||||
|
```
|
||||||
|
|
||||||
|
`source="provider_api"` заявляет измерение, которого не было — все корзины пусты. Либо `source="baseline"`, когда чисел нет, либо отдельное поле, различающее «провайдер ответил, но лимитов не даёт» и «провайдер не ответил». Причина уже пишется правильно, расходится только `source`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Что принято и переделке не подлежит
|
||||||
|
|
||||||
|
Не откатывать при слиянии:
|
||||||
|
|
||||||
|
- живые квоты Antigravity (`retrieveUserQuotaSummary` с обновлением токена при 401): шесть аккаунтов владельца отдают разные измеренные числа;
|
||||||
|
- правка плагина `2d62d39` и тест `tests/test_plugin_passthrough.py`;
|
||||||
|
- `_finish` мастера: `destroy()` выполняется всегда;
|
||||||
|
- исправление `is_expired` в `do_test_profile`;
|
||||||
|
- миграция конфигурации из A9 и точка входа `model_discovery.py`.
|
||||||
|
|
||||||
|
## Ограничения
|
||||||
|
|
||||||
|
- Строгая граница по файлам — см. выше.
|
||||||
|
- Никаких чисел, идентификаторов и названий моделей без измерения.
|
||||||
|
- Сеть и подпроцессы — не в UI-потоке.
|
||||||
|
- Тег `v0.1.1` не создавать.
|
||||||
|
|
||||||
|
## Критерии приёмки
|
||||||
|
|
||||||
|
1. Ветка в `origin`. Ни один файл зоны A12 не изменён.
|
||||||
|
2. Вызов без достоверно определённой роли уходит вниз, не тратя попыток роутера; отказ цепочки никогда не возвращается как ответ ассистента; правка `2d62d39` сохранена.
|
||||||
|
3. Граница между учётными системами Hub и Hermes описана в контракте; варианты связывания профилей поданы с ценой каждого, без односторонней реализации.
|
||||||
|
4. Токен Codex обновляется по `refresh_token`; переключение останавливает клиент до подмены учётных данных и не оставляет промежуточного состояния; закрыто тестами.
|
||||||
|
5. `agy models` используется как зонд; обнаружение возвращает непустой список; при таймауте кэш сохраняется; выдуманного запасного списка в адаптере нет.
|
||||||
|
6. `source` квоты не заявляет измерения там, где чисел нет.
|
||||||
|
7. Прогон **в окружении с UI-зависимостями**; число пропусков объяснено. На `main` набор даёт 307 passed, 2 skipped.
|
||||||
|
8. `ruff check .` чисто. Релизный гейт: назвать состояние до и после, объяснить расхождение с замером ревьюера; ухудшать нельзя.
|
||||||
|
9. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, точный `X passed / Y skipped / Z failed`.
|
||||||
|
|
||||||
|
## Порядок сдачи
|
||||||
|
Передать точный `FINAL_COMMIT_SHA`. **Сдано только после появления ветки в `origin`.**
|
||||||
220
agents/inbox/2026-08-23-A12-antigravity-flash-interface.md
Normal file
220
agents/inbox/2026-08-23-A12-antigravity-flash-interface.md
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
# Задание A12 (Antigravity Flash, другой ПК): интерфейс и чистка разделов
|
||||||
|
|
||||||
|
## Дата поступления
|
||||||
|
2026-08-23
|
||||||
|
|
||||||
|
## База
|
||||||
|
Проверочный HEAD на момент выдачи: **`cdfd9f1`**.
|
||||||
|
|
||||||
|
## Ветка
|
||||||
|
`antigravity/interface-cleanup`
|
||||||
|
|
||||||
|
## Кому
|
||||||
|
Быстрая ветка работ. Задачи описаны подробно и не требуют проектных решений — только аккуратное исполнение.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Порядок работы с git — читать первым
|
||||||
|
|
||||||
|
Прошлый раз работа A9 была готова, но **не отправлена в `origin`**, и трое суток её не существовало для проекта. Чтобы это не повторилось, порядок жёсткий.
|
||||||
|
|
||||||
|
**Шаг 1. В самом начале — обновить локальную копию из git:**
|
||||||
|
|
||||||
|
```
|
||||||
|
cd <каталог репозитория>; git fetch origin --prune; git status
|
||||||
|
```
|
||||||
|
|
||||||
|
Если рабочее дерево чистое:
|
||||||
|
|
||||||
|
```
|
||||||
|
git checkout main; git pull --ff-only origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
Если есть незакоммиченные правки — сначала сохранить их отдельной веткой, вслепую сбрасывать нельзя.
|
||||||
|
|
||||||
|
**Шаг 2. Создать ветку от свежего `main` и сразу отправить её:**
|
||||||
|
|
||||||
|
```
|
||||||
|
git checkout -b antigravity/interface-cleanup
|
||||||
|
git push -u origin antigravity/interface-cleanup
|
||||||
|
```
|
||||||
|
|
||||||
|
Пустая ветка в `origin` ничего не ломает и никого не обязывает. Зато с этого момента работа перестаёт зависеть от одного диска.
|
||||||
|
|
||||||
|
**Шаг 3. Пушить после каждого осмысленного коммита**, не копить.
|
||||||
|
|
||||||
|
**Шаг 4. В самом конце — обязательный финальный push и проверка, что он прошёл:**
|
||||||
|
|
||||||
|
```
|
||||||
|
git push origin antigravity/interface-cleanup
|
||||||
|
git status
|
||||||
|
git log --oneline -1 origin/antigravity/interface-cleanup
|
||||||
|
```
|
||||||
|
|
||||||
|
Последняя команда должна показать ваш финальный коммит. Если не показывает — push не прошёл, повторить.
|
||||||
|
|
||||||
|
Зафиксировать фактический `BASE_SHA` через `git rev-parse --short HEAD` и указать его в отчёте. Не считать `cdfd9f1` актуальным автоматически — параллельно идёт A11.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Параллельная работа: строгая граница по файлам
|
||||||
|
|
||||||
|
Одновременно выполняется **A11** вторым исполнителем.
|
||||||
|
|
||||||
|
**Ваши файлы:**
|
||||||
|
|
||||||
|
```
|
||||||
|
src/antigravity_provider/router/ui/**
|
||||||
|
src/antigravity_provider/router/model_discovery.py
|
||||||
|
src/antigravity_provider/router/model_discovery_service.py
|
||||||
|
src/antigravity_provider/router/router_config.py
|
||||||
|
src/antigravity_provider/router/auto_assigner.py
|
||||||
|
src/antigravity_provider/router/unified_health.py
|
||||||
|
installer/**
|
||||||
|
tests/test_ui_*.py
|
||||||
|
```
|
||||||
|
|
||||||
|
**Не ваши** (зона A11): `hermes_plugin.py`, `router_engine.py`, `codex_oauth.py`, `profile_manager.py`, `quota_collector.py`, `adapters/**`, `agy_subprocess.py`, `docs/UI_STATE_CONTRACT.md`.
|
||||||
|
|
||||||
|
Понадобился чужой файл — скажите, будет заказан отдельно.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Что принято по A9
|
||||||
|
|
||||||
|
Проверено исполнением, работа хорошая: миграция конфигурации подняла 16 профилей до 22, `claude` и `grok` получили слоты, резервная копия создаётся, десять профилей владельца не тронуты, комментарии не потеряны, флаг `/reinstall` заработал, предупреждение CS0219 исчезло.
|
||||||
|
|
||||||
|
**Один урок, который стоит запомнить.** Служба обнаружения моделей была написана правильно, но **недостижима**: файл назван `model_discovery_service.py`, а интерфейс импортирует `model_discovery`. Импорт в `ui/model_catalog.py` обёрнут в `except ImportError`, поэтому ошибки не возникало — выбор моделей просто оставался пустым навсегда, с надписью «Список моделей ещё не получен». Ревьюер добавил точку входа при слиянии.
|
||||||
|
|
||||||
|
Защитный `except ImportError` уместен в бою, но он же прячет несобранную интеграцию. Пишете модуль для чужого потребителя — проверьте импорт **исполнением**, а не глазами.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Что уже сделал Codex и переделывать не нужно
|
||||||
|
|
||||||
|
У Codex закончились лимиты, его работа влита частично. Не откатывайте:
|
||||||
|
|
||||||
|
- выбор модели: `ui/model_catalog.py` с честным пустым состоянием;
|
||||||
|
- **карточка кликабельна целиком** (`cursor="hand2"` + привязка `<Button-1>`), «три точки» перестали быть единственным входом;
|
||||||
|
- **окно настроек роли**: `_open_agent_settings_modal`;
|
||||||
|
- **правая панель «Статус в реальном времени» убрана**, центр расширен;
|
||||||
|
- жёсткие срезы `providers[:3]` и `agents[:5]` в диаграмме устранены;
|
||||||
|
- причины у части `Н/Д` через `unavailable_reason`.
|
||||||
|
|
||||||
|
Codex остановился ровно перед двумя пунктами ниже — они и есть основная работа задания.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## P0-1. Компактные карточки аккаунтов
|
||||||
|
|
||||||
|
`accounts_view.py` не менялся вообще. Это самый заметный для владельца пункт.
|
||||||
|
|
||||||
|
Жалобы дословно: **«аккаунты должны выглядеть как у кокпит тулс, компактно»**, **«вид не тот, не надо делать раскрывающееся окно»**, **«в аккаунтах квота так и не отображается»**.
|
||||||
|
|
||||||
|
Требуется:
|
||||||
|
|
||||||
|
- плотный список фиксированной высоты: провайдер, идентичность, роль, состояние авторизации, квота — одной строкой, **без раскрытия**;
|
||||||
|
- **квота видна сразу**, числом и полосой, с указанием пула и периода. У Antigravity четыре пула, и «просто процент» вводит в заблуждение;
|
||||||
|
- шестнадцать аккаунтов читаются без прокрутки внутрь карточек;
|
||||||
|
- **дельта-отрисовку по стабильным ключам не терять** — изменение одного аккаунта не перерисовывает остальные.
|
||||||
|
|
||||||
|
Данные для квоты **уже есть и настоящие**. На живых аккаунтах владельца приходят измеренные значения от провайдера:
|
||||||
|
|
||||||
|
```
|
||||||
|
ag-w2 Claude/GPT — неделя осталось 37.4% source=provider_api
|
||||||
|
ag-w3 Claude/GPT — неделя осталось 90.1% source=provider_api
|
||||||
|
ag-w1 Gemini — неделя осталось 99.7% source=provider_api
|
||||||
|
```
|
||||||
|
|
||||||
|
Где данных нет — `Н/Д` с причиной, а не ноль и не прочерк без объяснения. У `opencode-go` и `grok` провайдер лимитов не отдаёт, и причина уже заполняется в `unavailable_reason`.
|
||||||
|
|
||||||
|
Про дельта-отрисовку: в корне репозитория лежит `COCKPIT_TOOLS_ARCHITECTURE_COMPARISON.md` — там описано, почему это важно: при пересборке всех карточек на 50 аккаунтах выходит больше тысячи операций с виджетами в UI-потоке, и окно заметно подвисает. Документ — архитектурное сравнение, а не макет: берите принцип обновления и плотность, не буквальную вёрстку.
|
||||||
|
|
||||||
|
**Тест:** изменение квоты одного аккаунта не пересоздаёт виджеты остальных.
|
||||||
|
|
||||||
|
## P0-2. Разобрать дублирующие разделы
|
||||||
|
|
||||||
|
`quotas_view.py` не менялся, `providers_view.py` тронут на девять строк.
|
||||||
|
|
||||||
|
Жалоба: **«провайдеры и квоты и лимиты вообще не понятно для чего нужны, там всё то же, что и в аккаунты»**.
|
||||||
|
|
||||||
|
Владелец прав: после появления квот в карточках аккаунтов отдельный раздел квот потерял смысл. Нужно **решение**, а не сохранение обоих на всякий случай.
|
||||||
|
|
||||||
|
- **«Квоты и лимиты»** — убрать из навигации либо оставить только то, чего нет в «Аккаунтах»: сводка по провайдеру целиком, история расхода, ближайшие сбросы. Нет такого содержания — убрать раздел.
|
||||||
|
- **«Провайдеры»** — оставить относящееся к провайдеру, а не к аккаунту: доступность runtime, обнаруженные модели, версия CLI, состояние авторизации в целом.
|
||||||
|
|
||||||
|
В отчёте перечислить, что перенесено, что удалено и почему. Пустой раздел не оставлять: либо содержание, либо нет пункта навигации.
|
||||||
|
|
||||||
|
## P0-3. Причина у каждого Н/Д
|
||||||
|
|
||||||
|
Жалоба: **«что означает н/д в маршрутизация запросов»**.
|
||||||
|
|
||||||
|
Codex закрыл частично: `unavailable_reason` используется в `components.py` и на «Обзоре», но не везде.
|
||||||
|
|
||||||
|
Везде, где стоит `Н/Д`, причина должна быть доступна — подсказкой при наведении и текстом рядом, если место позволяет. Формулировки конкретные: «нет телеметрии: роль ещё не вызывалась», «провайдер не отдаёт лимиты», «аккаунт не подключён». Данные для этого есть.
|
||||||
|
|
||||||
|
Это претензия не к честности, а к молчаливости: владелец видит прочерк и не знает, это поломка, ненастроенное или неизмеримое.
|
||||||
|
|
||||||
|
## P0-4. Тест на достижимость службы обнаружения моделей
|
||||||
|
|
||||||
|
Ревьюер добавил точку входа `router/model_discovery.py`, и выбор моделей снова собран. Но защита от повторения этой ошибки отсутствует.
|
||||||
|
|
||||||
|
Требуется тест, который **падает**, если служба недостижима по согласованному пути:
|
||||||
|
|
||||||
|
- модуль: `src/antigravity_provider/router/model_discovery.py`
|
||||||
|
- класс: `ModelDiscoveryService`
|
||||||
|
- получение экземпляра: classmethod `get()`
|
||||||
|
|
||||||
|
Тест обязан отличать «службы нет» от «служба есть, но импорт не тот». Проверять через `ui/model_catalog` недостаточно — там `except ImportError` всё проглотит; импортируйте модуль напрямую.
|
||||||
|
|
||||||
|
## P0-5. Подключение Grok и Claude довести до конца
|
||||||
|
|
||||||
|
После миграции из A9 слоты появились, проверено:
|
||||||
|
|
||||||
|
```
|
||||||
|
find_free_slot(grok) -> grok-worker-1
|
||||||
|
find_free_slot(claude) -> claude-orch
|
||||||
|
```
|
||||||
|
|
||||||
|
Мастер больше не должен упираться в «свободный слот не найден». Но проверить нужно **весь путь**, а не только выдачу слота: подключение, назначение роли, появление в маршрутизации, тест профиля.
|
||||||
|
|
||||||
|
Жалоба владельца была **«при подключении грока ошибка»**. Принимается только пройденный вживую сценарий со скриншотами.
|
||||||
|
|
||||||
|
## P1-6. Порядок провайдеров в диаграмме
|
||||||
|
|
||||||
|
A9 задал детерминированный порядок провайдеров в `unified_health.get_provider_summaries()` (по числу авторизованных профилей, затем по общему числу слотов, затем по имени) и привёл `total_providers` к пяти.
|
||||||
|
|
||||||
|
Убедиться, что диаграмма на «Обзоре» этот порядок соблюдает и показывает всех пятерых, а не первых трёх. Срезы Codex убрал, но проверить связку целиком стоит — раньше `claude` и `grok` молча отбрасывались.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Ограничения
|
||||||
|
|
||||||
|
- Строгая граница по файлам — см. выше.
|
||||||
|
- Не выдумывать числа, идентификаторы и названия моделей. Нет данных — `Н/Д` с причиной либо блок отсутствует.
|
||||||
|
- Три темы сохранить, дельта-отрисовку не терять.
|
||||||
|
- Мастер не ломать: шесть потоков подключения, трёхэлементная распаковка `start_profile_oauth`, `destroy()` в `_finish` выполняется всегда.
|
||||||
|
- Сеть и подпроцессы — не в UI-потоке. Замерено: `agy models` в одном прогоне отвечает за 40 секунд, в следующем висит больше двух минут.
|
||||||
|
- Тег `v0.1.1` не создавать.
|
||||||
|
|
||||||
|
## Критерии приёмки
|
||||||
|
|
||||||
|
1. **Ветка в `origin`**, финальный коммит виден через `git log origin/antigravity/interface-cleanup`. Ни один файл зоны A11 не изменён.
|
||||||
|
2. Карточка аккаунта компактна, фиксированной высоты, без раскрытия; квота видна сразу с указанием пула и периода; шестнадцать аккаунтов без внутренней прокрутки.
|
||||||
|
3. Дельта-отрисовка сохранена: изменение одного аккаунта не пересоздаёт виджеты остальных; проверено тестом.
|
||||||
|
4. Принято решение по «Провайдерам» и «Квотам»; перенесённое и удалённое перечислено; пустых разделов нет.
|
||||||
|
5. У каждого `Н/Д` доступна причина.
|
||||||
|
6. Есть тест, падающий при недостижимости `router/model_discovery.ModelDiscoveryService`.
|
||||||
|
7. Grok и Claude подключаются вживую: подключение, роль, маршрутизация, тест профиля.
|
||||||
|
8. Диаграмма показывает всех пятерых провайдеров в заданном порядке.
|
||||||
|
9. Прогон **в обоих окружениях** — без UI-зависимостей и с `customtkinter`/`pillow`/`psutil`; обе команды и оба результата в отчёте. На `main` полный набор даёт 307 passed, 2 skipped.
|
||||||
|
10. `ruff check .` чисто. Релизный гейт не ухудшен.
|
||||||
|
11. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, точный `X passed / Y skipped / Z failed`.
|
||||||
|
12. **Скриншоты живого сценария с настоящими данными**: «Аккаунты» с видимыми квотами, подключение Grok, окно роли. Пустых состояний не присылать.
|
||||||
|
|
||||||
|
## Главное
|
||||||
|
|
||||||
|
Владелец сказал: «надо чтобы хаб уже заработал». Квоты настоящие, роли настраиваются, подключение Grok разблокировано. Осталось, чтобы шестнадцать аккаунтов читались с одного взгляда и в каждом непонятном месте был ответ, почему там прочерк.
|
||||||
|
|
||||||
|
## Порядок сдачи
|
||||||
|
Передать точный `FINAL_COMMIT_SHA`. **Сдано только после появления ветки в `origin`** — проверьте это командой перед тем, как отчитаться.
|
||||||
Loading…
Reference in a new issue