docs: review document for #530

Issue: #530
User-Visible: no
This commit is contained in:
claude[bot]
2026-09-11 09:54:24 +00:00
parent af2081cbc4
commit a261e54ce7
+235
View File
@@ -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 <SHA>` использован диф двух состояний тела 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 <SHA>` неприменим к этапу spec.
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `dev`, коммит `af2081cbc40e` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `08815814f33b6c836ecbd32deabf793353fc1bb1`
```
git log --all --format='%H %T' | grep 08815814f33b
```
- Тело issue: `53fbdfb3b618a562787718e73ee5aa952eda2d9846768cdac42273c2de7ec382`
- Вердикт конвейера: `green` · High 0