hermes-hub/agents/inbox/2026-09-02-A60-update-completes.md
ochenstarik-ui d39189ee8e docs(agents): A60 — база и порог тестов после вливания A59
A59 влит, база задания указана коммитом. Порог тестов поднят с 725 до 740:
столько в main после слияния с ветками A58 и A59.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EDLuenXmGjWaS2rs8E72En
2026-09-02 19:26:35 +07:00

12 KiB
Raw Blame History

Задание A60: обновление доводит себя до конца

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

2026-09-02

База

origin/main (2f35377). A59 влит: ветка antigravity/a59-visible-update принята с исправлениями ревьюера (285ae7c). Показ и загрузку переписывать второй раз не надо.

git fetch origin --prune
git checkout -b antigravity/a60-update-completes origin/main

В main напрямую не пушить.

Порядок исполнения

Два прохода: Flash реализует, Pro проводит аудит. Пункт P0-5 написан для аудитора.

Зона: применение обновления и перезапуск. Показа и загрузки не касается — там всё принято и проверено.


Что уже сделано — переделывать не надо

A59 довёл обновление до экрана. Ревьюер проверил и принял:

окно при запуске, отказ по версии, молчание без обновлений   работает
полоса хода, честное Н/Д без размера                          работает
отмена с удалением недокачанного файла                        работает
отмена принимается только на проверке и загрузке              работает
SHA-256 обязательна, непроверенный файл не запускается        работает
запись о применённом обновлении только после успеха           работает

Ничего из этого не трогать.


Задача

Владелец нажимает «Обновить сейчас». Пакет скачивается на глазах, сумма сходится, начинается установка — и на этом всё кончается. Хаб не поднимается, окно гаснет, владелец идёт ставить сборку руками. Ровно то, из-за чего писалось A59.


Разрыв, и он один на обеих системах

Установщик снимает тот процесс, который его запустил и ждёт.

install_latest_update делает так:

stop_running_hub()                                  свои процессы, кроме текущего
subprocess.run(["bash", installer], timeout=600)    ЖДЁТ здесь
schedule_restart()                                  сюда управление не доходит

Linux. installer/install-linux.sh:53 в своём stop_running_hub берёт pgrep -u $(id -u) -f "antigravity_provider.router.web|hermes_hub_web_entry" и не исключает никого. Под шаблон попадает тот самый питон, который висит на subprocess.run. Установщик снимает его, schedule_restart не выполняется никогда, окно прогресса умирает вместе с процессом. Скрипт при этом доживает сиротой и файлы обновляет — поэтому со стороны выглядит как «поставилось, но не запустилось».

Windows. installer/HermesHubSetup.cs:280 (StopOwnedRuntime) выглядит аккуратнее: строит $protected — цепочку собственных предков, чтобы не снять того, кто его запустил. Но проверка -notin $protected стоит только на дочерних процессах внутри Stop-HubBranch. Сам процесс-цель снимается безусловно, а хаб под шаблон antigravity_provider\.router\.web подходит. Прочитано по коду — подтвердить исполнением, а не поверить на слово.

Отката на путях установщика нет вообще: он есть только для .zip (apply_update_sync). Ни .sh, ни .exe при срыве на середине ничего не возвращают.


P0-1. Отсоединённый помощник

Порядок не выдумывать заново — он описан в docstring schedule_restart: сначала отсоединённый помощник, потом выход текущего процесса. Лаунчер считает хаб работающим, пока порт отвечает, поэтому поднимать новый, не освободив порт, бесполезно.

  1. Хаб порождает помощника (setsid или отдельная группа процессов на Linux, DETACHED_PROCESS на Windows), передаёт ему путь к уже проверенному пакету и выходит сам, освободив порт.
  2. Помощник: дожидается освобождения порта → запускает установщик → поднимает хаб → завершается.
  3. Помощник не наследует ни stdout хаба, ни его рабочий каталог: хаб исчезнет раньше, чем помощник закончит.
  4. Помощник пишет свой ход в файл ~/.hermes/updates/apply-<время>.log, чтобы после неудачи было что показать. Пустой отказ без причины — уже было в A59, второй раз не проходит.

