docs(agents): задание A58 — хаб видит состояние проверки доступности agy

Владелец теряет время не на сам обход, а на то, что узнаёт о слетевшем патче
случайно, по невнятному отказу посреди работы.

Установлено ревьюером: строки отказа в бинарнике нет — её присылает сервер, но
отказывается работать клиент. Прокси не помогает, измерено на двух странах:
ограничение привязано к аккаунту. Патчер владельца правит четыре байта машинного
кода, подменять в настройках нечего.

Хаб только читает и сообщает; действие остаётся за владельцем и выполняется его
собственным средством. Патчить чужой бинарник хабу запрещено отдельным пунктом.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hermes Team 2026-09-02 00:58:26 +07:00
parent e431e39915
commit 7b36538ded

View file

@ -0,0 +1,151 @@
# Задание A58: хаб видит состояние проверки доступности agy
## Дата поступления
2026-09-02
## База
`origin/main` (`e431e39`).
```
git fetch origin --prune
git checkout -b antigravity/a58-agy-eligibility-state origin/main
```
В `main` напрямую не пушить.
## Порядок исполнения
Два прохода: **Flash** реализует, **Pro** проводит аудит. Пункт **P0-7** написан для аудитора.
Зона: обнаружение состояния `agy`. С кодом входа (A57) пересекается только чтением пути к исполняемому файлу.
---
## Задача
Владелец не может пользоваться Antigravity: `agy` отвечает
```
Eligibility check failed: Your current account is not eligible for Antigravity,
because it is not currently available in your location.
```
Вход при этом проходит полностью: терминал открывается, каталог профиля верный, аккаунт опознан. Отказывает Google.
Владелец обходит это сторонним патчером, который держит у себя. После каждого обновления `agy` патч слетает, и владелец узнаёт об этом, только наткнувшись на отказ посреди работы. Задание закрывает именно это: **хаб должен замечать смену состояния и говорить о ней**, а не оставлять владельца выяснять причину заново.
---
## Что проверено ревьюером — заново не выяснять
### Проверка не в клиенте, но отказ выносит клиент
В бинарнике `agy` **нет** строки «not currently available in your location» — её присылает сервер. При этом есть перечисление `EPD_ELIGIBILITY_NOT_ELIGIBLE_REGION_OUT_OF_SCOPE`, `ENDPOINT_AIM_ELIGIBILITY` и `AIM_ELIGIBILITY_FETCH_STATUS_*`: клиент запрашивает право доступа у Google и отказывается работать сам.
### Прокси не помогает — ограничение привязано к аккаунту
Измерено на сервере владельца: выход через Финляндию и через Данию даёт один и тот же отказ. Описание патчера это подтверждает — он снимает ограничение «без VPN и смены региона аккаунта Google», то есть обычные пути именно эти два.
**Поддержку прокси, добавленную в `fa7bbef`, не удалять**: она нужна и работает, просто эту задачу не решает.
### Что делает патчер
Для CLI это правка машинного кода, а не настройка. Ищется последовательность байтов и переписывается так, чтобы ветвление всегда уходило по разрешённому пути:
```
было: test rax,rax ; je eligible ; cmp byte[rax+8],0 ; jne eligible ; call failure
стало: test rax,rax ; je eligible ; test rax,rax ; nop ; jne eligible
```
Четыре байта. В исходнике патчера это названо «единственный гейт начальной проверки». Есть подписи для x86-64 и для arm64.
Подменять в настройках нечего: проверка не в настройках.
### Версии
У владельца `Antigravity CLI 1.1.23`. Патчер объявляет минимальные версии `2.5.5` и `2.9.1` — соответствие надо проверить, иначе подпись не найдётся. Обновление CLI выполняется командой `agy update` и перезаписывает файл, снимая патч.
---
## P0-1. Хаб не патчит ничего сам
1. **Хаб не изменяет исполняемые файлы.** Ни при каких условиях, ни по кнопке, ни автоматически.
2. **Хаб ничего не скачивает и не запускает из сети.** Стороннего кода в хабе нет.
3. **Только чтение**: состояние определяется чтением файла, который уже лежит на машине.
## P0-2. Состояние определяется и показывается
1. **Признак патча** — по наличию в файле изменённой последовательности байтов. Подписи для x86-64 и arm64. Чтение файла, ничего больше.
2. **Три состояния, а не два**: «проверка снята», «проверка на месте», «определить не удалось» — с причиной. Не найдена подпись ни в исходном, ни в изменённом виде означает именно третье: другая версия CLI, а не «не пропатчен».
3. **Версия и отпечаток файла** запоминаются. Смена любого из них после обновления — повод пересчитать состояние и сказать владельцу.
4. **Показывать в карточке аккаунта Antigravity** и в «Состоянии системы».
## P0-3. Владелец узнаёт о смене состояния
1. **Событие в журнале**, когда состояние сменилось: было «снята» — стало «на месте».
2. **Заметное указание в интерфейсе**, а не строчка в глубине: этот отказ останавливает работу целиком.
3. **Не опрашивать в цикле.** Достаточно проверки при запуске, после обновления `agy` и по кнопке. Опрос в цикле уже приводил к тому, что интерфейс сам себя кормил запросами.
## P0-4. Кнопка запускает то, что владелец сам поставил
1. **Путь к сценарию владельца задаётся в настройках.** Умолчания не выдумывать: не задан — кнопки нет, показывается `Н/Д: сценарий не указан`.
2. **Запуск только по нажатию.** Никакого автоматического запуска при обновлении: владелец должен видеть, что и когда выполняется.
3. **Запуск в терминале**, как вход в A57 — владелец видит ход и результат. Использовать существующий `find_terminal_emulator`, заново не писать.
4. **После выполнения состояние пересчитывается** и показывается новое.
5. **Отказ запуска доходит текстом**, с указанием пути и причины.
## P0-5. Обновление CLI
1. **Показывать установленную версию** `agy`. Не удалось определить — `Н/Д` с причиной.
2. **Кнопка обновления** выполняет `agy update` в терминале.
3. **Предупредить о порядке**: обновление перезаписывает файл и снимает патч, поэтому сначала обновление, потом патч. Это подсказка в интерфейсе, а не комментарий в коде.
## P0-6. Проверка исполнением
1. **Определить состояние на настоящем `agy` владельца** и приложить вывод.
2. **Проверить все три состояния**, третье — на файле другой версии.
3. **Проверить, что хаб файл не изменил**: контрольная сумма до и после определения состояния совпадает.
4. **Проверить кнопку** на незаданном пути и на неверном.
## P0-7. Аудит вторым проходом
1. **Убедиться, что хаб не пишет в исполняемый файл** ни на одном пути.
2. **Проверить, что «определить не удалось» не выдаётся за «не пропатчен»** — это разные вещи, и путать их нельзя.
3. **Проверить, что нет опроса в цикле.**
4. **Побочные изменения** объяснить.
5. **Пропущенный пункт назвать пропущенным.**
---
## Ограничения
- Хаб не изменяет чужие исполняемые файлы и не выполняет загруженный из сети код.
- Поддержку прокси из `fa7bbef` не удалять.
- Правки ревьюера из `main` не откатывать.
- Фронтенд без npm, без сборки, без фреймворков — по `docs/web-api/CONTRACT.md` §1.
- Пути и версии в код не зашивать: определять и сообщать, что проверяли.
- Версию `0.1.3` не понижать.
- Правило честности без исключений: неопределённое — `Н/Д` с причиной.
## Критерии приёмки
1. Ветка в `origin`, `git status` чист.
2. Состояние проверки определяется на настоящем `agy`; вывод приложен.
3. Три состояния различаются; «определить не удалось» называет причину.
4. Контрольная сумма исполняемого файла до и после определения совпадает.
5. Смена состояния после обновления `agy` попадает в журнал и видна в интерфейсе.
6. Кнопка запускает указанный владельцем сценарий в терминале; путь не задан — кнопки нет.
7. Показывается версия `agy`; есть кнопка `agy update` с предупреждением о порядке.
8. Опроса в цикле нет.
9. `ruff check .` чисто; релизный гейт 10/10; тестов не меньше **704**.
10. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, `X passed / Y skipped / Z failed`.
## Главное
Владелец теряет время не на сам обход, а на то, что узнаёт о слетевшем патче случайно — посреди работы, по невнятному отказу. Хаб для того и нужен, чтобы состояние было видно заранее.
Поэтому хаб **смотрит и говорит**, а действие остаётся за владельцем и выполняется его собственным средством. Патчить чужой бинарник самому хабу нельзя: подпись привязана к версии, любое обновление её ломает, и отлаживать пришлось бы чужой код внутри своего.
## Порядок сдачи
Передать точный `FINAL_COMMIT_SHA`.