docs: review document for #481

Issue: #481
User-Visible: no
This commit is contained in:
claude[bot]
2026-09-06 21:00:39 +00:00
parent f8ae546fb0
commit df4104ab38
+150
View File
@@ -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`).
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/481-mutation-ledger`, коммит `2c50e7367100` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `3d4c141fe31c1bad1f12948956a3246c678eec0c`
```
git log --all --format='%H %T' | grep 3d4c141fe31c
```