docs: review document for #593

Issue: #593
User-Visible: no
This commit is contained in:
claude[bot]
2026-09-19 06:19:11 +00:00
parent 41722e159b
commit 0ebefbb189
+135
View File
@@ -0,0 +1,135 @@
# SPEC-REVIEW-593-r3 — «Заменить все иконки библиотеки и расширить каталог до 60 плановых символов»
Issue: [#593](https://github.com/Matysh/houseplan-card/issues/593)
Этап: spec (полный трек, унаследовано из r1 — критерий «одна поверхность» нарушен явно: `src/**`, генератор, i18n, PDF-путь, golden, бюджеты)
Заход: r3 · блокирующих циклов израсходовано на входе в раунд: 1 из 4 (дано конвейером; r1 — красный, спорный цикл засчитан; r2 — красный, но зелёный вердикт этого раунда бюджет не тратит — §4, #227)
## Вердикт
**Зелёный.** High: 0. Medium в скоупе: 0. Medium вне скоупа: 0. Low: 0.
Разбор по дельте (§2.10): единственная блокирующая находка r2 (H1(new), Q3/AC10 —
провенанс) закрыта по существу двумя действиями владельца и правкой ТЗ (редакция 4).
Новых находок в затронутой дельтой области не обнаружено.
## Материал раунда (входные данные разбора)
- Тело issue #593 на момент разбора: `gh issue view 593 --json body` — редакция 4 от
19.09.2026, раздел `## ТЗ`, сохранённое предложение автора выше него.
- Все 8 комментариев issue: `gh issue view 593 --json comments` (добавились три новых
относительно материала r2: ответ владельца на Q1–Q3 `#issuecomment-5739749394` уже
был учтён r2; новые — полноценный грант `#issuecomment-5739841899` (2026-09-19T06:09:00Z)
и ответ на красный вердикт r2 `#issuecomment-5739855252` (06:12:00Z), которым
поставлена `S4-spec-review`, заход r3).
- Предыдущий раунд: [`docs/reviews/SPEC-REVIEW-593-r2.md`](../../docs/reviews/SPEC-REVIEW-593-r2.md),
вердикт красный, материал зафиксирован в его собственном машинном блоке якорей:
ветка `dev`, коммит `dcd6657581ba205edb63713e011a498b51983a20`, дерево
`0b48707268e99ee38221c8e74fb1c48ce6793e35`, тело issue sha256
`d3303755f955b90dcdf74279c7b76a98de9814103c65cfeb2a5455a49201d457`.
- Прецедент [#159](https://github.com/Matysh/houseplan-card/issues/159) — использован
повторно только в объёме, нужном для проверки, что новый грант (06:09:00Z) содержит
все три элемента, которые сам r2 процитировал из него дословно; заново не перечитывал
весь `docs/reviews/CODE-REVIEW-159-*` — это уже сделано r2 и не относится к дельте.
- Код: `test/furniture-assets.test.mjs` (тест `'release provenance is normalized to the
repository MIT grant'`, три `assert.match`: `issuecomment-5454085168`,
`issuecomment-5449707137`, SHA-256 архива 0.3.0), `assets/furniture/houseplan-0.3.0/README.md`
(для сверки структуры, которую редакция 4 обязана воспроизвести под новыми
значениями) — оба прочитаны заново для проверки закрытия H1(new). Полный grep
`houseplan-0.3.0` по `src/**`, `scripts/**`, `test/**`, `docs/**` — сверка §4 п.11
(«пять живых ссылок»).
- Ветка/код продукта: не создавались. `git log --oneline -- src/ custom_components/`
и `git diff origin/dev..HEAD -- src custom_components` — пусто; веток `issue/593-*`
нет. Рабочая копия на `HEAD = 2167d4396884c3c45ce7991ba603a91a13cdb381` (коммит
публикации документа r2). Гейты `typecheck`/`test`/`build`/`bundle:budget` не
запускал — этап ревью ТЗ, продуктовый код не существует; это же делали r1 и r2.
## Закрытие раунда r2
| Находка r2 | Чем закрыта | Где это видно |
|---|---|---|
| **H1(new).** Ответ владельца на Q3 («Подтверждаю собственное авторство иконок») давал только один из трёх элементов прецедента #159 (авторство, но не разрешение под MIT и не привязку к архиву); ТЗ, удаляя каталог `houseplan-0.3.0`, не планировало ни новый SHA-256, ни обновление исполняемого провенанс-теста, вынуждая исполнителя либо выдумывать значения, либо молча ослабить единственную защиту от повторения истории #159. | Владелец опубликовал отдельным комментарием ([`#issuecomment-5739841899`](https://github.com/Matysh/houseplan-card/issues/593#issuecomment-5739841899), 2026-09-19T06:09:00Z) полноценный грант: «Я являюсь автором всех 93 SVG из архива `houseplan-furniture-0.4.0.zip`… SHA-256 `69BA5E0C398542D59F24269F637F57B8EBF31C2836C9D493F084AD29AB299FDE`, размер 695 379 байт, и разрешаю House Plan использовать, изменять и распространять их на условиях MIT License репозитория без обязательной отдельной атрибуции» — присутствуют все три элемента прецедента: (а) авторство, (б) разрешение на использование/изменение/распространение под MIT, (в) привязка к конкретному архиву/версии. Дополнительно владелец лично сверил байты вложения, поданного `nikitaevfz-commits`, с копией, переданной напрямую (совпадающие SHA-256 и размер) — это сильнее, чем было доступно в #159. ТЗ доведено до редакции 4: §4 п.10 вводит `assets/furniture/houseplan-0.4.0/README.md` как провенанс-документ (ссылка на грант, имя архива, SHA-256, запрет ручной правки generated-файлов) и требует обновить (не ослабить) провенанс-тест «на новые значения — число `assert.match` не уменьшается»; §4 п.11 перечисляет все пять живых ссылок на путь `houseplan-0.3.0`, которые нужно перевести на `0.4.0`; AC10 переписан под оба факта; в §8 добавлен мутант `furniture-provenance-doc-loses-its-hash`; риск добавлен в §11 с явной атрибуцией «найдено ревью r2». | Комментарий `#issuecomment-5739841899` (текст выше); тело issue редакция 4, §3 «Q3. Авторство и лицензия», §4 п.10–11, §8 «Доказательства» → «провенанс», §10 AC10, §11 (пункт «Потеря провенанса…»); комментарий владельца `#issuecomment-5739855252` фиксирует переход в `S4-spec-review`, заход r3. |
Разбор закрытия — не по заявлению автора: см. «Как проверялось» ниже, где приведён построчный разбор нового текста гранта против трёх обязательных элементов прецедента и построчная сверка §4 п.11 с фактическим деревом.
## Как проверялось (дельта r2→r3)
1. **Три элемента гранта.** Сверил текст `#issuecomment-5739841899` построчно с шаблоном, который сам r2 процитировал из #159 («Я являюсь автором всех 77 SVG… и разрешаю… на условиях MIT License… без обязательной отдельной атрибуции»). Новый текст воспроизводит структуру предложение-в-предложение с заменой чисел (93 SVG вместо 77) и явно называет архив по имени (`houseplan-furniture-0.4.0.zip`) и версии, чего не хватало в предыдущем ответе («Подтверждаю собственное авторство иконок»). Все три элемента присутствуют одновременно в одном комментарии.
2. **Чистота цепочки поставки.** Прочитал добавленный владельцем абзац о совпадении байт вложения `nikitaevfz-commits` с копией, переданной напрямую (SHA-256 + размер). Это прямо снимает опасение H1(new) п.1 («тот же самый посторонний аккаунт второй раз подряд поставляет архив») — в отличие от #159, здесь есть явная проверка, а не только совпадение по умолчанию.
3. **Провенанс-документ и тест не выдуманы, а специфицированы количественно.** Перечитал текущий `test/furniture-assets.test.mjs:51-58` (3 `assert.match`: два URL на разные комментарии #159 + SHA-256 0.3.0) и `assets/furniture/houseplan-0.3.0/README.md` (структура: абзац гранта со ссылкой + абзац об архиве со второй ссылкой + SHA-256 + примечание про правку руками). §4 п.10 редакции 4 называет для нового README конкретные значения: ссылку на `#issuecomment-5739841899`, точное имя архива `houseplan-furniture-0.4.0.zip`, точный SHA-256 `69BA5E0C398542D59F24269F637F57B8EBF31C2836C9D493F084AD29AB299FDE`. Структура отличается от прецедента (там было два независимых URL — грант и отдельная attachment-комментарий стороннего аккаунта; здесь оба факта объединены в один комментарий владельца, поскольку архив был приложен в теле issue, а не отдельным комментарием стороннего участника, и тот же комментарий владельца уже содержит верификацию байт). Это техническое, не продуктовое расхождение (расположение и число ссылок в служебном README — деталь реализации, не то, что видит пользователь), и ТЗ фиксирует конкретные значения, а не оставляет их на усмотрение будущего исполнителя — угадывать нечего. Требование «число `assert.match` не уменьшается» (т.е. не менее 3) — измеримый порог.
4. **§4 п.11 — «пять живых ссылок» сверены с деревом.** `grep -rn "houseplan-0\.3\.0"` по `src/**`, `scripts/**`, `test/**`, `docs/**` (за вычетом `docs/reviews/**`, `docs/specs/**`, которые ТЗ явно исключает как исторические) даёт ровно перечисленные файлы: `scripts/generate-furniture-assets.mjs:9`, `test/furniture-path-join.test.mjs:40`, `test/furniture-assets.test.mjs:13,55` (две строки, как и написано — «(две — `pack.json` и `README.md`)»), `docs/FURNITURE.md:19`, `docs/STATUS.md:34`. Полное совпадение, ни одна ссылка не пропущена и не выдумана лишняя.
5. **Мутант `furniture-provenance-doc-loses-its-hash`.** Проверил `scripts/mutation-registry.mjs` на коллизию имени — вхождений нет, как и у четырёх мутантов, названных в r1/r2 (`furniture-legacy-shadows-designer-art`, `furniture-pack-accepts-foreign-symbol-count`, `furniture-cactus-lands-in-exercise`, `bundle-budget-lazy-ceiling-never-fires`). Мутант логически привязан к третьему столбцу AC10 и закрывает ровно тот путь деградации, который называла находка H1(new) п.6(б) («тихо ослабить тест»).
6. **Согласованность SHA-256/размера архива по всему документу.** Значение `69BA5E0C398542D59F24269F637F57B8EBF31C2836C9D493F084AD29AB299FDE` и «695 379 байт» повторяются в комментарии `#issuecomment-5739841899`, в §3 Q3 и в §4 п.10 ТЗ — все три вхождения совпадают побайтово (сверено копированием, не визуально), источник один — комментарий владельца; расхождений «одно число — два значения» не найдено. Формат строки (64 hex-символа) соответствует SHA-256.
7. **Отсутствие регрессии по остальным разделам.** Сверил, что редакция 4 не тронула ничего за пределами §3 Q3, §4 п.10–11, §8 (абзац «провенанс»), §9, §10 AC10, §11 (новый пункт риска), §12 (без изменений — продуктовые пункты по-прежнему отсутствуют, что и требуется после закрытия H1(r1)). Текст Q1/Q2, §5–§7, AC1-9/11, таблица мутантов (кроме добавленного пятого) — побайтово те же формулировки, что цитирует r2 — делали построчную сверку конкретно этих разделов, не полное построчное сравнение всего документа целиком.
## Что проверено и корректно (унаследовано + новое)
- Закрытие H1(new) — подтверждено по существу, см. таблицу и «Как проверялось» выше.
- §4 п.10 и п.11 — специфицированы количественно (конкретные значения ссылки/имени/хеша, точный список из пяти ссылок), не оставляют технического решения на угадывание исполнителя.
- Мутант `furniture-provenance-doc-loses-its-hash` не конфликтует по имени с реестром и логически закрывает найденный r2 путь тихого ослабления теста.
- Число и содержание release-артефактов (§9) согласовано с §4 п.10 (тот же путь `assets/furniture/houseplan-0.4.0/README.md`).
- Одно число — один источник: SHA-256 и размер архива фигурируют в трёх местах текста, все совпадают и восходят к одному комментарию владельца.
## Унаследовано из r2 (и через него — из r1)
Дельта r2→r3 ограничена §3 Q3, §4 п.10–11, §8 (абзац «провенанс»), §10 AC10, §11 —
всё остальное принято без повторной проверки в этом раунде, со ссылкой на
[`SPEC-REVIEW-593-r2.md`](../../docs/reviews/SPEC-REVIEW-593-r2.md) (материал: ветка
`dev`, коммит `dcd6657581ba205edb63713e011a498b51983a20`, дерево
`0b48707268e99ee38221c8e74fb1c48ce6793e35`) и, где отмечено, на
[`SPEC-REVIEW-593-r1.md`](../../docs/reviews/SPEC-REVIEW-593-r1.md) (коммит
`073c45b04308cd613182c700f30c75ebfa8d2ca7`):
- Комплектность обязательных разделов §7.1 — проверена r1, дельта их не убирала.
- H1(r1) (продуктовые вопросы Q1/Q2 закрыты владельцем через `blocked` + отдельный
ответ, а не самоподтверждением автора) — закрыто в r2, дельта r3 этого не касалась.
- M1(r1) (AC9/бюджеты: два ленивых графа получают настоящий гейт вместо печати) —
закрыто в r2 (`lazyGraphCeilingViolation`, `LAZY_*_GZIP_CEILING`, мутант
`bundle-budget-lazy-ceiling-never-fires`), дельта r3 этого не касалась.
- Все фактические числа о текущем состоянии кода (состав `RETAINED_IDS`,
default-размеры 12 retained-символов, число ключей i18n 29/56 в исходном
состоянии, ловушка двойного объединения `FURNITURE`/`BY_ID`, состав golden-сцен,
существование npm-скриптов) — проверены r1 построчно, дельта их не меняла.
- Q1/Q2 содержательно (`cactus → plant`, 32 непустые категории, поведение при отказе
ленивого чанка для всех 60 предметов, снятие обещания `docs/FURNITURE.md`) —
проверены r2 по тексту и коду (`src/decor-image-editor.ts`,
`src/furniture-art-runtime.ts`, `toast.furniture_art_load_failed`), дельта r3 их
не трогала.
- Мутанты `furniture-legacy-shadows-designer-art`, `furniture-pack-accepts-foreign-
symbol-count`, `furniture-cactus-lands-in-exercise` — сверены на отсутствие
коллизий в r1/r2, не перепроверял заново.
## Чего не проверял
- Содержимое `houseplan-furniture-0.4.0.zip` побайтово (93 SVG, `pack.json`) — как и
в r1/r2, это предмет код-ревью, когда пакет окажется в дереве; полагаюсь на
проверенный аналитикой S2 прогон генератора («OK: 60 plan symbols, 33 menu icons»)
и на личное подтверждение владельца о побайтовом совпадении вложения issue с
переданной напрямую копией.
- Не пересчитывал SHA-256 архива самостоятельно (не скачивал вложение) — находка
H1(new) была не о неверном хеше, а об отсутствии закреплённого механизма; сейчас
механизм закреплён, независимая перепроверка байтов — задача код-ревью.
- `npm run typecheck`, `npm test`, `npm run build`, `npm run bundle:budget`,
`golden:verify`, любые смоки — этап ревью ТЗ, продуктовый код не существует
(нет коммитов и веток `issue/593-*`); так же поступали r1 и r2.
- Полное построчное сравнение всего тела ТЗ редакция 3 vs редакция 4 — сравнивал
прицельно разделы, которые называет комментарий владельца о редакции 4 (§3 Q3,
§4 п.10–11, §8, §10 AC10, §11); не проверял, что где-то за пределами названного
диапазона не появилось незамеченного текстового расхождения — риск низкий, так как
сам процесс написания ТЗ (правки поверх сохранённого текста с явным указанием
«что меняется») уже дважды подряд (r1→r2, r2→r3) точно называл границы своих правок.
- Дубликаты (аналогичные issue) — не проверял повторно; r1 не нашёл признаков
дублирования, дельта r2→r3 не создаёт нового риска дублирования.
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `dev`, коммит `2167d4396884` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `857164801ddbfc7450d2e95e1617b258d6704dd2`
```
git log --all --format='%H %T' | grep 857164801ddb
```
- Тело issue: `3a8d99615191f61cc781ac873210df277ce0951d828113e3efa89700a5b7b6a3`
- Вердикт конвейера: `green` · High 0