Решение владельца: у него сервер с 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>
166 lines
14 KiB
Markdown
166 lines
14 KiB
Markdown
# Задание 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` не создавать.
|
||
|
||
## Критерии приёмки
|
||
|
||
1. Ветка в `origin`, финальный коммит виден, `git status` чист.
|
||
2. Клиент работает против `snapshot.example.json` без сервера; переключение на живой API — не более одной строки.
|
||
3. Никакой сборки: страница открывается и отлаживается без npm и без инструментов.
|
||
4. Ответ с устаревшим `seq` игнорируется; проверено тестом.
|
||
5. «Аккаунты»: плотный список без раскрытия, квота видна сразу с пулом и периодом, шестнадцать аккаунтов без внутренней прокрутки.
|
||
6. «Обзор» и «Маршрутизация» на реальных данных фикстуры.
|
||
7. У каждого «Н/Д» доступна причина; загрузка отличается от отсутствия данных.
|
||
8. `ok: false` обрабатывается как результат, а не как сбой; ошибка видна в месте действия; окно при ошибке не закрывается.
|
||
9. Недоступные на сервере потоки авторизации показаны отключёнными с причиной и обходным путём.
|
||
10. **Скриншоты каждого экрана — открытые и проверенные.** Пустой кадр не прикладывать.
|
||
11. `ruff check .` чисто; релизный гейт остаётся 7/7.
|
||
12. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, точный `X passed / Y skipped / Z failed`.
|
||
|
||
## Главное
|
||
|
||
Веб-интерфейс — единственный способ пользоваться Hub на сервере владельца. Первый экран, который должен заработать по-настоящему, — «Аккаунты» с видимыми квотами: это самая старая незакрытая жалоба, и она тянется с самого начала проекта.
|
||
|
||
## Порядок сдачи
|
||
Передать точный `FINAL_COMMIT_SHA`. Сдано только после появления коммита в `origin`.
|