# CODE-REVIEW-330-r4 Issue: #330 — «Ограничения стыков (#329) блокируют event loop HA и дёргают ресайз на больших планах» Этап: code (PROCESS.md §2.7) Заход: r4 · блокирующих циклов израсходовано 3 из 4 (до этого раунда) Ветка: `issue/330-junction-limits-performance`, HEAD ревью — `d33aa0a7` ## 0. Разбор по дельте — почему и от какого SHA Предыдущий вердикт (code-review r3, 2026-08-28T00:49:49Z — жёлтый, High: 1, Medium: 0) назван на HEAD `04bb54ae`. Проверено, что этот SHA — прямой предок текущего HEAD и что ребейза не было: ``` $ git merge-base --is-ancestor 04bb54ae HEAD && echo ancestor ancestor $ git log --oneline 04bb54ae..HEAD d33aa0a7 docs: refresh the screenshot pair after the cache-key fix (#330 r3-H1) 90a3313d docs: review document for #330 ``` Также проверено, что `dev` не ушёл вперёд за это время: ``` $ git fetch origin dev --quiet $ git log --oneline -1 origin/dev eff786fa docs: review document for #62 $ git merge-base --is-ancestor origin/dev HEAD && echo "dev is ancestor of HEAD" dev is ancestor of HEAD ``` Дельта — два коммита: `90a3313d` — публикация документа r3 (класс C, не код), `d33aa0a7` — точечный фикс единственной находки r3 (H1). Контракт поведения не менялся, новая подсистема не задета, объём дельты меньше даже r2→r3. Условия §2.10/§7.2 для полного разбора не выполнены — разбираю по дельте `git diff 04bb54ae..HEAD`. ## 1. Скоуп дельты `git diff 04bb54ae..HEAD --stat`: ``` docs/images/screenshots.json | 22 ++-- docs/reviews/CODE-REVIEW-330-r3.md | 226 +++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+), 11 deletions(-) ``` Только r3-H1 (докс-гейт красный на HEAD предыдущего раунда): - `docs/images/screenshots.json` — `sourceFingerprint` и все десять `sourceSha256` заменены с устаревшего `2a5ae6c1…` на актуальный `dbac4a84d0eb558e66066f5072363977ff4a78c0a032e6f2b9a5d0848cd20f0f` — ровно то значение, которое r3 уже вычислил независимо (`visualFingerprint()` на дереве r3, см. документ r3 §3) как «реальное». Ни один `imageSha256` не изменился ни в одной из десяти сцен — предсказание r3 («UI не менялся, PNG, вероятно, останутся байт-в-байт те же») подтвердилось буквально. - `src/**`, `test/**`, `demo/**`, `scripts/**`, `custom_components/**`, `dist/**` — не тронуты вовсе. Никакого продуктового или тестового кода в дельте нет. - `docs/reviews/CODE-REVIEW-330-r3.md` — публикация документа предыдущего раунда (класс C, инфраструктурный шаг, не предмет код-ревью). ## 2. Закрытие раунда r3 | Находка r3 | Чем закрыта | Где это видно | |---|---|---| | H1 (в скоупе) — `node scripts/check-docs.mjs` завершался `exit 1`: записанный `sourceFingerprint` (`2a5ae6c1…`) разошёлся с реальным `visualFingerprint()` дерева (`dbac4a84…`) после того, как `04bb54ae` поменял `src/houseplan-card.ts` без пересчёта скриншот-манифеста | Манифест пересчитан прогоном `npm run build && node demo/docs/capture.mjs` и принят: новый `sourceFingerprint`/все `sourceSha256` равны `dbac4a84…` — ровно значению, которое r3 назвал ожидаемым. `imageSha256` не изменился ни в одной сцене, то есть пересчитан именно отпечаток источника, а не подменены сами PNG | `docs/images/screenshots.json` (диф выше); я прогнал `node scripts/check-docs.mjs` на текущем HEAD лично (не со слов автора) | Находка закрыта по существу и подтверждена исполнением, не только чтением коммита. ## 3. Как проверялось (дельта, r4) Validate на этом SHA (`d33aa0a7`) уже зелёный (см. вводную задачи, ссылка на прогон), поэтому `tsc`/`npm test`/`npm run build` + сверка бандла не перегоняю — они не относятся к предмету этой дельты (дельта не трогает `src/**`/`test/**`) и уже подтверждены на этом самом SHA. Единственный релевантный дельте гейт — сам докс-гейт, ради которого сделан коммит: | Гейт | Команда | Результат | |---|---|---| | Докс-гейт | `node scripts/check-docs.mjs` | `Documentation checks passed (7 files, 10 external links).`, exit 0 | | Ручная сверка значения фингерпринта | `git diff 04bb54ae..HEAD -- docs/images/screenshots.json` | все 11 вхождений `sourceFingerprint`/`sourceSha256` заменены на один и тот же новый хеш; все 10 `imageSha256` не изменились | | Trailers коммитов дельты | `git show 90a3313d -s --format=%B`, `git show d33aa0a7 -s --format=%B` | оба несут `Issue: #330`, `User-Visible: no` — корректно: `90a3313d` публикует документ ревью (класс C, не продукт), `d33aa0a7` пересчитывает служебный отпечаток без изменения видимого результата (PNG идентичны) | | Рёбейз/уход dev | `git merge-base --is-ancestor 04bb54ae HEAD`, `git fetch origin dev && git merge-base --is-ancestor origin/dev HEAD` | оба — да; условие полного разбора (§2.10, ребейз на ушедший вперёд dev) не выполнено | Дельта не трогает геометрию, рендер, стили, слои, публичный контракт, `custom_components/**` и ни один файл, упомянутый в §5 текста ревью (инварианты модели, смоки, golden, perf-профили, бэкенд-тесты) — поэтому эти гейты не перегоняю, наследую решениеr3 не гонять их (см. §5 ниже). ## 4. Находки Находок нет. Единственная находка предыдущего раунда (r3-H1) закрыта точным, минимальным коммитом, который меняет ровно то, что было названо дефектным (отпечаток источника), и ничего больше. ## 5. Унаследовано из r3 (без повторной проверки) Дельта r4 не касается ни одной строки продукта, теста или конфигурации — наследую весь корпус r3 целиком, включая то, что сам r3 унаследовал из r2: - **Архитектура срезов §4.1–§4.7** (executor-цепочка, rev-кэш `previous`, byNode-индекс П3, bucket-решётка П4, §4.6 «v9 как есть», общий проход §4.7) — признана верной в code-review r2 (`docs/reviews/CODE-REVIEW-330-r2.md`, HEAD `85636a65`) и подтверждена неизменной в r3 (`docs/reviews/CODE-REVIEW-330-r3.md`, HEAD `04bb54ae`, §5). Ни r3, ни r4 её не трогают. - **AC1 (event loop/executor)** — `pytest -k 330` → `1 passed`, исполнено в r2, не затронуто с тех пор (`custom_components/**` не в дельте ни r3, ни r4). - **AC2/AC3/AC5 (линейный П3/П4, rev-кэш бэкенда, эквивалентность §4.6)** — паритет-тесты TS↔Python, `pytest tests_backend -q` (423 passed), исполнены в r2, не затронуты в r3/r4. - **AC4 (баланс кэша фронта)** — закрыто по существу в r3 (см. таблицу закрытия r2→r3 в `docs/reviews/CODE-REVIEW-330-r3.md` §2): ключ кэша заменён на identity документа + `spacePhysicalGeometryFingerprint`, мутант `junction-limit-baseline-cache-stale` ловится смоком, `mutation-gate.mjs --id=junction-limit-baseline-cache-stale` зелёный. Дельта r4 не трогает `src/houseplan-card.ts`, `demo/smoke_junction_limits.mjs`, `test/junction-limits.test.mjs`, `scripts/mutation-gate.mjs` — код кэша байт-в-байт тот же, что был подтверждён исполнением в r3. - **AC7/перф-контракт §5, включение в `validate.yml`** — подтверждено исполнением в r2 и r3 (`benchmark:junction-limits` → `pass: true`, запас ≥2.6×). Не в дельте r4. - **golden:verify** — не гонял, как и в r2/r3: ни один раунд с r1 не касался рендера/геометрии/стилей/слоёв, r4 тем более (дельта — только `screenshots.json`, а он не входит в golden-контур). - **Полная матрица `demo/smoke_*.mjs` и полный `mutation-gate.mjs`** — не гонял целиком: предрелизные гейты (PROCESS.md §8), не гейт ревью. По дельте r4 гонять нечего — она не содержит кода, который могла бы затронуть какая-либо смок-проверка. - **`pytest tests_backend`** — не гонял; дельта r4 не содержит ни одного файла `.py`. - **`npm run invariants -- --config <...>`** — не гонял; дельта не вводит и не меняет геометрию, `layout`, `marker.space`, `open_spans` или записи толщины ни в r3, ни в r4. - **Одно число — один источник** — неприменимо: дельта r4 не вводит и не меняет ни одной пользователю видимой величины. Более того, она подтверждает обратное намеренно: `imageSha256` (то, что реально видит пользователь на скриншотах) не изменился ни на бит — изменился только служебный `sourceFingerprint`/`sourceSha256`, внутренний отпечаток дерева исходников для докс-гейта, невидимый конечному пользователю карточки. - **CHANGELOG** — не требуется ни для `90a3313d` (публикация документа ревью, класс C, не входит в DoD задачи по видимому поведению), ни для `d33aa0a7` (`User-Visible: no`, подтверждено фактом: PNG идентичны, меняется только служебный манифест). ## 6. Что проверено и корректно (эта дельта) - Значение нового `sourceFingerprint` в `docs/images/screenshots.json` совпадает с тем, которое r3 независимо вычислил как «реальное» (`dbac4a84…`) на том же дереве до этого коммита — не просто «файл изменился», а изменился на правильное значение. - Ни один `imageSha256` не менялся — фикс не подменяет и не портит сами скриншоты, трогает только служебное поле идентификации источника. - `node scripts/check-docs.mjs` зелёный на текущем HEAD, прогнан лично. - Trailers обоих коммитов дельты корректны для их класса изменений. - Дельта не расширяет и не сужает скоуп задачи: единственная цель коммита — закрыть ровно ту находку, которая была названа, ничего лишнего не задето. ## 7. Чего не проверял и почему - `npx tsc --noEmit`, `npm test`, `npm run build` + сверка бандла — Validate зелёный на этом самом SHA (`d33aa0a7`, ссылка в вводной задачи), а дельта не трогает ни `src/**`, ни `test/**` — перегонять нечего нового. - `pytest tests_backend`, `golden:verify`, инварианты модели, смоки помимо докс-гейта, perf-бенчи — дельта r4 не содержит ни одного файла, который могли бы затронуть эти гейты (только `docs/images/screenshots.json` и публикация документа ревью); все они наследуются из r2/r3 без повторного прогона (см. §5). - Ручное тестирование в браузере — вне цикла ревью по регламенту; предмет этого раунда — сугубо служебный докс-манифест, для него замена (докс-гейт) прогнана. ## 8. Итог High: 0. Medium: 0. Единственная находка r3 (H1) закрыта точным, минимальным, верифицированным коммитом — значение фингерпринта совпало с независимо вычисленным ожиданием, PNG не изменились, докс-гейт зелёный на исполнении, не со слов автора. Весь остальной корпус задачи (§4.1–§4.7, AC1–AC7, AC4-фикс r2→r3) наследуется без повторной проверки — дельта r4 его не касается ни одной строкой. Зелёный вердикт, бюджет циклов не тратится.