hermes-hub/agents/inbox/2026-08-21-A2-antigravity-close-contract-gaps.md
Hermes Team e8a404be03 docs(task): next Antigravity assignment — close the gaps its own contract declares
Seven of the twelve backend gaps in UI_STATE_CONTRACT.md block the UI outright:
no targeted event has a publisher, plan provenance never reaches
ProfileViewModel, and AgentViewModel/PipelineNode lack the fields the Team and
Routing screens need. Verified on c6876e9, alongside the release asset still
returning 404 and YAML comment loss now at 5 to 2 rather than 5 to 0.

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

11 KiB
Raw Permalink Blame History

Задание A2 (Antigravity): закрыть пробелы контракта и релизную инфраструктуру

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

2026-08-21

База

Проверочный HEAD: c6876e9, origin/main = c6876e9. Перед началом git fetch, зафиксировать фактический BASE_SHA.

Ветка

antigravity/contract-gaps. Ветка antigravity/state-layer влита в main и больше не нужна — можно удалить вместе с worktree ../hermes-hub-state-layer.


Что принято по Заданию A

Проверено исполнением, претензий нет:

  • контракт docs/UI_STATE_CONTRACT.md опубликован первым коммитом, 7 разделов, честный раздел «Backend gaps»;
  • граница работ соблюдена — в зоне UI ни одного изменения;
  • namespace-пакет устранён по корню: добавлен src/antigravity_provider/__init__.py, __path__ теперь содержит ровно один каталог, установленная копия из %LOCALAPPDATA% больше не подмешивается. Два теста, падавшие только в полном прогоне, проходят;
  • мёртвые модули удалены (capability_matrix, skill_registry, lifecycle_supervisor, 532 строки) — это был допустимый вариант;
  • честность источников квот сохранена: baseline 6, provider_auth 1, unconfigured 1, ни одного *_api;
  • headless-прогон 165 passed, ruff чисто, release gate PASSED.

Исправлено ревьюером, не откатывать: 0d9005f изменил start_profile_oauth на 3-кортеж (session_id, auth_url, port) и обновил тесты, но не вызывающий код. Мастер распаковывал два значения, ValueError глушился обработчиком, и URL авторизации не появлялся — подключение Antigravity-аккаунта было сломано с того коммита. Исправлено в 39b1f92 вместе с полем wizard.oauth_port. Файл в зоне Codex, вам его не трогать, но знать нужно.


ГРАНИЦА РАБОТ

Прежняя. Ваша зона — всё, кроме:

