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

14 KiB
Raw Blame History

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