diff --git a/docs/reviews/SPEC-REVIEW-333-r2.md b/docs/reviews/SPEC-REVIEW-333-r2.md new file mode 100644 index 00000000..050b5162 --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-333-r2.md @@ -0,0 +1,73 @@ +# SPEC-REVIEW-333-r2 + +Issue: [#333](https://github.com/Matysh/houseplan-card/issues/333) — «Ограничения стыков (#329): optimize и import пишут конфиг мимо валидатора — решить судьбу лазейки и мёртвого except» +Трек: `small` (ТЗ в теле issue, ревью — комментарий; лимит циклов ревью ТЗ — 2) +Заход: r2 · блокирующих циклов израсходовано 1 из 2 (r1 был жёлтым и потратил цикл; зелёный вердикт бюджет не тратит, #227) +Материал: тело issue #333 (ревизия 2 ТЗ) на момент ревью; `dev` на SHA `ff6e53a4` (тот же продуктовый код, что видел r1 на `59ae6b10` — единственный коммит между ними, `59ae6b10..ff6e53a4`, это публикация документа `SPEC-REVIEW-333-r1.md`, класс C, продуктового кода не задевает). + +## Предыдущий раунд + +Вердикт r1: **жёлтый** · High: 0 · Medium: 1 (в скоупе) → `docs/reviews/SPEC-REVIEW-333-r1.md`, получен на теле issue (ревизия 1 ТЗ) при `dev` на SHA `59ae6b10`. + +## Дельта r1 → r2 + +Единственное изменение — правка тела issue, помеченная автором «Ревизия 2»: пункт AC4. + +Было (ревизия 1, процитировано в r1-M1): +> AC4. Докстринг и спека #329 §5 описывают реальный периметр; `check-docs` зелёный. + +Стало (ревизия 2, текущее тело issue): +> AC4. Докстринг и спека #329 §5 описывают реальный периметр — доказательство: чтение изменённого докстринга и §5 на код-ревью (spec-ревью r1-M1: `check-docs` эти файлы не читает и зелен независимо от честности текста). Ревизия 2. + +Плюс подтверждающий комментарий автора (`IC_kwDOTOcLQM8AAAABRMZ_Rw`, 2026-08-28T05:29:39Z): «Ревизия 2 ТЗ (в теле issue): r1-M1 закрыт — способ доказательства AC4 заменён с `check-docs`… на явное чтение изменённого текста на код-ревью. Возвращаю S4.» + +Больше ничего в теле issue не менялось: контракт (п.1–3), AC1–AC3, мутант-тест, раздел «Откат» текстуально идентичны ревизии 1, сверено построчно с телом issue, зафиксированным в r1-документе (раздел «Скоуп»/цитаты внутри M1). + +Дельта локальна: правка одной строки формулировки критерия приёмки, не меняет контракт поведения, не задевает новую подсистему, не является ребейзом. Основание для сокращённого разбора по §2.10 есть. + +## Разбор дельты + +M1 требовал заменить способ доказательства AC4 (был: `check-docs`, который не читает ни докстринг `junction_limits.py`, ни `docs/specs/329-junction-limits.md` и был бы зелёным независимо от честности текста) на явную запись «код-ревью: чтение изменённого текста». + +Новая формулировка AC4 делает ровно это: способ доказательства — «чтение изменённого докстринга и §5 на код-ревью», без ссылки на `check-docs` как на доказательство пункта. Формулировка соответствует рекомендации r1 почти дословно (автор дополнительно вписал ссылку на находку `r1-M1` — это не меняет содержания критерия, просто прослеживаемость). + +Проверено, что правка не создаёт новых проблем: +- AC4 остаётся проверяемым: код-ревью должно будет прочитать финальный текст докстринга `junction_limits.py:3–5` и §5 `docs/specs/329-junction-limits.md` и убедиться, что оба говорят «гейт покрывает config/set и optimize; import сознательно вне» — однозначный, не оценочный критерий; +- формулировка не тянет за собой ложного ощущения автоматической проверки — прежний риск (гейт зелёный, а текст лживый) снят именно тем, что доказательство теперь явно ручное, а не гейтовое; +- `check-docs` из общего списка гейтов реализации не исчез (он по-прежнему обязателен как гейт §8 при правках `src/**`, если таковые случатся) — снята только его роль доказательства AC4, что и было предметом находки. + +Других AC дельта не задевает: AC1–AC3, контракт, мутант-тест и «Откат» текстуально не менялись, их доказательство не пересматривается в этом раунде. + +## Закрытие раунда r1 + +| Находка | Чем закрыта | Где это видно | +|---|---|---| +| M1 (Medium, в скоупе): AC4 предъявлял `check-docs` как доказательство текстовой правки, которую этот гейт не читает | Способ доказательства AC4 заменён на «код-ревью: чтение изменённого докстринга и §5» | Тело issue #333, пункт AC4 (ревизия 2, цитата выше) + комментарий автора `IC_kwDOTOcLQM8AAAABRMZ_Rw` | + +## Унаследовано из r1 + +Без повторной проверки в этом раунде, со ссылкой на `docs/reviews/SPEC-REVIEW-333-r1.md` (материал: `dev` на SHA `59ae6b10`, продуктовый код с тех пор не менялся): + +- **Скоуп и соответствие SCOPE.md** — задача закрывает дыру в контракте целостности геометрии (класс инвариантов П1–П4 из #329), держит план «честным» при эволюции (J6), продуктовых вопросов владельцу не требует (решение уже процитировано в теле issue). +- **Техническая точность контракта** — вызов `validate_junction_limits` в `ws_plan_optimize` после миграции кандидата (позиция вставки в `_validate_optimize_cpu`, websocket_api.py:1691–1698), сохранение наследования по правилу, симметрия rev-кэша `rt.junction_baseline` с `ws_config_set` (websocket_api.py:1396) — всё сверено с кодом на `dev`. +- **Доказуемость AC1–AC3** — `test_ha_websocket.py` существует и подходит для новых HA-тестов; AC10 #329 (`test/junction-limits.test.mjs`) корректно не подменяет AC2, так как проверяет только TS-алгоритм `optimizePlans`, а не WS-обвязку. +- **Непротиворечивость правки докстринга/спеки** — §5 спеки #329 сейчас утверждает «Оптимизация планов проверку не проходит», после задачи это станет буквально неверным, контракт это явно предусматривает; §3 спеки #329 правки не требует. +- **Откат** — чистый revert одного коммита, WS-контракт и формат данных не меняются, код ошибки уже объявлен. +- **Соответствие малому треку** — одна поверхность, без миграции, без нового UX-контракта, влияние на перф названо (~40 мс тёплых поверх executor-пути #330) и не перепроверялось эмпирически (не факт этого ревью, а заявление S2-аналитики). +- Незаблокирующее наблюдение r1: optimize не обязан *читать* `rt.junction_baseline` перед своим собственным вызовом валидатора для полной симметрии с #330 §4.2 — контракт и AC3 требуют только записи кэша после успешного optimize, этого достаточно для обещанного AC3; не заведено отдельным пунктом, дельта его не касается. + +## Гейты + +Стадия — ревью ТЗ (`S4-spec-review`), кода ещё нет, кодовый diff между r1 и r2 отсутствует (единственный коммит `59ae6b10..ff6e53a4` — публикация r1-документа, класс C). `typecheck`/`test`/`build`/`check-docs`/инварианты модели/смоки — гейты код-ревью и реализации, к этому этапу не относятся; они будут прогнаны на код-ревью реального диффа. Это решение по стадии, не пропуск — так же было отмечено в r1. + +## Чего не проверял + +- Финальную формулировку текста докстринга и §5 спеки #329 — они ещё не написаны (это код-ревью, ровно то, что теперь явно требует AC4). +- Производительность эмпирически — не перепроверялась ни в r1, ни в этом раунде; дельта её не касается. +- Вопрос о чтении `rt.junction_baseline` изнутри optimize — не заводился в r1 как блокирующий, дельта его не затрагивает, повторно не поднимаю. + +## Вердикт + +Единственная Medium-находка r1 (AC4) закрыта правкой, соответствующей рекомендации ревью, без побочных проблем. Новых находок в дельте нет. High нет, Medium нет. + +**Вердикт: зелёный · заход r2 · блокирующих циклов 1/2 · High: 0 · Medium: 0 → в задаче**