Files
houseplan-card/docs/reviews/SPEC-REVIEW-481-r2.md
T
2026-09-06 21:00:39 +00:00

151 lines
14 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-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
```