Files
houseplan-card/docs/reviews/CODE-REVIEW-113-r3.md
T
claude[bot] e88c23b8ee
Validate / docs (push) Failing after 34s
Validate / provenance (push) Successful in 45s
Validate / changes (push) Successful in 56s
Validate / process-gate (push) Failing after 58s
Validate / hacs (push) Skipped
Validate / hassfest (push) Skipped
Validate / frontend (push) Skipped
Validate / smoke (push) Skipped
Validate / golden (push) Skipped
Validate / performance_smoke (push) Skipped
Validate / backend (push) Skipped
docs: review document for #113
Issue: #113
User-Visible: no
2026-08-19 00:11:27 +00:00

177 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CODE-REVIEW-113-r3 — post-merge `docs` gate refresh, no product change
- **Issue:** https://github.com/Matysh/houseplan-card/issues/113
- **ТЗ:** `docs/specs/113-optional-space-model.md`, ревью ТЗ — `docs/reviews/SPEC-REVIEW-113-r1.md`
(зелёный, Medium-1 → #184, не блокирует)
- **Предыдущие циклы:**
- `docs/reviews/CODE-REVIEW-113-r1.md` — зелёный, High 0, Medium 0. Автослияние не прошло
(конфликт ветки с `dev`), возврат в `S6-in-progress` за ребейзом, не за переделкой.
- `docs/reviews/CODE-REVIEW-113-r2.md` — зелёный, High 0, Medium 0, после ребейза на
`dev`=`c1676cf`. Пайплайн слил ветку в `dev` и поставил `S8-merged`.
- После слияния параллельный прогон Validate на `dev` показал красный job `docs`
(`node scripts/check-docs.mjs --external`): встроенный в `docs/images/screenshots.json`
`sourceFingerprint` устарел относительно `src/**`, изменённого продуктовым коммитом #113
(`_spaceModel`/`src/space-model-selection.ts`). Автор исправил это отдельным docs-only
коммитом и вернул issue `S6-in-progress` → `S7-code-review`, чтобы не оставлять `dev`
красным без повторной проверки (комментарий автора от 2026-08-19).
- **Диапазон:** `origin/dev..HEAD` = один коммит `acad3b3` («Refresh documentation source
fingerprint»). `git merge-base origin/dev HEAD` = `origin/dev` (`b443a33`) — линейно, без
дивергенции и без конфликта.
- **Цикл:** r3/4 (счётчик по этапу код-ревью)
- **Роль:** ревьюер кода (Claude), свежая сессия, без контекста реализации и без контекста
собственных прогонов r1/r2.
## 1. Скоуп цикла r3
Единственный коммит диапазона, `acad3b3`:
```
docs/images/screenshots.json | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
```
Меняются только два повторяющихся поля манифеста — `sourceFingerprint` (один раз, в шапке) и
`sourceSha256` (в каждом из 10 сценариев, то же самое значение). Ни один PNG-файл, ни
`captureScriptSha256`, ни `imageSha256`, ни любой файл класса A/B в диапазоне не меняется —
подтверждено самим `git diff --stat` (единственный изменённый путь) и построчным чтением
diff'а (изменились ровно две пары хеш-строк на сценарий, форма и остальные поля манифеста —
`viewport`/`theme`/`language`/`file`/`imageSha256` — идентичны).
Класс файла — `docs/**` (класс C, `AGENTS.md`). Продуктовый код (`src/houseplan-card.ts`,
`src/space-model-selection.ts`) в этом коммите не тронут — байт в байт совпадает с тем, что
получило зелёный вердикт в r1/r2 (тот же вывод, что и в r2: `origin/dev` уже содержит
реализацию #113, в этом коммите нет новых продуктовых строк).
`Issue: #113` / `User-Visible: no` — корректно: манифест скриншотов документации не является
пользовательским интерфейсом, а сами PNG не изменились (см. §2) — то есть это не «видимое
изменение», а служебная синхронизация fingerprint-гейта с уже принятым исходным кодом.
Это не переход на новую фичу и не расширение скоупа #113: единственная причина коммита —
починка гейта, который стал красным из-за уже принятого продуктового изменения этого же issue,
не из-за постороннего кода. Формально это ближе к «предрелизному гейту» из `PROCESS.md` §11.4
(гейт называет дефект точно, исправление проверяется тем же гейтом), хотя `docs` — job,
запускаемый на каждый push, а не строго pre-beta; автор осторожно выбрал полный цикл ревью
вместо исключения §11.4, что процессом не запрещено и не требует правки с моей стороны.
## 2. Как проверялось — таблица гейтов
| Гейт | Команда | Результат |
|---|---|---|
| Typecheck | `npx tsc --noEmit` | OK, без ошибок |
| Unit | `npm test` | `877/877` OK — идентично r2 (продуктовый код не менялся) |
| Build + 3 копии бандла | `npm run build`, затем `cmp dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js` и `cmp dist/houseplan-card.js demo/srv/assets/houseplan-card.js` | OK, обе сверки — байт-в-байт совпадение |
| **Именно упавший гейт** | `node scripts/check-docs.mjs` | `Documentation checks passed (7 files, 10 external links).` — зелёный на итоговом дереве |
| **Пересчёт fingerprint напрямую** | `node -e "import('./scripts/source-fingerprint.mjs').then(({sourceFingerprint}) => console.log(sourceFingerprint(process.cwd())))"` | `b58a522cc70add7b12071bb5340ad3a1ad694c1979a39b46c2cb0b73fd719333` — **совпадает байт-в-байт** с `sourceFingerprint`, записанным в коммите |
| Process gate | `node scripts/process-gate.mjs --issues` | `диапазон origin/dev..HEAD, коммитов 1`, `гейт пройден, предупреждений 0` |
**Не прогонялось, и почему:**
- **Браузерные смоки (127+)** — не прогонялись. Диапазон не меняет ни строки `src/**`, ни
`demo/**`-кода, ни фикстур; единственный изменённый файл — JSON-манифест, потребляемый только
`check-docs.mjs`. Ни одна из тронутых поверхностей (документационные скриншоты) не имеет
функционального пути в карточке — прогон смоков не добавил бы информации к тому, что уже
зелено в r1/r2 на идентичном продуктовом коде.
- **`npm run golden:verify`** — не прогонялся. `docs/images/screenshots.json` — отдельный от
golden-эталонов (`demo/golden/baselines/**`) манифест с собственным гейтом (`check-docs.mjs`),
который прогнан и зелёный. Продуктовый рендер не менялся, пиксельного риска golden-эталонов
нет.
- **`python -m pytest tests_backend`** — не тронут ни один файл `custom_components/**/*.py`.
- **Performance-профили** — не названы в AC, ни один hot-path не тронут; диапазон не содержит
кода вообще, только JSON-метаданные.
- Обоснование сознательное, соразмерное объёму диапазона (PROCESS.md §8): один изменённый файл,
один назначенный ему гейт (`check-docs.mjs`), гейт прогнан и зафиксирован именно с помощью
команды и её результата — не «verified» без доказательства.
## 3. Проверка AC (docs/specs/113-optional-space-model.md §10)
Продуктовый код, доказывающий AC1–AC10, не менялся в этом цикле (§1) — доказательства r1/r2
переносятся без изменений. Этот коммит не реализует ни одного AC заново; ниже — что именно
перепроверено на итоговом дереве, а не процитировано.
| AC | Статус в r3 |
|---|---|
| AC1–AC10 | Код не менялся относительно r2 (единственный файл диапазона — `docs/images/screenshots.json`, не участвующий ни в одном AC из §10 ТЗ). `npx tsc --noEmit` и `npm test` (877/877) перепрогнаны на итоговом дереве и зелёные — подтверждают отсутствие регрессии, не переоткрывая доказательства по существу. |
Единственное новое утверждение этого цикла — не AC ТЗ #113, а факт того, что манифест
документационных скриншотов синхронизирован с текущим `src/**`. Оно доказано исполнением
(`check-docs.mjs` зелёный + независимый пересчёт fingerprint, см. §2), а не пересказом.
## 4. Дисциплина «тест умеет падать» — что проверено исполнением
- **`check-docs.mjs` умеет падать на этом классе дефекта** — до `acad3b3` (на состоянии `dev`
сразу после слияния r2) этот же скрипт краснел в CI ровно с сообщением `screenshot source
fingerprint is stale; run npm run build && node demo/docs/capture.mjs` (см. слово автора и
сам факт, что job `docs` был красным в Validate). Причина понятна и воспроизводима логикой
скрипта (`scripts/check-docs.mjs:118-119`): сравнение `manifest.sourceFingerprint !==
sourceFingerprint(ROOT)`; это прямое сравнение, которое **обязано** покраснеть при любом
расхождении, а не эвристика, которую можно обмануть.
- **Пересчёт fingerprint выполнен независимо от `check-docs.mjs`**, отдельным вызовом
`sourceFingerprint()` через `node -e`, и его значение сверено вручную с байтами, записанными
в коммите — совпадение подтверждает, что коммит не мог быть подделан (вписан руками) и что он
действительно является продуктом `npm run build && node demo/docs/capture.mjs` на этом дереве,
как и заявлено автором.
- **PNG не менялись** — сам `git diff --stat` не содержит ни одного `.png`-пути; отдельно
`check-docs.mjs` сверяет `scenario.imageSha256` с фактическим SHA-256 файла на диске для всех
10 сценариев и прошёл зелёным — то есть на диске лежат ровно те же байты, что были приняты в
r1/r2, а не новый, неотрецензированный рендер.
## 5. Находки
Нет находок High. Нет находок Medium в диапазоне этого коммита.
**Наблюдение вне скоупа диффа** (не находка кода #113, заведено отдельным issue по правилу
преамбулы `PROCESS.md`: «расхождение процесса с фактической автоматизацией не игнорируется, а
заводится issue с меткой `process`»): канонический список Validate-джобов в `AGENTS.md` («CI is
pinned to an exact SHA... Jobs: `provenance`, `hacs`, `hassfest`, `frontend`, `smoke`, `golden`,
`performance_smoke`, `backend`») не упоминает job `docs`, который и стал причиной этого цикла.
Строка `AGENTS.md` не менялась с `0f8d35f` (2026-08-14), `docs`-job/`check-docs.mjs` появился
позже, `88a647f` (2026-08-16) — это и есть расхождение, а не пересказ известного факта. Заведён
[#191](https://github.com/Matysh/houseplan-card/issues/191) (`process`, `docs`, `P3`), не
блокирует #113 — сам этот коммит корректно работает с фактическим, не с задокументированным,
набором гейтов.
## 6. Что проверено и корректно
- Диапазон `origin/dev..HEAD` линеен (`git merge-base origin/dev HEAD == origin/dev`) — ветка не
разошлась, конфликта нет, ребейз не требуется.
- Единственный изменённый файл диапазона — `docs/images/screenshots.json`, класс C; не задевает
ни одного файла класса A/B. Трейлеры коммита (`Issue: #113`, `User-Visible: no`) соответствуют
содержанию (нет пользовательского поведения, только служебные хеши).
- `sourceFingerprint`/`sourceSha256`, записанные в коммите, воспроизведены независимым прогоном
`sourceFingerprint()` на этом дереве и совпали байт-в-байт — коммит не является догадкой или
скопированным чужим значением.
- `captureScriptSha256` и все 10 `imageSha256` в манифесте не изменились и совпадают с файлами на
диске (подтверждено зелёным `check-docs.mjs`) — PNG не перегенерировались заново без рецензии,
ранее принятые скриншоты используются как есть.
- Продуктовый код (`src/houseplan-card.ts`, `src/space-model-selection.ts`) байт-в-байт идентичен
версии, получившей зелёный вердикт в r1 и повторно в r2 — AC1–AC10 не требуют переоткрытия.
- Быстрые гейты (`tsc --noEmit`, `npm test` 877/877, `npm run build` + сверка 3 копий бандла) —
зелёные на итоговом дереве.
- `node scripts/process-gate.mjs --issues` — зелёный, 0 предупреждений, диапазон 1 коммит.
- `docs/CHANGELOG.md`/`docs/CHANGELOG.ru.md` корректно не тронуты — `User-Visible: no`.
## 7. Чего не проверял
- Полный набор браузерных смоков и `golden:verify` — обоснование в §2 (диапазон не содержит ни
строки `src/**`/`demo/**`-кода, только JSON-манифест документационных скриншотов).
- `pytest tests_backend` — класс A/B бэкенда не тронут.
- Performance-профили — не названы в AC, не затронуты (диапазон без кода).
- Содержательное AC1–AC10 переисполнение «с нуля» — не требуется: продуктовый код не менялся
байт в байт относительно r1/r2 (подтверждено `git diff --stat`, не предположением).
- Medium-1/#184 (fallback-семантика ТЗ §6, explicit-id команды) — по-прежнему отдельный issue вне
скоупа этого код-ревью.
- Правомерность конкретно выбранного автором пути (полный цикл вместо §11.4-исключения) по
существу не оценивалась дальше констатации, что оба варианта процессом допустимы для этого
случая; выбор автора не создаёт находки.
## 8. Вердикт
Единственный коммит цикла — служебная синхронизация fingerprint-манифеста документационных
скриншотов с уже принятым (дважды зелёным) продуктовым кодом #113; PNG не менялись, продуктовый
код не менялся, упавший гейт (`check-docs.mjs`) воспроизведён и подтверждён зелёным, а записанный
в коммите fingerprint независимо пересчитан и совпал байт-в-байт. Все быстрые гейты зелёные.
High: 0. Medium: 0 в диапазоне диффа. Одно наблюдение вне скоупа диффа заведено отдельным issue
(#191, `process`), не блокирует.
**Вердикт: зелёный · цикл r3/4 · High: 0 · Medium: 0 → #191 (вне скоупа диффа, не блокирует) · Документ: docs/reviews/CODE-REVIEW-113-r3.md**