# Задание A13 (Antigravity Pro, этот ПК): граница продукта и устойчивость тестов ## Дата поступления 2026-08-23 ## База Проверочный HEAD на момент выдачи: **`9c0da36`**. ## Ветка `antigravity/contract-stability` --- ## Порядок работы с git **В начале — обновить локальную копию:** ``` cd <каталог репозитория>; git fetch origin --prune; git status git checkout main; git pull --ff-only origin main git checkout -b antigravity/contract-stability ``` **Сразу после первого коммита — отправить ветку:** ``` git push -u origin antigravity/contract-stability ``` **В конце — push и проверка, что он прошёл:** ``` git push origin antigravity/contract-stability git log --oneline -1 origin/antigravity/contract-stability ``` Последняя команда обязана показать ваш финальный коммит. **Отдельно и важно.** В прошлый раз работа была выполнена, но осталась незакоммиченной в рабочем каталоге, а в `origin` ушла пустая ветка — она указывала на тот же коммит, что и `main`. Ревьюер обнаружил правки случайно и восстановил их вручную. Инструкция «push ветку сразу» была выполнена буквально, а коммит забыт. **Push без коммита ничего не сохраняет.** Перед отчётом убедитесь, что `git status` показывает чистое дерево, а не список изменённых файлов. --- ## Что принято по A11 Проверено исполнением — работа сделана и работает: - **Пропуск вызова без роли работает.** Замер на слитом коде: вызов в стиле Hermes без роли уходит вниз за **0.10 секунды**, цепочка не пробуется вовсе. Раньше каждый вызов Hermes шёл как `orchestrator` и тратил попытки на исчерпанную цепочку. Это главный пункт A11, и он закрыт. - **Зонд обнаружения моделей переведён на `agy models`** вместо разбора ошибки заведомо неверной модели. - **Выдуманный запасной список `gemini-2.5-*` убран** из адаптера — моделей с такими именами у провайдера нет. - **`refresh_codex_token` появился** — обновления токена Codex не существовало вовсе. - **`source` квоты больше не заявляет `provider_api`**, когда ни одна корзина не измерена; применено последовательно к `antigravity` и `opencode-go`. Замечание по обнаружению моделей: сейчас оно возвращает пустой список, но **не по вине кода**. Проверено прямым вызовом — `agy models` виснет и сам по себе (`rc=124` по таймауту 100 секунд), хотя часом раньше отвечал за 40 секунд. Зонд ведёт себя правильно: отдаёт пусто и сохраняет кэш вместо того, чтобы выдумать список. **Релизный гейт теперь зелёный, 7/7** — проверка 4 проходит. Она была красной несколько раундов подряд. Исправлено ревьюером при фиксации: тест `test_opencode_shows_published_limits` закреплял прежнюю семантику `source` и падал после вашей правки. Приведён к честной. Код был прав, тест — нет. --- ## P0-1. Граница между учётными системами Hub и Hermes — единственный незакрытый пункт A11 `docs/UI_STATE_CONTRACT.md` не изменялся. Это тот пункт, ради которого владелец и задал вопрос, решив, что «хаб никак не привязан к гермесу». Что установлено и должно быть записано: 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-*`, теперь ещё `claude-*` и `grok-*` — **другое множество идентификаторов**. Один и тот же аккаунт Google живёт в двух учётных системах под разными именами: у Hermes он `agy-05`, у Hub `ag-w2`. **Требуется раздел в контракте**, отвечающий на четыре вопроса прямо: 1. Что Hub получает от Hermes на каждом вызове. Перечислить фактически: `task_id`, `turn_id`, `api_request_id`, `session_id`, `platform`, `model`, `provider`, `base_url`, `api_mode`, `api_call_count`. И явно: **роли среди них нет.** 2. Чего Hub не видит: профиль Hermes, которым выполняется вызов; настройки `delegate_task`; состав субагентов. 3. Чем Hub управляет: собственными профилями, цепочками отказоустойчивости, квотами своих аккаунтов. 4. Чем не управляет: ничем из перечисленного в пункте 2. Без этого интерфейс, показывающий «команду агентов» и роли, вводит владельца в заблуждение — он видит на экране роли, которых Hermes не спрашивает, и разумно ожидает, что настройка роли на что-то влияет. ## P0-2. Варианты связывания профилей Hub и Hermes **Подготовить варианты с ценой каждого. Решение принимает владелец. Молча не реализовывать.** Как минимум разобрать три: 1. **Сопоставление по идентичности аккаунта** — email из `id_token`. У Hub он уже извлекается (`extract_jwt_identity` в `profile_manager.py`). Насколько надёжно сопоставляются профили Hermes по тому же признаку? Что делать с профилями без email — `worker-fast`, `deepseek`, ключи OpenCode? 2. **Чтение профилей Hermes как источника** — Hub перестаёт вести свой список и отражает список Hermes. Что при этом теряется: цепочки отказоустойчивости привязаны к профилям Hub, роли тоже. 3. **Явная таблица соответствия** — владелец сам связывает `agy-05` с `ag-w2`. Самое предсказуемое и самое ручное. По каждому: что становится возможным, что ломается, сколько работы, какие данные владельца затрагиваются. Формат — таблица плюс абзац рекомендации с обоснованием. ## P0-3. Набор тестов нестабилен: семь ошибок на прогон Полный прогон на `main` даёт **309 passed и до семи ошибок**, причём **ошибки кочуют между файлами от запуска к запуску**: то `test_ui_contract_v11.py`, то `test_ui_mockup_redesign.py`, то `test_oauth_lifecycle.py`. Те же тесты **изолированно проходят**: ``` pytest tests/test_ui_contract_v11.py -> 9 passed pytest -q -> 4 ERROR в этом же файле ``` Диагноз: исчерпание ресурсов Tk. В наборе **шесть отдельных вызовов `ctk.CTk()`** в пяти файлах, каждый создаёт свой корень интерпретатора Tcl. Сообщение — `TclError: ... This probably means that tk wasn't installed properly`, что к установке отношения не имеет. Это мешает работе прямо сейчас: **невозможно отличить настоящую поломку от шума.** За последние раунды каждый прогон приходилось перепроверять изолированно, и один раз настоящая поломка была замечена только со второго захода. **Требуется** один общий корень Tk на весь прогон: фикстура в `tests/conftest.py` с областью видимости `session`, к которой приводятся все UI-тесты; отдельные `ctk.CTk()` в тестовых файлах убираются. Осторожно: тесты, проверяющие поведение при уничтожении окна (`test_ui_wizard_finish.py` проверяет `winfo_exists() == 0` после `_finish`), должны продолжать работать — уничтожается дочернее окно, а не корень. **Критерий проверки:** десять полных прогонов подряд без единой ошибки. Не один — десять: дефект плавающий, и единственный зелёный прогон ничего не доказывает. --- ## Ограничения - Параллельно идёт **A14** (интерфейс). Ваши файлы: `docs/**`, `tests/conftest.py`, `tests/test_ui_*.py` **только в части фикстуры корня Tk**, `src/antigravity_provider/router/**` кроме `ui/`. Не ваши: `router/ui/**` по существу, `installer/**`. - Правку `2d62d39` и пропуск вызова без роли не откатывать. - Никаких чисел и идентификаторов без измерения. - Тег `v0.1.1` не создавать. ## Критерии приёмки 1. Ветка в `origin`, финальный коммит виден через `git log origin/antigravity/contract-stability`, `git status` чист. 2. В контракте есть раздел о границе Hub и Hermes, отвечающий на все четыре вопроса; явно сказано, что роль Hermes не передаёт. 3. Варианты связывания профилей поданы с ценой каждого и рекомендацией; ни один не реализован без решения владельца. 4. Десять полных прогонов `pytest -q` подряд без ошибок; вывод всех десяти в отчёте. 5. Тесты, проверяющие уничтожение окна, продолжают проходить. 6. `ruff check .` чисто; релизный гейт остаётся зелёным (7/7 на момент выдачи задания). 7. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, точный `X passed / Y skipped / Z failed`. ## Порядок сдачи Передать точный `FINAL_COMMIT_SHA`. **Сдано только после появления коммита в `origin`** — проверьте командой перед отчётом.