P0-2. Владелец видит, что происходит

  1. Перед выходом статус restarting с текстом, что хаб сейчас закроется и поднимется сам. Не «установлено» — установка ещё идёт.
  2. Интерфейс переживает разрыв. Опрос get_update_progress получит отказ соединения: это ожидаемое состояние, а не ошибка. Показывать «Hermes Hub перезапускается», продолжать пробовать, при возврате — перечитать страницу.
  3. Не молчать бесконечно. Не поднялся за отведённое время — сказать это прямо и назвать путь к журналу помощника.

P0-3. Откат на путях установщика

  1. Помощник снимает копию установленного до запуска установщика.
  2. Установщик вернул не ноль или хаб не поднялся за отведённое время — вернуть прежнее и поднять его.
  3. Причина отказас кодом возврата и хвостом вывода — в журнал и на экран при следующем старте.
  4. Программа обязана остаться работоспособной. Это главное требование пункта: неудачное обновление не имеет права оставить владельца без хаба.

P0-4. Проверка исполнением

Тестами это не ловится: дело в живом переходе между версиями и в том, кто кого снимает.

  1. Поставить v0.1.2-b7, обновиться на v0.1.3-b1 через интерфейс. Оба релиза опубликованы, установщики и checksums.txt на месте. Скриншоты: окно, полоса, экран после возврата.
  2. Замерить время от нажатия до готовности.
  3. Проверить, что работает новый код — по running_commit, снятому при старте процесса, а не по номеру версии.
  4. Повторить на Windows.
  5. Сорвать установку намеренно (испорченный установщик) — проверить откат и что хаб жив.
  6. Проверить, что старый процесс не остался и порт занят новым.

P0-5. Аудит вторым проходом

  1. Пройти обновление целиком на обеих системах.
  2. Проверить, что помощник не снимает чужого — только процессы хаба своего пользователя.
  3. Проверить откат при сорвавшейся установке и что после него хаб отвечает.
  4. Проверить, что интерфейс не объявляет успех раньше времени — ни на выходе хаба, ни на разрыве связи.
  5. Побочные изменения объяснить.
  6. Пропущенный пункт назвать пропущенным. В A59 живая проверка была пропущена молча, при том что релиз для неё был опубликован за девять часов до сдачи.

Ограничения

  • Показ и загрузку из A59 не переделывать.
  • Проверку SHA-256 и список разрешённых адресов не ослаблять.
  • Показ работающего коммита и времени запуска не ломать.
  • Фронтенд без npm, без сборки, без фреймворков — по docs/web-api/CONTRACT.md §1.
  • Правки ревьюера из main не откатывать — включая комментарии. В A59 сняли шесть блоков с объяснением прошлых регрессий, ревьюер возвращал их руками.
  • Версию 0.1.3 не понижать.
  • Правило честности без исключений: неизвестное — Н с причиной, а не правдоподобное число и не полоса во всю ширину.

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

  1. Ветка в origin, git status чист.
  2. Обновление, запущенное из интерфейса, доходит до работающего нового хаба без участия владельца — на Linux и на Windows, подтверждено скриншотами.
  3. После перезапуска running_commit соответствует новой сборке.
  4. Сорвавшаяся установка откатывается, хаб остаётся работоспособным.
  5. Старый процесс не остался, порт занят новым.
  6. Журнал помощника пишется, и при отказе на него указывают.
  7. ruff check . чисто; релизный гейт пройден; тестов не меньше 740.
  8. Отчёт: START_HEAD, FINAL_HEAD, origin/main, git status, X passed / Y skipped / Z failed, тайминги, скриншоты.

Главное

A59 сделал обновление видимым: владелец видит окно и видит загрузку. Дальше механизм обрывается на самом простом — установщик снимает того, кто его запустил и ждёт результата.

Задание про один шаг: чтобы после нажатия «Обновить сейчас» владелец больше ничего не делал.

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

Передать точный FINAL_COMMIT_SHA.