Решение владельца: у него сервер с Ubuntu Server и Xubuntu, Hermes там будет линуксовый. Веб-интерфейс на сервере строго лучше десктопа. Десктоп остаётся рабочим до паритета, router/ui/** не трогается. A15 (Pro): веб-API поверх готового снапшота — GET /api/snapshot и POST /api/action на семнадцать существующих действий; безопасность (127.0.0.1 по умолчанию, отказ стартовать на внешнем адресе без токена, тест на отсутствие секретов в ответе); порт на Linux — восемь мест, читающих LOCALAPPDATA в обход paths.py; честное сообщение о том, какие потоки авторизации на headless-сервере не работают. Плюс долг из прошлого раунда: снапшот не различает «данных нет» и «данные грузятся». A16 (Flash): клиент без сборки на обычном JS. Не заблокирован сервером — разрабатывает против docs/web-api/snapshot.example.json. Экраны по ценности: Аккаунты с видимыми квотами, затем Обзор и Маршрутизация. Обе стороны пишутся против docs/web-api/CONTRACT.md и до слияния друг друга не видят — отсюда требование не менять контракт односторонне. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
14 KiB
Задание A16 (Antigravity Flash, другой ПК): веб-клиент
Дата поступления
2026-08-23
База
Проверочный HEAD на момент выдачи: 7ae4a28.
Ветка
antigravity/web-client
Порядок работы с git
cd <каталог репозитория>; git fetch origin --prune; git status
git checkout main; git pull --ff-only origin main
git checkout -b antigravity/web-client
Сначала коммит, потом git push -u origin antigravity/web-client. В конце — push и проверка:
git status <- дерево чистое
git log --oneline -1 origin/antigravity/web-client <- ваш финальный коммит
Что принято по A14
Приложены восемь скриншотов, пять содержательных. Скриншот «Аккаунты» подтверждает компактные карточки фиксированной высоты без раскрытия. В unified_health добавлено свойство auth_label_ru — правка вне заявленной зоны, но безобидная. Слияние без конфликтов, 316 passed.
Что не сошлось, и это важно для нового задания.
accounts_view.py и quotas_view.py не изменялись — второе задание подряд. Пункты при этом оказались закрыты чужой работой: компактные карточки пришли из components.py, а пункт навигации «Квоты и лимиты» убрал Codex ещё в 40b3466. То есть в отчёте они числятся сделанными вами, а сделаны не вами.
Три скриншота из восьми — пустой чёрный кадр: шаг мастера Grok, окно роли, детали аккаунта. Два весят ровно по 1148 байт. Живое подключение Grok ими не подтверждено, а именно оно и требовалось.
Скриншот, который ничего не показывает, хуже отсутствующего: он создаёт впечатление проверки, которой не было. Проверяйте, что сняли, прежде чем прикладывать.
Решение владельца: переходим на веб-интерфейс
У владельца сервер с Ubuntu Server и Xubuntu. Веб-интерфейс там строго лучше десктопа. Десктоп остаётся рабочим до паритета — router/ui/** не трогаем вообще.
Ваша часть — клиент. Параллельно A15 делает серверную.
Читать перед началом: docs/web-api/CONTRACT.md. Это единственный источник истины. Вы пишете против документа, а не против чужого кода — сервера вы не увидите до слияния. Любое отклонение от контракта — дефект, даже если у вас всё работает.
Вы не заблокированы готовностью сервера
Рядом лежит docs/web-api/snapshot.example.json — настоящий снапшот с машины владельца: 63 профиля, 187 КБ, почты замаскированы, секретов нет.
Разрабатывайте против этого файла. Пока сервера нет, fetch('/api/snapshot') подменяется загрузкой фикстуры — один флаг в начале app.js. Когда сервер появится, переключение будет стоить одну строку.
P0-1. Клиент без сборки
src/antigravity_provider/router/web/static/
index.html
app.js
style.css
Обычный JavaScript и fetch. Без npm, без сборки, без фреймворка.
Это не вкусовщина. Проект ведут агенты на трёх машинах; любой шаг сборки означает согласование версий Node и дрейф lock-файлов. Страница, которую можно открыть файлом и отладить в браузере без инструментов, снимает целый класс проблем. React в проекте отклонён и раньше, по той же причине.
Опрос /api/snapshot раз в 5 секунд и после каждого действия.
Обязательно: поле seq в снапшоте монотонно растёт. Ответ с seq меньше уже применённого игнорировать — иначе поздний ответ затрёт свежий. Этот дефект в десктопе уже ловили, повторять не нужно.
P0-2. Экраны — порядок по ценности
Не пытайтесь сразу повторить все девять разделов десктопа. Порядок такой, и он не случаен:
1. Аккаунты — самый нужный экран и самая старая жалоба владельца.
- плотный список фиксированной высоты: провайдер, идентичность, роль, состояние авторизации, квота — одной строкой, без раскрытия;
- квота видна сразу, числом и полосой, с указанием пула и периода. У Antigravity четыре пула, «просто процент» вводит в заблуждение — нужно
Claude/GPT — неделя, а не62%. В фикстуре эти данные есть, посмотрите структуруquotas; - шестнадцать аккаунтов читаются без прокрутки внутрь карточек.
2. Обзор — готовность, роли, схема маршрутизации, последние события.
3. Маршрутизация — цепочка основной → резервы, активный узел, причина последнего переключения.
Дальше — по остатку времени. Пустой раздел не заводить: либо содержание, либо нет пункта меню.
P0-3. Действия
Все через POST /api/action с телом {"action": "...", "data": {...}}. Семнадцать имён перечислены в контракте.
Ответ {"ok": bool, "message": str}. ok: false приходит с кодом 200 — это нормальный отказ действия, а не ошибка сети. Обрабатывать как результат, а не как сбой.
Требования к обратной связи, купленные прошлыми раундами:
- результат действия виден в месте действия, а не в строке состояния внизу, где его не замечают;
- при ошибке модальное окно не закрывается — человек должен видеть причину;
- долгие операции (
refresh_all,test) возвращают «запущено» сразу, результат приходит следующим снапшотом. Показывать это как выполняющееся, а не как зависшее.
P0-4. Честность на экране
Правило проекта действует в вебе без исключений.
- Ни одного числа, идентификатора или названия модели без измерения.
- Нет данных — «Н/Д» и причина рядом, доступная пользователю. Причина уже приходит в снапшоте полем
unavailable_reason. Владелец прямо спрашивал: «что означает н/д в маршрутизации» — прочерк без объяснения его не устраивает. - Отличать «данных нет» от «данные ещё грузятся». Найдено при проверке прошлого раунда: квота появляется только после фонового опроса, а до него карточки стоят пустыми и это выглядит как поломка. A15 добавит в снапшот поле состояния — до его появления показывайте загрузку по отсутствию значения при
is_stale.
P0-5. Авторизация на сервере без экрана — сказать правду
Разобрано по коду:
| Провайдер | Поток | На headless-сервере |
|---|---|---|
| OpenAI Codex | device-code | работает — код вводится с любой машины |
| Grok | device-code | работает |
| Antigravity | redirect на localhost | не работает |
| Claude | redirect на localhost | не работает |
У двух последних редирект придёт на машину пользователя, а не сервера.
A15 сообщит клиенту доступность потоков с причиной. Недоступный поток показывать отключённым с объяснением и обходным путём, а не рабочей кнопкой, которая молча ничего не сделает. Это то же правило честности: кнопка, обещающая невозможное, — та же ложь, что выдуманная квота.
Для device-code повторить то, что уже отработано в десктопе: пронумерованная последовательность, код крупно и моноширинным, кнопки копирования ссылки и кода. Владелец жаловался «появляется код, куда его вставлять, не понятно» — не повторяйте.
P0-6. Оформление
Тёмная тема как основная — по образцу существующего десктопа, чтобы переход не выглядел другой программой. Семантика цвета прежняя: зелёный работает, янтарный предупреждение, красный ошибка, серый нет данных. Золото остаётся брендом, а не статусом.
Ширина от 1280 и выше. Мобильную вёрстку не делать.
Ограничения
- Ваши файлы:
src/antigravity_provider/router/web/static/**,tests/test_web_client_*.py. Не ваши:router/web/кромеstatic/,router/ui/**, backend целиком. - Контракт не менять в одностороннем порядке. Нужна правка — скажите, она согласуется с A15.
- Секретов на клиенте не хранить и в URL не передавать.
- Тег
v0.1.1не создавать.
Критерии приёмки
- Ветка в
origin, финальный коммит виден,git statusчист. - Клиент работает против
snapshot.example.jsonбез сервера; переключение на живой API — не более одной строки. - Никакой сборки: страница открывается и отлаживается без npm и без инструментов.
- Ответ с устаревшим
seqигнорируется; проверено тестом. - «Аккаунты»: плотный список без раскрытия, квота видна сразу с пулом и периодом, шестнадцать аккаунтов без внутренней прокрутки.
- «Обзор» и «Маршрутизация» на реальных данных фикстуры.
- У каждого «Н/Д» доступна причина; загрузка отличается от отсутствия данных.
ok: falseобрабатывается как результат, а не как сбой; ошибка видна в месте действия; окно при ошибке не закрывается.- Недоступные на сервере потоки авторизации показаны отключёнными с причиной и обходным путём.
- Скриншоты каждого экрана — открытые и проверенные. Пустой кадр не прикладывать.
ruff check .чисто; релизный гейт остаётся 7/7.- Отчёт:
START_HEAD,FINAL_HEAD,origin/main,git status, точныйX passed / Y skipped / Z failed.
Главное
Веб-интерфейс — единственный способ пользоваться Hub на сервере владельца. Первый экран, который должен заработать по-настоящему, — «Аккаунты» с видимыми квотами: это самая старая незакрытая жалоба, и она тянется с самого начала проекта.
Порядок сдачи
Передать точный FINAL_COMMIT_SHA. Сдано только после появления коммита в origin.