17 KiB
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, дельта эти фразы не трогает; - три «унаследованных решения владельца» и отсутствие продуктовых вопросов владельцу — не пересматривались, дельта их не касается.
Как проверялось
- Найден вердикт r1 и SHA:
docs/reviews/SPEC-REVIEW-265-r1.mdназывает SHA2cf47fc1в шапке документа явно — искать по логу не пришлось. - Дельта:
git diff 2cf47fc1..HEAD --stat— изменены толькоdocs/specs/265-import-reference-seam.md(+168/-63 строк) и сам файлdocs/reviews/SPEC-REVIEW-265-r1.md(добавлен публикующим шагом, не автором). Продуктового кода в дельте нет. - По каждой из находок M1–M4 найдена конкретная замена в тексте (таблица
выше), а не общее заявление «поправлено» — сверено построчно через
git diff 2cf47fc1..HEAD -- docs/specs/265-import-reference-seam.md. - Проверены новые фактические утверждения, добавленные именно в этой дельте
(§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 ниже.
- Проверена внутренняя согласованность перенумерации:
grep -n '§[0-9]'по всему файлу — все перекрёстные ссылки (§8в 6.2, AC3, 15.1;§10в AC10) указывают на корректный новый номер соответствующего раздела; провисших ссылок на старые номера не найдено. - Гейты этапа:
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 → в задаче