mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-30 19:58:50 +00:00
+163
-174
@@ -1,208 +1,197 @@
|
||||
# SPEC-REVIEW-369-r1
|
||||
# SPEC-REVIEW-369-r2
|
||||
|
||||
- Issue: https://github.com/Matysh/houseplan-card/issues/369
|
||||
- Этап: ТЗ на ревью (PROCESS.md §2.4), полный трек (владелец назвал критерий
|
||||
«одна поверхность» §5 как не выполненный — семь несвязанных поверхностей)
|
||||
- Артефакт: `docs/specs/369-audit-lows.md`
|
||||
- Материал ревью: SHA `cbf9318e` (`docs: specify #369 audit-lows batch`,
|
||||
только этот файл, 117 строк, `User-Visible: no` — корректно для docs-коммита)
|
||||
- Заход: r1 · блокирующих циклов израсходовано 0 из 4 (лимит для полного трека — 4)
|
||||
- Материал ревью: дельта `cbf9318e..c50d9e42` («ревизия 2» документа,
|
||||
`docs: #369 spec revision 2 per SPEC-REVIEW-369-r1`) — тот же единственный
|
||||
файл, 3 хунка (+11/-7 строк), `User-Visible: no`, корректно для docs-коммита
|
||||
- Заход: **r2** · блокирующих циклов израсходовано **1 из 4** (лимит для
|
||||
полного трека — 4)
|
||||
|
||||
## Скоуп
|
||||
## Несовпадение номера раунда в заголовке задачи — зафиксировано, не находка по ТЗ
|
||||
|
||||
Семь независимых Low-находок из аудита beta.2/beta.3 (а–ж): документирование
|
||||
поведения purge пылесоса, консольный warn при отбраковке NaN-точки трейла,
|
||||
нормализация `area === undefined` в климате легаси-маркеров (#317),
|
||||
уточнение доступности контроллера при полностью отключённых entities (#318),
|
||||
Shift-реактивность превью мебели без движения мыши, фильтр правой кнопки при
|
||||
установке мебели/декора, унификация имени правообладателя furniture-pack.
|
||||
Ни один пункт не расширяет продуктовый контракт — все семь чинят
|
||||
рассогласование между заявленным и фактическим поведением уже принятых
|
||||
функций (J1/J2/J4/J5/J6 по `docs/SCOPE.md`), нарушения `SCOPE.md` не найдено.
|
||||
Заголовок этой задачи ревью объявлял «Заход: r1 · блокирующих циклов 0 из 4».
|
||||
Это неверно относительно фактического состояния issue: в `docs/reviews/`
|
||||
уже лежит `SPEC-REVIEW-369-r1.md` с вердиктом «жёлтый» (три Medium: M1, M2,
|
||||
M3), и это подтверждено комментарием issue от `2026-08-29T07:41:01Z`
|
||||
(«Вердикт: жёлтый · заход r1 · блокирующих циклов 0/4 · High: 0 · Medium: 3
|
||||
→ в задаче»), а следующий комментарий владельца («Ревизия 2 ТЗ (dev
|
||||
`c50d9e4`) по r1: **M1**...**M2**...**M3**... Возвращаю S4-spec-review»)
|
||||
подтверждает, что это и есть возврат на правки по r1. Жёлтый вердикт тратит
|
||||
бюджет §4 (не зелёный, #227) — значит фактический счёт: заход **r2**,
|
||||
циклов **1/4**, а не r1/0. Использую r2 в имени этого документа: назвать
|
||||
его r1 означало бы затереть уже существующий `SPEC-REVIEW-369-r1.md` —
|
||||
ровно тот сценарий, от которого предостерегает сам процесс триггера. Не
|
||||
продуктовая находка (не про ТЗ #369), но стоит сообщить о рассинхроне
|
||||
источника номера раунда в автоматизации, которая формирует заголовок
|
||||
задачи — иначе следующий заход рискует получить то же самое имя дважды.
|
||||
|
||||
## Скоуп раунда (правило дельты, PROCESS.md §2.9, #214)
|
||||
|
||||
Дельта — три точечных правки одного файла, отвечающие ровно на находки r1:
|
||||
1. `- Ревизия: 1` → `- Ревизия: 2 ... — по SPEC-REVIEW-369-r1 (M1–M3)`
|
||||
(метаданные, не содержательно).
|
||||
2. Контракт (ж): список файлов расширен `docs/FURNITURE.md:41` (M1).
|
||||
3. AC1: доказательство переформулировано с «check-docs зелёный» на «код-ревью
|
||||
читает три файла» (M2).
|
||||
4. AC8: добавлен мутант для (д) — «attach выброшен → смок AC5 красный по
|
||||
free-флагу и счётчику слушателей» (M3).
|
||||
|
||||
Ни рекомбейза на ушедший вперёд `dev`, ни смены контракта поведения, ни
|
||||
новой подсистемы — дельта локальна классически. Разбор этого раунда
|
||||
ограничен M1–M3 и тем, не сломала ли точечная правка что-то из уже
|
||||
подтверждённого в r1 (правки чисто аддитивны: добавлено имя файла, снята
|
||||
формулировка доказательства AC1, добавлен один пункт списка мутантов —
|
||||
ни один не пересекается текстуально с AC2–AC7 или разделами «Риски»,
|
||||
«Release-артефакты», «Вне скоупа», «Откат»).
|
||||
|
||||
## Как проверялось
|
||||
|
||||
Ревью ТЗ проверяет заявимость и проверяемость контракта, а не код будущей
|
||||
реализации — но каждый пункт (а)–(е) сверен построчно с текущим деревом
|
||||
`dev` на SHA `cbf9318e`, чтобы отличить решение от догадки:
|
||||
- `git diff cbf9318e..c50d9e42 -- docs/specs/369-audit-lows.md` — прочитан
|
||||
целиком, три хунка перечислены выше.
|
||||
- M1: контракт (ж) в текущем тексте (строка 66-68) действительно называет
|
||||
четыре файла, включая `docs/FURNITURE.md:41`. `grep -rn Matyushin docs/
|
||||
assets/` на HEAD (`c50d9e42`) по-прежнему находит все четыре целевых
|
||||
файла (правка кода ещё не сделана — стадия ТЗ, ожидаемо) плюс историческую
|
||||
прозу `docs/reviews/SPEC-REVIEW-369-r1.md` и сам текст спеки, цитирующие
|
||||
старое имя как часть описания правки — см. находку L1 ниже.
|
||||
- M2: AC1 в текущем тексте (строка 72-74) — «доказательство: код-ревью
|
||||
читает три файла (check-docs содержимое не проверяет, он лишь не должен
|
||||
покраснеть от ссылок/фингерпринта)» — снимает именно то расхождение
|
||||
инструмент/утверждение, которое было найдено в r1 (`scripts/check-docs.mjs`
|
||||
не читает содержимое абзацев).
|
||||
- M3: AC8 (строка 92-96) теперь перечисляет мутант для (д) отдельно от
|
||||
(б)/(в)/(г)/(е), с двумя названными детекторами (смена free-флага,
|
||||
счётчик addEventListener/removeEventListener) — то же, что требовало M3.
|
||||
- Трейлеры `c50d9e42`: `Issue: #369`, `User-Visible: no` — верно для
|
||||
docs-only правки класса C (PROCESS.md §1).
|
||||
- Диапазон изменений всей спек-стадии #369 (`cbf9318e` и `c50d9e42`) —
|
||||
единственный файл `docs/specs/369-audit-lows.md` оба раза
|
||||
(`git show --stat` на каждом коммите); `src/**`/`custom_components/**`
|
||||
не тронуты ни разу.
|
||||
|
||||
- `src/devices.ts:1402-1410` (`markerClimateTarget`) — подтверждает (в):
|
||||
условие сейчас `marker.area === null`, замена на `== null` описана точно.
|
||||
- `src/device-presentation.ts:210-224` (`controllerAvailability`) — базовое
|
||||
условие (г) подтверждено; уточнение с `ha_disabled`/`allEntityIds`
|
||||
сверено с `src/ha-binding-status.ts:14-17,440-444` — поле `kind:
|
||||
'ha_disabled'` с `reason: 'all_entities'` уже возвращается ровно в
|
||||
описанном случае (allEntityIds непуст, enabledEntityIds пуст), так что
|
||||
вторая половина условия «ИЛИ allEntityIds непуст при пустом
|
||||
enabled-ростере» по инварианту резолвера избыточна (у `kind==='active'`
|
||||
такой комбинации не бывает). Не блокирует: AC4 сформулирован через
|
||||
наблюдаемый результат (available/not available), а не через внутреннее
|
||||
ветвление, и мутант в AC8 целится в тот же результат — избыточность не
|
||||
плодит двусмысленность. Отмечено ниже как Low.
|
||||
- `src/vacuum.ts:250-256` (`smoothVacPath`) — подтверждает (б): нефинитный
|
||||
сегмент отбрасывается сейчас молча (`continue`), без побочных эффектов.
|
||||
- `src/houseplan-editor-runtime.ts:4756` (`_furnPointerMove`) — подтверждает
|
||||
(д): `free: ev.shiftKey` читается только в pointermove, ни один
|
||||
keydown/keyup-листенер на Shift не найден (`grep shiftKey` по `src/`).
|
||||
- `src/houseplan-card.ts:6109` → `_decorPointerDown`
|
||||
(`src/houseplan-editor-runtime.ts:4076-…`) — подтверждает (е): ни в одной
|
||||
ветке (`line`/`rect`/`ellipse`/`text`/`furniture`) нет проверки
|
||||
`ev.button`; правый клик проходит тем же путём, что и левый.
|
||||
- `custom_components/houseplan/trails.py:252-274` — подтверждает (а):
|
||||
`async_purge_orphans` действительно чистит трейлы orphan-маркеров на
|
||||
каждый `config/set`, ссылка на #335 корректна.
|
||||
- Репо-wide `grep -rn "Matyushin"` — см. находку H1 ниже: список файлов в
|
||||
контракте (ж) неполон.
|
||||
- `docs/USER-GUIDE.ru.md:867` уже фиксирует «Позиция, вложения и след
|
||||
пылесоса при удалении маркера удаляются» — терминология «след» из (а)
|
||||
согласована с уже принятой, не изобретена заново.
|
||||
- `scripts/check-docs.mjs` прочитан целиком — см. находку M2.
|
||||
- `assets/furniture/houseplan-0.3.0/README.md` — SHA-256 источника
|
||||
архива не привязан к строке имени автора, утверждение AC7 о том, что
|
||||
пересчитывать нечего, корректно.
|
||||
Дешёвые гейты (`typecheck`/`test`/`build`/`check-docs`) на этом заходе не
|
||||
запускал — тот же довод, что в r1: диапазон дельты не содержит ни одного
|
||||
файла класса A/B (PROCESS.md §1), гейты нечего было бы доказать. Смоки,
|
||||
golden, инварианты модели — не запускались по той же причине (ни
|
||||
геометрия, ни `src/**`, ни визуальный результат в этой дельте не задеты).
|
||||
|
||||
Дешёвые гейты (`typecheck`/`test`/`build`) на этом заходе **не запускал**:
|
||||
диапазон изменений — класса C, единственный файл
|
||||
`docs/specs/369-audit-lows.md`, ни один файл `src/**` или
|
||||
`custom_components/**/*.py` не тронут (`git show --stat cbf9318e`). Запуск
|
||||
кодовых гейтов на неизменённом коде ничего не доказал бы и не входит в
|
||||
§8 «объём соразмерен задаче» для этапа ТЗ. `check-docs.mjs`,
|
||||
`model-invariants`, смоки и golden не запускались по той же причине — ни
|
||||
геометрия, ни `src/**`, ни визуальный результат в этом коммите не заде́ты.
|
||||
## Закрытие раунда r1
|
||||
|
||||
## Находки
|
||||
| Находка (r1) | Чем закрыта | Где видно |
|
||||
|---|---|---|
|
||||
| **M1** — AC7 требовал пустой repo-wide grep, но контракт (ж) не покрывал все вхождения имени (`docs/FURNITURE.md:41` пропущен) | Контракт (ж) расширен до четырёх файлов, включая `docs/FURNITURE.md:41` | `docs/specs/369-audit-lows.md:66-68`, diff-хунк 2 (`cbf9318e..c50d9e42`) |
|
||||
| **M2** — AC1 называл `check-docs` доказательством содержимого абзаца, хотя скрипт содержимое не проверяет | AC1 переформулирован: доказательство — прямое чтение трёх файлов на код-ревью, `check-docs` оставлен только структурным требованием | `docs/specs/369-audit-lows.md:72-74`, diff-хунк 3 |
|
||||
| **M3** — AC8 не называл мутант для (д), смок AC5 нельзя было отличить «проверяет логику» от «проходит без неё» | AC8 получил явный мутант «attach выброшен → смок красный по free-флагу и счётчику слушателей» | `docs/specs/369-audit-lows.md:92-96`, diff-хунк 4 |
|
||||
|
||||
### Medium (в скоупе, чинится в этом же ТЗ)
|
||||
Все три Medium из r1 закрыты предметно (текст ТЗ, не заявление автора).
|
||||
|
||||
**M1 — AC7 требует пустой repo-wide grep, но контракт (ж) не покрывает все вхождения имени.**
|
||||
`docs/specs/369-audit-lows.md`, пункт (ж) и AC7.
|
||||
## Унаследовано из r1
|
||||
|
||||
Контракт называет три файла для правки:
|
||||
`assets/furniture/houseplan-0.3.0/{LICENSE.md,README.md,pack.json}`. Но
|
||||
`docs/FURNITURE.md:41` тоже несёт старое имя: «The 77 drawings were created
|
||||
by Sergey Matyushin (`Matysh`) and granted to the project under its MIT
|
||||
License in issue #159» — тот же автор, тот же furniture-pack. AC7 требует
|
||||
«grep «Matyushin» по репо пуст» — как написано, это repo-wide grep,
|
||||
который останется красным после правки ровно трёх названных файлов.
|
||||
Документ: `docs/reviews/SPEC-REVIEW-369-r1.md`, разобран на SHA `cbf9318e`.
|
||||
Дельта r2 не касается ничего из перечисленного ниже — принимается без
|
||||
повторной построчной проверки:
|
||||
|
||||
*Воспроизведение:* `grep -rn Matyushin docs/ assets/` на SHA `cbf9318e`
|
||||
даёт 4 файла с вхождением (три названных в контракте + `docs/FURNITURE.md`).
|
||||
- Сценарий («до/после», персона home admin/десктоп-редакторы) и соответствие
|
||||
J1/J2/J4/J5/J6 из `docs/SCOPE.md` — нарушения не найдено.
|
||||
- Все шесть кодовых утверждений контракта (а)–(е) сверены r1 построчно с
|
||||
деревом `dev` на `cbf9318e` (`src/devices.ts:1402-1410`,
|
||||
`src/device-presentation.ts:210-224` + `src/ha-binding-status.ts:14-17,440-444`,
|
||||
`src/vacuum.ts:250-256`, `src/houseplan-editor-runtime.ts:4756`,
|
||||
`src/houseplan-card.ts:6109`→`_decorPointerDown`,
|
||||
`custom_components/houseplan/trails.py:252-274`) — ни одно не оказалось
|
||||
догадкой, выданной за факт.
|
||||
- AC2–AC6 — однозначны, способ доказательства (юнит/смок) назван, дельта их
|
||||
текст не трогает.
|
||||
- «Вне скоупа», «Откат», «Риски», «Release-артефакты» — не тронуты дельтой,
|
||||
корректны по r1.
|
||||
- **L1** (избыточное условие в контракте (г): вторая половина условия по
|
||||
инварианту `resolveHaBindingStatus` не добавляет новых случаев) — снята
|
||||
r1 с записью, не блокирует; дельта (г) не касалась.
|
||||
- **L2** (не все разделы §7.1 вынесены отдельными заголовками) — снята r1
|
||||
с записью как необязательная рекомендация «на следующую правку»;
|
||||
ревизия 2 её не применила — это не нарушение, поскольку r1 явно
|
||||
зафиксировал находку как dismissed (не «to-do»), см. PROCESS.md: Low
|
||||
«либо правится, либо снимается с записью» — уже снята.
|
||||
|
||||
Правка: либо добавить `docs/FURNITURE.md` в список файлов контракта (ж) —
|
||||
согласуется с духом решения владельца «автор — Sergey Matyunin», либо явно
|
||||
сузить grep в AC7 до `assets/furniture/houseplan-0.3.0/`. Первое
|
||||
предпочтительнее: расхождение имени в двух местах одного репозитория —
|
||||
ровно тот дефект, который пункт (ж) должен закрыть целиком, а не частично.
|
||||
## Находки (этот раунд)
|
||||
|
||||
**M2 — AC1 называет неверный инструмент доказательства.**
|
||||
`docs/specs/369-audit-lows.md`, AC1: «(а) VACUUM.md + оба USER-GUIDE
|
||||
содержат абзац; check-docs зелёный.»
|
||||
### Low — AC7 не станет буквально «grep по репо пуст» даже после точечной правки; положительная проверка не покрывает добавленный файл
|
||||
|
||||
Прочитан `scripts/check-docs.mjs` целиком: скрипт проверяет структуру
|
||||
public-документов — битые ссылки, `alt` у картинок, отпечаток скриншотов
|
||||
(`sourceFingerprint`) и связность заголовков. Он не читает содержимое
|
||||
абзаца и не упадёт, если требуемый текст отсутствует или отредактирован
|
||||
мимо смысла — «content лежит, значит и абзац лежит» здесь неверно.
|
||||
Зелёный `check-docs` докажет только то, что новый абзац не сломал ссылки
|
||||
и не устарел фингерпринт скриншотов; он не докажет, что абзац вообще
|
||||
добавлен и говорит то, что нужно.
|
||||
`docs/specs/369-audit-lows.md`, AC7 (строка 88-91): «(ж) grep «Matyushin» по
|
||||
репо пуст; pack.json/LICENSE.md/README.md несут «Sergey Matyunin»…».
|
||||
|
||||
Правка: заменить доказательство AC1 на явное «ревью читает три файла и
|
||||
подтверждает наличие абзаца с описанным содержанием» (проверено чтением,
|
||||
не исполнением — единственный законный способ для строкового факта,
|
||||
которого никакой существующий автотест не проверяет), `check-docs`
|
||||
оставить дополнительным (структурным) требованием, а не единственным.
|
||||
Два самостоятельных нюанса одной находки:
|
||||
|
||||
**M3 — AC8 не называет мутант для пункта (д).**
|
||||
`docs/specs/369-audit-lows.md`, AC8 перечисляет мутанты для (б), (в), (г),
|
||||
(е), но не для (д) — хотя (д) тоже вносит новую логику (keydown/keyup на
|
||||
`window`, обновление `free`-флага и его снятие при закрытии палитры).
|
||||
Без названного способа сломать смок AC5 умышленно, ревьюер кода не сможет
|
||||
отличить «смок проверяет добавленную логику» от «смок технически
|
||||
проходит, потому что фикстура не создаёт условие, при котором листенер
|
||||
вообще нужен» — тот самый класс дефекта, который уже стоил цикла на смоке
|
||||
`visual_continuity` (PROCESS.md §13 п.5) и который правило «тест должен
|
||||
уметь падать» (§2.7, §18) существует, чтобы ловить до код-ревью, а не во
|
||||
время него.
|
||||
1. Позитивная часть AC7 («несут «Sergey Matyunin»») по-прежнему называет
|
||||
только три исходных файла и не упоминает добавленный `docs/FURNITURE.md`
|
||||
— асимметрично контракту (ж), который теперь называет четыре. Негативная
|
||||
часть («grep пуст») это транзитивно покрывает, так что асимметрия не
|
||||
создаёт дыру в доказательстве, только небольшую редакционную
|
||||
рассогласованность.
|
||||
2. Буквально пустой repo-wide grep недостижим и после полной правки: сам
|
||||
этот файл ТЗ (`docs/specs/369-audit-lows.md`) в прозе контракта (ж) и в
|
||||
AC7 цитирует «Sergey Matyushin» как часть описания правки, `docs/reviews/
|
||||
SPEC-REVIEW-369-r1.md` цитирует то же самое как историческую находку, и
|
||||
этот документ (SPEC-REVIEW-369-r2) продолжит цитировать обе формы имени
|
||||
после публикации в `docs/reviews/`. Ровно тот же класс дефекта AC уже
|
||||
разбирался в прецеденте `docs/reviews/CODE-REVIEW-269-r1.md` (Low,
|
||||
«буквальная формулировка AC2 не выполняется, хотя цель AC2 достигнута») —
|
||||
там тоже historical-документ ревью цитировал старый текст, и находка была
|
||||
снята без правки: архивный документ «описывает код, которого уже нет»
|
||||
(§7.3), переписывать его задним числом бессмысленно и запрещено духом
|
||||
канона.
|
||||
|
||||
Правка: добавить в AC8 явный мутант, например «keyup не сбрасывает
|
||||
`free` → смок красный» либо «keydown-листенер не навешен → смок красный».
|
||||
*Почему не блокирует:* цель AC7 — отсутствие живого расхождения имени в
|
||||
активных ассетах/документации (`assets/furniture/houseplan-0.3.0/**`,
|
||||
`docs/FURNITURE.md`), а не буквальный ноль совпадений во всём git-дереве
|
||||
включая архив ревью. Это то же различие буквы и духа AC, что и в #269.
|
||||
|
||||
### Low (снимается с записью, не блокирует)
|
||||
*Снимается без правки, с записью:* код-ревьюер этой задачи должен читать
|
||||
AC7 как «`grep -rn Matyushin` пуст вне `docs/specs/**` и `docs/reviews/**`»
|
||||
— не нужно заводить эту находку заново на код-ревью, ссылка на этот раздел
|
||||
и на прецедент #269 достаточна.
|
||||
|
||||
**L1 — избыточное условие в контракте (г).**
|
||||
См. раздел «Как проверялось»: вторая половина условия («ИЛИ `allEntityIds`
|
||||
непуст при пустом enabled-ростере») по текущему инварианту
|
||||
`resolveHaBindingStatus` (`src/ha-binding-status.ts`) не добавляет новых
|
||||
случаев к `bindingStatus.kind === 'ha_disabled'` — `kind==='active'`
|
||||
никогда не сочетается с непустым `allEntityIds` и пустым
|
||||
`enabledEntityIds`. Снимаю без правки: AC4 сформулирован через наблюдаемый
|
||||
результат, а не через внутреннее ветвление, двусмысленности для
|
||||
реализации и для теста это не создаёт, а привязка к конкретному дереву
|
||||
условий — техническое решение автора, которое ревьюер вправе не разделять,
|
||||
но не обязан блокировать (PROCESS.md §7.1: техническое решается автором,
|
||||
оспаривается — не запрещается).
|
||||
|
||||
**L2 — не все разделы §7.1 вынесены отдельными заголовками.**
|
||||
Явных заголовков «Модель данных и миграция», «i18n» (есть только внутри
|
||||
«Release-артефакты»), «План автотестов» (растворён по AC), «Скоуп» как
|
||||
отдельного позитивного раздела (есть только «Вне скоупа») в документе нет.
|
||||
По содержанию всё покрыто — компат-полей и миграции нет («конфиг/схема/
|
||||
контракты не меняются» в «Откате»), i18n не требуется, план автотестов
|
||||
проступает через доказательства при каждом AC — поэтому не блокирую и не
|
||||
возвращаю по этой находке отдельно. Снимаю с записью: при следующей
|
||||
правке документа (M1–M3 всё равно требуют редактирования файла) стоит
|
||||
добавить три короткие явные строки-заголовка, чтобы трассируемость по
|
||||
DoR-чеклисту (§2.5) не зависела от того, что читающий сам разложит текст
|
||||
по разделам.
|
||||
High: 0. Medium: 0 (у обеих Medium из r1 — M1, M2, M3 — закрытие
|
||||
подтверждено выше построчно).
|
||||
|
||||
## Что проверено и корректно
|
||||
|
||||
- Сценарий и «что человек увидит до/после» — есть, продуктовый, без
|
||||
терминов реализации, определяет персону (home admin, десктоп-редакторы)
|
||||
корректно по `docs/SCOPE.md`.
|
||||
- Все шесть кодовых утверждений (а)–(е) сверены с фактическим деревом на
|
||||
SHA `cbf9318e` построчно (см. «Как проверялось») — ни одно не оказалось
|
||||
догадкой, выданной за факт; расхождение с кодом не найдено, кроме
|
||||
избыточности L1, которая не меняет наблюдаемый контракт.
|
||||
Решение владельца по (ж) (Sergey Matyunin) зафиксировано в ТЗ дословно.
|
||||
- AC2–AC6 однозначны и указывают способ доказательства (юнит/смок/grep),
|
||||
кроме зафиксированных выше M1 (неполный grep) и M2 (неверный инструмент
|
||||
для AC1).
|
||||
- «Вне скоупа» отсекает ровно то, что нужно — семантику purge (а) кодом.
|
||||
- Откат — один revert, конфиг/схема не меняются, соответствует
|
||||
содержанию (все шесть кодовых пунктов point-fix, седьмой — метаданные).
|
||||
- Риски названы по существу: (г) — видимое сужение недавнего #318,
|
||||
(д) — утечка листенеров на `window`, обе снабжены проверкой
|
||||
(регресс-юнит и счётчик addEventListener/removeEventListener
|
||||
соответственно) — это ровно то, что нужно, чтобы риск не остался
|
||||
голым наблюдением.
|
||||
- Release-артефакты названы: одна пачка CHANGELOG en+ru (User-Visible: yes
|
||||
для в/г/д/е — корректно, а/б/ж действительно не меняют видимое
|
||||
пользователю поведение или являются мета/документацией), i18n верно
|
||||
помечен как не требуемый.
|
||||
- Трейлеры коммита `cbf9318e` корректны для docs-коммита класса C
|
||||
(`Issue: #369`, `User-Visible: no`); AGENTS.md/PROCESS.md по классам
|
||||
файлов не нарушены.
|
||||
- Все три Medium из r1 (M1, M2, M3) закрыты текстом документа, не
|
||||
заявлением автора — см. таблицу «Закрытие раунда r1».
|
||||
- Дельта аддитивна и не пересекается текстуально ни с одним из унаследованных
|
||||
разделов — риск регрессии на уже подтверждённых AC (класс дефекта #102)
|
||||
отсутствует: правки не касаются формулировок AC2–AC6, контрактов (а)–(е),
|
||||
разделов «Риски»/«Release-артефакты»/«Вне скоупа»/«Откат».
|
||||
- Трейлеры коммита `c50d9e42` (`Issue: #369`, `User-Visible: no`) корректны
|
||||
для docs-коммита класса C.
|
||||
- Владелец вернул задачу в `S4-spec-review` после правки — процесс §2.4
|
||||
соблюдён (комментарий `2026-08-29T07:41:51Z`).
|
||||
|
||||
## Чего не проверял
|
||||
|
||||
- Не проверял `docs/CONFIG-COMPATIBILITY.md` построчно на предмет скрытых
|
||||
compatibility-полей — ни один из семи пунктов не трогает конфигурацию
|
||||
или схему маркера, поэтому применимость документа сочтена нулевой без
|
||||
построчной сверки.
|
||||
- Не запускал `typecheck`/`test`/`build`/`check-docs`/смоки/golden —
|
||||
причина в разделе «Как проверялось»: диапазон изменений этого SHA не
|
||||
содержит кода, гейты нечего было бы проверять.
|
||||
- Не проверял вживую логи покупателя фикстур для (б)/(г)/(д)/(е) —
|
||||
тестов ещё нет (стадия ТЗ), сверка «умеет ли тест падать» относится к
|
||||
код-ревью (§2.7) и будет сделана там по фактическим юнитам/смокам.
|
||||
- Не проверял точную формулировку будущего абзаца в VACUUM.md/USER-GUIDE
|
||||
— контракт (а) специально не фиксирует финальный текст, только смысл;
|
||||
это осознанная свобода автора, а не пробел.
|
||||
- `typecheck`/`test`/`build`/`check-docs`/смоки/golden/инварианты модели —
|
||||
не запускал: за всю спек-стадию #369 (оба коммита, `cbf9318e` и
|
||||
`c50d9e42`) единственный тронутый файл — `docs/specs/369-audit-lows.md`;
|
||||
ни `src/**`, ни `custom_components/**/*.py` не задеты ни разу, гейтам
|
||||
нечего было бы доказать.
|
||||
- Не проверял живьём будущие юниты/смоки для (б)–(е) и (д) — их ещё нет,
|
||||
сверка «умеет ли тест падать» относится к код-ревью (§2.7).
|
||||
- Не проверял точную будущую формулировку абзацев VACUUM.md/USER-GUIDE —
|
||||
контракт (а) намеренно не фиксирует финальный текст, только смысл; это
|
||||
было явно принято в r1 и дельта этого не меняла.
|
||||
- Не проверял `docs/CONFIG-COMPATIBILITY.md` — ни один из семи пунктов не
|
||||
трогает конфигурацию/схему маркера (унаследовано из r1, дельта не
|
||||
расширяет скоуп).
|
||||
|
||||
## Вердикт
|
||||
|
||||
Жёлтый: три находки Medium в скоупе задачи (M1, M2, M3), High нет. Все три
|
||||
чинятся правкой того же файла `docs/specs/369-audit-lows.md` — не требуют
|
||||
нового issue (#202). L1 и L2 сняты с записью выше.
|
||||
Зелёный: обе стороны условия закрытия соблюдены — все три Medium из r1
|
||||
(M1, M2, M3) закрыты предметно текстом документа, новых Medium/High не
|
||||
найдено. Одна Low-находка этого раунда (AC7: буквально недостижимый
|
||||
repo-wide grep, асимметрия позитивной проверки) снята без правки, с
|
||||
записью и ссылкой на прямой прецедент #269. Расхождение номера раунда в
|
||||
автоматике (задача звала себя «r1/0», фактически это «r2/1») зафиксировано
|
||||
отдельно выше — не находка по ТЗ, но стоит сообщить в процесс.
|
||||
|
||||
Reference in New Issue
Block a user