# SPEC-REVIEW-482-r2 — Доводка экспорта пространства в PDF - **Issue:** https://github.com/Matysh/houseplan-card/issues/482 - **Этап:** ревью ТЗ (PROCESS.md §2.4) - **ТЗ:** `docs/specs/482-pdf-export-polish.md` - **Трек:** полный (не пересматривается в r2 — решение аналитики #482 не задето дельтой) - **Заход:** r2 · блокирующих циклов израсходовано 1 из 4 (до этого вердикта) ## Скоуп ревью Второй заход, разбор по дельте (PROCESS.md §2.10, issue #214) — дельта локальна, полный повторный разбор не требуется, обоснование ниже. 1. **Вердикт предыдущего раунда:** комментарий `claude`, 2026-09-07T06:15:24Z — жёлтый · r1 · High: 0 · Medium: 1 → в задаче (M1, provenance/лицензия векторного компаса). Документ: `docs/reviews/SPEC-REVIEW-482-r1.md`. 2. **Материал r1** взят из блока «Материал раунда» в конце того документа: ветка `issue/482-pdf-export-polish`, коммит `bc93babdf8e7dc346e3465a72b8f2927875095d7`. SHA живой, не осиротел: `git cat-file -t bc93babdf8e7` → `commit`; дерево `38bf116ad9ad52b85ed8e0aaee3799819a5a1e58` резолвится тем же коммитом (`git log --all --format='%H %T' | grep 38bf116ad9ad` → одна строка, тот же SHA). Дельта объявляется напрямую по SHA, без content-addressing якорей — ребейза между r1 и r2 не было. 3. **Дельта:** `git diff bc93babd..HEAD` (HEAD = `5c1175cebc8d393f0b08488f76c11411ed686cd0`, коммит «docs: pin PDF compass provenance»). Единственный содержательный файл — `docs/specs/482-pdf-export-polish.md`, 16 insertions / 5 deletions, целиком внутри раздела «13. Векторный компас». Второй изменившийся файл — `docs/reviews/SPEC-REVIEW-482-r1.md`, который дельту не образует: это публикация предыдущего вердикта, ожидаемый артефакт конвейера, а не правка автора. Тела issue #482 и комментариев дельта не касается: сверил текущее тело issue и полный список комментариев (5 шт.) — новых продуктовых вопросов или уточнений владельца после r1 нет, последний комментарий владельца — анонс фикса M1. 4. **`src/**` не тронут:** `git log --oneline 08aad891..HEAD -- src/` пуст — ветка по-прежнему содержит только ТЗ и review-документы поверх `v1.73.0-beta.3`; это по-прежнему этап spec, гейтов кода нет и не может быть. 5. **Почему разбор сокращённый, а не полный:** дельта не задевает ни ребейз на ушедший вперёд `dev` (SHA r1 жив в текущей истории), ни новую подсистему, ни контракт поведения — правка меняет только текст обоснования provenance одного SVG-ассета. Объём дельты (11 чистых строк) несопоставим с исходной задачей (485 строк ТЗ, 12 AC, 6 подсистем). Единственный AC, чьё доказательство эта дельта задевает, — AC8 (§17, «license сохранена», `docs/specs/482-pdf-export-polish.md:393`). ## Как проверялось - Перечитал §13 ТЗ целиком (`docs/specs/482-pdf-export-polish.md:308-338`) — и старую версию на `bc93babd`, и новую на `HEAD`, построчно через `git diff bc93babd..5c1175ce -- docs/specs/482-pdf-export-polish.md`. - Сверил формулировку M1 (r1) с текстом финта: старая ссылка на `master` (`.../blob/master/icons/travel/compass-line.svg`) заменена на три ссылки на **неизменяемый** upstream commit `bf6bdd0dd3f247f1a320d44d13fecdeda18c071c` (сам commit, файл в нём, `LICENSE` в нём) — это устраняет именно тот дефект, который называл r1: ссылка на движущуюся `master` не может уехать и стать неверной незаметно, потому что коммит зафиксирован по SHA. - Проверил, что новая формулировка **не скрывает** несовпадение SHA-256: старый текст утверждал «совпадает по path с каноническим ассетом» без уточнений; новый прямо признаёт, что файл владельца **не совпадает побайтово** с upstream (SVG Repo добавил обёртку и `800×800` вместо `36×36`), и указывает, что совпадают именно `viewBox` и оба `d` — то есть сузил claim ровно до того, что можно проверить сравнением текста, а не расширил его. Это соответствует одному из трёх путей закрытия, которые предлагал r1 («заменить ссылку на master точным commit/blob»), хотя автор не добавил формальную пометку «принято предположительно» — см. ниже, почему это не считаю новым замечанием. - Попытался независимо дойти до upstream `LICENSE` и `compass-line.svg` на зафиксированном commit через `WebFetch` — инструмент запросил разрешение и не получил его в этой сессии (тот же результат, что в r1 при попытке через `mcp__github__get_issue`/`WebFetch`; ограничение окружения, не находка). Поэтому байт-в-байт я по-прежнему не подтверждаю и не опровергаю — см. «Чего не проверял». - Проверил AC8 (`docs/specs/482-pdf-export-polish.md:393`) — текст критерия и способ доказательства («license check» отдельным пунктом в списке методов) не менялись дельтой и не нуждались в изменении: AC8 уже предполагал отдельную проверку лицензии на этапе код-ревью (когда ассет реально вендорится и появляется файл, который можно сравнить построчно), а не на этапе ТЗ. Пиннинг на неизменяемый commit — это именно то, что делает такую будущую проверку осмысленной (проверять фиксированный SHA, а не «текущее состояние master»). - Проверил остальные части ТЗ (§1–§12, §14–§20) на предмет того, не появилось ли противоречий или ссылок, которые эта правка могла разбалансировать — дельта географически изолирована в §13, соседние разделы (§12 — layout, §14 — footer/i18n) не ссылаются на provenance компаса и не пострадали. - Дешёвые гейты кода (`tsc`/`test`/`build`) не гонял: `src/**` не менялся ни в r1, ни в дельте r2 — гонять их не по чему, как и в r1. ## Закрытие раунда r1 | Находка r1 | Чем закрыта | Где это видно | |---|---|---| | **M1** — provenance/лицензия компаса заявлены как факт со ссылкой на движущуюся `master`, без воспроизводимого способа перепроверить | Ссылка на `master` заменена тремя ссылками на неизменяемый upstream commit `bf6bdd0dd3f247f1a320d44d13fecdeda18c071c` (сам коммит, файл, LICENSE); дополнительно текст перестал скрывать несовпадение SHA-256 владельца с upstream и объяснил его источником обёртки SVG Repo, сузив claim до проверяемого (`viewBox` + оба `d`) | `docs/specs/482-pdf-export-polish.md:312-329` (diff `bc93babd..5c1175ce`); коммит `5c1175cebc8d393f0b08488f76c11411ed686cd0` «docs: pin PDF compass provenance» | Считаю M1 закрытой без выхода за скоуп: правка того же раздела того же ТЗ, не новая подсистема. **Остаточное наблюдение (не новое Medium/Low, входит в «чего не проверял»):** фраза «Provenance проверен перед реализацией» звучит как уже свершившийся факт, хотя ни в r1, ни в r2 никто с доступом к вебу это не подтвердил — у меня `WebFetch` не авторизован в обеих сессиях. Это не возвращаю как отдельную находку, потому что: (а) сама правка отвечает на процессуальное требование r1 — reproducibility ссылки, а не немедленное личное подтверждение ревьюером; (б) AC8 уже называет «license check» отдельным методом доказательства, который по своей природе относится к моменту, когда ассет реально появляется в репозитории на этапе кода — это точка, где сравнение станет механическим (файл в коммите против зафиксированного upstream SHA), а не вопросом доверия к прозе ТЗ. Рекомендую код-ревью этой задачи явно подтвердить совпадение путём чтения обоих файлов (или через веб-доступ, если он будет у код-ревьюера), а не принимать формулировку ТЗ как готовое доказательство. ## Унаследовано из r1 Всё содержимое ТЗ вне §13 принято без повторной проверки в этом раунде — оно не входит в дельту (`git diff bc93babd..5c1175ce` не касается ничего, кроме §13.) Основание: `docs/reviews/SPEC-REVIEW-482-r1.md`, вердикт жёлтый на коммите `bc93babdf8e7dc346e3465a72b8f2927875095d7` (дерево `38bf116ad9ad52b85ed8e0aaee3799819a5a1e58`), раздел «Что проверено и корректно»: - продуктовая рамка и предложение «до/после» (§1–§2 ТЗ); - скоуп/не-скоуп и изменяемый контракт (§4–§6); - нормализация контуров, включая корневую причину ложной диагонали (§8); - локальная дедупликация противоположных сторон (§9); - полосы размещения размеров (§10); - материал стен/штриховка и компоновка листа (§11–§12); - footer/i18n (§14); - модель/миграция/rollback, touch/a11y/perf/security (§15–§16); - AC1–AC7, AC9–AC12 (§17) — не переоткрывались, дельта их доказательств не задевает; - тест-план и Windows/Linux границы golden (§18); - документация и release-артефакты (§19), карта изменений (§20). Наследование не распространяется на AC8 и §13 — они разобраны заново выше. ## Находки Нет. High: 0. Medium: 0 (M1 закрыта, новых не появилось). ## Что проверено и корректно - M1 закрыта воспроизводимым способом: ссылка на неизменяемый commit вместо движущейся ветки — именно то процессуальное требование, которое не выполнялось в r1 (аналогия с #159, где ссылка тоже не была проверяемой). - Текст стал честнее, а не более уверенным: явно признано несовпадение SHA-256 файла владельца с upstream и указана причина — это снижает, а не создаёт риск «выдать догадку за факт», потому что граница знания названа прямо (совпадают path/viewBox, не совпадает контейнер). - AC8 и способ его доказательства не нуждались в изменении: «license check» как отдельный метод уже покрывает верификацию на этапе кода. - Дельта не задела ни одну другую подсистему ТЗ; соседние разделы (§12 layout, §14 footer) остались согласованными сами с собой и с §13. - `src/**` не менялся — код по задаче ещё не написан, дешёвые гейты неприменимы на этом этапе, как и в r1. ## Чего не проверял - Не подтверждал независимо через веб, что зафиксированный upstream commit `bf6bdd0dd3f247f1a320d44d13fecdeda18c071c` в репозитории `vmware-archive/clarity-assets` действительно содержит указанный `compass-line.svg` с `viewBox 0 0 36 36` и обоими `d`-путями, и что `LICENSE` в том же коммите — действительно MIT с copyright VMware 2018: `WebFetch` запросил разрешение и не получил его в этой сессии, как и `mcp__github__get_issue`/`get_issue_comments` (те два я обошёл через `gh` CLI, у `WebFetch` такого обхода нет). Это не молчаливый пропуск — то же ограничение зафиксировано в r1, и я явно оставляю его на код-ревью (см. «Закрытие раунда r1» выше). - Не перепроверял AC1–AC7, AC9–AC12 — дельта их не касается, основание наследования указано в разделе выше. - Не гонял `tsc`/`test`/`build`/`golden`/смоки/инварианты модели — `src/**` не менялся ни разу за всю историю ветки, гонять нечего; это верно и для r1, и для r2. - Не проверял `docs/specs/README.md`/`docs/STATUS.md` на актуальность записи — дельта их не касается (эти файлы не менялись между `bc93babd` и `HEAD`, кроме самого добавления записи в r1, уже принятой). ## Вердикт Единственная находка предыдущего раунда (M1, Medium в скоупе) закрыта воспроизводимым способом; новых High/Medium/Low находок дельта не породила. Зелёный вердикт цикла не образует и бюджет не тратит (PROCESS.md §4, #227): израсходованный бюджет остаётся 1 из 4, заход — r2. --- --- ## Материал раунда - Ветка: `issue/482-pdf-export-polish`, коммит `5c1175cebc8d` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала: `4237e7ddaa1fab740d71ebb69648c824f2dd45c8` ``` git log --all --format='%H %T' | grep 4237e7ddaa1f ``` - ТЗ `docs/specs/482-pdf-export-polish.md`, блоб `c6f4fbd7cf5b3e84473ec68513054c3e5ff1e0f9` ``` git log --all --find-object=c6f4fbd7cf5b3e84473ec68513054c3e5ff1e0f9 -- docs/specs/482-pdf-export-polish.md ```