# Задание A26: аккаунты без слотов, распределение по агентам и пороги квот ## Дата поступления 2026-08-25 ## База Проверочный HEAD на момент выдачи: **`d4b99a4`**. ## Ветка `antigravity/accounts-without-slots` ## Порядок исполнения Два прохода: **Flash** реализует, **Pro** проводит аудит. Пункт **P0-6** написан для аудитора. --- ## Порядок работы с git ``` cd <каталог репозитория>; git fetch origin --prune; git status git checkout main; git pull --ff-only origin main git checkout -b antigravity/accounts-without-slots git commit -m "..." <- сначала коммит git push -u origin antigravity/accounts-without-slots ``` В `main` напрямую не пушить. В конце — push и проверка `git log --oneline -1`, `git status` чистый. --- ## Ради чего это всё Дословно от владельца: > «вот для этого хаб и делался. чтобы вручную правильно распределять аккаунты и играться с лимитами. где подзаканчиваются, там ставить другой аккаунт» Сейчас продукт этого не даёт. Модель «слотов» — десять предсозданных ячеек Antigravity, три Codex, три OpenCode — навязывает пользователю внутреннее устройство конфигурации. Владелец выбирает слот, ничего не зная о последствиях, и получает результат, которого не ожидал: аккаунт подключён, а на экранах его нет, потому что слот не входит ни в одну цепочку. Это уже случилось вживую. Нужен обратный порядок: **сначала аккаунты, потом назначение**. --- ## Что уже проверено исполнением — заново не выясняйте Три факта, снятые ревьюером на `d4b99a4`. Они сильно сокращают работу. **1. Один профиль может обслуживать все шесть ролей.** Движок это держит уже сейчас: ``` persist_role_chain(role, ['ag-w1']) для всех шести ролей -> True конфигурация: все шесть цепочек равны ['ag-w1'] ``` Значит требование «если есть только Antigravity, он встаёт во всех агентах» **не требует изменений в маршрутизаторе**. Не переписывайте `router_engine`. **2. Произвольный идентификатор профиля регистрируется.** ``` ensure_profile_definition('openai-codex', 'codex-worker-9') -> True 'codex-worker-9' in load_router_config().profiles -> True ``` Значит потолок «три аккаунта Codex» — это **только** зашитый список `provider_slots` в `auto_assigner.py:144`, а не структурное ограничение. Снятие потолка не требует переделки формата конфигурации. **3. Порогов квот в коде нет вообще.** Поиск по `threshold|min_quota|quota_floor|switch_at` в `router/` не даёт ни одного совпадения. Это делается с нуля. --- ## P0-1. Снять потолок на число аккаунтов Дословно: «например у меня есть 4 кодекса, и их все я хочу добавить. или 5 опенкодов». Сейчас `AutoAssigner.find_free_slot` (`auto_assigner.py:140`) перебирает жёсткий список и возвращает `None`, когда список кончился. Четвёртый Codex подключить невозможно. Требуется: число аккаунтов провайдера **ничем не ограничено**. Когда предопределённые имена кончились, идентификатор выдаётся автоматически по понятной схеме (`codex-4`, `codex-5`, …), с проверкой, что такого ещё нет. Идентификатор — деталь реализации, и в интерфейсе он не должен быть главным. Владелец мыслит аккаунтами и почтами, а не слотами. ## P0-2. «Аккаунты» показывают только настоящие аккаунты Дословно: «надо убрать все ячейки со вкладки аккаунты. как добавляю аккаунт, тогда он там появляется. не надо захламлять страницу». Сейчас в умолчаниях предсозданы **24 профиля**, и страница показывает их все, включая никогда не подключённые: «Аккаунт не добавлен», «Холодный резерв». У владельца это 24 карточки при одном реальном аккаунте. Требуется показывать **только подключённые**. Осторожно: не удаляйте профили из конфигурации молча — на них ссылаются цепочки ролей. Речь о том, что показывать, а не о том, что хранить. Решите чистить и конфигурацию — обоснуйте в отчёте и сохраните работоспособность цепочек. ## P0-3. Назначение аккаунта агенту — в «Обзоре» Дословно: «просто загрузка аккаунтов, а уже в обзоре прикреплять нужный аккаунт к агенту». На «Обзоре» уже есть схема ролей и выбор модели в узле (A24). Добавить туда выбор **аккаунта**: какой обслуживает эту роль и в каком порядке резервирования. Действия существуют — `assign_role`, `save_chain`, `reorder_chain`; второй реализации не заводить. Ключевое требование, вытекающее из факта №1: **один аккаунт можно назначить сразу нескольким агентам**, вплоть до всех шести. Интерфейс не должен этому препятствовать и не должен считать это ошибкой. ## P0-4. Кнопка «Авто» Дословно: «или при нажатии авто, сам распределяет аккаунты согласно маршрутизации». Действие `auto_assign_all` существует (`action_handler.py:509`), но что оно делает и совпадает ли с ожиданием владельца — **проверьте исполнением и опишите в отчёте**. Отчёт без запуска не принимается. Ожидаемое поведение: - **Один провайдер.** Есть только Antigravity — он встаёт во все шесть ролей. Владелец дальше сам меняет модель у каждого агента. Это нормальный режим, а не вырожденный случай. - **Несколько провайдеров.** Распределение идёт по назначению роли: «оркестратор у меня первый кодекс, а кодер антигравити» — у каждой роли есть предпочтительный провайдер, и авто-распределение ему следует, а не раскладывает аккаунты подряд. - **Несколько аккаунтов одного провайдера** разводятся по разным ролям, чтобы не жечь квоту одного на всё сразу. Порядок предпочтений по ролям возьмите из текущего `config/router_profiles.example.yaml` — он и выражает замысел владельца. Решите его менять — сначала спросите в отчёте, молча не меняйте. ## P0-5. Пороги квот: предупреждение или переключение Дословно: «выставлять минимальные лимиты (например 10% или 5%) и при достижении этих лимитов или оповещение или автоматом переключает на резервный аккаунт». Это то, ради чего хаб задумывался. Требуется: 1. **Настраиваемый порог** — общий и, если несложно, отдельный для аккаунта. Значения владельца: 10% и 5%. **В код их не зашивать**, это умолчание, а не константа. 2. **Выбор поведения** при достижении: только оповестить либо переключиться на следующий аккаунт в цепочке. Решает владелец, не код. 3. **Оповещение видно в интерфейсе** — в «Состоянии» и в журнале событий. Достаточно ли тоста — решите и обоснуйте. 4. **Переключение обратимо.** Квоты восстанавливаются по `reset_at`; отставленный по порогу аккаунт обязан вернуться в строй сам. Урок A23 уже оплачен: у `AUTH_REQUIRED` не было выхода, и шесть профилей выпали навсегда. **Повторять нельзя.** Данные есть: `quota_collector` собирает проценты и `reset_at`, они видны в карточках. Честность обязательна: порог срабатывает по **измеренной** квоте. Неизвестная квота («Н/Д») — **не** повод считать её нулевой и переключаться. Нет данных — так и сказать, поведение не менять. ## P0-6. Аудит вторым проходом Для проверяющего. Список составлен из дефектов, уже проходивших мимо первого прохода. 1. **Выдуманные значения.** Находились захардкоженные коды устройства `GRK-7842`, `CDX-9104`, запасной коммит `fb23bff` в манифесте. Здесь особый риск в P0-5: соблазн подставить «разумный» процент при отсутствии данных. 2. **Тесты, закрепляющие дефект.** `test_headless_server_auth_matrix` дважды защищал заглушку: сначала требовал неверный адрес `x.ai/device`, затем слова «Headless» и «agy», хотя вход через веб уже работал. Новые тесты должны описывать желаемое поведение. 3. **Запустить изменённое.** Импорт ничего не доказывает. На днях вложенная функция оказалась не видна части точек вызова и давала `NameError` внутри обработки успеха — поймал `ruff`, а не тест. 4. **Кэш состояния.** Только что чинилось: учётные данные сохранялись, но `refresh(force_scan=False)` состояние не обновлял, и подключённый аккаунт не появлялся никогда. Любое изменение состава аккаунтов обязано быть видно **сразу**, без перезапуска. 5. **Побочные изменения** в файлах, которых задание не касалось, — объяснить каждое. 6. **Пропущенный пункт назвать пропущенным.** --- ## Ограничения - Десктоп (`router/ui/**`) не трогать: он выводится из обращения. - Правило честности без исключений. Нет данных — «Н/Д» и причина. - Действия только через существующий `action_handler`; второй реализации `assign_role`, `save_chain`, `set_model` быть не должно. - Меняете контракт — правьте `docs/web-api/CONTRACT.md` и скажите в отчёте. - Конфигурацию владельца литералами не править. - Тег `v0.1.1` не создавать. ## Критерии приёмки 1. Ветка в `origin`, `git status` чист. 2. Подключается **пятый** аккаунт одного провайдера; проверено исполнением, вывод в отчёте. 3. «Аккаунты» показывают только подключённые; при нуле подключённых — внятное пустое состояние, а не 24 пустые карточки. 4. Аккаунт назначается агенту из «Обзора»; один аккаунт назначается **всем шести** ролям; изменение доходит до `router_profiles.yaml` и переживает перезапуск. 5. «Авто» описано по факту запуска: что делает при одном провайдере, при двух, при нескольких аккаунтах одного провайдера. 6. Порог настраивается, значение не зашито; при достижении срабатывает выбранное поведение; при неизвестной квоте не срабатывает. 7. Аккаунт, отставленный по порогу, возвращается в строй после восстановления квоты **без ручного вмешательства**; проверено тестом. 8. Изменения состава аккаунтов видны в интерфейсе сразу, без перезапуска. 9. Ни одного выдуманного значения; проверено отдельно и описано в отчёте. 10. `ruff check .` чисто; релизный гейт не ухудшен. 11. **Скриншоты:** «Аккаунты» с одним аккаунтом, «Обзор» с назначением, настройка порога. 12. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, `X passed / Y skipped / Z failed`. На `main` сейчас **432 passed, 2 skipped**. ## Главное Владелец хочет управлять аккаунтами, а не слотами: загрузил аккаунты, распределил по агентам, следит за квотами и переставляет, когда они подходят к концу. Всё остальное в задании обслуживает это. ## Порядок сдачи Передать точный `FINAL_COMMIT_SHA`. Сдано только после появления коммита в `origin`.