hermes-hub/agents/inbox/2026-08-23-A17-antigravity-pro-honest-status.md
Hermes Team 18695a3f6e docs(tasks): A17, A18, A19 — честный статус, выбор модели, два установщика
A17 (Pro): «Работает» — ветка else в определении здоровья, она означает
«мы не знаем о проблемах», а подана как утверждение. Отказы попадают в
статус только после боевого сбоя, поэтому непроверенный профиль
автоматически зелёный. Плюс «Проверить подключение» не вызывает модель
вовсе — Grok её проходит и не работает.

A18 (Flash): действия смены модели не существует ни среди семнадцати, ни
в клиенте; десктоп это умеет, но логика заперта в методе интерфейса.
И выбирать не из чего: кэш моделей пуст по всем провайдерам, потому что
agy models нестабильна — в одном прогоне 40 секунд, в следующем висит
больше двух минут.

A19: два установщика. Windows — ярлык, открывающий веб окном приложения
через --app без адресной строки (проверено на машине владельца: Edge и
Chrome есть, окно открывается). Linux — скрипт установки, .desktop и
удаление с сохранением данных, плюс честная подсказка про проброс порта
при пустом DISPLAY.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 21:57:11 +07:00

137 lines
13 KiB
Markdown
Raw Permalink 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.

