# SPEC-REVIEW-511-r2 - Issue: #511 — «release-gate: судить по последнему завершённому прогону на SHA, отменённые не блокируют» - Этап: ТЗ на ревью (PROCESS.md §2.4), лёгкий трек (`small`) - Заход: r2 · блокирующих циклов израсходовано 1 из 2 (этот раунд — зелёный, бюджет не тратится, #227) - Вердикт: **зелёный** ## Скоуп раунда и объявление дельты Предыдущий вердикт — r1, жёлтый, документ `docs/reviews/SPEC-REVIEW-511-r1.md`, опубликован коммитом `6842b69e` (текущий `HEAD`, дерево между раундами не менялось вовсе — задача лёгкого трека, ТЗ живёт в теле issue, кода ещё нет). Материал раунда r1 сам называл SHA пустым («ребейз его осиротит» — якорь не резолвился, ветки задачи не было, читали по `dev`); в r2 сверка проще: между раундами не было ни одного коммита, только правка тела issue. Дельта объявлена через историю правок issue (`userContentEdits` GraphQL, единственный способ увидеть точный до/после тела issue, раз обычный `git diff` тут неприменим — ТЗ не файл). Правка сделана 2026-09-09T14:20:49Z, через 17 секунд после публикации вердикта r1 (14:20:32Z). Точный diff: ```diff - AC3. `docs/performance/README.md`/`docs/TESTING.md` — одна фраза о семантике «последний завершённый». + AC3. `docs/DEVELOPMENT.md` (канонический документ релиза; строка «A missing, failed, cancelled or one-hour-timed-out Validate withholds the asset» становится неверной) описывает новую семантику: «последний завершённый прогон, `cancelled` не считаются»; `demo/performance/README.md` — та же фраза рядом с требованием Full Performance для stable. Доказательство AC2 — `release.yml` без диффа; доказательство AC3 — grep этих фраз в тесте `release-gate.test`. + + ## Откат + + Revert одного коммита; данных и форматов нет. ``` «Проблема», «Решение владельца», AC1, AC2 — байт в байт без изменений. Дельта локальна по всем критериям §2.10: не ребейз, не смена контракта поведения, не новая подсистема, объём — одна строка AC плюс один трёхстрочный раздел. Разбор ограничен дельтой; AC1/AC2 наследуются из r1 без повторного вывода алгоритма. ## Закрытие раунда r1 | Находка r1 | Чем закрыта | Где это видно | |---|---|---| | **Medium** — AC3 указывал на несуществующий `docs/performance/README.md` и топически неподходящий `docs/TESTING.md`; реальная строка `docs/DEVELOPMENT.md:360` не была названа | AC3 переписан: целевой файл — `docs/DEVELOPMENT.md`, с точной цитатой строки, которая станет неверной; `docs/performance/README.md`/`docs/TESTING.md` убраны | Тело issue #511, раздел AC, пункт AC3 (см. diff выше); подтверждено чтением `docs/DEVELOPMENT.md:359-360` — цитата совпадает дословно (перенос строки в исходнике не меняет фразу) | | **Low 1** — раздел «откат» отсутствовал в теле issue дословно | Раздел `## Откат` добавлен в тело: «Revert одного коммита; данных и форматов нет» | Тело issue #511, последний раздел | | **Low 2** — AC2/AC3 не называли явно способ доказательства | Дописано прямым текстом: «Доказательство AC2 — `release.yml` без диффа; доказательство AC3 — grep этих фраз в тесте `release-gate.test`» | Тело issue #511, конец пункта AC3 | Все три находки r1 закрыты содержательно, не декларативно — по каждой указана конкретная строка текста, а не заявление автора. ## Унаследовано из r1 Без повторной проверки принято из `docs/reviews/SPEC-REVIEW-511-r1.md` (материал: `dev`, документ опубликован коммитом `6842b69e`, тем же, что и текущий `HEAD`, — дерево кода между раундами идентично): - **AC1** полностью и однозначно описывает алгоритм: `cancelled` исключаются целиком, из оставшихся берётся хронологически последний (`run_started_at`/`created_at`); все шесть пар вход/выход в тексте взаимно непротиворечивы. Текст AC1 не менялся дельтой — переверять нечего. - **AC2** структурно подтверждён чтением `release.yml` (оба вызова `release-gate.mjs` идут через общую `classifyValidateRuns`, третьего места с отдельной логикой нет). Текст AC2 не менялся дельтой. - Продуктовая рамка: задача не расширяет скоуп, не трогает `src/**`, не создаёт новый UX-контракт, `User-Visible: no` подразумевается верно. - Отсутствие догадок, выданных за решение: «Решение владельца» — прямая цитата ретроспективы 09.09, п.5, алгоритм AC1 полностью выводится из неё. - Продуктовых вопросов владельцу не требуется — весь материал технический. - Трек `small` выбран корректно (одна поверхность класса B — `scripts/**` + `test/**`, риск 2/10, нет конфига/i18n/перфа/touch). ## Что проверено заново в этом раунде - **Цитата в AC3 для `docs/DEVELOPMENT.md`.** Прочитан файл, строки 359–360: «*A missing, failed, cancelled or one-hour-timed-out Validate withholds the asset*» — фраза реальна, совпадает с цитатой в AC3 дословно (в источнике перенесена по мягкому переносу markdown между «failed,» и «cancelled», это не меняет содержание). `grep -n` подтверждает построчно (359, 360). - **Путь `demo/performance/README.md`.** Файл существует (`ls demo/performand/README.md` → есть), в отличие от использованного в r1 ошибочного `docs/performance/README.md` (`docs/performance/` не существует вовсе — перепроверено `ls docs/performance` → «No such file or directory»). Так что сама подмена пути — реальное исправление, не косметика. - **Смысл «та же фраза» для `demo/performance/README.md`.** Проверил построчно (`grep -n -i "exact-SHA|stable release|withhold|asset"`) — в этом файле **нет** существующей фразы вида «A missing, failed, cancelled...», которая «становится неверной»; единственное релевантное место — строки 122–124 («Stable release assets require both exact-SHA `Validate` and exact-SHA `Full Performance`»), и это утверждение остаётся истинным после AC1 (требование «нужен зелёный Validate» не меняется, меняется только то, как это «зелёный» вычисляется). Прочитав AC3 целиком («описывает новую семантику: «последний завершённый прогон, `cancelled` не считаются»; … та же фраза…»), нахожу более естественным прочтение «та же фраза» = та же **новая** поясняющая фраза, добавляемая в оба файла, а не тождественная старая формулировка, которую надо «исправить» во втором файле (там исправлять нечего — искажённого утверждения там сейчас нет). Это не единственно возможное прочтение, но при этом чтении AC3 однозначно выполнимо и проверяемо (grep новой фразы в обоих файлах), а неоднозначность — не о продукте (не «что видит пользователь», а «в какой документ разработки идёт вспомогательное предложение») и не годится для эскалации владельцу по правилу §7.1. Не блокирую: пограничная формулировка, а не фактическая ошибка или неисполнимость — граница между «дефект» и «стилистика», по-моему, здесь пройдена в пользу автора, потому что оба чтения ведут к одному и тому же безопасному действию разработчика (добавить/поправить одну поясняющую фразу в названном месте) и к проверяемому тесту. - **Тест-цель `release-gate.test`.** `test/release-gate.test.mjs` существует уже сегодня (класс B, правится в этой же задаче), текущие тесты (`release gate fails closed for red, cancelled and skipped runs`, `one red duplicate blocks a green duplicate for the same SHA`) кодируют именно старую семантику, которую AC1 переворачивает, — подтверждает, что задача не вакуумна и есть что менять и проверять. Новых assert'ов на grep docs-файлов в тесте пока нет (ожидаемо — реализации ещё нет), но добавление такого теста ничем не блокировано: `docs/DEVELOPMENT.md` и `demo/performance/README.md` — обычные текстовые файлы, `readFileSync` + `includes` тривиален. - **Раздел «Откат».** «Revert одного коммита; данных и форматов нет» — точно для скоупа (правка одного CI-скрипта, одного теста и двух документационных файлов, без миграций, без хранимого состояния, без config-полей). Проверено чтением, не исполнением (откатывать нечего — кода ещё нет). ## Чего не проверял - Продуктовые команды (`typecheck`/`test`/`build`) не гонял — на этапе ТЗ кода нет, гонять нечего (наследуется из r1, ситуация не изменилась). - Историческую точность инцидента 09.09 (конкретные ID прогонов) — факт прошлого CI, не проверяемый чтением репозитория; для ревью ТЗ достаточно, что баг воспроизводится логикой текущего `classifyValidateRuns` (принято в r1, дельта этого не касалась). - Не открывал `docs/CHANGELOG.md`/`.ru.md` — `User-Visible: no`, оба changelog не требуются (наследуется из r1). - Не проверял, действительно ли задача подходила бы под инфраструктурный обход без спецификации (AGENTS.md, «ни одного файла класса A» — она бы подошла, `scripts/**` + `test/**` только класс B). Это выбор автора/ аналитика идти полным лёгким треком, а не нарушение процесса — необязателен к проверке ревьюером ТЗ. ## Итог Все три находки r1 (1 Medium, 2 Low) закрыты конкретным текстом, не заявлением. Дополнительная проверка второй половины переписанного AC3 (`demo/performance/README.md`) не вскрыла блокирующего дефекта — формулировка пограничная, но исполнима и проверяема при разумном прочтении, последствия обеих трактовок безопасны и совпадают в действии. High-находок нет, новых Medium/Low не заводится. AC1/AC2 наследуются из r1 без повторной проверки алгоритма — дельта их не касалась. Вердикт — зелёный; переход в `S5-ready`. --- ## Материал раунда - Ветка/дерево: `dev`, коммит `6842b69eed1a6530d7475f4427132b4a1b501e49` (код не менялся с r1; дельта — только тело issue). - Материал ТЗ: тело issue #511 на момент вывода вердикта; правка зафиксирована `userContentEdits` (GraphQL), `editedAt: 2026-09-09T14:20:49Z`, editor `Matysh`. - Вердикт: `green` · High 0 · Medium 0 --- ## Материал раунда - Ветка: `dev`, коммит `` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Якоря снять не удалось: ветки задачи нет, материал читался по `dev`. - Вердикт конвейера: `green` · High 0