src/antigravity_provider/router/ui/**
src/antigravity_provider/router/hermes_hub_app.py
tests/test_ui_*.py

Codex параллельно выполняет фазы 26 по интерфейсу и опирается на контракт. Любое расширение контракта — сначала документ, потом код, иначе он будет писать против несуществующих полей.


Приоритет: пробелы, блокирующие интерфейс

Эти пункты вы сами зафиксировали в разделе 7 контракта. Пока они открыты, Codex обязан рисовать «Н/Д» — то есть продукт остаётся полупустым.

P0-1. Точечные события никто не публикует (gap 9)

Проверено на c6876e9:

publish(EVENT_REFRESH_STARTED            1
publish(EVENT_REFRESH_FAILED             1
publish(EVENT_SYSTEM_READINESS_CHANGED   1

EVENT_ACCOUNT_UPDATED   публикаций: 0
EVENT_ACCOUNT_ADDED     публикаций: 0
EVENT_QUOTA_UPDATED     публикаций: 0
EVENT_ROUTING_UPDATED   публикаций: 0
EVENT_AGENT_UPDATED     публикаций: 0

Константы объявлены, публикаторов нет — событийная модель существует только на бумаге, и любое изменение по-прежнему означает полный снапшот. Требование Задания A («изменение квоты одного аккаунта порождает событие с идентификатором аккаунта») не выполнено.

Нужно: канонический публикатор для каждого объявленного события либо удаление константы, если событие не нужно. Тест: изменение квоты одного аккаунта публикует ровно одно событие с его profile_id и не порождает полного пересбора.

P0-2. Происхождение тарифа не доходит до ProfileViewModel (gap 6)

Из-за этого Codex не может показать PlanBadge — компонент готов и не используется. Нужно довести до модели и тариф, и его происхождение, чтобы UI отличал «известно от провайдера» от «выведено эвристикой».

P0-3. AgentViewModel и PipelineNode неполны (gaps 7, 8)

  • AgentViewModel без активной сессии и квоты → экран «Команда» показывает пустые строки;
  • PipelineNode без идентичности аккаунта, состояния квоты и причины переключения → экран «Маршрутизация» не может ответить на главный вопрос «почему переключились и что с резервом».

Добавить поля и описать в контракте. Причину переключения брать из реального состояния маршрута, а не выводить задним числом.


P1. Достоверность данных

P1-4. Реальный сбор квот (gaps 1, 2)

Сейчас ни один провайдер не отдаёт живых чисел: все корзины baseline. Структура мульти-корзин у Antigravity есть, значения и время сброса не измеряются.

Довести реальный сбор там, где провайдер это отдаёт. Правила прежние: локально вычисленное не помечать источником провайдера, отсутствие данных отдавать как отсутствие, а не как число. Для каждого провайдера в контракте указать, что именно теперь измеряется.

P1-5. Свежесть и защита от устаревшего ответа (gaps 3, 10, 11)

Вы сами отметили: seq наружу не выставлен, вложенные квотные воркеры могут перестроить состояние до завершения, а seq записывается до окончания медленной работы — то есть доказательства, что поздний ответ не перезапишет свежий, нет.

Нужно: публичный seq в снапшоте, запись seq по завершении работы, тест с искусственной задержкой, где поздний ответ гарантированно отбрасывается.

P1-6. Релизная инфраструктура

package_url из живого манифеста по-прежнему отдаёт HTTP 404 — проверено сейчас. Порядок публикации: build → checksum → upload artifact → verify → publish manifest → verify feed. Манифест не должен рекламировать несуществующий артефакт. dist/checksums.txt — только из scripts/build_dist.py.

Тег v0.1.1 не создавать.


P2. Долги

  • Комментарии router_profiles.yaml — стало лучше (было 5 → 0, теперь 5 → 2), но потеря остаётся. Либо round-trip YAML, либо явная фиксация долга с указанием, что файл перезаписывается приложением.
  • HKCU в тестах установщикаRegistry.CurrentUser по-прежнему используется дважды; переменными окружения реестр не перенаправляется. Вынести реальный запуск в явный integration-режим либо параметризовать ключ.
  • Сериализация Antigravity_AGY_INVOCATION_LOCK держит вызовы профилей со своим auth по одному. Либо отказаться от глобальной записи gemini:antigravity в пользу изоляции через USERPROFILE, либо записать как осознанный долг с обоснованием.
  • fastapi/uvicorn остаются обязательными зависимостями, хотя gui_server живёт в legacy/ и не поставляется. Привести в соответствие.

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

  1. Ни один файл зоны Codex не изменён.
  2. Для каждого объявленного события есть публикатор либо константа удалена; тест доказывает точечность.
  3. PlanBadge можно показать: тариф и его происхождение доходят до ProfileViewModel.
  4. AgentViewModel и PipelineNode содержат поля, которых требуют экраны «Команда» и «Маршрутизация».
  5. Раздел «Backend gaps» контракта сокращён; по каждому закрытому пункту указан коммит. Что осталось — осталось честно.
  6. Ни одно локально вычисленное значение не помечено источником провайдера.
  7. Поздний ответ не перезаписывает свежий — доказано тестом с задержкой, а не порядком строк.
  8. curl -I <package_url> → HTTP 200, sha256 совпадает с артефактом.
  9. Прогон в обоих окружениях: без UI-зависимостей и с установленными customtkinter, pillow, psutil. Оба зелёных, обе команды и оба результата в отчёте.
  10. ruff check . чисто; release gate PASSED на финальном коммите, без функциональных коммитов после него.
  11. Отчёт содержит START_HEAD, FINAL_HEAD, origin/main, git status и точный X passed / Y skipped / Z failed.

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

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