hermes-hub/agents/inbox/2026-08-21-A7-antigravity-two-defects.md
Hermes Team 09d5e5dccb docs(task): A7 — add network counter presented as a live metric
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 21:58:23 +07:00

129 lines
8.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Задание A7 (Antigravity): два дефекта в данных дашборда
## Дата поступления
2026-08-21
## База
Проверочный HEAD: **`69cbefc`**, `origin/main` = `69cbefc`. `git fetch`, зафиксировать `BASE_SHA`.
## Ветка
`antigravity/dashboard-fixes`
---
## Что принято по A6
Проверено исполнением, работа хорошая:
- **разрезы телеметрии в снапшоте.** Прогнал 6 вызовов оркестратора и 2 исследователя (последние с переключением) — получил 10 записей, что верно: неуспешная попытка тоже учитывается. Доли сошлись точно:
```
openai-codex : total_calls=6, call_share=0.6
antigravity : total_calls=2, call_share=0.2
opencode-go : total_calls=2, call_share=0.2
сумма = 1.0
```
- **разрез по ролям**: `orchestrator=6`, `research=4` — совпадает с числом попыток;
- **пустое окно честно**: `has_data=False`, `latency_p50_ms=null`, `total_tokens=null`, при этом `total_calls=0` — счётчик как факт, а латентность как отсутствие. Ровно то различие, которого добивались;
- **контракт снова разделён правильно**: Gap 13 закрыт как самоизмеряемый, для недоступного заведён **Gap 14** — RPS провайдера, SLA, очереди задач, окно обслуживания, с сохранённым требованием «Н/Д либо скрыть». Третий раз подряд без молчаливых пропаж;
- прогон: headless 189 passed, с UI-зависимостями 235 passed, ruff чисто, гейт PASSED.
---
## P0-1. `active_calls` всегда ноль: два разных `LeaseManager`
`state_store.py:172` читает синглтон:
```python
active_leases_total = LeaseManager.get().total_active_count()
```
`router_engine.py:31` создаёт **собственный** экземпляр:
```python
self.leases = leases or LeaseManager()
```
Роутер захватывает лизы в своём приватном менеджере, снапшот читает синглтон, который всегда пуст. Проверено:
```
движок и синглтон — один объект? False
id(engine.leases) = 2732720631632
id(LeaseManager.get()) = 2732720631376
после acquire на движке:
движок видит : 1
синглтон видит: 0
```
Итог: `active_calls_total` в снапшоте будет **постоянно 0** при любой нагрузке. Блок «Активные задачи» на дашборде покажет ноль всегда — то есть правдоподобное, но неверное число.
Требуется: один источник истины по лизам. Либо `RouterEngine` по умолчанию берёт синглтон, либо `state_store` читает лизы у движка. Второе честнее: лизы принадлежат движку, а не глобальному состоянию.
**Тест обязателен:** захватить лиз через тот же путь, которым пользуется роутер, и убедиться, что снапшот его видит.
Попутно: `ProfileHealthRecord.active_leases` по-прежнему всегда 0 и при этом выводится в CLI и API — это отмечалось ещё в первом аудите. Либо заполнять, либо убрать из вывода.
## P0-2. CPU при первом измерении всегда 0 %
`host_metrics.py:57``psutil.cpu_percent(interval=None)`. Без предыдущей точки отсчёта первый вызов возвращает `0.0` по устройству самой библиотеки. Проверено:
```
первый вызов (холодный): 0.0
второй вызов: 44.1
третий вызов: 12.0
```
На старте приложения пользователь увидит «CPU 0 %» — и это тот же класс дефекта, с которым мы боролись в квотах: число выглядит измеренным, но измерением не является.
Требуется одно из: прогреть счётчик при инициализации сервиса (один вызов, результат отбросить), либо возвращать `None` для первого измерения, либо использовать короткий интервал. Первый вариант предпочтительнее — он не создаёт «дырки» в интерфейсе.
**Тест обязателен:** первое значение не должно быть нулём, полученным из-за холодного старта.
## P1-3. Остаток по YAML
Комментарии сохраняются только заголовочные, внутренние теряются:
```
# Antigravity (10 accounts)
# OpenAI Codex (3 accounts)
# OpenCode Go (3 accounts)
# Optional: User Model Pricing Table (USD per 1M tokens)
# Telemetry will compute call cost in USD only if a model price is defined below.
```
Первыми стираются пояснения к таблице цен, добавленные в A5. В отчёте статус указан «Закрыт» — это неточно. Либо довести до полного round-trip, либо переписать статус на «частично» с перечнем теряемого.
---
## P1-4. «Сеть» показывает счётчик, а не текущий показатель
`host_metrics.py:79-80` отдаёт `net_bytes_sent` / `net_bytes_recv` — накопительные счётчики `psutil.net_io_counters()` с момента загрузки машины. `dashboard_view.py:630-633` складывает их и делит на 1024², получая «Сеть 56155 МБ».
Это число стоит в одном ряду с CPU, памятью и диском — то есть читается как текущее состояние, а на деле это ~55 ГБ трафика за всё время работы системы. На макете в этой позиции была скорость («42 Мбит/с»).
Число настоящее, вводит в заблуждение подача. Нужно одно из двух: считать скорость по разнице двух замеров (это и просил макет) либо отдавать значение с явной семантикой «всего с момента загрузки», чтобы интерфейс мог подписать его правильно.
Отрисовка — зона Codex, но решение о том, что именно отдавать, принимается здесь: сейчас в контракте `net_bytes_*` описаны без указания, что это накопительный счётчик.
## Ограничения
- Граница прежняя: зона Codex (`router/ui/**`, `hermes_hub_app.py`, `tests/test_ui_*.py`) — не трогать.
- Никаких чисел без измерения. Ноль допустим только как результат подсчёта, а не как значение по умолчанию.
- Тег `v0.1.1` не создавать.
## Критерии приёмки
1. Ни один файл зоны Codex не изменён.
2. Захваченный роутером лиз виден в снапшоте; проверено тестом через реальный путь захвата.
3. `ProfileHealthRecord.active_leases` заполняется либо убран из вывода CLI и API.
4. Первое измерение CPU не равно нулю из-за холодного старта; проверено тестом.
5. Статус YAML в отчёте и контракте соответствует фактическому поведению.
6. Прогон **в обоих окружениях**; обе команды и оба результата в отчёте.
7. `ruff check .` чисто; release gate PASSED на финальном коммите.
8. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, точный `X passed / Y skipped / Z failed`.
## Порядок сдачи
Передать точный `FINAL_COMMIT_SHA`.