# Ревью, раунд 4: вердикт по кандидату v0.1.1 **Отчёт исполнителя описывает `8314d46`. Фактический `origin/main` — `3aae1a8`, на 3 коммита впереди.** Проверка проводилась по фактическому HEAD. **Вердикт: ⛔ тег `v0.1.1` не выпускать.** Заявленное в отчёте сделано и подтверждено, но на текущем HEAD релизный гейт **падает**, а публичный фид обновлений указывает на несуществующий пакет. --- ## 1. Заявленное в отчёте — подтверждаю | Пункт | Проверка | Итог | |---|---|---| | Канонический `.cs`: `EnsurePythonDependencies` | `installer/HermesHubSetup.cs:89` — проверка импорта → `ensurepip` → `pip` → фолбэк на `uv` → повторная верификация | ✅ | | Канонический `.cs`: копирование assets | строки 263–269, три целевых каталога (install dir, плагин, hermes home) | ✅ | | Post-install smoke test | строка 303, `HERMES_HUB_IMPORT_OK`, проверяется ExitCode и наличие маркера | ✅ | | M1 — dev-bypass | `allow_dev_local` по умолчанию `False`, оба продакшен-вызова передают `False` явно (`:130`, `:187`) | ✅ | | M2 — счётчик гейта | `16/16` в заголовке и в сообщении согласованы | ✅ | | M3 — кэш настроек | mtime-кэш + `invalidate_settings_cache()` при сохранении | ✅ | | Публичный фид | `HTTP 200`, манифест валидный, v0.1.1 | ✅ | Блокер раунда 3 (исправление P0-1 не в каноническом установщике) **закрыт**. --- ## 2. ⛔ Блокер 1: релизный гейт падает на текущем HEAD Отчёт цитирует `[RELEASE GATE: PASSED]` — это результат для `8314d46`. На `3aae1a8` фактически: ``` [RELEASE GATE: FAILED] One or more checks failed. Release blocked. ``` Причина — новый `tests/test_codex_opencode_wizard.py` из коммита `3aae1a8` импортирует `customtkinter` на уровне модуля **без `pytest.importorskip`**, и сбор всей сессии прерывается: ``` ERROR tests/test_codex_opencode_wizard.py !!! Interrupted: 1 error during collection !!! 1 skipped, 3 deselected, 1 error ``` Падают пункты гейта 2, 3 и 4. Это возврат ровно того дефекта, который закрывался как **S8** в раунде 2: отсутствие опциональной UI-зависимости должно давать *skip*, а не обрывать прогон. Остальные три тестовых модуля (`test_ui_refinement`, `test_p0_release_gate`, `test_oauth_lifecycle`) `importorskip` содержат — забыли только в новом. Без этого файла суite зелёный: **57 passed, 4 skipped, 3 deselected**. Исходный код, который тестируется (`CodexOAuthSession`, `enable_clipboard_shortcuts`, `HubEntry`, `extract_jwt_identity`), на месте. **Оговорка:** на машине, где `customtkinter` установлен, гейт пройдёт. Но инвариант «отсутствие UI-зависимости не ломает прогон» нарушен — а это ровно тот сценарий, ради которого существует P0-1. **Правка:** одна строка `pytest.importorskip("customtkinter")` в новом файле. --- ## 3. ⛔ Блокер 2: фид обновлений указывает на несуществующий пакет Манифест живой и отдаёт `HTTP 200`, но пакет из него — нет: ``` package_url: https://github.com/ochenstarik-ui/hermes-hub-releases/releases/download/v0.1.1/hermes-hub-0.1.1.zip -> HTTP 404 gh release list --repo ochenstarik-ui/hermes-hub-releases -> пусто ``` Пункт гейта 7 проверяет только наличие полей `version` и `package_url` в манифесте, но не достижимость самого пакета — поэтому печатает `[LIVE STATUS] Public update manifest live`. Формально верно, по существу — обновление скачать нельзя. Сейчас это не проявится (манифест объявляет 0.1.1, приложение 0.1.1 → «обновлений нет»), но как только выйдет 0.1.2, пользователь получит ошибку загрузки. **Правка:** опубликовать релизный ассет с заявленным `sha256`, а в `check_production_update_feed` добавить HEAD-запрос по `package_url`. --- ## 4. Артефакт релиза непроверяем из репозитория Отчёт приводит SHA256 собранного установщика `1D41B9D6…`. Проверить его нельзя: ``` файлов dist/ в git: 0 (dist/ в .gitignore) локальный dist/HermesHubSetup.exe: 7e2531… (сборка от 20.08 00:16, устаревшая) dist/checksums.txt: содержит старую сумму 7E2531… ``` Собранный установщик существует только на машине исполнителя. Любой, кто клонирует репозиторий, установщика не получает, а `checksums.txt` вводит в заблуждение. Для релиза артефакт должен попасть в GitHub Release (там же, где ассет обновления), а `checksums.txt` — обновляться сборочным скриптом. Заявленный clean-install тест в изолированном venv я подтвердить не могу — воспроизвести его без артефакта нечем. Код установщика при этом проверен и выглядит корректно (см. раздел 1). --- ## 5. Отчёт отстал от кода на 2097 строк После `8314d46` в `main` влиты три коммита, которых отчёт не касается: ``` 0d9005f fix(oauth): eliminate ERR_CONNECTION_REFUSED, immediate listener binding, single session reuse 249a888 feat(oauth): Cockpit Tools model, manual callback fallback, race protection 3aae1a8 feat(wizard): Codex OAuth/API Key & OpenCode Go with clipboard UX ``` `+2097 / −232` строк: новый `codex_oauth.py` (296), переработанный `profile_oauth.py` (+296), `add_account_wizard.py` (+880), `components.py` (+83), два новых тестовых модуля. Это функциональная разработка, а не закрытие замечаний, и она не отревьюирована. Беглая проверка на утечки: в `codex_oauth.py` и `profile_oauth.py` токены и коды в логи не пишутся — логируются только `source` и HTTP-код. Полноценного ревью этих коммитов не проводилось. **Вердикт по релизу не может покрывать неотрецензированный код.** Либо тег ставится на `8314d46` (после закрытия блокера 2), либо новые коммиты идут на отдельное ревью. --- ## 6. Условия выпуска v0.1.1 1. Добавить `pytest.importorskip("customtkinter")` в `tests/test_codex_opencode_wizard.py`; убедиться, что гейт зелёный в окружении **без** UI-зависимостей. 2. Опубликовать релизный ассет `hermes-hub-0.1.1.zip` с суммой из манифеста; расширить проверку 7 HEAD-запросом по `package_url`. 3. Положить `HermesHubSetup.exe` в GitHub Release и обновить `dist/checksums.txt` сборочным скриптом. 4. Определиться с областью тега: `8314d46` либо отдельное ревью коммитов `0d9005f…3aae1a8`. Пункты 1 и 2 — блокирующие. 3 и 4 — обязательны для честного релиза, но могут быть закрыты процедурно. --- ## 7. Остаточное из прошлых раундов (не блокирует) - Комментарии в `router_profiles.yaml` стираются при сохранении. - `model_timeout_seconds`, `monitoring_interval_seconds`, `auto_monitoring` сохраняются, но не читаются (работают 4 настройки из 7). - `tests/test_installer.py` по-прежнему пишет в Start Menu и `HKCU` при запуске с `-m installer`. - `_CM_LOCK` на всё время subprocess; глобальная запись `gemini:antigravity` без восстановления; session affinity без TTL; `router_state.json` без межпроцессной блокировки; roadmap-модули не подключены; веб-стек мёртв.