From d071ac2e143c3402b02be33f2a7710ccf740be5a Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Thu, 24 Sep 2026 08:04:09 +0300 Subject: [PATCH] docs: review document for #631 Issue: #631 User-Visible: no --- docs/reviews/CODE-REVIEW-631-r1.md | 152 +++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 docs/reviews/CODE-REVIEW-631-r1.md diff --git a/docs/reviews/CODE-REVIEW-631-r1.md b/docs/reviews/CODE-REVIEW-631-r1.md new file mode 100644 index 00000000..0f95b0bc --- /dev/null +++ b/docs/reviews/CODE-REVIEW-631-r1.md @@ -0,0 +1,152 @@ +# CODE-REVIEW — issue #631, заход r1 + +Материал: `36f0db6e1ae9388ff31e84cdb7cbae26545d38f9` (рабочая копия на нём, детач HEAD). +Диапазон: `origin/dev..HEAD`, один коммит: +`test(editors): unit contracts for dialog baselines and form problems (#631)`. + +## Скоуп + +Класс B (инфраструктурный трек, `src/**` не тронут — подтверждено `git diff +origin/dev...HEAD --stat`, только 4 файла): `tsconfig.test.json`, +`test/dialog-baseline.test.mjs`, `test/dialog-form-problems.test.mjs`, +`scripts/mutation-registry.mjs`. Задача: покрыть юнитами `dialog-baseline.ts` +(`stableKey`, `dialogDirty`, warm-перенос) и четыре `*-form-state.ts` +(`*Problems`), которые раньше были доказаны только браузерными смоками и +мутантами с гардами на те же смоки, и перевести три существующих мутанта на +юнит-гарды. + +Трейлеры коммита: `Issue: #631`, `User-Visible: no` — оба на месте. При +`User-Visible: no` правка обоих changelog не требуется; ни один changelog в +диффе не тронут — согласовано. + +Продуктовая рамка (SCOPE.md): задача не добавляет пользовательского +поведения, это укрепление доказательной базы существующего контракта +Save/dirty (относится к J6 «Keep the plan true as the home evolves» — +уверенность в том, что редакторы ведут себя как задокументировано). Класс B +такой рамки не требует по существу, отклонений от неё нет. + +## Как проверялось + +1. Прочитан код без исполнения: `src/editors/dialog-baseline.ts`, + `space-form-state.ts`, `general-form-state.ts`, `marker-form-state.ts`, + `room-form-state.ts` (все — не в диффе, сверены построчно с утверждениями + новых тестов: транзиентные наборы, порядок ошибок, условия create/edit). +2. Собран `test-build` (`npx tsc -p tsconfig.test.json && node + scripts/fix-test-build.mjs`) и прогнаны сами тесты: + `node --test test/dialog-baseline.test.mjs test/dialog-form-problems.test.mjs` + → pass 25, fail 0 (совпадает с числом автора). +3. «Тест умеет падать» — не декларативно, а прогоном: + - Все 9 мутантов, названных в AC3/новых контрактах, прогнаны индивидуально + через `node scripts/mutation-gate.mjs --id=`: + `dialog-baseline-key-order-sensitive`, `dialog-baseline-missing-reads-clean`, + `space-dialog-key-counts-raw-scale-input`, `room-draft-key-drops-label-scale`, + `room-create-ignores-area`, `marker-ha-binding-accepts-virtual`, + `general-required-number-falls-back-to-hidden-value`, + `space-required-temperature-forgets-raw-draft`, + `marker-virtual-name-remains-a-late-toast` — все девять «поймано 1 из 1». + - `node scripts/mutation-gate.mjs --check` (статическая проверка якорей + реестра) — rc 0, без ошибок. + - Дополнительно проверен участок, для которого в реестре нет отдельного + мутанта — контракт «вложенный объект сравнивается как есть» в + `stableKey` (тест `#631 stableKey: nested objects…`, строки 79–91). Я + вручную пропатчил `stableKey` на рекурсивную нормализацию вложенных + ключей (правдоподобная ошибочная реализация) и убедился, что именно + этот тест краснеет (`AssertionError`, `notStrictEqual`), затем откатил + патч (`git status` после отката — чистый) и пересобрал `test-build`. + Это не пробел AC3 (AC3 требует перевода гардов существующих мутантов, а + не мутанта на каждую фразу AC1) — просто эта конкретная ветка теста не + зарегистрирована в реестре, но нефиктивна. +4. `node scripts/smoke-select.mjs --base origin/dev --head HEAD` → + «Исполняемого frontend-диффа нет… Browser-smoke этим диффом не + выбираются». Согласуется с тем, что `src/**` не менялся и рендер не + затронут — смоки не нужны. +5. `node scripts/process-gate.mjs` → «гейт пройден, предупреждений 0» (без + `--issues`, как и заявлено автором). +6. Дешёвые гейты (`npx tsc --noEmit`, `npm test` полностью, `npm run build` со + сверкой бандла) не перегонялись — они уже подтверждены зелёным Validate на + этом же SHA `36f0db6e` (https://github.com/Matysh/houseplan-card/actions/runs/35942748069). + Целевые юнит-файлы из этого прогона я перепрогнал отдельно (см. п.2) как + часть проверки конкретных находок задачи, а не для замены Validate. + +## Соответствие AC + +- **AC1** (одинаковые черновики с разным порядком ключей — не dirty; + транзиентные ключи каждого диалога игнорируются; вложенный объект — как + есть, выбор задокументирован; без снимка → dirty): доказано юнитами в + `dialog-baseline.test.mjs` и подтверждено чтением четырёх + `*-form-state.ts` — наборы транзиентных ключей в тестах совпадают + дословно с константами в коде (`SPACE_DIALOG_TRANSIENT_KEYS`, + `TRANSIENT` в general, `MARKER_DIALOG_TRANSIENT_KEYS`, десять полей + `roomDraftKey`). Выбор по вложенным объектам зафиксирован комментарием в + тесте (стр. 80–84) и в src (`stableKey` doc-комментарий). Мутационно + доказаны 3 из 4 пунктов (порядок ключей, транзиентность per-диалог, no + baseline → dirty); четвёртый (вложенные объекты) проверен вручную по п.3 + выше и падает на правдоподобной мутации. +- **AC2** (тесты `*Problems` на каждый код ошибки и на пустой список): + выполнено для всех четырёх форм в `dialog-form-problems.test.mjs`, + включая совместный порядок кодов («все ошибки сразу — в порядке полей») и + ранее не покрытую `roomProblems` (edit/create, границы диапазона). + Мутанты `room-create-ignores-area` и `marker-ha-binding-accepts-virtual` + подтверждают, что это не тавтологичные ассерты. +- **AC3** (гарды соответствующих мутантов переведены со смоков на юниты): + подтверждено диффом `scripts/mutation-registry.mjs` (три `guard:` заменены + с `node demo/smoke_*_settings_form.mjs` на `node --test + test/dialog-form-problems.test.mjs`) и прогоном каждого из трёх — «поймано + 1 из 1» за секунды, без браузера. + +## Проверено чтением, не исполнением + +- Соответствие тестовых фикстур (`spaceDraft`, `generalDraft`, `markerDraft`, + `roomHost`) реальной форме полей `SpaceDialogState`, + `GeneralSettingsDraft`, `MarkerDialogDraft`, `RoomDraftHost` — сверено + построчно с src, расхождений нет. +- Логика `spaceDialogProblems`/`generalProblems`/`markerProblems`/ + `roomProblems` (порядок веток, условия `edit`/`create`, режим `ha` для + маркера, режим заливки для температуры) — прочитана и сопоставлена с + ассертами; исполняемо подтверждена прогоном тестов (не только чтением). + +## Чего не проверял + +- Полный `npm test` (250 файлов), `npx tsc --noEmit`, `npm run build` — + не перегонял; основание — зелёный Validate на этом же SHA (см. выше), + диффу без правок src это не противоречит. +- Полный ночной прогон `mutation-registry.mjs` (все мутанты, не только + девять из этой задачи) — не запускал, это предрелизный/ночной гейт, не + гейт ревью. +- `node scripts/check-inputs.mjs --coverage`, `node scripts/no-new-any.mjs` — + не перегонял; диффу не касается (нет `src/**`, нет новых `input`-полей). +- `node scripts/check-docs.mjs` — не требуется: `src/**` не тронут. +- golden/perf/pytest — не по диффу (нет рендера, нет `custom_components/**`). +- Браузерные смоки — не запускал; `smoke-select.mjs` подтвердил, что для + этого диффа выбирать нечего. +- Ручное тестирование в браузере не проводилось (задача не меняет `src/**`, + User-Visible: no). + +## Находки + +Не выявлено. High — 0, Medium — 0, Low — 0. + +## Итог + +Все три AC доказаны исполняемыми тестами и/или мутациями (плюс один +мутационно не зарегистрированный, но лично проверенный на «умение падать» +пункт AC1). Диапазон материала подтверждён совпадением blob-хешей файлов +диффа с якорями, приложенными автором в issue (`89e6f73f…`, `a08b616a…`, +`107801f8…`, `858994a6…`) — несмотря на разные корневые деревья до/после +ребейза, содержание изменённых файлов идентично заявленному. Рабочая копия +после проверки чиста (`git status` — «nothing to commit, working tree +clean»). + +--- + + + +## Материал раунда + +- Ветка: `issue/631-form-state-units`, коммит `36f0db6e1ae9` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `a7cbed4ee3b2c1bd0a8334bae66400e50e2c26ba` + ``` + git log --all --format='%H %T' | grep a7cbed4ee3b2 + ``` +- Тело issue: `65fb6131e45f761b7a50d4daf8a05706d1c987d495b7132e1fba4307f9549702` +- Вердикт конвейера: `green` · High 0