diff --git a/docs/reviews/SPEC-REVIEW-481-r2.md b/docs/reviews/SPEC-REVIEW-481-r2.md new file mode 100644 index 00000000..57ccdbb7 --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-481-r2.md @@ -0,0 +1,150 @@ +# SPEC-REVIEW-481-r2 + +Issue: #481 «changed_mutants: журнал пойманных свидетелей вместо суда по диапазону» +Этап: ТЗ на ревью (PROCESS.md §2.4). Трек: `small` — ТЗ в теле issue, файл +`docs/specs/481-*.md` не создан (проверено: `ls docs/specs/ | grep -i 481` — пусто). +Заход: r2 · блокирующих циклов израсходовано 1 из 2 (r1 был жёлтым и потратил цикл; +зелёный вердикт цикла не образует, #227). + +## Скоуп + +Предмет ревью — тело issue #481 на текущий момент, целиком, но разбор — по дельте +между r1 и r2 (PROCESS.md §2.10): полностью переразобраны только два места, которых +касалась правка автора; остальное (AC1–AC5, AC7, ссылки, оценка, список файлов) +унаследовано из r1 без повторной проверки по существу, с точечной сверкой фактов, +которые дёшево перепроверить (см. «Унаследовано из r1»). + +## Как проверялось + +1. Найден вердикт r1 — комментарий в issue (жёлтый, High: 0, Medium: 2) и документ + `docs/reviews/SPEC-REVIEW-481-r1.md` (коммит `2f65a184`, `git show 2f65a184:docs/reviews/SPEC-REVIEW-481-r1.md`). + Блок «Материал раунда» в конце r1-документа несёт **пустой SHA ветки** («Ветка: dev, + коммит `` — ... Якоря снять не удалось: ветки задачи нет, материал читался по dev»). + По PROCESS.md §2.10 это прямо названо нормальным случаем, а не находкой: «если SHA не + резолвится — это не находка, а обычное дело»; находкой было бы только SHA, мёртвое уже + на момент публикации — здесь SHA просто не указано, а не указано неверно. Дельту + поэтому объявляю не по коду, а по тексту: r1-документ дословно цитирует то, что было + в теле issue на момент r1 (формулировки находок 1 и 2 ниже), и комментарий автора + после r1 прямо перечисляет, что изменено. Оба источника сверены с текущим телом + issue построчно. +2. Дельта = добавленный `### 6. Откат` внутри «Решение» + переписанная колонка + «Доказательство» строки AC6 в таблице критериев. Больше правок в теле issue между + r1 и r2 нет (сверено построчно с текстом, процитированным в r1-документе и с + комментарием автора). +3. По каждой из двух Medium-находок r1 — сверено дословное совпадение предложенного + в r1 исправления с тем, что появилось в issue (см. таблицу ниже). +4. AC1–AC5, AC7 дельта не затрагивает — не переразбирались по существу. Дёшево + сверено: файл `docs/specs/` по-прежнему отсутствует; названные в AC7 идентификаторы + свидетелей (`ledger-records-escaped`, `ledger-version-sensitive`, + `ledger-written-at-end-only`) и тесты `#481 AC1`…`#481 AC5` по-прежнему существуют в + коде ветки (`grep` по `scripts/mutation-gate.mjs`, `test/mutation-gate.test.mjs`, + `test/validate-workflow.test.mjs`) — спецификация не разошлась с уже существующей + реализацией на ветке задачи. Это не код-ревью (реализация по существу не + оценивалась), а та же перекрёстная сверка реализуемости, что делал r1. +5. Числа в комментарии автора после r1 (132/134 отобрано, 132 пропущено, 113/113 без + изменения отпечатка) — не доказательство (AC6 явно это оговаривает), поэтому не + перепроверялись побитово; но сами исторические SHA, на которые они ссылаются, + проверены на существование и соответствие описанию: `052549fa` — «test: accept + golden baselines after #471 and #476», `f2e38e48` — «build: prepare v1.73.0-beta.2 + candidate», `5d281171` — «ci: shard changed mutants before release», `04f4cd10` — + «docs: refresh screenshot source fingerprint». Все существуют, ни один не выдуман, + описание соответствует содержимому коммитов. +6. Гейты (typecheck/test/build) не гонялись — по прецеденту r1 и по существу этапа: + материал spec-review — текст ТЗ, а не диапазон кода; их прогон принадлежит + код-ревью (§2.7). + +## Закрытие раунда r1 + +| Находка r1 | Чем закрыта | Где видно | +|---|---|---| +| Medium 1: отсутствует обязательный раздел «откат» (шаблон §5) | Добавлен `### 6. Откат` внутри «Решение», текст почти дословно повторяет формулировку, предложенную r1 («ревёрт коммита… `readLedger` трактует отсутствующий, битый или чужой по схеме файл как пустой журнал… старое поведение восстанавливается без ручных действий») | Тело issue #481, раздел «Решение» → «### 6. Откат» | +| Medium 2: AC6 доказывается способом вне таксономии §2.5 («замер при реализации, числа в issue» — запрещено правилом 18) | Колонка «Доказательство» строки AC6 переписана на «ревью кода (иллюстративные числа — комментарий автора в issue, не доказательство)» — выбран путь (b) из двух предложенных r1; критерий AC6 сформулирован как структурное утверждение, проверяемое чтением кода (отбор по диффу не изменён, сужение только через `splitByLedger`, версия-инвариантность — следствие AC1), а не как конкретное число мутантов | Тело issue #481, таблица «Критерии приёмки», строка AC6 | +| Low 3: влияние на perf/touch не названо явно словом «нет» (снято r1 без правки, с запиской) | Закрыто попутно тем же новым разделом: «Влияние на perf/touch/UX — нет: затронуты только скрипты, workflow и тесты» | Тело issue #481, конец «### 6. Откат» | + +## Унаследовано из r1 + +Документ: `docs/reviews/SPEC-REVIEW-481-r1.md` (коммит `2f65a184`; материал раунда — +`dev` на момент r1, SHA ветки в документе не резолвлен — по §2.10 это нормальный +случай, не находка). + +Принято без повторной проверки по существу: +- AC1–AC5 и AC7 однозначны, проверяемы, попадают в разрешённую таксономию доказательств + (unit / контрактный тест воркфлоу / отрицательные прогоны свидетелей); на ветке + задачи для них есть реальные автотесты, различающие правильное и сломанное поведение. +- Ссылки на #475, #480, #472, #388 точны и соответствуют описанию автора. +- Технические факты не домысел: `guardFiles()` экспортирована, `visualFingerprint` и + нормализация версии существуют в `scripts/source-fingerprint.mjs`, структура + `MUTANT_DEFINITIONS` соответствует описанию. +- Раздел «Что не меняется» корректно ограничивает скоуп (полный прогон, `--check`, + `--id` журнал не читают). +- `actions/cache/save … if: always()` — осознанное обоснованное отступление от + соседнего success-only паттерна `performance_smoke`. +- Трек `small` обоснован: критерии §5 выполняются одновременно; файла + `docs/specs/481-*.md` нет. +- «Затронутые файлы» — верно, всё класса B/C, ни одного класса A; подтверждено + дополнительно и в этом раунде: `git diff --stat` с момента r1-документа (коммит + `2f65a184`) по текущий HEAD `2c50e736` трогает ровно перечисленные файлы + (`scripts/mutation-gate.mjs`, `scripts/source-fingerprint.mjs`, + `.github/workflows/validate.yml`, `test/mutation-gate.test.mjs`, + `test/validate-workflow.test.mjs`, `docs/TESTING.md`) плюс служебный + `docs/images/screenshots.json` (отпечаток скриншотов, механика докс-гейта, не + продуктовый файл) — класс A по-прежнему не задет. + +## Находки нового раунда + +Нет. High: 0, Medium: 0. + +## Что проверено и корректно (в этом раунде) + +- Текст нового раздела «Откат» точно соответствует поведению `readLedger`, + независимо подтверждённому ещё в r1 чтением кода ветки: отсутствующий, битый или + несовпадающий по схеме файл трактуется как пустой журнал. +- AC6 больше не привязан к нефальсифицируемому числу и не требует ручного «замера»: + формулировка проверяема чтением кода, а поле доказательства явно в разрешённой + таксономии §2.5 и не нарушает правило 18 (числа помечены как иллюстрация, не + доказательство). +- Названные в комментарии автора исторические SHA (`052549fa`, `f2e38e48`, + `5d281171`, `04f4cd10`) существуют и соответствуют описанным событиям (релизный + кандидат, шардирование, докс-коммит) — иллюстрация не построена на выдуманных + ссылках, хотя сама она и не является доказательством AC6. +- Открытых продуктовых вопросов в тексте нет; догадок, выданных за решённое + поведение, не найдено — как в дельте, так и в унаследованной части (перепроверено + r1, не оспаривается). + +## Чего не проверял + +- Гейты (`tsc --noEmit`, `npm test`, `npm run build`) не гонялись: на этапе + spec-review материал — текст ТЗ, а не диапазон кода; тот же выбор сделал r1 для + этой же задачи по той же причине. `node scripts/check-docs.mjs` не запускался по + той же причине — этот этап не проверяет состояние `src/**`. +- Не пересчитывал побитово иллюстративные числа из комментария автора (132 из 134 + отобранных пропущено по журналу; 113 из 113 без изменения отпечатка на бампе + версии) — они явно помечены как не-доказательство, реальный прогон на историческом + диапазоне и фиксация команды/результата — задача код-ревью (вариант (b) из + находки r1 №2 прямо поручает это код-ревьюеру). +- Не переоценивал по существу реализацию на ветке `issue/481-mutation-ledger` — + это предмет код-ревью (§2.7), не этого этапа; использовал код только как + перекрёстную проверку (не домысел ли текст ТЗ), как и в r1. + +## Вердикт + +Зелёный. High: 0, Medium: 0. Обе Medium-находки r1 закрыты текстом issue дословно +по предложенным вариантам исправления, Low закрыт попутно. Статус — «Готово к +разработке». + +--- +Материал раунда: тело issue #481 на момент r2; предыдущий документ — +`docs/reviews/SPEC-REVIEW-481-r1.md` (коммит `2f65a184`); HEAD ветки на момент +этого разбора — `2c50e736` (detached, `origin/issue/481-mutation-ledger`). + +--- + + + +## Материал раунда + +- Ветка: `issue/481-mutation-ledger`, коммит `2c50e7367100` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `3d4c141fe31c1bad1f12948956a3246c678eec0c` + ``` + git log --all --format='%H %T' | grep 3d4c141fe31c + ```