# Ревью, раунд 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-модули не подключены; веб-стек мёртв.
