hermes-hub/agents/inbox/2026-08-21-B3-codex-contract-v11-fields.md
Hermes Team 9ffc815ed5 docs(task): B3 — wire the contract v1.1 fields the UI never picked up
Codex built phases 2-6 against contract v1.0 while Antigravity shipped v1.1, so
eight fields now exist in the snapshot and render nowhere: plan_code,
plan_source, active_quota_status, active_quota_label, quota_status,
failover_reason, unavailable_reason and seq. PlanBadge was built in phase 1 and
still has nothing to display.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 08:50:22 +07:00

8.1 KiB
Raw Permalink Blame History

Задание B3 (Codex): подключить поля контракта v1.1

Дата поступления

2026-08-21

База

Проверочный HEAD: 2c612f2, origin/main = 2c612f2. Перед началом git fetch и обязательно подтянуть main — ваши фазы 26 уже влиты, поверх них есть правки.

Ветка

codex/contract-v11. Ветка codex/ui-redesign влита в main.


Что принято по фазам 26

Проверено исполнением, работа хорошая:

  • граница соблюдена — вне вашей зоны только файл отчёта;
  • пересоздания виджетов не осталось нигде: ни одного winfo_children() в views/, всё на стабильных ключах;
  • выдуманных метрик нет, «Н/Д» используется в семи экранах;
  • views вообще не обращаются к backend — ни HubStateStore, ни scan_all, ни сервисов; данные приходят только снапшотом;
  • мастер подключения пережил слияние: трёхэлементная распаковка start_profile_oauth и oauth_port на месте;
  • защита от краша при старте не только сохранена, но усилена — update_data выходит рано вместо отката к хранилищу.

Одна правка с моей стороны: инвариант tests/test_view_startup_contract.py требовал обращения к хранилищу и после вашей переделки начал скипаться для всех девяти views, то есть перестал защищать тот самый краш. Переписан под новый контракт — проверка isinstance(snapshot, HubSnapshot) теперь обязательна независимо от того, читает ли view хранилище.


Задача

Вы работали по контракту v1.0, а Antigravity параллельно выпустил v1.1 и добавил поля, которых на тот момент не было. Данные в снапшоте есть, но интерфейс их не показывает. Проверено на 2c612f2:

Поле Где появилось Используется в UI
plan_code ProfileViewModel 0 файлов
plan_source ProfileViewModel 0 файлов
active_quota_status AgentViewModel 0 файлов
active_quota_label AgentViewModel 0 файлов
quota_status PipelineNode 0 файлов
failover_reason PipelineNode 0 файлов
unavailable_reason QuotaBucket 0 файлов
seq HubSnapshot 0 файлов
session_id AgentViewModel 1 файл
account_identity PipelineNode 4 файла
is_estimated QuotaSnapshot 2 файла

Перечитайте docs/UI_STATE_CONTRACT.md целиком — он переписан, появился раздел «Provider Truth Matrix».

1. Тариф — PlanBadge наконец можно показать

Компонент вы сделали в PHASE 1, данные появились в v1.1. Показывать бейдж, когда plan_source говорит, что тариф известен от провайдера (provider_api, jwt_claim, provider_auth), и не показывать при inferred/unknown — либо показывать с явной пометкой, что значение выведено, а не получено. Пользователь должен отличать «PRO по данным провайдера» от «похоже на PRO».

2. Квоты — состояние без данных

QuotaBucket.unavailable_reason объясняет, почему данных нет. Сейчас пользователь видит пустоту без причины. Показывать причину в подсказке или подписи корзины.

Важно: по контракту baseline-значения теперь None, а не числа. Убедитесь, что QuotaBar и QuotaBucketWidget корректно отрисовывают именно отсутствие значения, а не «0 %» — ноль означает «квота исчерпана», это принципиально разные состояния.

3. Команда — состояние агента

active_quota_status и active_quota_label показывают, в каком состоянии квота у аккаунта, на котором сейчас работает агент. Это прямо отвечает на вопрос «сколько осталось у того, кто выполняет задачу».

4. Маршрутизация — причина переключения

PipelineNode.failover_reason и quota_status — то, ради чего экран существует: видно не только «активен резерв 1», но и почему ушли с основного. Показывать причину у узла, с которого произошло переключение.

5. Свежесть данных

HubSnapshot.seq и политика is_stale (по контракту — просрочка фонового обновления свыше 300 с). Показать пользователю, что данные устарели, вместо молчаливого показа старых значений.


Ограничения

  • Граница прежняя: ваша зона — src/antigravity_provider/router/ui/**, hermes_hub_app.py, tests/test_ui_*.py. Остальное не трогать.
  • Не добавлять сбор данных в UI. Не хватает поля — строка в разделе «Backend gaps» отчёта.
  • Нет данных — «Н/Д» либо скрытый блок. Ноль и отсутствие значения не путать.
  • Секреты маскировать, в логи не писать.
  • Тег v0.1.1 не создавать.

Критерии приёмки

  1. Ни один файл чужой зоны не изменён.
  2. PlanBadge отображается и различает известный тариф от выведенного.
  3. Отсутствие данных о квоте отрисовано как отсутствие, а не как ноль; причина видна пользователю.
  4. Экран «Команда» показывает состояние квоты активного аккаунта агента.
  5. Экран «Маршрутизация» показывает причину переключения там, где она есть в состоянии.
  6. Устаревание снапшота видно пользователю.
  7. Тесты на каждый пункт: известный и выведенный тариф, корзина без данных против нулевой, причина переключения, устаревший снапшот.
  8. Прогон в обоих окружениях — без UI-зависимостей и с customtkinter/pillow/psutil; обе команды и оба результата в отчёте. Прогон только headless не считается: ваши UI-тесты там пропускаются.
  9. ruff check . чисто; release gate не ухудшен.
  10. Отчёт: BASE_SHA, FINAL_SHA, изменённые файлы, что подключено, что осталось, раздел «Backend gaps».

Порядок сдачи

Передать точный FINAL_COMMIT_SHA и не вести разработку поверх него до вердикта.