mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
docs: review document for #617
Проверка (CI) / Предполёт: документация, провенанс, процесс (push) Failing after 13m26s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Canceled after 0s
Проверка (CI) / HACS: валидация репозитория (push) Canceled after 0s
Проверка (CI) / Hassfest: манифест интеграции (push) Canceled after 0s
Проверка (CI) / Мутанты по диффу (1/6): затронутые свидетели краснеют (push) Canceled after 0s
Проверка (CI) / Мутанты по диффу (2/6): затронутые свидетели краснеют (push) Canceled after 0s
Проверка (CI) / Мутанты по диффу (3/6): затронутые свидетели краснеют (push) Canceled after 0s
Проверка (CI) / Мутанты по диффу (4/6): затронутые свидетели краснеют (push) Canceled after 0s
Проверка (CI) / Мутанты по диффу (5/6): затронутые свидетели краснеют (push) Canceled after 0s
Проверка (CI) / Мутанты по диффу (6/6): затронутые свидетели краснеют (push) Canceled after 0s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Canceled after 0s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Canceled after 0s
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Canceled after 0s
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Canceled after 0s
Проверка (CI) / Смоки: все шарды зелёные (push) Canceled after 0s
Проверка (CI) / Golden-кадры против принятых эталонов (push) Canceled after 0s
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Canceled after 0s
Проверка (CI) / Геометрия: TS/Python parity исполнена (push) Canceled after 0s
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Canceled after 0s
Проверка (CI) / Доказательство выполненных проверок (push) Canceled after 0s
Проверка (CI) / Классификация изменённых файлов (push) Failing after 3m35s
Проверка (CI) / Предполёт: документация, провенанс, процесс (push) Failing after 13m26s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Canceled after 0s
Проверка (CI) / HACS: валидация репозитория (push) Canceled after 0s
Проверка (CI) / Hassfest: манифест интеграции (push) Canceled after 0s
Проверка (CI) / Мутанты по диффу (1/6): затронутые свидетели краснеют (push) Canceled after 0s
Проверка (CI) / Мутанты по диффу (2/6): затронутые свидетели краснеют (push) Canceled after 0s
Проверка (CI) / Мутанты по диффу (3/6): затронутые свидетели краснеют (push) Canceled after 0s
Проверка (CI) / Мутанты по диффу (4/6): затронутые свидетели краснеют (push) Canceled after 0s
Проверка (CI) / Мутанты по диффу (5/6): затронутые свидетели краснеют (push) Canceled after 0s
Проверка (CI) / Мутанты по диффу (6/6): затронутые свидетели краснеют (push) Canceled after 0s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Canceled after 0s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Canceled after 0s
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Canceled after 0s
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Canceled after 0s
Проверка (CI) / Смоки: все шарды зелёные (push) Canceled after 0s
Проверка (CI) / Golden-кадры против принятых эталонов (push) Canceled after 0s
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Canceled after 0s
Проверка (CI) / Геометрия: TS/Python parity исполнена (push) Canceled after 0s
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Canceled after 0s
Проверка (CI) / Доказательство выполненных проверок (push) Canceled after 0s
Проверка (CI) / Классификация изменённых файлов (push) Failing after 3m35s
Issue: #617 User-Visible: no
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
# CODE-REVIEW-617-r2
|
||||
|
||||
- Issue: [#617 «Загрузка плана > ~3 МиБ обрывает WebSocket без сообщения»](https://github.com/Matysh/houseplan-card/issues/617)
|
||||
- ТЗ: тело issue #617, раздел `## ТЗ` (файла в `docs/specs/` нет — решение #517)
|
||||
- Спек-ревью: `SPEC-REVIEW-617-r1.md`, зелёный, High 0 / Medium 0
|
||||
- Код-ревью r1: `CODE-REVIEW-617-r1.md`, зелёный, High 0 / Medium 0, все 8 AC доказаны
|
||||
- Ревью-SHA этого раунда: `43b52826e4259bf7be04d9dea07c9f36b3127221` (сверен
|
||||
`git rev-parse HEAD` перед выводом вердикта), дерево `06503abc6ca4b8664d7e1aef1a37291452bb6411`
|
||||
- База диапазона: `origin/dev` = `f8e089bdf2bca59340eea0395b159454e319f8d7`
|
||||
- Заход: **r2** · блокирующих циклов израсходовано **0 из 2** (лёгкий трек, `small`)
|
||||
- Материал: `git log --oneline origin/dev..HEAD` — 4 коммита: `857369b1` (fix,
|
||||
класс A/B, `User-Visible: yes`), `3fafd9f2` (test, класс B, `User-Visible: no`),
|
||||
`9f3511f2` (docs: публикация `CODE-REVIEW-617-r1.md`), `43b52826` (build:
|
||||
ребейз, `User-Visible: no`)
|
||||
|
||||
## Почему это r2, а не продолжение зелёного r1
|
||||
|
||||
Код-ревью r1 (SHA `e5305cff67d7…`) было зелёным и не должно было открывать
|
||||
новый цикл (§4). Слияние отказало на конфликте с ушедшим вперёд `dev`
|
||||
(issue-комментарии от `2026-09-24T…`): «Код-ревью зелёное — вердикт выше в
|
||||
силе, переделывать работу не нужно. Не удалось только слияние». Задача
|
||||
вернулась автору не на правку кода, а на ребейз; после ребейза «это другой
|
||||
код, и принимать его без проверки нельзя» (§2.10) — отсюда новый заход
|
||||
код-ревью, номер r2, бюджет считается по этапу отдельно от ревью ТЗ.
|
||||
|
||||
## Важная процедурная находка (унаследована из r1, не блокирует)
|
||||
|
||||
r1 уже фиксировал, что тело issue менялось после зелёного спек-ревью
|
||||
(хеш `f8d7f51e…` → `696d986c…`). Проверил, не изменилось ли тело ещё раз
|
||||
между код-ревью r1 и этим раундом:
|
||||
|
||||
```
|
||||
sha256(gh issue view 617 --json body -q '.body') = d67ce50bd2746fd0b060f6a11f6917247944aa06e5d21a848bee797833f74c34 (27143 байта)
|
||||
sha256(первые 27142 байта того же текста) = 696d986cca3720a468ba776055d544cececd4713062b4c5e5b6e2e44ced87092 (совпадает с r1)
|
||||
```
|
||||
|
||||
Разница — ровно один добавленный завершающий байт (`\n`) после уже
|
||||
финального `\n`. Содержательного изменения ТЗ нет: AC1–AC8 и весь текст,
|
||||
который проверял r1, идентичны байт-в-байт. Не завожу это отдельной
|
||||
находкой второй раз — тот же вывод, что и в r1: реализация соответствует
|
||||
финальному тексту ТЗ.
|
||||
|
||||
## Дельта r1 → r2: ребейз, не правка
|
||||
|
||||
По инструкции разбор остаётся полным, если дельта — «ребейз на ушедший
|
||||
вперёд dev» (именно этот случай). Ниже — как я убедился, что дельта не
|
||||
меняет смысл, а не принял слово автора хендоффа.
|
||||
|
||||
**1. Коммиты `857369b1`/`3fafd9f2` — тот же патч, что и в r1, просто с новым
|
||||
родителем.** Сравнил список файлов и текст коммит-сообщений с r1
|
||||
(`CODE-REVIEW-617-r1.md`, коммиты `f2c9321a`/`e5305cff`): дословно те же
|
||||
файлы (`http_api.py`, `plans.py`, `websocket_api.py`, `backdrop-pick.ts`,
|
||||
оба runtime, i18n×4, тесты, смоки), то же описание правки multipart-теста
|
||||
(«теперь случай "multipart без части file" задаётся явно… тело без
|
||||
multipart… ждёт `bad_request`»). Хеши коммитов другие — ожидаемо при
|
||||
ребейзе.
|
||||
|
||||
**2. Криптографическая проверка неизменности продуктового кода.** Автор
|
||||
хендоффа (`2026-09-24T17:13:11Z`) назвал дерево `06503abc6ca4…` и блобы
|
||||
пяти ключевых файлов. Я не поверил на слово — пересчитал сам:
|
||||
|
||||
| Файл | Блоб на `HEAD` | Заявлено в хендоффе |
|
||||
|---|---|---|
|
||||
| `src/backdrop-pick.ts` | `c36f98fa60a7…` | совпадает |
|
||||
| `src/houseplan-onboarding-runtime.ts` | `18d7a4aa3279…` | совпадает |
|
||||
| `src/houseplan-editor-runtime.ts` | `99d6ca83e41f…` | совпадает |
|
||||
| `custom_components/houseplan/http_api.py` | `a5bc56080b60…` | совпадает |
|
||||
| `custom_components/houseplan/plans.py` | `7d17d5d17b0f…` | совпадает |
|
||||
|
||||
`git log --format=%T -1 HEAD` = `06503abc6ca4…` — дерево тоже совпадает.
|
||||
Это не признание автора, это математический факт: если бы код отличался,
|
||||
хеш блоба был бы другим.
|
||||
|
||||
**3. Полный список файлов, изменённых во всём диапазоне
|
||||
`origin/dev...HEAD` вне `dist/**`/`houseplan-assets/**` (сборка),
|
||||
совпадает построчно со списком r1** (`git diff origin/dev...HEAD --stat`
|
||||
по `src/**`, `custom_components/**`, `i18n/**`, `test/**`,
|
||||
`tests_backend/**`, `docs/**`, `scripts/**`, `demo/**`) — 66 файлов, те же
|
||||
имена и те же количества изменённых строк (`http_api.py` +98, `plans.py`
|
||||
+60, `websocket_api.py` +41, `backdrop-pick.ts` +151/−… и т.д.), плюс два
|
||||
файла, которых в r1 не было: `docs/reviews/CODE-REVIEW-617-r1.md` (публикация
|
||||
r1) и `docs/reviews/INDEX.md` (регенерация индекса). Никаких новых
|
||||
продуктовых файлов, никаких «случайно» изменённых соседних строк.
|
||||
|
||||
**4. Коммит `43b52826` сам по себе — только сгенерированное.**
|
||||
`git show 43b52826 --stat --name-only`, за вычетом `dist/**` и
|
||||
`custom_components/houseplan/frontend/houseplan-assets/**` — единственный
|
||||
файл `scripts/monolith-baseline.json`. Никаких `.py`/`.ts` там нет, конфликт
|
||||
не трогал логику.
|
||||
|
||||
**5. Проверил, что `dev` действительно продвинулся не только на #642/#627,
|
||||
как говорит коммит-сообщение, а шире** —
|
||||
`git log --oneline c8f9b5d3…(база r1)..origin/dev`: помимо #642
|
||||
(refactor: вынос диалога «Оптимизировать планы» — это диалог **геометрической**
|
||||
оптимизации плана редактора: `preflightDiagnostics`, coincident-partition,
|
||||
near-axis — не имеет отношения к загрузке ФАЙЛА плана) и #627 (ленивые
|
||||
i18n-чанки `settings/support/topology` — другие namespace, не
|
||||
`toast.plan_too_large`/`backdrop.over_limit_body`), там же #623/#620/#631/#632/#643 —
|
||||
все CI/процесс/тест-инфраструктура (`scripts/task-packet.mjs`,
|
||||
`.github/workflows/*`, новые файлы `test/dialog-baseline.test.mjs`,
|
||||
`test/dialog-form-problems.test.mjs`, `scripts/rebase-generated.mjs`). Ни
|
||||
один не касается `src/backdrop-pick.ts`, `houseplan-editor-runtime.ts` в
|
||||
части плана, `http_api.py`, `plans.py`, `websocket_api.py` или
|
||||
`src/i18n/{en,ru,de,fr}.json`. Отсюда и бесконфликтный автомёрж, о котором
|
||||
сообщает хендофф, — не совпадение, а отсутствие пересечения зон правки.
|
||||
|
||||
**Вывод:** дельта r1→r2 не меняет ни одной строки логики, которую проверял
|
||||
r1. Она меняет только сборку (новые хеши чанков, дерево `bundleBytes`
|
||||
+1 698, `hostRefs` 4 869→4 872 — тот же относительный +3, что был принят на
|
||||
r1, только на новой абсолютной базе `dev`). Дальше в этом документе я
|
||||
заново читаю код и таблицу AC своими глазами (не копирую r1 без проверки),
|
||||
но не переоткрываю то, что уже математически доказано неизменным.
|
||||
|
||||
## Закрытие раунда r1
|
||||
|
||||
r1 не оставил находок High/Medium — закрывать нечего. Единственный пункт r1
|
||||
(процедурная заметка о более раннем расхождении хеша тела issue) не был
|
||||
находкой кода и не требовал действия; см. раздел выше — актуальность
|
||||
подтверждена повторно на этом SHA.
|
||||
|
||||
| Из r1 | Статус на r2 |
|
||||
|---|---|
|
||||
| High/Medium в скоупе | нет (0/0 в r1) |
|
||||
| Low в скоупе | нет |
|
||||
| Процедурная заметка (хеш тела issue) | переподтверждена: текущий хеш = хешу r1 + 1 байт перевода строки, содержимого не меняет |
|
||||
|
||||
## Унаследовано из r1 (без повторного личного прогона в этом раунде)
|
||||
|
||||
Продуктовый код байт-в-байт идентичен (раздел выше), поэтому следующие
|
||||
результаты r1 переносятся как валидные для `43b52826`, а не перепрогонялись
|
||||
мной лично в этом раунде — но каждый из них независимо ПОДТВЕРЖДЁН зелёным
|
||||
прогоном CI на самом SHA `43b52826` (см. таблицу гейтов ниже), а не принят
|
||||
только на слово r1:
|
||||
|
||||
- Личный прогон 5 мутантов `plan-upload-*` (r1, `CODE-REVIEW-617-r1.md`,
|
||||
таблица гейтов) — все «поймано 1/1». На `43b52826` их прогнал шардированный
|
||||
`mutation-gate.mjs --changed` в CI (см. ниже) и независимо ещё раз лично
|
||||
автор хендоффа.
|
||||
- Личный прогон `smoke_plan_upload_limit/reject/race`, `smoke_backdrop_guard`,
|
||||
`smoke_decor_images` (r1) — код, который они проверяют, не менялся;
|
||||
`smoke_backdrop_guard`/`smoke_plan_upload_limit` дополнительно
|
||||
переисполнены CI как «чистый гвард» перед каждой мутацией (см. §«Как
|
||||
проверялось», пункт про `runCleanGuards`).
|
||||
- Разбор HA-веток чтением (`http_api.py:388-436`, AC4) — файл не менялся,
|
||||
разбор остаётся в силе.
|
||||
- «Одно число» (AC6), общий writer (AC7), общий хелпер (AC8) — код-путь не
|
||||
менялся, вывод r1 остаётся в силе; перечитал сам (см. ниже) и подтверждаю.
|
||||
|
||||
## Как проверялось в этом раунде
|
||||
|
||||
Прочитано: `docs/SCOPE.md` (J4/J6, лок-инвариант — не задет),
|
||||
`docs/process/REVIEWER.md`, `AGENTS.md`, тело issue #617 целиком (комментарии
|
||||
включая оба хендоффа ребейза и решение о возврате в `S6`), `CODE-REVIEW-617-r1.md`,
|
||||
`SPEC-REVIEW-617-r1.md`, `docs/USER-GUIDE.ru.md` (термины «План», «8 МБ» не
|
||||
изменились).
|
||||
|
||||
Лично перечитан код (не только сверка хешей из раздела «Дельта»):
|
||||
- `custom_components/houseplan/http_api.py:372-448` (`HouseplanPlanUploadView`
|
||||
целиком — авторизация, `Content-Length` preflight, разбор multipart,
|
||||
порядок проверок, `store_plan_upload` под `upload_lock`, коды ответов) —
|
||||
совпадает с описанием AC4 в ТЗ и с r1.
|
||||
- `src/houseplan-editor-runtime.ts:8087-8246` (`_saveSpaceDialog` целиком,
|
||||
включая `catch`) — подтверждено лично: `uploadPlanFile` вызывается ДО
|
||||
правки `cfg`/`sp`, `catch` НЕ обнуляет `this.host._spaceDialog` (диалог
|
||||
остаётся открытым) и не вызывает `_saveConfigNow`/`config/set` повторно —
|
||||
ровно то, что требует AC5.
|
||||
- `src/houseplan-editor-runtime.ts:221,7948,8110` — импорт и оба вызова
|
||||
`stagePlanFile`/`uploadPlanFile` из `backdrop-pick.ts` присутствуют.
|
||||
- `scripts/mutation-registry.mjs:3512-3570` — все 5 записей `plan-upload-*`
|
||||
на месте, их `find`-паттерны синтаксически совпадают с текущим
|
||||
`backdrop-pick.ts`/`plans.py` (иначе `applyPatches` не нашёл бы совпадение
|
||||
и CI-шард упал бы с ошибкой подготовки, а не «поймано» — этого не
|
||||
случилось, все 6 шардов зелёные).
|
||||
- `git grep '<<<<<<<\|=======\|>>>>>>>'` по `src/**`/`custom_components/**` —
|
||||
ложных срабатываний нет (только декоративные `// =====` разделители
|
||||
секций), настоящих следов незакрытого конфликта нет.
|
||||
|
||||
### Гейты
|
||||
|
||||
| Гейт | Результат | Как |
|
||||
|---|---|---|
|
||||
| Validate CI на `43b52826` (общий статус) | **success** | [run 36032869059](https://github.com/Matysh/houseplan-card/actions/runs/36032869059), назван во вводной к ревью |
|
||||
| `npx tsc --noEmit`, `npm test`, `npm run build` + сверка копий бандла | ok | job «Фронтенд: типы, юниты, мутанты, синхрон бандла» в 36032869059, зелёный — не перегонял лично, дешёвые гейты приняты по инструкции |
|
||||
| `node scripts/check-docs.mjs` | ok | job «Предполёт: документация, провенанс, процесс», зелёный |
|
||||
| `npm run lint:unused` (связность монолита) | ok | тот же job «Фронтенд…»; числа монолита сошлись с новой базой `dev` |
|
||||
| `node scripts/no-new-any.mjs` | ok | тот же job |
|
||||
| `npm run bundle:budget` | ok (предупреждение о запасе 11 508 < 15 000 — известный несвязанный долг #367/#474, было и до ребейза) | тот же job |
|
||||
| `node scripts/mutation-gate.mjs --changed=<base>..HEAD` (диффовые мутанты, 6 шардов) | **ok, 6/6 зелёные** | jobs «Мутанты по диффу (1…6/6)» в 36032869059; каждый шард сначала гоняет `runCleanGuards` — чистый прогон гварда на пересобранном дереве ДО мутации, затем патчит и требует красного — это и есть личный (не по заявлению автора) прогон гвардов `smoke_plan_upload_limit.mjs`, юнита `plan-upload-limit.test.mjs`, `pytest tests_backend/test_plan_upload.py` на этом SHA, устроенный самим CI, а не мной вручную |
|
||||
| `python -m pytest` в HA-харнессе | ok | job «Бэкенд: pytest в Home Assistant», зелёный |
|
||||
| Смоки полного набора / golden / perf-смок / геометрия TS↔Python | **не гонялись в этом Validate-прогоне** (jobs показывают `-`/0s) | по дизайну: полный набор смоков/golden/perf в Validate условен на входе `heavy` (флаг «полный набор» у `workflow_dispatch`, см. `.github/workflows/validate.yml:817-822`), в этом прогоне не запрошен — это стандартное поведение лёгкого Validate, не пропуск с моей стороны |
|
||||
| `node scripts/smoke-select.mjs --base origin/dev --head HEAD` | 46 прямых совпадений, все 46 прогнаны | не мной лично в этом раунде — приложено к хендоффу автора (`2026-09-24T17:13:11Z`), результат `exit 0`; полагаюсь на него, потому что код, который эти смоки проверяют, доказанно (раздел «Дельта») идентичен коду, на котором те же смоки прогнал лично r1 (`smoke_plan_upload_limit/reject/race`, `smoke_backdrop_guard`) — не слепое доверие, а перенос уже проверенного результата на доказанно тот же код |
|
||||
| `node scripts/mutation-gate.mjs --id=plan-upload-*` (5 мутантов поимённо) | ok, 5/5 поймано | автор хендоффа лично; независимо продублировано CI-шардами (диффовый прогон тех же ID, см. выше) |
|
||||
| `npm run invariants` | не применимо | геометрия не менялась ни в одном коммите диапазона |
|
||||
| performance-профили | не применимо | AC их не называет |
|
||||
|
||||
Я не перегонял тяжёлые гейты (полный `npm test`, полный HA pytest, полный
|
||||
мутация-реестр, полный смок-набор, golden) лично на своей машине —
|
||||
принимаю их по зелёному CI на этом самом SHA, что и предписывает вводная
|
||||
инструкция («Дешёвые гейты на этом SHA уже подтверждены»). Дополнительно (и
|
||||
это не предписано, а моя личная проверка) я убедился, что диффовые
|
||||
мутация-шарды CI реально включали гварды этой задачи: гварды `plan-upload-*`
|
||||
— это ровно `smoke_plan_upload_limit.mjs`, юнит-тест и `pytest
|
||||
test_plan_upload.py`, а `runCleanGuards` в `scripts/mutation-execution.mjs:202`
|
||||
гоняет каждый такой гвард на пересобранном чистом дереве ДО мутации и
|
||||
проваливает гейт (`return 2`), если гвард не зелёный — то есть зелёные 6/6
|
||||
шардов математически means эти три гварда прошли на `43b52826`, а не только
|
||||
на дереве r1.
|
||||
|
||||
## Разбор критериев приёмки (текущий текст ТЗ, идентичен тексту, проверенному r1)
|
||||
|
||||
| AC | Разбор на этом SHA | Вердикт |
|
||||
|---|---|---|
|
||||
| AC1 (5 МиБ → один POST, `plan_url` из ответа, соединение живо) | Код идентичен r1 (раздел «Дельта», блобы совпали). `smoke_plan_upload_limit.mjs`/юнит — тот же гвард, зелёный на этом дереве и как «чистый» перед каждой из 6 диффовых мутаций CI. | **Доказан** (перенос доказательства r1 на доказанно идентичный код) |
|
||||
| AC2 (SVG `MAX+1` → тост, без запросов) | `src/backdrop-pick.ts` идентичен блобом r1; мутант `plan-upload-client-limit` красный — подтверждено CI-шардом (`runCleanGuards` + мутация). | **Доказан, защитный AC подтверждён мутацией на этом SHA** |
|
||||
| AC3 (растр `MAX+1` → диалог без «Оставить оригинал», уменьшенная копия `>` предела → тост) | Тот же файл, те же строки (`renderBackdropGuard` вызов с `size <= MAX_PLAN_BYTES`). Мутанты `plan-upload-guard-original`, `plan-upload-reduced-over-limit-staged` — красные на CI. | **Доказан, обе ветки подтверждены мутацией на этом SHA** |
|
||||
| AC4 (сервер: граница включительная, коды ответов) | Лично перечитал `http_api.py:372-448` на `43b52826` — порядок проверок, коды и `507`/`413`/`400×3` совпадают с ТЗ построчно. Мутант `plan-upload-server-bound` красный на CI; HA-специфичные ветки (403/`may_write`, реальный multipart) — «проверено чтением, не исполнением» + зелёный `pytest в Home Assistant` job на этом SHA. | **Доказан** (чтением для HA-веток, мутацией+CI для границы) |
|
||||
| AC5 (413 → текст с пределом, диалог открыт, `config/set` не отправлялся) | Лично перечитал `_saveSpaceDialog`/`catch` (`houseplan-editor-runtime.ts:8087-8246`) на `43b52826`: `uploadPlanFile` до правки конфига, `catch` не закрывает диалог и не вызывает сохранение повторно. Мутант `plan-upload-413-text-dropped` красный на CI. | **Доказан, подтверждён и личным чтением, и мутацией на этом SHA** |
|
||||
| AC6 (одно число TS/Python/оба USER-GUIDE) | Файлы-источники (`validation.py`, `docs/USER-GUIDE*.md`) вне диапазона правок #617 в этом ребейзе, не менялись; юнит-тест, сверяющий все 4 источника, зелёный (CI). | **Доказан** |
|
||||
| AC7 (WS не меняется, общий writer) | `websocket_api.py` идентичен блобом r1; `ws_plan_set` по-прежнему вызывает `store_plan_upload` без собственного `atomic_write`. | **Доказан** |
|
||||
| AC8 (оба рантайма — один хелпер) | Лично перепроверил оба места вызова (`houseplan-editor-runtime.ts:7948/8110`, импорт `:221`) — идентичны r1; `houseplan-onboarding-runtime.ts` не менялся (блоб совпал). | **Доказан** |
|
||||
|
||||
## Проверено чтением и корректно (без отдельного личного прогона)
|
||||
|
||||
- Единая авторизация (`may_write`) и единый набор `PLAN_EXTENSIONS` — файлы
|
||||
не менялись со времён r1, разбор r1 остаётся в силе.
|
||||
- Копия-при-записи и отказ по квоте без следов — тот же код, тесты
|
||||
`test_issue_617_store_plan_upload_is_copy_on_write` и
|
||||
`..._quota_refusal_leaves_nothing` зелёные в CI (job «Бэкенд: pytest в Home
|
||||
Assistant»).
|
||||
- Декор не задет: единственный вызов `renderBackdropGuard` из декор-пути не
|
||||
передаёт `planLimitBytes` — код не менялся; `smoke_decor_images.mjs`
|
||||
проверял это лично r1, код идентичен.
|
||||
- i18n: 4 языка, 2 новых ключа — файлы `src/i18n/*.json` не входят в diff
|
||||
#627 (там другие namespace-файлы `settings/support/topology`), блобы не
|
||||
менялись со времён r1.
|
||||
- Трейлеры: `857369b1` — `Issue: #617`, `User-Visible: yes`, оба changelog в
|
||||
том же коммите (не изменилось); `3fafd9f2` — `User-Visible: no` (тест-онли);
|
||||
`43b52826` — `Issue: #617`, `User-Visible: no` (только сборка/база
|
||||
монолита, ни одной пользовательской строки не добавлено — корректная
|
||||
разметка); `9f3511f2` — `User-Visible: no` (публикация ревью-документа,
|
||||
тоже корректно).
|
||||
- «Одно число — один источник» (§8): дельта ребейза не вводит второго места
|
||||
с числом «8» или «8388608» — единственная правка чисел в этом раунде это
|
||||
`monolith-baseline.json` (техническая метрика связности, не
|
||||
пользовательское число) и `bundle-budget`-замеры, оба объяснены в
|
||||
commit-message и в полосе допуска.
|
||||
- `git rev-parse HEAD` = `43b52826e4259bf7be04d9dea07c9f36b3127221`, сверено
|
||||
перед выводом вердикта; ветки/чекауты на другой SHA не делал (только
|
||||
`git fetch origin dev`, что не двигает рабочую копию).
|
||||
|
||||
## Чего не проверял
|
||||
|
||||
- Полный `npm test`, полный HA pytest (`test_ha_*.py`), полный
|
||||
мутация-реестр, полный набор смоков/golden/perf — не гонял лично; приняты
|
||||
по зелёному Validate/CI на этом же SHA `43b52826` (`run 36032869059`).
|
||||
Полные наборы — предрелизный гейт, не гейт ревью (§8).
|
||||
- `node scripts/smoke-select.mjs --base origin/dev --head HEAD` — не гонял
|
||||
сам; использую результат из хендоффа автора (46 прямых совпадений, все
|
||||
прогнаны, `exit 0`), потому что независимо доказал (раздел «Дельта»), что
|
||||
проверяемый этими смоками код на `43b52826` идентичен коду, на котором
|
||||
r1 те же смоки уже прогнал лично.
|
||||
- Ручное тестирование в браузере — ручного тестирования в цикле нет
|
||||
(инструкция); эквивалент — прогнанные CI и указанные выше личные прогоны
|
||||
гвардов через диффовые мутация-шарды.
|
||||
- `npm run invariants`, performance-профили — не применимо, геометрия и
|
||||
перф не задеты ни одним коммитом диапазона (как и в r1).
|
||||
- Не проверял вживую реальный внешний прокси перед HA (413 без тела) —
|
||||
как и r1, только юнит-симуляцией; в этом раунде код `_pickPlanFile`/
|
||||
`uploadPlanFile` не менялся, разбор r1 остаётся в силе.
|
||||
- Не проверял содержимое коммита `9f3511f2` (публикация `CODE-REVIEW-617-r1.md`
|
||||
в `docs/reviews/`) на предмет полноты — это конвейерный шаг публикации
|
||||
предыдущего вердикта, не продуктовый код и не предмет этого код-ревью.
|
||||
|
||||
## Находки
|
||||
|
||||
Нет находок High или Medium ни в скоупе, ни вне скоупа. Процедурная заметка
|
||||
о хеше тела issue унаследована из r1 и переподтверждена (см. выше) — не
|
||||
дефект кода, не открывает цикл.
|
||||
|
||||
## Вердикт
|
||||
|
||||
Дельта r1→r2 — исключительно технический ребейз: криптографически (сверка
|
||||
дерева и блобов пяти ключевых файлов) и построчно (список изменённых файлов
|
||||
всего диапазона) подтверждено, что продуктовый код, тесты, i18n и AC-текст
|
||||
не изменились ни на байт с момента зелёного `CODE-REVIEW-617-r1.md`.
|
||||
Коммиты `dev`, вошедшие при ребейзе (#642 — геометрический диалог
|
||||
«Оптимизировать планы», #627 — ленивые i18n-чанки другого namespace,
|
||||
#623/#620/#631/#632/#643 — CI/процесс/тест-инфраструктура), не пересекаются
|
||||
ни с одним файлом, который трогает #617 — этим объясняется бесконфликтный
|
||||
автомёрж. Единственное реальное изменение раунда — пересборка бандла и
|
||||
обновление базы монолита, оба в допустимой полосе и с трейлером
|
||||
`User-Visible: no`, что верно.
|
||||
|
||||
Все 8 AC остаются доказанными: пять защитных AC (AC2, AC3×2, AC4, AC5)
|
||||
подтверждены не заявлением автора, а зелёными диффовыми мутация-шардами CI
|
||||
на этом самом SHA (`runCleanGuards` гоняет гвард на чистом дереве ДО
|
||||
мутации, затем требует красного после — оба факта видел в зелёном логе
|
||||
CI), плюс личным чтением ключевых мест (`http_api.py`, `_saveSpaceDialog`)
|
||||
на `43b52826`, а не по памяти о r1. Трейлеры и changelog в порядке, «одно
|
||||
число — один источник» не нарушено.
|
||||
|
||||
**Вердикт: зелёный · заход r2 · блокирующих циклов 0/2 · High: 0 · Medium: 0**
|
||||
|
||||
---
|
||||
|
||||
<!-- material-anchors: сгенерировано конвейером (#414) -->
|
||||
|
||||
## Материал раунда
|
||||
|
||||
- Ветка: `issue/617-plan-http-upload`, коммит `43b52826e425` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
|
||||
- Дерево материала: `06503abc6ca4b8664d7e1aef1a37291452bb6411`
|
||||
```
|
||||
git log --all --format='%H %T' | grep 06503abc6ca4
|
||||
```
|
||||
- Тело issue: `6682a2131de842acea0a178f21d254b2d3c0fb88309a244451362a5bb4475514`
|
||||
- Вердикт конвейера: `green` · High 0
|
||||
@@ -1,6 +1,6 @@
|
||||
# Индекс ревью
|
||||
|
||||
Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 1034, issue: 365. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`.
|
||||
Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 1035, issue: 365. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`.
|
||||
|
||||
| Issue | Документ | Этап · раунд | Вердикт | H | M | Находки | Файлы |
|
||||
|---|---|---|---|---:|---:|---|---|
|
||||
@@ -49,6 +49,7 @@
|
||||
| #618 | [SPEC-REVIEW-618-r1.md](SPEC-REVIEW-618-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | нотация h<ref> в B5 не встречается в коде | `docs/FILTERING.md` |
|
||||
| #617 | [SPEC-REVIEW-617-r1.md](SPEC-REVIEW-617-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | «новый необязательный параметр» уже существует | `src/backdrop-pick.ts` `houseplan-editor-runtime.ts` |
|
||||
| #617 | [CODE-REVIEW-617-r1.md](CODE-REVIEW-617-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — |
|
||||
| #617 | [CODE-REVIEW-617-r2.md](CODE-REVIEW-617-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — |
|
||||
| #615 | [SPEC-REVIEW-615-r1.md](SPEC-REVIEW-615-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | AC3 называет несуществующую защиту от расползания на плашки цвета | `smoke_room_settings_form.mjs` `smoke_space_settings_form.mjs` `smoke_device_settings_form.mjs` `smoke_dialog_polish_605.mjs` `smoke_general_settings_form.mjs` |
|
||||
| #615 | [SPEC-REVIEW-615-r2.md](SPEC-REVIEW-615-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — |
|
||||
| #614 | [SPEC-REVIEW-614-r1.md](SPEC-REVIEW-614-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — |
|
||||
|
||||
Reference in New Issue
Block a user