docs(task): A7 — two dashboard data defects found by execution
active_calls is permanently zero: state_store reads LeaseManager.get() while RouterEngine constructs its own instance, so the router's leases are invisible to the snapshot. And psutil.cpu_percent(interval=None) returns 0.0 on its first call, so the dashboard shows CPU 0% at startup — a measured-looking number that is not a measurement. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
69cbefcab6
commit
1efaf78a7a
1 changed files with 118 additions and 0 deletions
118
agents/inbox/2026-08-21-A7-antigravity-two-defects.md
Normal file
118
agents/inbox/2026-08-21-A7-antigravity-two-defects.md
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
# Задание 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, либо переписать статус на «частично» с перечнем теряемого.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Ограничения
|
||||||
|
|
||||||
|
- Граница прежняя: зона 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`.
|
||||||
Loading…
Reference in a new issue