14 KiB
CODE-REVIEW-313-r2
Issue: #313 · этап: код (code) · трек: small · заход: r2 · блокирующих циклов
израсходовано: 1 из 2 · SHA материала ревью: ed126d6a436c7e4499c13d37d0068627235ab7c3
· SHA предыдущего раунда (r1, красный): 5e5dad277cbdc238a5af899ff6727aed60d604b1
Скоуп
Один коммит поверх r1 — ed126d6a («fix: keep a stored zero draft thickness
and guard both thickness writers (#313)»), заявленный автором как закрытие
ровно двух находок CODE-REVIEW-313-r1 (High + Medium), без новых AC и без
изменения контракта ТЗ.
Дельта git diff 5e5dad27..ed126d6a:
.../houseplan/frontend/houseplan-card.js | 4 ++--
demo/smoke_wallthick_standalone.mjs | 12 +++++++++++-
dist/houseplan-card.js | 4 ++--
docs/images/screenshots.json | 22 +++++++++++-----------
src/houseplan-card.ts | 7 ++++++-
test/wall-union-isolation.test.mjs | 11 ++++++++++-
(плюс docs/reviews/CODE-REVIEW-313-r1.md, добавленный отдельным
docs-коммитом d34e56ba конвейером публикации между r1 и r2 — не продуктовый
код, не часть разбора.)
Дельта строго локальна: одна ветка резолвера драфта в _wallThickHit
(1 файл src/) и один тестовый гвард (1 файл test/), плюс фикстура и три
новых ассерта в уже существующем смоке. Нет ребейза на ушедший вперёд dev
(родитель ed126d6a — тот же 5e5dad27/d34e56ba, dev не двигался),
контракт поведения не меняется, новая подсистема не задета. Объём разбора —
по дельте, полный повторный проход по r1 не требуется; раздел «Унаследовано»
ниже перечисляет, что принято без повторной проверки.
Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
High — _wallThickHit, ветка сегментов драфта: Number(draft.segments[i]?.cm) || 15 не отличает «сегмента нет» от «cm сегмента = 0»; сохранённый 0 читался/показывался/при Apply-без-правки записывался как 15 |
src/houseplan-card.ts:11978-11981: const rawCm = Number(draft.segments[i]?.cm); … cm: Number.isFinite(rawCm) ? rawCm : 15 — фолбэк на 15 срабатывает только когда Number(...) даёт NaN (запись отсутствует), сохранённый 0 проходит Number.isFinite и доходит до диалога нулём |
demo/smoke_wallthick_standalone.mjs: фикстура room_drafts[0].segments расширена вторым сегментом { cm: 0 } (строки 20-24); три новых ассерта — zeroSegmentSurvives (hit несёт cm===0), zeroSegmentFieldEmpty (_wallDialog.value === ''), zeroSegmentNotCorrupted (Apply без правки не меняет segments[1].cm). Перепроверил исполнением: смок зелёный на HEAD; откатив резолвер на старый || 15 и пересобрав бандл, получил ровно эти три ассерта красными (FAILED (3): zeroSegmentSurvives / zeroSegmentFieldEmpty / zeroSegmentNotCorrupted) — тест умеет падать именно на этом дефекте |
Medium — гвард test/wall-union-isolation.test.mjs:107 (regexp по всему исходнику одной строкой) не отличает мутацию новой точки коммита независимой кладки от мутации легаси-точки; «поймано 1 из 1» у мутанта обманчиво |
test/wall-union-isolation.test.mjs: паттерн приведён к \/_commitPhysicalGeometry\(\s*this\._t\('history\.${historyKey}'/ (терпит перенос строки после открывающей скобки) плюс новый явный ассерт assert.equal((source.match(/_commitPhysicalGeometry\(\s*this\._t\('history\.wall_thickness'/g) || []).length, 2, 'both thickness writers route through the common barrier') |
Изолированно мутировал только новую точку коммита независимой кладки (src/houseplan-card.ts:12069-12071, _commitPhysicalGeometry → _recordGeometry), пересобрал тестовый бандл (npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs) и прогнал node --test test/wall-union-isolation.test.mjs: тест красный — both thickness writers route through the common barrier / 1 !== 2. Легаси-точку не трогал — до правки такая изолированная мутация гварду проходила незамеченной (ровно то, что описывал r1). Дополнительно прогнал node scripts/mutation-gate.mjs --id=wall-thickness-writer-bypasses-common-barrier на чистом дереве — «поймано 1 из 1», согласуется с заявлением автора «pass 0 / fail 1» |
Обе находки закрыты минимальными, локальными правками, ровно там, где были найдены; новых находок делта не добавляет.
Унаследовано из r1
Всё, кроме двух исправленных находок, принято без повторной проверки —
делта их не задевает. Источник: docs/reviews/CODE-REVIEW-313-r1.md,
SHA 5e5dad277cbdc238a5af899ff6727aed60d604b1.
- AC1 (перегородка: hit → диалог →
partition.cm→ Undo) — закрыт в r1 смоком + ручной проверкой Undo (_geometryHistory.size === 1). Делта не трогает партиционную ветку резолвера/writer'а. - AC3 (приоритет наложения #308-фикстуры; отказ нуля/пусто для независимой
кладки) — закрыт в r1 смоком +
smoke_optimize_coincident_partition. Делта не трогает тай-брейкoffer(...)и ветку валидации диапазона. - AC4 (комнатные стены не регрессируют) — закрыт в r1:
wallIntervals(...)байтово не менялся, три названных смока +npm testзелёные. Делта не трогает комнатную ветку резолвера/writer'а (строка 12100 не изменилась). - Приоритет независимой кладки при точном наложении, разные объекты
sp/spaceи корректность поиска поid, скрытие кнопки «на всю комнату» поd.source.kind, порядок валидации диапазона до/после ветвления по источнику, переиспользование тостов и ключей i18n — прочитано и принято в r1, код этих участков в делте не изменился. - CHANGELOG (оба файла) и трейлеры
Issue:/User-Visible: yesдля фичи в целом — заведены коммитом5e5dad27, проверены в r1. Коммит r2 (ed126d6a) сам несётUser-Visible: noбез правки CHANGELOG — это корректно: фича ещё не смержена/не выпущена, CHANGELOG уже описывает её на уровне контракта («любую стену… ноль отклонён»), а r2 лишь чинит внутреннюю порчу данных в ещё не выпущенном коде, не меняя ни задокументированное поведение, ни его формулировку — проверилgit diff 5e5dad27..ed126d6a -- docs/CHANGELOG.md docs/CHANGELOG.ru.md: дельта пуста, значит новый видимый факт CHANGELOG не потерял. docs/USER-GUIDE.ru.md— дополнен в r1, делта его не трогает.- Инварианты модели — в r1 обосновано и проверено (
npm run invariants -- config test/fixtures/276-coincident-partition.json, 1 предсуществующее нарушение, не следствие диффа): диф вообще не создаёт новую форму записи геометрии, пишет вpartition.cm/draft.segments[i].cmтем же путём, что уже существующий_savePhysicalDialog. Делта r2 меняет только fallback при ЧТЕНИИ значения и текст тестового регэкспа — ниwall_segments[], ни ключи, ниopen_spansне затронуты ни в r1, ни в r2, поэтому инварианты в r2 не перепрогонялись. - Golden/
pytest tests_backend/perf — не запускались ни в r1 (рендер и бэкенд не менялись), ни в r2 (та же причина, делта тем более не касается рендера — только числовой fallback и текст теста).
Гейты — прогнал (r2)
| Гейт | Команда | Результат |
|---|---|---|
| typecheck | npx tsc --noEmit |
зелёный, без вывода |
| unit (полный) | npm test |
1335 pass / 1 skip / 0 fail (1336 total) |
| build + bundle sync | npm run build && npm run bundle:sync |
пересобрал; sha256sum dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js demo/srv/assets/houseplan-card.js — три одинаковых хеша |
| docs fingerprint | node scripts/check-docs.mjs (диф трогает src/**) |
«Documentation checks passed (7 files, 10 external links)» |
| новый смок (AC1/AC2, High) | node demo/smoke_wallthick_standalone.mjs |
OK, все 13 под-проверок true, включая три новых |
| смок умеет падать (High) | откат резолвера на || 15, пересборка бандла, повторный прогон смока |
FAILED (3): zeroSegmentSurvives, zeroSegmentFieldEmpty, zeroSegmentNotCorrupted — красный ровно на закрытой находке; вернул файл, дерево снова чистое |
| гвард умеет падать (Medium) | мутация только новой точки коммита (_commitPhysicalGeometry→_recordGeometry, houseplan-card.ts:12069), пересборка тестового бандла (npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs), node --test test/wall-union-isolation.test.mjs |
красный: both thickness writers route through the common barrier / 1 !== 2; вернул файл, дерево чистое |
| точечный мутационный гейт | node scripts/mutation-gate.mjs --id=wall-thickness-writer-bypasses-common-barrier |
«поймано 1 из 1» на чистом дереве |
| смок-выборка по делте | node scripts/smoke-select.mjs --base 5e5dad27 --head HEAD |
«НЕОПРЕДЕЛЁННОСТЬ: … ни один смок не связан доказуемо» (0 символов проекта на изменённых строках делты — новая локальная переменная rawCm, регэксп теста). Не повод ничего не гонять: смок, напрямую относящийся к находкам (smoke_wallthick_standalone), уже прогнан выше вместе с падением на мутации — этого достаточно для делты такого размера |
| три названных смока AC4 (регрессия комнатных стен, делта их не трогает, но дёшево перепроверить) | node demo/smoke_wall_thickness.mjs, node demo/smoke_wallthick_hover_width.mjs, node demo/smoke_resize_wall_thickness.mjs |
все три OK |
Не прогонял (и почему)
- Полная матрица
smoke_*.mjs(191 файл) иgolden:verify— предрелизная обязанность (PROCESS.md §8), не гейт ревью; делта не меняет рендер/геометрию результата,smoke-selectне назвал ни одного дополнительного кандидата. python -m pytest tests_backend -q—custom_components/**/*.pyне тронут ни в делте, ни в r1.npm run invariantsна конкретной конфигурации — делта не меняет запись геометрии (см. «Унаследовано» выше); повторный прогон не добавил бы информации к выводу r1.- Performance-профили — не названы в AC, чувствительные к перфу пути не тронуты.
Вердикт
Зелёный. Обе находки r1 (High и Medium) закрыты точными, локальными правками ровно в тех местах, где были найдены; для каждой перепроверил исполнением не только «стало зелёным», но и «умеет падать» — откатил правку и получил ожидаемое красное на смоке (High) и на юнит-гварде (Medium). Делта не затрагивает ни один из участков, закрытых r1 («Унаследовано» выше), новых находок не обнаружено.