From d2307362b58c691f91cd59c3db0658eb8fda728d Mon Sep 17 00:00:00 2001 From: ochenstarik-ui <267932263+ochenstarik-ui@users.noreply.github.com> Date: Wed, 2 Sep 2026 19:19:14 +0700 Subject: [PATCH] =?UTF-8?q?docs(agents):=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20A60=20=E2=80=94=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B4=D0=BE=D0=B2=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D1=82=20=D1=81=D0=B5=D0=B1=D1=8F=20=D0=B4=D0=BE=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D1=86=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A59 довёл обновление до экрана: окно при запуске, видимая загрузка, честное Н/Д, отмена. Дальше механизм обрывается на самом простом — установщик снимает тот процесс, который его запустил и ждёт результата, поэтому перезапуск не наступает никогда. Корень один на обеих системах. На Linux install-linux.sh снимает всё по шаблону, никого не исключая. На Windows StopOwnedRuntime строит цепочку предков, но проверяет её только для дочерних процессов, а сам процесс-цель снимает безусловно — прочитано по коду, подтвердить исполнением. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01EDLuenXmGjWaS2rs8E72En --- .../inbox/2026-09-02-A60-update-completes.md | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 agents/inbox/2026-09-02-A60-update-completes.md diff --git a/agents/inbox/2026-09-02-A60-update-completes.md b/agents/inbox/2026-09-02-A60-update-completes.md new file mode 100644 index 0000000..a1cd629 --- /dev/null +++ b/agents/inbox/2026-09-02-A60-update-completes.md @@ -0,0 +1,190 @@ +# Задание 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`.