The mockup's headline blocks divide three ways against the code at2b2ccd8: already available (latency, readiness, events, routing chain), derivable but not yet exposed (per-provider aggregates, call share, host metrics via the unused psutil dependency, active leases), and absent by design (task queues, service window, incidents, provider RPS/SLA). A6 supplies the second group; B5 redesigns against the contract and restores the four account actions thatd0d15aedropped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
10 KiB
Задание A6 (Antigravity): данные для нового дашборда
Дата поступления
2026-08-21
База
Проверочный HEAD: 2b2ccd8, origin/main = 2b2ccd8. git fetch, зафиксировать BASE_SHA.
Ветка
antigravity/dashboard-data
Что принято по A5
Проверено исполнением:
- телеметрия пишется и агрегируется: 3 вызова →
total_prompt_tokens=360,completion=135, суммы сходятся;source: own_measurement; - честность подтверждена тремя проверками: без вызовов
has_data=Falseиp50=Noneвместо нулей; провайдер не вернулusage→total_tokens=None, а не оценка; подставленные в запросhunter2и секретный текст в файл телеметрии не попали; - ограничение размера настоящее: очередь 10 000 записей, файл 5 МБ, 3 ротации;
- контракт разделён правильно — Gap 12 закрыт как самоизмеряемый, для неизмеримого заведён новый Gap 13, молчаливой пропажи ограничений нет;
- долги:
HKCUза флагомHERMES_HUB_NO_REGISTRY,fastapi/uvicornперенесены вoptional-dependencies.
Одна неточность в отчёте: YAML-комментарии помечены «Закрыт», фактически сохраняются только заголовочные. Теряются пять внутренних, включая пояснения к таблице цен, которые вы же и добавили. Не блокирует, но статус — «частично».
Контекст
Владелец утвердил макет главного экрана в трёх цветовых схемах. Codex получает задание на редизайн (B5). Часть блоков макета уже обеспечена данными после A5, часть — нет. Ваша задача: закрыть недостающее, чтобы Codex рисовал правду, а не заглушки.
Разбор макета по источникам:
| Блок макета | Источник | Состояние |
|---|---|---|
| Время отклика 412 мс | TelemetryService latency |
есть |
| Агенты онлайн 18/20 | SystemReadiness |
есть |
| Последние события | EventLogService |
есть |
| Провайдеры 3/3 + мс на каждого | get_aggregates(provider=…) |
есть срез, не выставлен в снапшот |
| Доли маршрутизации 45/35/20 % | доля вызовов по провайдеру | выводимо, не считается |
| Счётчики запросов 128/74/56 | вызовы по ролям | выводимо, не считается |
| Квота сегодня 78 % | QuotaSnapshot, baseline None |
Н/Д до реального 429 — так и оставить |
| Системные показатели CPU/Память/Диск/Сеть | psutil — в зависимостях, не используется |
см. P1-3 |
| Активные задачи 24 | подсистемы задач нет | см. P1-4 |
| Очереди задач по приоритетам | подсистемы очередей нет | не делать |
| Окно обслуживания 09:00–21:00 | понятия нет | не делать |
P0-1. Вывести телеметрию в снапшот
get_aggregates() уже умеет резать по provider, profile_id, model, role — но наружу, в HubSnapshot, ничего из этого не попадает. UI получает снапшот и не может показать ни латентность, ни токены.
Добавить в снапшот готовые агрегаты:
- общие: латентность P50/P95, токены, доля ошибок, число вызовов;
- на провайдера: латентность и число вызовов — для правой панели «Статус в реальном времени»;
- на роль: число вызовов — для счётчиков на схеме маршрутизации.
Считать в том же цикле обновления, что и остальное состояние, чтобы UI не инициировал вычисления сам. Окно агрегации — параметр, по умолчанию сутки.
P0-2. Доля вызовов по провайдеру
Проценты на схеме (45 / 35 / 20) — это распределение вызовов между провайдерами за окно. Данные для этого уже в телеметрии, самой доли нет.
Добавить в агрегаты call_share по провайдеру. При отсутствии вызовов в окне — None, а не «0 %» и не равномерное деление. Правило прежнее: нет данных — нет числа.
P1-3. Показатели хоста через psutil
psutil объявлен обязательной зависимостью и не используется ни в одном модуле. Между тем блок «Системные показатели» на макете — это CPU, память, диск и сеть самой машины, и они измеримы честно.
В контракте Gap 13 сейчас объявляет их «неизмеримыми, так как не относятся к логике роутера». Формулировка неточна: они не относятся к провайдерам, но вполне измеримы. Владелец включил их в утверждённый макет — значит, они нужны.
Требуется: сбор показателей хоста через psutil с источником host_measurement, отдельным от own_measurement (вызовы роутера) и от данных провайдера. Обновить Gap 13: оставить в нём только действительно недоступное — RPS провайдера, SLA, uptime внешних сервисов.
Частота опроса — щадящая, в общем цикле обновления, без отдельного потока на каждый показатель.
P1-4. Активные вызовы
«Активные задачи» на макете — в терминах Hermes Hub это вызовы, выполняющиеся прямо сейчас. LeaseManager уже знает число занятых лизов по каждому профилю; наружу это не выставлено (active_leases в ProfileHealthRecord всегда 0 — старое замечание, до сих пор не закрыто).
Вывести в снапшот число активных вызовов — суммарно и по профилям. Очереди по приоритетам не изобретать: подсистемы очередей нет, и придумывать её ради макета не нужно.
P1-5. Дописать контракт
Все новые поля — в docs/UI_STATE_CONTRACT.md: имя, тип, источник (own_measurement / host_measurement), окно агрегации, поведение при отсутствии данных. Раздел 8 уже есть, дополнить его.
P2-6. Остаток долга
YAML-комментарии: сохраняются только заголовочные, внутренние теряются. Либо довести до полного round-trip, либо переписать статус в контракте и отчёте на «частично» с указанием, что именно теряется.
Ограничения
- Граница прежняя: зона Codex (
router/ui/**,hermes_hub_app.py,tests/test_ui_*.py) — не трогать. - Никаких оценок вместо измерений. Отсутствие данных —
None, не ноль, не среднее, не равномерное распределение. - Не изобретать подсистемы ради макета: очередей задач и окна обслуживания в продукте нет.
- Тег
v0.1.1не создавать.
Критерии приёмки
- Ни один файл зоны Codex не изменён.
- В
HubSnapshotдоступны агрегаты: общие, на провайдера, на роль; проверено тестом. call_shareсчитается верно на известном наборе вызовов; при отсутствии вызовов —None; проверено тестом.- Показатели хоста собираются через
psutilс источникомhost_measurement; при недоступностиpsutil— отсутствие данных, а не нули. - Число активных вызовов отражает реальные лизы; проверено тестом с занятым лизом.
- Gap 13 переформулирован: в нём осталось только недоступное.
- Контракт дополнен по всем новым полям.
- Прогон в обоих окружениях; обе команды и оба результата в отчёте.
ruff check .чисто; release gate PASSED на финальном коммите.- Отчёт:
START_HEAD,FINAL_HEAD,origin/main,git status, точныйX passed / Y skipped / Z failed.
Порядок сдачи
Передать точный FINAL_COMMIT_SHA.