Files
houseplan-card/docs/reviews/CODE-REVIEW-580-r2.md
T
2026-09-15 06:16:08 +00:00

232 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-580-r2
Issue: #580 · Этап: code · Заход: r2 · Материал: `c044e9ea3861b777c04233073a02a0a3e2da354a`
(рабочая копия проверена на этом SHA, `git fetch`/`checkout` не выполнялись)
## Почему это r2, а не продолжение r1
Первый код-ревью (`CODE-REVIEW-580-r1.md`) вынес **зелёный** вердикт на материале
`4cb6827c3d1ea0e8307ff7f406b425262c25649a`. Пока ревью шло, `origin/dev` продвинулся на
один коммит, автоматическое слияние отказало (§7.2 — «это другой код»), и автор
перебазировал ветку на новый `origin/dev` скриптом `scripts/rebase-on-dev.mjs`
(комментарий issue от 2026-09-15T06:07:14Z). Новая вершина — `c044e9ea` — и это
материал текущего раунда. Старые SHA r1 (`4cb6827c`, `23e66392`, `c22eaf7d`) после
ребейза не существуют в истории (`git cat-file -t` — `Not a valid object name`),
поэтому дельта «дословно» через `git diff <старый SHA>..HEAD` невозможна.
Это ребейз на ушедший вперёд `dev` — по правилам раунда такой случай **не
сокращается до дельты** и требует полного разбора. Ниже — полный разбор, но
методом, который эксплуатирует то, что можно проверить дёшево: побайтовое
сравнение каждого изменённого файла в `git diff origin/dev...HEAD` с тем, что
цитировал и проверял r1, плюс независимая проверка, что тяжёлые CI-гейты на новом
SHA подтверждены не «переиспользованием ради переиспользования», а совпадением
хеша содержимого с ранее проверенным деревом.
## Скоуп
`git log --oneline origin/dev..HEAD` — шесть коммитов, из них три содержательных
(остальные три — `docs: review document for #580`, коммиты документов SPEC-REVIEW
r1/r2 и этого самого CODE-REVIEW r1, наследие этапа spec и предыдущего раунда, не
трогаются):
- `d2c7e6f7` (`fix`, User-Visible: yes) — окклюзия комнатной части внешнего луча
внутренними откосами толстой стены.
- `a32b280b` (`fix`, User-Visible: no) — типизация того же кода (`Geom` вместо
`as any`).
- `8b8260b2` (`test`, User-Visible: no, несёт `Release: v1.76.0-beta.4` и
`Baseline-Reviewed:`) — принятие двух golden-эталонов (DPR1/DPR2).
`git diff origin/dev...HEAD --stat`: 57 файлов, из них по существу —
`src/sun.ts`, `test/sun.test.mjs`, `test/golden-matrix.test.mjs`,
`demo/smoke_sun.mjs`, `demo/golden/matrix.mjs`, `scripts/mutation-registry.mjs`,
`docs/SUN.md`, оба `CHANGELOG`; плюс два новых PNG-эталона,
`demo/golden/baselines/baselines-index.json` и весь бандл
(`dist/**`, `custom_components/houseplan/frontend/**`) — бандл пересобран с новыми
хешами файлов из-за нового `dev` в основании, это ожидаемо и не несёт логики.
`custom_components/**/*.py` в диффе отсутствует — AC7 по touch/i18n/схеме не
задет.
Трейлеры: `d2c7e6f7` — `User-Visible: yes`, оба changelog в этом же коммите
(проверено `git show --stat`). `8b8260b2` — `Release:`/`Baseline-Reviewed:` со
ссылкой на реальный run.
## Проверка того, что ребейз не изменил код по существу
Построчно сравнил `git diff origin/dev...HEAD` для каждого содержательного файла
с текстом, который `CODE-REVIEW-580-r1.md` цитировал и разбирал:
- `src/sun.ts` — diff идентичен описанному в r1 (тот же `intersectRings`,
та же сигнатура `rayRimEdges`/`rimSources`, те же номера механик — `intersectRings(quad,
rayQuad(innerA, innerB, away, len), clipPoly)` и дедупликация источников по
`eps=1e-4`).
- `test/sun.test.mjs` — оба новых теста (`#580: an oblique outer ray...`,
`#580: normal incidence...`) побайтово совпадают с тем, что цитировал r1,
включая константу `328.4529946162075`.
- `demo/smoke_sun.mjs` — тот же `pointInRing`, тот же `innerFaceX` через отражение
экрана, те же четыре новых `check(...)`.
- `demo/golden/matrix.mjs`, `test/golden-matrix.test.mjs` — та же пара
сценариев `dpr{1,2}`, версия матрицы `62→63`.
- `scripts/mutation-registry.mjs` — те же два новых мутанта
(`sun-ray-outer-jamb-occlusion-ignored`,
`sun-ray-outer-occluded-rim-source-ignored`), `find`-паттерны совпадают со
строками текущего `src/sun.ts`.
- `docs/SUN.md`, оба `CHANGELOG` — тот же текст.
Вывод: продуктовая дельта #580 после ребейза не изменилась ни на строку —
изменился только бандл (новые хеши ассетов) и добавились три коммита документов
ревью. Это подтверждает и сам автор в комментарии («продуктовая дельта #580 не
менялась»), но здесь это установлено чтением диффа, а не принято на слово.
## Как проверялось
### Гейты
Валидация на точном материале `c044e9ea` — **зелёная**, дважды: run `34935586944`
(упомянут во вводном сообщении) и более ранний `34935525859` того же SHA — оба
`conclusion: success`.
Не поверил заявлению «зелёный» буквально: посмотрел job-логи run `34935586944` и
обнаружил, что тяжёлые джобы (browser-смоки, golden, perf-смок, geometry-parity,
backend) в нём **skipped** через `Переиспользование: это дерево уже проверено`.
Чтобы отличить легитимный реюз от «зелёного, потому что не запускалось», прочитал
лог этого job'а: ключи реюза считает `scripts/gate-reuse.mjs --job=<job>` **по
содержимому**, не по SHA коммита и не по полному git-дереву (иначе ребилд бандла
сломал бы совпадение):
| job | результат |
|---|---|
| `smoke` | `Cache hit for: reuse-smoke-bb7d10d9…` |
| `golden` | `Cache hit for: reuse-golden-ac206839…` |
| `performance_smoke` | `Cache hit for: reuse-performance_smoke-c2e55df8…-glow` |
| `geometry_parity` | `Cache not found` (ожидаемо — diff не трогает модель геометрии) |
| `backend` | `Cache not found` (ожидаемо — `custom_components/**/*.py` не тронут) |
Кэш-хиты для `smoke`/`golden`/`performance_smoke` означают, что релевантное
содержимое (то, что реально проверяют эти гейты) на `c044e9ea` побайтово
совпало с деревом, на котором r1 уже нашёл **реально выполненный** (не
переиспользованный) прогон — `34933022019`, зафиксированный в r1 как run с
3/3 browser-смоками, golden и 6/6 mutation-шардами зелёными. Это закрывает
AC4/AC5 без повторного локального прогона: реюз здесь не «дыра», а
детерминированная функция от неизменного содержимого, что я проверил, а не
предположил.
Мутационные джобы (`Мутанты по диффу 1–6/6`) на `c044e9ea` — **не** переиспользованы,
выполнены заново и зелёные: `npx tsc --noEmit`/typecheck и юнит-тесты прошли
свежо на этом самом SHA.
**Не гонял локально:** `npx tsc --noEmit`, `npm test`, `npm run build`,
`node scripts/check-docs.mjs`, `npm run golden:verify` — покрыты зелёным Validate
на точном SHA (см. выше), плюс отдельно проверенным содержательным реюзом.
`npm run invariants`, `python -m pytest tests_backend` — diff не касается
персистентной модели геометрии (рёбра/толщина/layout/marker.space/open_spans) и
не трогает `custom_components/**/*.py`; толщина стены здесь только читается
(`wallDepthByOpening`), не записывается.
### Разбор кода
Продуктовый код (`src/sun.ts`) не изменился относительно того, что r1 уже
разобрал построчно (независимый вывод формулы окклюзии в базисе {нормаль,
тангенциальная ось окна}, ручной пересчёт константы `328.4529946162075` с
совпадением до 13 знаков, проверка что мутанты бьют именно по изменённым
строкам, проверка что `demo/smoke_sun.mjs` — независимая, не скопированная из
продукта реализация геометрии). Побайтовое совпадение диффа (раздел выше)
означает, что этот разбор остаётся в силе без повторного вывода — не потому что
я поверил документу r1, а потому что сверил текст, который он проверял, с
текстом, который лежит в `origin/dev...HEAD` сейчас.
Дополнительно к r1 проверил:
- что три «продуктовых» коммита (`d2c7e6f7`, `a32b280b`, `8b8260b2`) после
ребейза не имеют собственных CI-прогонов (`gh run list --commit <sha>` → `[]`
для каждого) — Validate гонялся только на итоговом SHA ветки, что ожидаемо для
push после ребейза без промежуточных пушей;
- что коммиты `d37b2c9f` (`Prepare v1.76.0-beta.4`) и `e54ff33c` (новый tip
`origin/dev`, docs-ревью #581), которые вошли в основание после ребейза, не
трогают `src/sun.ts` и вообще не пересекаются с темой солнечных лучей —
подтверждено `git diff d37b2c9f..e54ff33c -- src/sun.ts` (пусто) и
`git show --stat` обоих коммитов;
- что коммиты #577 (`внешний луч`, та же тема) целиком лежат в основании
**до** ребейза (были в `dev` ещё когда открывалась ветка #580) — новых
пересечений с #577 не возникло, `src/sun.ts` в диапазоне `d37b2c9f..e54ff33c`
не менялся.
## Закрытие раунда r1
| находка r1 | статус |
|---|---|
| Блокирующих находок не было | — |
| Не-Medium наблюдение (неточность формулировки ТЗ «одно дополнительное пересечение») | не относится к коду; сам код и диагноз не изменились ребейзом — наблюдение остаётся зафиксированным для памяти, не требует действия |
Раздел «находка → чем закрыта» здесь вырожден: r1 был зелёным без замечаний в
скоупе задачи, поэтому r2 не закрывает правки — он подтверждает, что зелёный
вердикт остаётся верным на новом материале после механического (не
содержательного) ребейза.
## Унаследовано из r1
Из `docs/reviews/CODE-REVIEW-580-r1.md` (материал `4cb6827c3d1ea0e8307ff7f406b425262c25649a`,
дерево `eb607a98d8c5a3f34ff9545a589358b50988c20f`) принято без повторного
самостоятельного вывода, поскольку побайтовое сравнение диффов (раздел выше)
подтвердило отсутствие изменений в этих файлах:
- независимый математический вывод формулы окклюзии и ручной пересчёт константы
`328.4529946162075` — сверено, что тест и код не изменились;
- анализ `rayRimEdges`/`uniqueSources`/отката на `[ray.a, ray.b]` при
`rimSources === undefined` (AC3, режим `inner`/`d<=0`) — код не изменился;
- проверка независимости `demo/smoke_sun.mjs` (`pointInRing`, `innerFaceX` через
отражение) от продуктовой формулы — файл не изменился;
- проверка `demo/golden/matrix.mjs`/хешей PNG на не-пустой принятый эталон и на
корректный DPR при рендере — сценарии не изменились, только версия матрицы;
- вывод «единственный источник числа» (обрезанная ширина луча входит в тот же
`SunRay.polys`, второго независимого вычисления в продукте нет) — код не
изменился.
## Найдено
Блокирующих находок нет.
## Что проверено и корректно
- AC1–AC3 — код идентичен r1-проверенному, юнит-тесты не изменились.
- AC4 (browser smoke), AC5 (golden DPR1/DPR2) — реюз-кэш на точном SHA `c044e9ea`
подтверждён как совпадение по содержимому с деревом, где эти джобы реально
выполнялись (см. таблицу `gate-reuse` выше), а не как слепое доверие статусу
Validate.
- AC6 — Validate зелёный на точном материале раунда, двумя независимыми run.
- AC7 — diff по-прежнему ограничен солнечной геометрией/тестами/документацией и
пересборкой бандла; `custom_components/**/*.py`, UI, i18n, touch-контракт и
схема конфигурации не тронуты.
- Трейлеры и оба changelog — в правильном коммите (не изменилось).
- Ребейз на новый `dev` — чисто механический: без конфликтов исходников,
продуктовая дельта #580 не изменилась ни на строку, новое основание
(`d37b2c9f`, `e54ff33c`) не пересекается с темой солнечных лучей.
## Чего не проверял
- Не запускал `npx tsc --noEmit`, `npm test`, `npm run build`,
`node scripts/check-docs.mjs`, `npm run golden:verify` локально — переиспользовал
зелёный Validate на этом самом SHA, дополнительно проверив легитимность
реюза тяжёлых джобов по ключам содержимого (см. выше), а не только по статусу.
- Не запускал `npm run invariants` — diff не касается персистентной модели
геометрии (рёбра/толщина/layout/marker.space/open_spans).
- Не запускал `python -m pytest tests_backend` — `custom_components/**/*.py` не
тронут.
- Не перевыводил независимо математику окклюзии и не пересчитывал константу
`328.4529946162075` — унаследовано из r1, поскольку строки `src/sun.ts` и
`test/sun.test.mjs` не изменились (подтверждено побайтовым сравнением диффа).
---
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/580-outer-sun-wall-occlusion`, коммит `c044e9ea3861` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `723c351607934580f0bfbbc19bef5b182273f939`
```
git log --all --format='%H %T' | grep 723c35160793
```
- Тело issue: `558be5cfc33a8fe1f475fbc5a0210392339265c20fad0c22e82858b57c96b848`
- Вердикт конвейера: `green` · High 0