Files
houseplan-card/docs/reviews/SPEC-REVIEW-265-r2.md
T
2026-08-25 11:09:33 +00:00

17 KiB
Raw Blame History

SPEC-REVIEW-265-r2

  • Issue: #265 — «Рефакторинг 2/5: один контракт шва импорта — ремап ссылок за собой и идемпотентная уборка»
  • Этап: S4-spec-review (ревью ТЗ, PROCESS.md §2.4)
  • Заход: r2 · блокирующих циклов израсходовано 1/4 до этого вердикта
  • ТЗ: docs/specs/265-import-reference-seam.md, ветка issue/265-import-seam-contract, SHA на момент ревью — HEAD (67bcce8e, коммит «docs: address import seam spec review»)
  • Ревьюер: Claude (свежая сессия, без переписки с автором)

Скоуп ревью

Второй заход, разбор по дельте (PROCESS.md §2.10, issue #214). Продукт кода в этой задаче ещё нет — единственный изменённый файл класса C — docs/specs/265-import-reference-seam.md; диапазон дельты git diff 2cf47fc1..HEAD -- docs/specs/265-import-reference-seam.md (2cf47fc1 — SHA, на котором получен вердикт r1, назван явно в шапке SPEC-REVIEW-265-r1.md, повторно искать его не пришлось).

Дельта локальна: автор правил ровно те четыре раздела, на которые указали находки r1 (сценарий/«до-после», i18n-обязательства AC10, способ доказательства по каждому AC, раздел рисков), плюс сквозную перенумерацию заголовков, вызванную вставкой двух новых секций. Контракт поведения (lineage-алгоритм, матрица ссылок, immutable candidate, порядок remap, edge cases) не менялся ни по одной строке — рёбейза на ушедший вперёд dev не было, новая подсистема не затронута, объём правки заметно меньше исходной задачи. Условия «разбор остаётся полным» (§2.10) не выполнены — сокращение объёма законно.

Закрытие раунда r1

Находка r1 Чем закрыта Где это видно
M1 — «что человек увидит» слито со сценарием, написано языком реализации; поверхность/touch не названы Раздел разделён на «§1 Сценарий и персона» и «§2 Что человек увидит до и после»; «До/После» переписаны бытовым языком без «lineage»/«canonical root»/«candidate»; отдельно назван desktop-only статус и touch/kiosk-поведение docs/specs/265-import-reference-seam.md:19-50
M2 — AC10 хеджирует «если отчёт станет виден», хотя §9(старое)/§10(новое) уже безусловно описывает новый текст; i18n-ключи не перечислены AC10 переписан без условности; конкретные RU/EN ключи перечислены поимённо AC10: 265-import-reference-seam.md:435-439; список ключей: 265-import-reference-seam.md:292-305
M3 — AC1–AC9 не называют способ доказательства Добавлена таблица «§15.1 Матрица доказательств» — по одной строке на каждый AC1–AC10 265-import-reference-seam.md:441-454
M4 — нет отдельного обязательного раздела «Риски» Добавлен «§13. Риски» — таблица из 8 строк (риск / последствие / снижение) 265-import-reference-seam.md:347-358

Все четыре находки r1 закрыты предметно, не декларативно: в каждом случае в дельте есть конкретный новый текст, а не переформулировка старого абзаца под тем же смыслом.

Унаследовано из r1

Без повторной проверки принято (документ docs/reviews/SPEC-REVIEW-265-r1.md, SHA 2cf47fc1, полный разбор первого захода):

  • §3 «Подтверждённое состояние кода» (было §2) — построчная сверка с import_export.py (_fresh, _repair_target_space_refs, preview/apply/revalidate) и с пробелами scripts/model-invariants.mjs; текст не менялся, изменился только номер раздела;
  • §4 «Унаследованные продуктовые решения» (было §3) — сверка со статусом и текстом закрытых #244/#248/#252/#258/#262; содержимое не менялось;
  • §5 «Цели и границы» (было §4), §6 «Канонический lineage id» (было §5, включая проверку edge case с ложным совпадением root), §7 «Неизменяемый кандидат preview/apply» (было §6), §9 «Порядок remap и конфликты» (было §8), §11 «Инварианты и отказоустойчивость» (было §10), §12 «Совместимость и миграция» (было §11), §14 «Edge cases» (было §12), §16–§19 (план реализации, проверки, rollback, допущения) — содержимое не менялось, изменилась только нумерация;
  • терминология («Оптимизировать планы», «carrier») — сверена с docs/USER-GUIDE.ru.md/docs/WALL-THICKNESS.md в r1, дельта эти фразы не трогает;
  • три «унаследованных решения владельца» и отсутствие продуктовых вопросов владельцу — не пересматривались, дельта их не касается.

Как проверялось

  1. Найден вердикт r1 и SHA: docs/reviews/SPEC-REVIEW-265-r1.md называет SHA 2cf47fc1 в шапке документа явно — искать по логу не пришлось.
  2. Дельта: git diff 2cf47fc1..HEAD --stat — изменены только docs/specs/265-import-reference-seam.md (+168/-63 строк) и сам файл docs/reviews/SPEC-REVIEW-265-r1.md (добавлен публикующим шагом, не автором). Продуктового кода в дельте нет.
  3. По каждой из находок M1–M4 найдена конкретная замена в тексте (таблица выше), а не общее заявление «поправлено» — сверено построчно через git diff 2cf47fc1..HEAD -- docs/specs/265-import-reference-seam.md.
  4. Проверены новые фактические утверждения, добавленные именно в этой дельте (§2.10 требует разбирать AC/утверждения, которых касается дельта, а новый текст i18n-ключей и таблицы доказательств — целиком продукт этой дельты):
    • backup.repaired_target_refs и backup.dropped_marker_links — существуют в src/i18n/en.json:995-996 и src/i18n/ru.json:995-996, утверждение «существующие … сохраняются» подтверждено, а не угадано;
    • docs/USER-GUIDE.md/docs/USER-GUIDE.ru.md существуют, термины «Оптимизировать планы»/«Общие настройки» в них есть;
    • check-docs (упомянут в матрице доказательств AC10) — scripts/check-docs.mjs существует;
    • check-i18n (упомянут в той же строке AC10) — не существует: нет такого имени ни в package.json (python3 -c "..." дамп секции scripts), ни файла scripts/check-i18n.mjs, ни упоминания в .github/workflows/*.yml. Единственная реальная механическая проверка en/ru паритета ключей — тест test/i18n.test.mjs («i18n: en and ru dictionaries carry the same key set»), часть обычного npm test, а не отдельная команда с таким именем. См. находку M5 ниже.
  5. Проверена внутренняя согласованность перенумерации: grep -n '§[0-9]' по всему файлу — все перекрёстные ссылки (§8 в 6.2, AC3, 15.1; §10 в AC10) указывают на корректный новый номер соответствующего раздела; провисших ссылок на старые номера не найдено.
  6. Гейты этапа: npx tsc --noEmit/npm test/npm run build не запускались — диапазон дельты не содержит кода (только docs/specs/**), на этапе S4-spec-review продуктового кода ещё нет, гейты по своему условию неприменимы — то же основание, что в r1. node scripts/check-docs.mjs не запускался: дельта не касается src/**.

Находки

M5 — AC10 называет несуществующий гейт check-i18n как обязательное доказательство (Medium, в скоупе)

Файл: docs/specs/265-import-reference-seam.md, §15.1 «Матрица доказательств», строка AC10 (443-454, конкретно строка со списком `check-i18n`, `check-docs`, RU/EN guide/changelog diff, targeted browser smoke и reviewed canonical golden import preview).

Это прямое следствие правки M3 (появление самой таблицы) — то есть новая находка внутри дельты этого раунда, а не наследие r1.

check-i18n не существует нигде в репозитории: ни как npm-скрипт в package.json (полный список ключей scripts не содержит такого имени; единственный i18n-related артефакт — test/i18n.test.mjs), ни как файл scripts/check-i18n.mjs, ни как шаг в .github/workflows/*.yml. Реальная механическая проверка паритета en/ru-ключей — тест test/i18n: en and ru dictionaries carry the same key set внутри обычного npm test; check-docs.mjs в этой же строке — существующий скрипт (scripts/check-docs.mjs), это единственная корректная часть строки.

Это ровно тот класс дефекта, о котором предупреждает регламент ревью: утверждение об инструменте, которого нет ни в одном документе и ни в одном скрипте, вписано в раздел, чья единственная функция — назвать проверяемый способ доказательства AC (DoR §2.5: «у каждого указано, чем он доказывается»). Разработчик на S7 либо потратит время на поиск несуществующей команды, либо спишет её как опечатку без исправления текста ТЗ — оба исхода хуже правильной строки с самого начала.

Почему Medium, а не High: не меняет дизайн, не блокирует понимание контракта — соседние 9 строк таблицы верны и однозначны, ошибка локальна к одному имени в одной ячейке.

Как чинится: заменить check-i18n на существующий механизм — например, «npm test (test/i18n.test.mjs, паритет ключей en/ru) плюс ручная сверка переводов ревьюером» — без изменения остального содержания строки AC10 и без изменения самого AC10.

Что проверено и корректно

  • Все четыре находки r1 (M1–M4) закрыты предметно: в каждом случае есть новый фрагмент текста, отвечающий именно на то, что просила находка, а не косметическая переформулировка (детали — таблица «Закрытие раунда r1»).
  • Новые фактические утверждения, добавленные этой дельтой (существующие i18n-ключи, check-docs.mjs, наличие USER-GUIDE.md/USER-GUIDE.ru.md), проверены по факту, а не приняты на слово — кроме check-i18n (см. M5), все подтвердились.
  • Раздел рисков (§13) содержит по одному пункту на каждый архитектурно значимый риск, который upstream-документ и r1-ревью уже обсуждали (ложное совпадение lineage, расхождение Python/TS, память preview, неполнота матрицы, duplicate-policy vs light-link, fail-closed на legacy, revalidate race, повреждение геометрии) — пусто не осталось.
  • Перенумерация разделов (1→19) внутренне согласована, ни одной "битой" перекрёстной ссылки на старый номер не найдено.
  • Раздел «Что человек увидит» (§2) теперь отвечает на вопрос PROCESS.md §7.1 без терминов реализации, а §1 явно называет desktop/View/kiosk/touch поверхности — ровно то, чего не хватало в r1.
  • docs/specs/README.md не тронут в этой дельте (правка не требовалась, строка таблицы уже добавлена в r1 и остаётся верной).

Чего не проверял

  • Не запускал typecheck/test/build/смоки/инварианты — продуктового кода в дельте нет, гейты неприменимы на этапе S4-spec-review (то же основание, что в r1).
  • Не проверял node scripts/check-docs.mjs — дельта не касается src/**.
  • Не пересматривал технические решения §3–§9, §11–§12, §14, §16–§19 — дельта их не касается, унаследованы из r1 (раздел выше).
  • Не проверял конкретные будущие формулировки переводов en/ru строк отчёта (backup.preserved_unresolved_hint и др.) на стилистическую корректность — тексты появятся в реализации, это предмет код-ревью.
  • Не оценивал эффективность/производительность заново — алгоритмическая часть (§6, §8, §9, §11) дельтой не изменена, оценка r1 остаётся в силе.

Вердикт

Все четыре находки r1 закрыты предметно и проверяемо. Дельта этого раунда, однако, сама вносит одну новую Medium-находку в скоупе — несуществующий гейт check-i18n, названный обязательным доказательством AC10. High-находок нет, находка вне скоупа не заводится: правка ограничена той же ячейкой той же таблицы, которую и так предстоит один раз перечитать.

Вердикт: жёлтый · заход r2 · блокирующих циклов 2/4 · High: 0 · Medium: 1 → в задаче