Files
houseplan-card/docs/reviews/CODE-REVIEW-461-r2.md
T
2026-09-05 11:46:31 +00:00

15 KiB
Raw Blame History

CODE-REVIEW-461-r2

  • Issue: https://github.com/Matysh/houseplan-card/issues/461
  • ТЗ: docs/specs/461-wall-draw-click-performance.md (SPEC-REVIEW-461-r1, зелёный)
  • Материал: SHA 41e6eef941c29675095365b472e063ff1caa8482, ветка issue/461-wall-draw-click-performance, диапазон origin/dev..HEAD = 6 коммитов (добавились 13ab4b12 — публикация документа r1, 41e6eef9 — исправление M1).
  • Заход: r2 · блокирующих циклов израсходовано 1 из 4
  • Вердикт: зелёный

Скоуп ревью (дельта, не с нуля)

Предыдущий раунд (r1) получил жёлтый вердикт на SHA 34d53bf2 — единственная находка M1 (Medium, в скоупе): AC4 требовал parity-свидетеля fast/full на матрице §8 (10 пунктов ТЗ), а тестами была покрыта только часть матрицы. Документ: docs/reviews/CODE-REVIEW-461-r1.md.

Дельта между 34d53bf2 и текущим HEAD (git diff 34d53bf2..HEAD --name-only):

docs/reviews/CODE-REVIEW-461-r1.md   (публикация документа r1 конвейером, не автор)
test/draft-live-preflight.test.mjs   (+89 строк, новый test-case, коммит 41e6eef9)