# Задание A17 (Antigravity Pro): честный статус аккаунта и настоящая проверка
## Дата поступления
2026-08-23
## База
Проверочный HEAD на момент выдачи: **`fb23bff`**.
## Ветка
`antigravity/honest-status`
---
## Порядок работы с git
```
cd <каталог репозитория>; git fetch origin --prune; git status
git checkout main; git pull --ff-only origin main
git checkout -b antigravity/honest-status
```
**Сначала коммит, потом push.** В прошлый раз работа A15 была выполнена целиком, но осталась незакоммиченной в рабочем каталоге — git в вашем окружении был недоступен, и ветка в `origin` оказалась пустой. Её нашли случайно.
Если git снова недоступен — **скажите об этом первой строкой отчёта**, а не в предупреждении под ним. Это меняет весь порядок приёмки.
В конце:
```
git status <- дерево чистое
git log --oneline -1 origin/antigravity/honest-status <- ваш коммит
```
---
## Что принято по A15
Веб-API и вынесение действий в общий `ActionExecutor` — правильная архитектура, и она работает. Порт путей на Linux почти закрыт: осталось одно место, `hermes_hub_app.py:37`.
Но в сданном виде **не работало ни то, ни другое**, и это важнее похвалы:
1. **Десктоп был уничтожен.** При выносе действий пропало объявление `class HermesHubApp` вместе с 13 методами каркаса — `__init__`, `_build_layout`, `_create_view`, `_show_view`, `_refresh_data`. Оставшиеся 14 методов оказались вложены **внутрь функции `_load_saved_theme` после её `return`** — синтаксически валидный недостижимый код. Поэтому модуль импортировался, и дефект выглядел безобидным, а `launch_hub()` упал бы с `NameError`.
2. **Веб-API падал с 500 на обоих значимых эндпоинтах**: `get_auth_token` и `run_server` читали `config.hub`, которого у `RouterConfig` нет. Работал только `/api/health`у него нет проверки авторизации, из-за чего сервер и выглядел поднявшимся.
3. **`do_save_settings` при переносе потеряла** атомарную запись через `os.replace`, `ensure_ascii=False` и вызов `set_refresh_interval` — интервал обновления квот из настроек перестал применяться.
Всё восстановлено ревьюером. Урок один и он общий для проекта: **крупное перемещение кода проверяется запуском того, что перемещали.** Импорт модуля ничего не доказывает — Python примет и недостижимый код.
---
## Главное: «Работает» — вымышленный статус
Владелец сообщил про два аккаунта: «стоит опенкод аккаунт, который не подключён… аккаунт не работает» и «и грок не работает». Оба показаны зелёным **«Работает»**.
По одному из них причина найдена и уже исправлена: адаптер OpenCode не читал сохранённый ключ (`fb23bff`). Но осталась причина, общая для обоих и более глубокая.
`unified_health.py:429``STATUS_HEALTHY` с подписью «Работает» назначается в **ветке `else`**, когда ни одно условие отказа не совпало:
```
1. не enabled -> Отключён
2. нет учётных данных -> Аккаунт не добавлен / Требуется вход / Холодный резерв
3. cooldown или квота -> Квота исчерпана
4. rate limit -> Лимит запросов
5. precord.overall_state -> Ошибка
6. иначе -> «Работает» <- сюда попадает всё непроверенное
```
Состояния отказа берутся из `precord` — записей health tracker, которые появляются **только после настоящего сбоя в бою**. Профиль, который ни разу не вызывали, автоматически получает зелёное «Работает».
**То есть надпись означает «мы не знаем о проблемах», а подана как утверждение, что аккаунт работает.** Это тот же класс дефекта, из-за которого в первом аудите проекта были удалены выдуманные проценты квот: отсутствие данных выдаётся за положительный результат.
### Что требуется
1. **Различать «проверено и работает» и «не проверялось».** Профиль без подтверждения не должен выглядеть так же, как подтверждённо рабочий. Формулировку выберите сами, но она обязана быть честной: «Не проверялся» — правда, «Работает» — нет.
2. **Хранить результат и время последней успешной проверки** рядом с профилем и отдавать их в снапшоте. Интерфейсу нужно показать «проверено 12:05», а не только цвет.
3. Состояние отказа по-прежнему приходит из боевых сбоев — это правильно и ломать не нужно.
**Тест:** профиль со свежесохранёнными учётными данными и без единой проверки не получает статус, утверждающий работоспособность.
## P0-2. «Проверить подключение» ничего не проверяет
`do_test_profile` проверяет наличие учётных данных и доступность локального runtime — и **никогда не вызывает модель**. Поэтому Grok эту проверку проходит и всё равно не работает.
Так сложилось не случайно: требование «тест не должен запускать OAuth и открывать браузер» стоит в проекте с первого аудита, и ради него вызов модели убрали целиком. Требование верное, но реализация выплеснула вместе с ним смысл проверки.
**Требуется настоящая проверка**, не нарушающая прежнего запрета:
- минимальный реальный вызов к провайдеру — самый дешёвый из возможных, с жёстким таймаутом;
- **интерактивный вход не запускается ни при каких условиях**: просроченные учётные данные дают ошибку «Авторизация истекла», а не окно браузера. Для Antigravity это уже обеспечено флагами `BROWSER=none` и `CI=1` в окружении подпроцесса и проверкой срока токена до вызова;
- результат сохраняется как последняя проверка (P0-1) с временем;
- по каждому провайдеру в отчёте: что именно вызывается и сколько это стоит владельцу. Если у провайдера нет дешёвого способа — **сказать об этом прямо**, а не имитировать проверку.
Осторожно с ценой: у владельца шесть аккаунтов Antigravity, три Codex, три OpenCode. Проверка всех подряд не должна съедать квоту. Массовую проверку делать по явной команде, а не автоматически при каждом обновлении.
**Тест:** просроченные учётные данные дают ошибку авторизации без попытки интерактивного входа; успешная проверка фиксируется с временем.
## P1-3. Остаток порта на Linux
`hermes_hub_app.py:37` по-прежнему читает `LOCALAPPDATA` напрямую:
```python
_LOCAL = Path(os.environ.get("LOCALAPPDATA", ""))
```
На Linux это даст пустой путь. Провести через `paths.get_hermes_home()`, как остальные семь мест.
В `agy_subprocess.py` два оставшихся упоминания трогать не нужно: строка 41 — комментарий, строка 414 — список переменных окружения, пробрасываемых подпроцессу на Windows, и он там уместен.
---
## Ограничения
- Параллельно идут **A18** (смена модели) и **A19** (установщики). Ваши файлы: `unified_health.py`, `health_tracker.py`, `action_handler.py`, `adapters/**`, `state_store.py`, `hermes_hub_app.py`, `docs/UI_STATE_CONTRACT.md`, `docs/web-api/CONTRACT.md`. **Не ваши:** `router/web/**`, `router/ui/**`, `model_discovery*`, `installer/**`, `launcher/**`.
- Меняете снапшот — правьте `docs/web-api/CONTRACT.md` и скажите об этом в отчёте: против него пишется клиент.
- Никаких статусов без основания. Нет проверки — так и написать.
- Тег `v0.1.1` не создавать.
## Критерии приёмки
1. Ветка в `origin`, `git status` чист. Если git был недоступен — сказано первой строкой отчёта.
2. Непроверенный профиль не показывается как работающий; проверено тестом.
3. Результат и время последней проверки хранятся и приходят в снапшоте; контракт обновлён.
4. «Проверить подключение» делает реальный вызов с таймаутом и **не запускает интерактивный вход ни при каких условиях**; проверено тестом на просроченных данных.
5. В отчёте по каждому провайдеру сказано, что вызывается при проверке и во что это обходится владельцу.
6. Массовая проверка не запускается автоматически при обновлении данных.
7. `hermes_hub_app.py:37` больше не читает `LOCALAPPDATA` напрямую.
8. Прогон в обоих окружениях; `ruff check .` чисто; релизный гейт не ухудшен (сейчас 7/7).
9. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, точный `X passed / Y skipped / Z failed`. На `main` сейчас 331 passed, 2 skipped.
## Главное
Зелёная галочка на нерабочем аккаунте — худший вид лжи в этом продукте: она не просто бесполезна, она уводит от поиска настоящей причины. Владелец потратил на это два обращения. Лучше честное «не проверялся», чем уверенное «работает».
## Порядок сдачи
Передать точный `FINAL_COMMIT_SHA`. Сдано только после появления коммита в `origin`.