diff --git a/docs/reviews/CODE-REVIEW-400-r2.md b/docs/reviews/CODE-REVIEW-400-r2.md new file mode 100644 index 00000000..757d3696 --- /dev/null +++ b/docs/reviews/CODE-REVIEW-400-r2.md @@ -0,0 +1,170 @@ +# CODE-REVIEW-400-r2 + +- Issue: https://github.com/Matysh/houseplan-card/issues/400 +- ТЗ: `docs/specs/400-beta-polish.md` (r1), ревью ТЗ зелёное (комментарий 2026-08-31T04:44:56Z) +- Ревью r1: `docs/reviews/CODE-REVIEW-400-r1.md`, вердикт жёлтый, SHA `73ecfbd1d74a6d194f62e8e83766294018f8eb81`, опубликовано коммитом `f07e3c54` (2026-08-31T05:06:35Z) +- Диапазон материала r2: `origin/dev...HEAD`, HEAD на момент разбора и на момент вердикта — `f07e3c54ffea88b0d77b12065bf318fc820d0ebf` +- Заход r2, блокирующих циклов израсходовано **1 из 4** до этого вердикта + +## Дельта раунда (§2.10) + +Предыдущий вердикт получен на SHA `73ecfbd1`. Дельта: + +``` +$ git diff 73ecfbd1..HEAD --stat + docs/reviews/CODE-REVIEW-400-r1.md | 196 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 196 insertions(+) +``` + +Это **единственный** коммит между r1 и r2 — публикация документа r1-ревью самим +конвейером. `git diff 73ecfbd1..HEAD -- src/ scripts/ demo/` пуст. Ни один файл +кода, теста или мутанта не изменился с момента r1. + +Однако в issue после публикации r1 есть комментарий автора (2026-08-31T05:14:07Z, +**позже** документа r1 на 5:06:35Z): *«Medium закрыт, HEAD обновлён»*, описывающий +конкретную правку — именованную константу `HANDLE_PAINT_ORDER = ['edges', +'corners']`, изменённый патч мутанта, замену `handles[3]` на выбор ручки по роли +в `smoke_furniture`. Это и есть предмет разбора r2: делает ли фактический +репозиторий то, что утверждает комментарий. + +**Ответ: нет.** Ни одна из трёх заявленных правок не существует ни в одном +коммите ни одной ветки: + +``` +$ git grep -l "HANDLE_PAINT_ORDER" $(git rev-list --all) -- src/ +(пусто — по всей истории репозитория) + +$ for b in $(git branch -a --format='%(refname)' | grep issue/400); do git log $b --oneline -3; done +f07e3c54 docs: review document for #400 +73ecfbd1 build: refresh bundle trees and the doc capture for #400 +fe3b85c0 fix: the corner handle wins on small furniture, guides exclude the real drag (#400) +(других веток с #400 нет) + +$ grep -n "handles\[3\]" demo/smoke_furniture.mjs +360: const se = handles[3] || stageEl(); // SE — четвёртый угол +``` + +`git fetch origin issue/400-beta-polish` не принёс новых коммитов — `HEAD` на +удалённой ветке совпадает с локальным. Единственное отдалённо связанное действие +после комментария — коммит `f07e3c54`, но это публикация r1-ревью, а не фикс. + +## Закрытие раунда r1 + +| Находка r1 | Чем закрыта | Где это видно | +|---|---|---| +| **M1** — мутант `furniture-edge-handles-steal-the-corner` правит только текст JS-комментария, не порядок отрисовки; регрессию AC1 не ловит | **Не закрыта.** Автор заявил фикс в комментарии, но код не изменился | `git diff 73ecfbd1..HEAD -- src/ scripts/` пуст; повторный прогон ниже даёт тот же результат, что в r1 | + +Повторный прогон того же гейта, что дал находку в r1: + +``` +$ node scripts/mutation-gate.mjs --id=furniture-edge-handles-steal-the-corner +ok чистый прогон: node demo/smoke_furniture_polish.mjs +FAIL furniture-edge-handles-steal-the-corner: тест остался зелёным на сломанном коде +поймано 0 из 1 +``` + +Идентично записи в CODE-REVIEW-400-r1.md. Патч мутанта в +`scripts/mutation-gate.mjs:756-759` по-прежнему меняет только строку внутри +`/* ... */`. + +## Унаследовано из r1 + +Всё, что предметно не связано с M1, дельта не задевает (дельта нулевая), поэтому +принимается без повторной проверки по документу `docs/reviews/CODE-REVIEW-400-r1.md`, +SHA `73ecfbd1`: + +- AC1/AC2 (угловая ручка выигрывает хит на мелкой мебели) — доказаны живым + браузерным смоком `smoke_furniture_polish.mjs` (`smallFurnitureCornerWinsTheHit: + true`, `largeFurnitureKeepsBothHandles: true`), прогнано вживую в r1. +- AC4/AC5 (`_alignCandidates` исключает по `_deviceDrag`) — доказаны смоком + `smoke_align_guides.mjs` и вторым мутантом (`align-guides-exclude-dead-source`, + «поймано 1 из 1»); перепрогнан в r2 с тем же результатом (см. таблицу гейтов). +- AC3/AC6 (решение по 38 help-строкам в `docs/ARCHITECTURE.md`, бюджет + 285 425 / 300 000) — подтверждены в r1 чтением записи и прогоном `bundle:budget`; + в r2 бюджет перепрогнан и даёт то же число (см. ниже) — код не менялся, значит + и вывод не мог измениться. +- Трейлеры четырёх содержательных коммитов (`60c211c8`, `532743b0`, `fe3b85c0`, + `73ecfbd1`) — проверены в r1, дельта их не касается. +- Смок-выборка `scripts/smoke-select.mjs --base origin/dev --head HEAD` и 9 + зелёных прямых совпадений — не перезапускались в r2: набор файлов, который они + покрывают, не изменился (дельта r2 — один docs-файл). + +## Как проверялось (r2) + +Дешёвые гейты гоняются в каждом раунде независимо от локальности дельты (§2.10). +Диапазон src/scripts не менялся, но числа сверены заново, а не унаследованы вслепую. + +| Гейт | Команда | Результат | +|---|---|---| +| typecheck | `npx tsc --noEmit` | чисто | +| unit | `npm test` | 1668 tests, 1667 pass, 0 fail, 1 skipped — совпадает с r1 | +| build | `npm run build` | успешно, 15.6s | +| сверка трёх копий бандла | `npm run bundle:sync` | `git status --porcelain` пуст до и после — `dist`, `custom_components/houseplan/frontend`, `demo/srv/assets` уже синхронизированы, дрейфа нет | +| бюджет | `npm run bundle:budget` | initial 285 425 / 300 000, тот же варнинг про запас < 15 000 Б (#367, фоновый, не следствие этой задачи) — число идентично r1 | +| мутант (предмет M1) | `node scripts/mutation-gate.mjs --id=furniture-edge-handles-steal-the-corner` | **красный, как в r1**: поймано 0 из 1 | +| мутант (контроль) | `node scripts/mutation-gate.mjs --id=align-guides-exclude-dead-source` | зелёный: поймано 1 из 1, без изменений | + +Не прогонялось (дельта — один docs-файл, ничего из перечисленного её не +задевает и было закрыто в r1): `check-docs.mjs` (diff r2 не трогает `src/**`), +`no-new-any.mjs` (нет новых строк кода), `smoke-select.mjs` (набор символов не +менялся), `model-invariants.mjs` (diff не про геометрию), `golden:verify`, +`pytest tests_backend`, performance-профили, полный набор смоков. + +## Находки + +### Medium (в скоупе задачи — по-прежнему открыта из r1) + +**M1 (перенесена из r1, не закрыта).** Мутационный гейт +`furniture-edge-handles-steal-the-corner` всё ещё не воспроизводит регрессию +AC1: патч правит текст JS-комментария в `src/houseplan-card.ts`, физический +порядок отрисовки `sides`/`corners` не меняется, «поймано 0 из 1» — +воспроизведено исполнением, идентично r1. + +Дополнительно к находке r1: комментарий автора от 2026-08-31T05:14:07Z +заявляет закрытие с конкретными деталями (константа `HANDLE_PAINT_ORDER`, +переписанный патч мутанта, замена `handles[3]` на роль в `smoke_furniture.mjs`), +которых нет ни в одном коммите ни одной ветки репозитория — проверено +`git diff`, `git grep` по всей истории и `git fetch` удалённой ветки. Это не +новый дефект по существу (функциональность AC1/AC2 по-прежнему работает и +доказана живым смоком, унаследовано из r1), а расхождение между тем, что +записано в issue, и тем, что лежит в git. Возможные причины — потерянный push, +работа в незакоммיтированной рабочей копии, коммит на изолированной среде, +которая не долетела до `origin`. Это не блокирует зелёный вердикт сверх того, +что уже блокировала находка M1 сама по себе, но без исправления **само +исправление M1 остаётся фактически не начатым**, и владельцу до следующего +раунда стоит убедиться, что описанная в комментарии правка вообще существует +где-то за пределами текста комментария. + +**Почему Medium, а не High**: тот же довод, что в r1 — сама функциональная +правка AC1/AC2 верна и доказана живым браузерным смоком, ломается только +постоянная защита от будущего отката (мутационный гейт), а не текущее +поведение продукта. + +**Ожидаемо** (не изменилось с r1): патч мутанта должен реально возвращать +`corners` перед `sides` (или иным способом менять фактический порядок +рендера). Проверка приёмки: `node scripts/mutation-gate.mjs +--id=furniture-edge-handles-steal-the-corner` → «поймано 1 из 1», и это должно +быть видно в `git diff` этой ветки, а не только в тексте комментария. + +## Что проверено и корректно + +- Все AC, кроме предмета M1, — без изменений с r1, унаследовано с указанием + источника выше. +- Дешёвые гейты r2 воспроизводят те же числа, что в r1 (tsc чист, 1667/0 тестов, + бюджет 285 425/300 000, три копии бандла синхронизированы) — ожидаемо, так как + дельта нулевая по коду. +- Контрольный мутант `align-guides-exclude-dead-source` по-прежнему ловит свою + регрессию (1 из 1) — AC4/AC5 не деградировали. +- Ветка `issue/400-beta-polish` — единственная с материалом по #400; других + мест, где могла бы жить заявленная правка, не найдено. + +## Чего не проверял + +- Не искал вне git (например, в артефактах CI-запусков или локальных стейджах + автора) заявленную правку — ревью материалом считает только репозиторий, как + предписано; если правка существует где-то ещё, её нужно закоммитить и + запушить, тогда она попадёт в следующую дельту. +- Не прогонял `check-docs.mjs`, `no-new-any.mjs`, `smoke-select.mjs`, + `model-invariants.mjs`, `golden:verify`, `pytest tests_backend`, + performance-профили и полный набор смоков — дельта r2 их не касается + (единственный файл дельты — docs), и они были закрыты в r1 на том же коде.