Это ровно фикс M1 и ничего сверх него — src/**, demo/**, scripts/**, .github/**, changelog не тронуты. Коммит 41e6eef9 несёт Issue: #461, User-Visible: no (корректно: чисто тестовое изменение, видимого поведения нет). Ребейза на ушедший вперёд dev не было, контракт поведения не менялся, новая подсистема не задета — дельта локальна, разбор веду по ней, а не заново. Остальные 10 AC (AC1–AC3, AC5–AC12) не имеют отношения к этой дельте и наследуются из r1 без повторной проверки (раздел ниже).

Закрытие раунда r1

Находка r1 Чем закрыта Где это видно
M1 — AC4: матрица §8 не проверена ни одним тестом через новый путь; фикс — repräsentативное подмножество (границы 14°/15°, 19/20 см, 4/5 см, valence 6/7) через реальные junctionLimitViolations/increasedViolations на local vs full candidate Новый тест test/draft-live-preflight.test.mjs:184 '#461 local and full junction verdicts agree at every limit boundary' (коммит 41e6eef9) 8 сценариев (по одному на каждую сторону границы), для каждого: строит полный previous/candidate (с активным draft и валидной удалённой геометрией через partitions: [..., remote]), проецирует обе стороны через draftLiveCandidateSpace, сравнивает introducedRules(local) с introducedRules(full) (assert.deepEqual), проверяет нормативный ожидаемый verdict (['angle']/['length']/['distance']/['valence']/[]) и что remote-партиция не попала в bounded projection

Проверил, что это не бумажный тест, а свидетель, который умеет падать: временно понизил MIN_JUNCTION_ANGLE_DEG с 15 на 10 в src/junction-limits.ts, пересобрал test-build (npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs) и прогнал файл целиком — '14 degree junction is rejected: boundary verdict' покраснел (+ [] / - ['angle']), остальные 7 сценариев остались зелёными. Откатил правку (git checkout -- src/junction-limits.ts), пересобрал test-build, дерево снова чистое (git status --porcelain пусто).

Проверил, что тест использует настоящий production-путь, а не параллельную реализацию: _junctionLimitsIntroduced (src/houseplan-editor-runtime.ts:2070) вызывает _junctionLimitViolations (2049), который оборачивает тот же самый junctionLimitViolations из src/junction-limits.ts, а затем increasedViolations (2126) — ровно те две функции, что тест импортирует напрямую из test-build/junction-limits.js и вызывает с той же сигнатурой (config, spaceId, segments, sharedGeometry, roomIds). Локальный helper limitSegments() в тесте воспроизводит _limitSegmentsOf (houseplan-editor-runtime.ts:2020) построчно (wall_segments + partitions + room_drafts.flatMap на пары точек) — форма и порядок совпадают на корректных фикстурах.

Требование r1 было явно сформулировано как «хотя бы репрезентативное подмножество матрицы §8, в первую очередь четыре границы» — потому что остальные 6 пунктов матрицы (intersection room/partition/foreign draft/column, wall-degraded-extra, hosted opening, zero wall, malformed carrier) это по сути «объект есть/объекта нет», а не «поведение проектора у существующей числовой границы», и они уже были свидетельствованы существующими тестами 'retains interacting geometry and drops remote work' (test/draft-live-preflight.test.mjs:101) и 'malformed local geometry fails closed into the proof' (255) — неизменными в этой дельте. Фикс закрывает именно то, что было названо условием закрытия, не больше и не меньше — сверка со спекой (docs/specs/461-*.md:223-238, раздел §8) подтверждает список из 10 пунктов совпадает буквально с текстом находки M1.

M1 закрыта. Других находок r1 не было (High: 0, Medium: 1 — закрыт, Low: 1 — L1, снят автором в r1 без правки, дельта его не касается).

Унаследовано из r1

Без повторной проверки принимаю из docs/reviews/CODE-REVIEW-461-r1.md (материал 34d53bf2d1b9252e37b356c1a295b1bcab7865f9), поскольку дельта r2 их не задевает:

  • AC1, AC2 — единственная точка изменения (_persistActiveDraftSegment, houseplan-editor-runtime.ts:2795), route guard isSingleDraftAppend, доказано demo/benchmark_wall_draw_click.mjs и test/draft-live-preflight.test.mjs.
  • AC3 — pure local projector: не мутирует space, сохраняет неизвестные поля, реальная толщина при отборе, итеративное закрытие collinear run и junction rays, fail-closed на malformed.
  • AC5 — переиспользование wall-артефакта между local proof и junction proof, мутант wall-draw-wall-artifact-discarded.
  • AC6 — rollback до before при отказе, смок + мутант wall-draw-rejection-rollback-skipped.
  • AC7 — независимый full-space preflight на terminal finish, мутант wall-draw-terminal-full-check-skipped.
  • AC8 — регрессия одиннадцати существующих _markupClick-смоков через единственный call site; Validate на 34d53bf2 зелёный по всем трём шардам.
  • AC9 — perf-профиль wall-draw-click-v1: structural + timing (median 10.9 мс / max 13.8 мс / remote 16.7 мс против бюджетов 150/250/~36.3 мс); числа не перепроверялись повторно и в r1 (нет Chromium под рукой), доверие к структуре ассертов, прочитанных построчно.
  • AC10 — tsc/test/build/no-new-any: были зелёными на 34d53bf2 (Validate https://github.com/Matysh/houseplan-card/actions/runs/33962804004); для r2 я перегнал их заново на текущем HEAD (см. «Как проверялось» ниже) — дельта их косвенно затрагивает (новый тестовый файл компилируется через tsc -p tsconfig.test.json), поэтому это не чистое наследование, а подтверждение.
  • AC11 — golden/screenshots: docs/images/screenshots.json, все 10 imageSha256 идентичны dev, изменился только sourceFingerprint на 34d53bf2; дельта r2 не трогает src/**, снимок не может устареть повторно.
  • AC12 — оба changelog, ARCHITECTURE, CONFIG-COMPATIBILITY обновлены в 04a1de09 (User-Visible: yes); дельта r2 не меняет пользовательское поведение (User-Visible: no на 41e6eef9), новых записей не требуется.
  • L1 (§6.4 vs !safe handling в draft-live-commit.ts) — снят автором в r1 без правки, обоснование (совпадает с конвенцией houseplan-editor-runtime.ts:1846-1854) дельтой не затронуто.

Как проверялось (r2)

Зелёного Validate на 41e6eef9 не найдено на момент ревью — прогнал дешёвые гейты сам, они минуты:

Гейт Прогнал сам Результат
npx tsc --noEmit да exit 0, без вывода
npm test да tsc -p tsconfig.test.json + node --test test/*.test.mjs: 1996 pass, 0 fail, 1 skip (1997 всего) — совпадает с заявленным автором числом в комментарии-фиксе; новый тест '#461 local and full junction verdicts agree at every limit boundary' — в списке, зелёный
npm run build + сверка 3 копий бандла да tsc --noEmit && rollup -c — success; diff -rq dist/ custom_components/houseplan/frontend/ — пусто (байт-в-байт); git status --porcelain после build — пусто (дельта не меняет бандл)
node scripts/no-new-any.mjs да «Новых any нет» (560 добавленных строк в 3 файлах — число из полного диапазона origin/dev..HEAD, не только дельты r2)
node scripts/check-docs.mjs да «Documentation checks passed» — дельта r2 не трогает src/**, отпечаток скриншотов устареть повторно не мог
node scripts/smoke-select.mjs --base 34d53bf2 --head HEAD да «Исполняемого frontend-диффа нет (src/**/*.ts не тронут). Browser-smoke этим диффом не выбираются — выбирать нечего»; тронуто файлов: 2
Мутационная проверка «тест умеет падать» да вручную занизил MIN_JUNCTION_ANGLE_DEG 15→10 в src/junction-limits.ts, пересобрал test-build, новый тест покраснел ровно на ожидаемом сценарии (14 degree junction is rejected), остальные 7 сценариев не задеты; откатил правку и test-build
node scripts/model-invariants.mjs нет дельта r2 не трогает ни один файл геометрии/записи модели (только тест и review-doc); риск рассинхронизации ключей толщины/решётки не создаётся ни этой дельтой, ни задачей в целом (см. наследование, r1 уже это установил для полного diff)
python -m pytest tests_backend -q нет дельта и весь diff не трогают custom_components/**/*.py
Targeted/full browser smoke нет smoke-select.mjs на дельте прямо говорит «выбирать нечего» — дельта r2 не пересобирает бандл и не меняет исполняемый путь; полный набор — предрелизный гейт, не гейт ревью
npm run golden:verify нет дельта r2 не может изменить пиксель — не трогает src/**, demo/**, стили
Мутанты scripts/mutation-gate.mjs нет дельта их не трогает (не менялись после r1)

Находки

Нет находок в этом раунде. High: 0, Medium: 0.

Чего не проверял

  • Не воспроизводил числа npm run benchmark:wall-draw-click в браузере ни в r1, ни в r2 — дельта r2 их не касается (не трогает perf-профиль).
  • Не гонял python -m pytest tests_backend — ни разу за обе итерации, diff никогда не касался custom_components/**/*.py.
  • Не гонял node scripts/model-invariants.mjs повторно — обоснование (диф не меняет функции записи геометрии) установлено в r1 для полного diff и остаётся верным: дельта r2 добавляет только чтение production функций в тесте, не меняет их.
  • Не прогонял browser smoke (targeted или полный) — инструмент smoke-select.mjs на дельте 34d53bf2..HEAD прямо сообщает, что исполняемого frontend-диффа нет и выбирать нечего; полный набор — гейт предрелиза, а не код-ревью соразмерного объёма для тестового патча на 89 строк.


Материал раунда

  • Ветка: issue/461-wall-draw-click-performance, коммит 41e6eef941c2 — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 3185737736d19e808ba8b85dcfc99b6265c177d5
    git log --all --format='%H %T' | grep 3185737736d1
    
  • ТЗ docs/specs/461-wall-draw-click-performance.md, блоб ccf374b1c0797ace0156b7cfb366007f1271fd35
    git log --all --find-object=ccf374b1c0797ace0156b7cfb366007f1271fd35 -- docs/specs/461-wall-draw-click-performance.md