mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-02 21:01:21 +00:00
Validate / docs (push) Successful in 28s
Validate / process-workflow-sync (push) Successful in 36s
Validate / provenance (push) Successful in 40s
Validate / process-gate (push) Failing after 40s
Validate / changes (push) Successful in 37s
Validate / hacs (push) Skipped
Validate / hassfest (push) Skipped
Validate / frontend (push) Skipped
Validate / reuse (push) Successful in 47s
Validate / smoke (1) (push) Skipped
Validate / smoke (2) (push) Skipped
Validate / smoke (3) (push) Skipped
Validate / smoke_done (push) Skipped
Validate / golden (push) Skipped
Validate / performance_smoke (push) Skipped
Validate / backend (push) Skipped
Issue: #290 User-Visible: no
153 lines
16 KiB
Markdown
153 lines
16 KiB
Markdown
# CODE-REVIEW-290-r4
|
||
|
||
- **Issue:** #290 — «Уступ в один шаг на общей стене создаётся молча и невидим при обычном зуме»
|
||
- **Этап:** код-ревью (PROCESS.md §2.7)
|
||
- **Заход:** r4 · блокирующих циклов израсходовано на входе 2 из 4
|
||
- **Ветка:** `issue/290-near-axis-authoring-repair`
|
||
- **HEAD на момент ревью:** `01512081db0d41cb86c921a61961275c8c18aedb`
|
||
- **Предыдущий раунд:** r3, жёлтый, `docs/reviews/CODE-REVIEW-290-r3.md`,
|
||
SHA на котором получен вердикт — `d33ae88da4049bdbdfd02c57f935199007157cf3`
|
||
(назван в самом документе r3, раздел «HEAD на момент ревью» — в этот раз
|
||
находки в процессе нет).
|
||
|
||
## Разбор по дельте (PROCESS.md §2.10) — почему сокращённый объём законен
|
||
|
||
Дельта: `git diff d33ae88d..HEAD` — **2 коммита, 2 файла, только классы C и B**:
|
||
|
||
```
|
||
docs/reviews/CODE-REVIEW-290-r3.md | 218 ++++++++++++++++ (класс C, документ ревью r3)
|
||
test/near-axis.test.mjs | 15 ++ (класс B, только новый тест)
|
||
```
|
||
|
||
Ни одного файла класса A. `src/**` этим раундом не тронут вовсе — проверено
|
||
`git diff --stat d33ae88d..HEAD -- src/`: пусто. Ветка полностью содержит
|
||
`origin/dev` (`git merge-base --is-ancestor origin/dev HEAD` — true, `dev` не
|
||
уходил вперёд после r3), контракт поведения не менялся, новая подсистема не
|
||
задета, объём дельты (15 строк теста) многократно меньше исходной задачи.
|
||
Ни одно из исключений §2.10 («ребейз на ушедший вперёд dev», «смена контракта»,
|
||
«новая подсистема», «объём сопоставим с задачей») не применяется →
|
||
разбор ограничен закрытием единственной находки r3 (M1) и дешёвыми гейтами,
|
||
которые гоняются в любом раунде.
|
||
|
||
## Скоуп раунда
|
||
|
||
Единственная находка r3 (Medium M1, в скоупе задачи, жёлтый вердикт) требовала
|
||
механического source guard на AC1: «Authoring, Optimize и renderer #279
|
||
импортируют один threshold source; source guard запрещает отдельные литералы
|
||
`0.25` в этих classifiers» (`docs/specs/290-near-axis-authoring-and-repair.md:173-174`).
|
||
Автор выбрал вариант (а) из двух, предложенных r3: статический guard-тест,
|
||
читающий исходники трёх потребителей как текст и требующий literal import +
|
||
literal вызов/присваивание общего near-axis API, а не инлайн-константу.
|
||
|
||
## Закрытие раунда r3
|
||
|
||
| Находка | Чем закрыта | Где это видно |
|
||
|---|---|---|
|
||
| **M1** (Medium, в скоупе): AC1 обещает source guard против инлайн-литерала `0.25` в renderer/authoring/Optimize; такого guard'а не было — числовое равенство в `test/near-axis.test.mjs:23` не ловит дублирование значения, только его совпадение | Новый тест `#290 authoring, Optimize and renderer use one near-axis threshold source` (`test/near-axis.test.mjs:22-34`, коммит `01512081`) читает `src/wall-thickness.ts`, `src/houseplan-card.ts`, `src/plan-optimizer.ts` как текст и требует буквального `import … from './near-axis'` плюс использования соответствующего экспорта в каждом из трёх файлов | Воспроизвёл ровно ту же мутацию, что и r3: заменил в `src/wall-thickness.ts:85` импортированную ссылку на инлайн-литерал `= 0.25` (удалив зависимость от `NEAR_AXIS_MAX_DEGREES`) — новый guard-тест **краснеет** (`The input did not match the regular expression /import \{ NEAR_AXIS_MAX_DEGREES \} .../`). Дополнительно проверил ту же схему для двух других потребителей: убрал `import { snapNearAxisEndpoint } from './near-axis';` из `src/houseplan-card.ts` — тест краснеет; убрал `import { repairNearAxisRoomWalls } from './near-axis';` из `src/plan-optimizer.ts` — тест краснеет. После каждой мутации файл восстановлен, `git status --short` пуст, `npm test` снова зелёный (см. таблицу гейтов) |
|
||
|
||
Других находок в r3 не было (High:0, остальные Medium:0) — закрывать больше
|
||
нечего.
|
||
|
||
## Как проверялось — гейты
|
||
|
||
| Гейт | Команда | Результат |
|
||
|---|---|---|
|
||
| Typecheck | `npx tsc --noEmit` | чисто, без ошибок |
|
||
| Unit (полный, дешёвый гейт гоняется в любом раунде) | `npm test` | 1235 тестов: 1234 passed, 1 skipped, 0 failed (на 1 больше, чем в r3 — новый guard-тест); подтверждено `npm run inventory` (Node unit: 1235) |
|
||
| Build + сверка копий бандла | `npm run build`; `diff dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js`; `git status --short` | пересобранный `dist` побайтово идентичен закоммиченному и копии в `custom_components`; `git status` после пересборки чист — рабочая копия не разошлась с закоммиченными артефактами |
|
||
| Дисциплина «тест умеет падать» — M1 (renderer) | откат `src/wall-thickness.ts:85` к инлайн-литералу `0.25` без импорта, `npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs && node --test --test-name-pattern="#290 authoring, Optimize and renderer..." test/near-axis.test.mjs` | тест краснеет (regex import не совпал); после отката файла — снова зелёный, `git status` чист |
|
||
| Дисциплина «тест умеет падать» — M1 (authoring) | тот же приём для `import { snapNearAxisEndpoint } from './near-axis';` в `src/houseplan-card.ts` | тест краснеет; откат — зелёный |
|
||
| Дисциплина «тест умеет падать» — M1 (Optimize) | тот же приём для `import { repairNearAxisRoomWalls } from './near-axis';` в `src/plan-optimizer.ts` | тест краснеет; откат — зелёный |
|
||
| Smoke-select по дельте раунда | `node scripts/smoke-select.mjs --base d33ae88d --head HEAD` | «Исполняемого frontend-диффа нет (src/**/*.ts не тронут). Browser-smoke этим диффом не выбираются — выбирать нечего» — согласуется с тем, что дельта не трогает `src/**` |
|
||
| Docs fingerprint | не перезапускал | не требуется этим раундом: `src/**` дельтой не тронут (см. «Разбор по дельте»); последний прогон — r3, «Documentation checks passed (7 files, 10 external links)», наследуется |
|
||
| Инварианты геометрии | не перезапускал | не требуется: дельта не трогает геометрию/`layout`/`marker.space`/`open_spans`; последний прогон — r3, код 0 на обоих real-plan фикстурах, наследуется |
|
||
| Golden | не перезапускал | не требуется: дельта не меняет рендер/UI; последний прогон — r3, 161/161 passed, наследуется |
|
||
| Backend pytest | не запускал | `git diff --stat d33ae88d..HEAD -- 'custom_components/**/*.py'` пуст |
|
||
|
||
## Находки
|
||
|
||
Нет. High: 0, Medium: 0.
|
||
|
||
## Что проверено и корректно
|
||
|
||
- **M1 закрыт по существу, не только по факту существования теста** — три
|
||
прямые мутации (см. таблицу гейтов) доказывают, что guard действительно
|
||
ловит инлайн-литерал в каждом из трёх названных AC1 потребителей
|
||
(`wall-thickness.ts`, `houseplan-card.ts`, `plan-optimizer.ts`), а не только
|
||
в одном из них.
|
||
- **Guard читает исходник, а не собранный бандл** — `sourceOf()`
|
||
(`test/near-axis.test.mjs:20`) делает `readFileSync` из `src/*.ts` напрямую,
|
||
минуя `test-build/`; расхождение между исходником и типизированной сборкой
|
||
тест не маскирует.
|
||
- **Регекс на вызов, а не только на импорт** — `assert.match(authoring,
|
||
/snapNearAxisEndpoint\(/)` и `assert.match(optimizer,
|
||
/repairNearAxisRoomWalls\(space\)/)` отдельно требуют реального использования
|
||
импортированного символа, а не только присутствия строки импорта (мёртвый
|
||
импорт не прошёл бы эту часть проверки).
|
||
- **Трейлеры и класс изменения** — `01512081` (`test: enforce shared near-axis
|
||
threshold source`) несёт `Issue: #290`, `User-Visible: no`; правильно, это
|
||
чисто тестовый файл (`test/**`, класс B), продуктовое поведение не менялось,
|
||
changelog не требуется.
|
||
- **Дерево не расходится с гейтами** — до, во время и после всех мутационных
|
||
проверок `git status --short` оставался чист; финальная пересборка `dist`
|
||
побайтово совпадает с обеими закоммиченными копиями.
|
||
- **AC2–AC10, H1-регрессия r1, mutation-gate ×6, golden, инварианты, single
|
||
source of numbers, совместимость, performance** — не пересматривались в этом
|
||
раунде: дельта их не задевает (см. «Разбор по дельте»), полностью
|
||
унаследованы из r3 (раздел ниже), который сам разобрал их читая весь
|
||
`origin/dev...HEAD` (а не по дельте) из-за промежуточного ребейза.
|
||
|
||
## Чего не проверял
|
||
|
||
- **`node scripts/check-docs.mjs`, `npm run invariants`, `npm run
|
||
golden:verify`, полный `mutation-gate`, touch-смоки, `pytest tests_backend`**
|
||
— не перезапускал в этом раунде; все они не выбираются ни диффом (`src/**`
|
||
не тронут), ни AC, задетым этой дельтой (только AC1/source guard). Их
|
||
последние зелёные прогоны — в r3, см. таблицу гейтов там и «Унаследовано»
|
||
ниже.
|
||
- **Внешний Linux CI Validate на точном HEAD `01512081`** — не проверял
|
||
напрямую; последняя подтверждённая владельцем ссылка (Validate 32733382537)
|
||
относится к SHA `d33ae88d`, до этого раунда. Пересборка/тесты локально
|
||
воспроизводят зелёное состояние, но отдельного прогона CI на новом HEAD в
|
||
комментариях issue не найдено на момент ревью.
|
||
- **Комментарий-хендофф автора после r3** (issue #290, id `5396316118`,
|
||
2026-08-24T14:03:02Z) обрывается на полуслове: «Исправление Medium M1 из
|
||
code review r3 запушено в \» — SHA коммита-фикса в нём не назван. Это не
|
||
влияет на вердикт: коммит независимо идентифицирован через `git log
|
||
d33ae88d..HEAD` (`01512081`, единственный коммит с продуктовым/тестовым
|
||
содержимым в дельте) и проверен напрямую, а не со слов автора. Отмечаю как
|
||
находку процесса, не как находку кода — вердикт не снижается, править
|
||
нечего в этой ветке.
|
||
|
||
## Унаследовано из r3
|
||
|
||
Документ: `docs/reviews/CODE-REVIEW-290-r3.md`, SHA `d33ae88da4049bdbdfd02c57f935199007157cf3`
|
||
(назван в самом документе r3). Принято без повторной проверки в этом раунде,
|
||
так как дельта `d33ae88d..HEAD` их не задевает:
|
||
|
||
- **AC1 (кроме source guard), AC2–AC10** — весь предметный разбор по коду
|
||
(`src/near-axis.ts`, `src/houseplan-card.ts`, `src/resize.ts`,
|
||
`src/plan-optimizer.ts`, `src/wall-thickness.ts`,
|
||
`scripts/model-invariants.mjs`) — r3 прочитал и перепроверил их **полностью**
|
||
(не по дельте относительно r2, а заново, из-за промежуточного ребейза на
|
||
ушедший вперёд `dev`), включая прямой откат H1-регрессии r1 и все 6
|
||
обязательных mutation-gate ID индивидуально.
|
||
- **Golden (161/161 сценариев)**, **docs fingerprint** (7 файлов, 10 внешних
|
||
ссылок), **near-axis профиль на обоих real-plan фикстурах** (`--near-axis`
|
||
CLI), **bundle parity на момент r3** — гоняны и зафиксированы в r3, дельта
|
||
этого раунда не меняет ни один из задействованных там файлов.
|
||
- **Продуктовые решения владельца** (авто-выравнивание без modifier bypass,
|
||
подтверждаемый lossy-пас Optimize с отчётом/Undo, единый допуск `0.25°`) —
|
||
зафиксированы на этапе ТЗ (`SPEC-REVIEW-290-r2`, зелёный, `dc9f9a6c`) и не
|
||
относятся к коду; ребейз и текущая дельта их не касаются.
|
||
- **Backend** — `custom_components/**/*.py` не менялся ни в r3, ни в этой
|
||
дельте; `pytest tests_backend` по-прежнему не требуется.
|
||
|
||
## Вывод
|
||
|
||
Единственная находка предыдущего раунда (M1) закрыта и подтверждена прямой
|
||
мутацией на всех трёх названных в AC1 потребителях, а не только заявлением
|
||
автора. Новых находок дельта не создаёт. Дешёвые гейты (`tsc`, `npm test`,
|
||
`build` + сверка бандла) зелёные на текущем HEAD. High: 0, Medium: 0 →
|
||
**зелёный вердикт**.
|