hermes-hub/agents/inbox/2026-09-02-A60-update-completes.md
ochenstarik-ui d2307362b5 docs(agents): задание A60 — обновление доводит себя до конца
A59 довёл обновление до экрана: окно при запуске, видимая загрузка, честное Н/Д,
отмена. Дальше механизм обрывается на самом простом — установщик снимает тот
процесс, который его запустил и ждёт результата, поэтому перезапуск не наступает
никогда.

Корень один на обеих системах. На Linux install-linux.sh снимает всё по шаблону,
никого не исключая. На Windows StopOwnedRuntime строит цепочку предков, но
проверяет её только для дочерних процессов, а сам процесс-цель снимает
безусловно — прочитано по коду, подтвердить исполнением.

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

190 lines
12 KiB
Markdown
Raw 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.

# Задание A60: обновление доводит себя до конца
## Дата поступления
2026-09-02
## База
`origin/main` **после вливания A59**. Ветка A59 принята с исправлениями ревьюера
(`antigravity/a59-visible-update`, `2e35e2d`); пока она не в `main`, за это
задание не браться — иначе показ и загрузка будут переписаны второй раз.
```
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 .` чисто; релизный гейт пройден; тестов не меньше **725**.
8. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`,
`X passed / Y skipped / Z failed`, тайминги, скриншоты.
## Главное
A59 сделал обновление видимым: владелец видит окно и видит загрузку. Дальше
механизм обрывается на самом простом — установщик снимает того, кто его запустил
и ждёт результата.
Задание про один шаг: чтобы после нажатия «Обновить сейчас» владелец больше
ничего не делал.
## Порядок сдачи
Передать точный `FINAL_COMMIT_SHA`.