Files
houseplan-card/docs/reviews/SPEC-REVIEW-511-r2.md
T
2026-09-09 14:27:52 +00:00

166 lines
15 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.
# 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`.
---
<!-- material-anchors: заполняется конвейером -->
## Материал раунда
- Ветка/дерево: `dev`, коммит `6842b69eed1a6530d7475f4427132b4a1b501e49` (код не менялся с r1; дельта — только тело issue).
- Материал ТЗ: тело issue #511 на момент вывода вердикта; правка зафиксирована `userContentEdits` (GraphQL), `editedAt: 2026-09-09T14:20:49Z`, editor `Matysh`.
- Вердикт: `green` · High 0 · Medium 0
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `dev`, коммит `` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Якоря снять не удалось: ветки задачи нет, материал читался по `dev`.
- Вердикт конвейера: `green` · High 0