From a261e54ce707266de04a30c030cff251cf964b5f Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Fri, 11 Sep 2026 09:54:24 +0000 Subject: [PATCH] docs: review document for #530 Issue: #530 User-Visible: no --- docs/reviews/SPEC-REVIEW-530-r2.md | 235 +++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 docs/reviews/SPEC-REVIEW-530-r2.md diff --git a/docs/reviews/SPEC-REVIEW-530-r2.md b/docs/reviews/SPEC-REVIEW-530-r2.md new file mode 100644 index 00000000..b150575d --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-530-r2.md @@ -0,0 +1,235 @@ +# SPEC-REVIEW-530-r2 + +**Issue:** #530 — «Экспорт в PDF: план занимает половину листа A4, а столбец выносов отбирает у него целый шаг масштаба» +**Этап:** spec (ревью ТЗ, PROCESS.md §2.4) +**Трек:** полный (см. r1 — обоснование не изменилось) +**Заход:** r2 · блокирующих циклов израсходовано 1 из 4 (зелёный вердикт этого раунда бюджет не тратит, #227) + +## Скоуп раунда + +Разбор по дельте (PROCESS.md §2.10): предмет этого раунда — правка тела issue, +которую автор внёс в ответ на SPEC-REVIEW-530-r1.md (вердикт: жёлтый, Medium 1, +Low 1). Раунд НЕ переоткрывает продуктовую рамку, AC1–AC6 и техническое +обоснование полного трека — они не входят в дельту и наследуются из r1. + +## Как найдена дельта + +Тело issue правится на месте (ТЗ живёт в теле issue, #517), поэтому вместо +`git diff ` использован диф двух состояний тела issue: + +1. якорь материала r1 в конце `docs/reviews/SPEC-REVIEW-530-r1.md`: `Тело issue: + 3c6248e088a3948ba1b6a44fafbc15118b8ad7706edb941b92b3fd9a4c8135ac`; +2. история правок тела issue вытянута через GraphQL + (`Repository.issue.userContentEdits`, поле `diff` = полный снимок тела на + момент каждой правки, 5 снимков, автор — Matysh, последняя правка + `2026-09-11T09:48:17Z`); +3. `sha256sum` снимка `2026-09-11T09:37:32Z` (правка, сделанная непосредственно + перед комментарием «ТЗ готово — на ревью», `09:37:50Z`) — + `3c6248e088a3948ba1b6a44fafbc15118b8ad7706edb941b92b3fd9a4c8135ac` — совпал + побайтово с якорем r1. Это доказывает, что снимок и есть точный текст, + получивший вердикт r1, а не приближение; +4. `diff -u` этого снимка с текущим телом issue (снимок `09:48:17Z`, совпадает + с текущим телом issue с точностью до конечного перевода строки) дал + дельту раунда — приведена целиком ниже. + +```diff +@@ раздел «ТЗ», шапка @@ +-**Чего задача не трогает:** i18n, кроме удаления ключа `pdf.internal_dimensions`; ... ++**Документация:** правка меняет канонический `docs/PDF-EXPORT.md` — раздел ++«Sheet and measurement rules» описывает и выноски («required values that ++cannot fit beside an edge use numbered callouts», «architecture, enabled ++dimensions and callouts»), и правило отказа («If a fixed annotation itself ++cannot fit on one A4 sheet, export stops with an error»), единственный ++код-путь к которому — именно столбец. Документ правится тем же коммитом, ++формулировки — в п. 1 и 5 контракта. ++ ++**Чего задача не трогает:** i18n, кроме удаления ключа `pdf.internal_dimensions` ++из словарей; ... + +@@ Контракт, п.1 @@ +-... становится общим. ++... становится общим. `docs/PDF-EXPORT.md`: фраза про numbered callouts ++заменяется на «значение, которому не хватает места у ребра, не печатается», ++упоминание callouts в перечне состава сцены снимается. + +@@ Контракт, п.5 @@ +-5. **Отказ «fail closed» сохраняется** для архитектуры, которая не влезает ни +- в один масштаб (#53). Существующий тест ... не удаляется молча. ++5. **Отказ «fail closed» сохраняется только для архитектуры**, которая не ++ влезает ни в один масштаб (#53); формулировка в `docs/PDF-EXPORT.md` ++ сужается соответственно. Существующий тест ... не удаляется молча. ++6. **Мутант `pdf-room-edge-dropped` переоформляется.** Сегодня он защищает ++ гарантию «каждое неукороченное ребро сохраняет прямое значение или ++ нумерованный вынос», которую отменяет п. 1. Его `because` и гард ++ переписываются под новую гарантию (значение печатается там, где ++ помещается, и не печатается дважды) либо мутант снимается с явной ++ записью — решение принимается при реализации и называется в хендоффе. + +@@ AC-таблица @@ ++| AC7 | `docs/PDF-EXPORT.md` описывает новое поведение: ни «numbered ++ callouts», ни отказ из-за неразмещаемой аннотации | тест свежести ++ документации на слова-маркеры либо проверка ревьюером построчно | ++ расхождение документа и кода — находка ревью | + +@@ Откат @@ +-Один revert: возвращаются блок выносов, метки и прежние кегли; golden-кадры +-и два теста восстанавливаются из истории. ... ++Один revert: возвращаются блок выносов, метки, прежние кегли и прежний текст ++`docs/PDF-EXPORT.md`; golden-кадры и два теста восстанавливаются из истории. ... +``` + +Больше ничего в теле issue не изменилось (сверено полным `diff -u` двух +снимков — выше единственные пять хвостов различий, плюс безобидное «нет +финального перевода строки» в самом старом снимке). + +## Закрытие раунда r1 + +| Находка r1 | Чем закрыта | Где это видно | +|---|---|---| +| **Medium** — правка меняет два поведения, задокументированные в `docs/PDF-EXPORT.md` (строки 32/58-59 про callouts, строки 41-42 про fail-closed), но документ не назван ни в скоупе, ни в release-артефактах | Добавлен абзац **«Документация»** в шапку ТЗ с прямой цитатой обеих исходных фраз документа и указанием, что они правятся тем же коммитом; п.1 контракта получил конкретную замену фразы про numbered callouts; п.5 сужен явно («только для архитектуры... формулировка в `docs/PDF-EXPORT.md` сужается соответственно»); добавлен **AC7**, прямо требующий отсутствия обеих устаревших формулировок в документе, с указанным способом доказательства | Тело issue #530, абзац «Документация» (после раздела «ТЗ»); Контракт п.1 и п.5; строка AC7 в таблице AC | +| **Low** — мутант `pdf-room-edge-dropped` защищает гарантию, которую AC1 отменяет, и его судьба не названа | Добавлен **п.6 контракта**: мутант либо переоформляется под новую гарантию, либо снимается — решение и его запись обязательны в хендоффе реализации, то есть решается явно, а не молчанием | Тело issue #530, Контракт п.6 | + +Обе находки закрыты предметно (конкретной правкой текста, а не общим +заявлением автора) — проверено чтением дельты выше, не пересказом комментария. + +## Дельта: что перепроверено заново + +Дельта не задевает продуктовую рамку, контракт п.2–п.4, AC1–AC6, риски, +блок допущений и таблицу критериев полного трека — эти AC перепроверке не +подлежат в этом раунде (см. «Унаследовано из r1»). + +Перепроверено: + +- **Абзац «Документация» и правки п.1/п.5.** Сверено с текущим текстом + `docs/PDF-EXPORT.md` (прочитан целиком, строки 29-59 — раздел «Sheet and + measurement rules»): обе цитаты в ТЗ («required values that cannot fit + beside an edge use numbered callouts», строка 58-59; «If a fixed annotation + itself cannot fit on one A4 sheet, export stops with an error», строки 41-42) + совпадают с документом дословно. Раздел «Release-артефакты» после правки + всё ещё называет только два бюллетеня changelog и не включает документацию + явным пунктом — но абзац «Документация» в шапке ТЗ и п.1/п.5 контракта + закрывают именно то требование DoR §2.5 («документация... либо явное "нет"»), + на которое указывала находка r1: документ назван, что в нём меняется — + указано текстуально. Формального отдельного пункта в самом + «Release-артефакты» нет, но это не тот же дефект: r1 требовал, чтобы + задача **знала**, что трогает канон, и зафиксировала это — так и сделано, + двумя явными местами в тексте, а не одним. Дробить находку второй раз за + место расположения абзаца было бы формализмом без нового риска для DoR. +- **AC7.** Проверяем самостоятельно, так как в r1 не существовал. + Утверждение проверяемо построчным чтением: после правки в `PDF-EXPORT.md` + не должно остаться ни фразы про «numbered callouts», ни фразы про отказ + из-за неразмещаемой фиксированной аннотации, кроме случая «архитектура не + влезает ни в один масштаб». Способ доказательства назван («тест свежести + документации... либо проверка ревьюером построчно») — это ровно два + метода, разрешённых DoR/§2.7 для этого класса критерия (`unit`-тест на + маркерные слова, либо `«ревью кода»`/чтением). Формулировка «либо» не + делает AC недоказуемым: она называет запасной путь на случай, если + автоматический тест на слова-маркеры не будет написан, а не оставляет + открытым вопрос, что именно проверяется. +- **П.6 контракта (мутант).** Прочитан `scripts/mutation-gate.mjs:224-247` + повторно: `pdf-room-edge-dropped` — единственный мутант, ссылающийся на + тест `dense non-rectangular rooms keep mandatory dimensions in stable + callouts`, который AC1 переписывает на противоположное утверждение. Два + новых мутанта из AC1/AC2 (`pdf-restores-dimension-callouts`, + `pdf-keeps-large-in-plan-labels`) покрывают ту же зону риска (столбец не + возвращается; подписи не растут обратно) — значит, снятие старого мутанта + без замены не оставляет гарантию непокрытой, и формулировка «переоформляется + либо снимается» не открывает дыру в защите, а фиксирует, что она перенесена. +- **Язык замены фразы.** П.1 даёт русскую формулировку-замену + («значение, которому не хватает места у ребра, не печатается») для + англоязычного документа. Не находка: весь текст ТЗ русский и описывает + предполагаемую английскую формулировку по смыслу, а не диктует точную + строку символ-в-символ — точная английская фраза прямо оставлена + реализации (AGENTS.md: не-продуктовая формулировка — техническая свобода + автора кода), и AC7 проверяет результат («нет старых фраз»), а не текст + замены дословно. + +Ни один из пересмотренных пунктов не порождает новой High- или +Medium-находки. + +## Унаследовано из r1 + +Без повторной проверки в этом раунде — документ `docs/reviews/SPEC-REVIEW-530-r1.md`, +материал `Тело issue: 3c6248e08...8135ac` (совпадение подтверждено выше): + +- продуктовая рамка §7.1 (персона, поверхность, момент, «до/после» одной фразой); +- выбор полного трека и оба названных нарушенных критерия §5 (перф-бюджет + 200 мс, смена UX-контракта — ориентация и потеря раздела); +- все количественные утверждения о текущем коде: `PDF_SCALE_SERIES`, кегли + 7/8/9-7/6/8/6, хром страницы 14/10/8/7, арифметика ×0.75; +- AC1–AC6 по существу (состав, формулировка, способ доказательства и мутанты + каждого) — дельта их текст не меняла; +- содержание блока «Принято предположительно» (пилообразное заполнение вне + задачи, поля/шапка/подвал не трогаются, выноска у стены — не эта задача); +- риски (кегль 5.25 pt на грани практики, потеря семи коротких размеров, + необходимость пересъёмки golden на Linux CI, смена ориентации на книжную); +- откат — один revert (дельта лишь добавила упоминание `docs/PDF-EXPORT.md` + в перечень возвращаемого, не изменив механику). + +## Что проверено и корректно (этот раунд) + +- Обе находки r1 закрыты предметно, текстом, а не декларацией — таблица выше. +- Новый AC7 сформулирован проверяемо и называет способ доказательства из + разрешённого набора. +- Новый п.6 контракта не оставляет гарантию, отменяемую AC1, без замены — + два новых мутанта AC1/AC2 покрывают тот же риск. +- Цитаты ТЗ из `docs/PDF-EXPORT.md` (строки 41-42, 58-59) сверены с файлом + дословно — расхождений нет. +- Дельта не расширяет скоуп и не меняет ни одного количественного значения + из AC1–AC6. + +## Чего не проверял + +- Не переоткрывал разделы, не затронутые дельтой (продуктовая рамка, AC1–AC6, + риски, блок допущений) — согласно PROCESS §2.10 п.4, это наследуется из r1 + без повторной проверки; см. раздел выше. +- Не проверял `demo/smoke_pdf_export.mjs` и golden-фикстуры повторно — дельта + их не касается, а r1 уже отметил их как непроверенные построчно (без + видимого зазора при беглом grep) и это не изменилось. +- Не запускал никаких гейтов (`tsc`, `test`, `build`) — этап ТЗ, продуктового + кода ещё нет, оценивать нечем; так же было отмечено в r1. +- Не проверял точность самих числовых замеров аналитики S2 повторно — это + вне дельты, r1 объяснил, что это воспроизводимый прогон Node-скрипта, а не + предмет ревью ТЗ. + +## Вердикт + +Зелёный. Обе находки предыдущего раунда (Medium — документация не названа в +скоупе/release-артефактах; Low — судьба мутанта `pdf-room-edge-dropped` не +решена) закрыты предметной правкой текста ТЗ, а не заявлением. Дельта не +вносит новых High- или Medium-находок: новый AC7 проверяем, новый п.6 +контракта не оставляет отменяемую AC1 гарантию без замены. Остальное ТЗ +(продуктовая рамка, AC1–AC6, риски, блок допущений, откат) не затронуто +дельтой и наследуется из r1 без повторной проверки. + +--- + +Вердикт: зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0 + +--- + +## Материал раунда + +- Тело issue #530: снимок `2026-09-11T09:48:17Z` (текущее состояние на момент + ревью), сверено побайтово (`diff -u`, единственное расхождение — конечный + перевод строки). +- Предыдущий материал (r1): тело issue, снимок `2026-09-11T09:37:32Z`, + `sha256: 3c6248e088a3948ba1b6a44fafbc15118b8ad7706edb941b92b3fd9a4c8135ac` + — совпадает с якорем `docs/reviews/SPEC-REVIEW-530-r1.md`. +- Источник снимков: GraphQL `Repository.issue.userContentEdits.nodes[].diff` + (5 правок автора Matysh между `09:15:46Z` и `09:48:17Z`), так как тело issue + правится на месте и `git diff ` неприменим к этапу spec. + +--- + + + +## Материал раунда + +- Ветка: `dev`, коммит `af2081cbc40e` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `08815814f33b6c836ecbd32deabf793353fc1bb1` + ``` + git log --all --format='%H %T' | grep 08815814f33b + ``` +- Тело issue: `53fbdfb3b618a562787718e73ee5aa952eda2d9846768cdac42273c2de7ec382` +- Вердикт конвейера: `green` · High 0