17 KiB
SPEC-REVIEW-369-r2
- Issue: https://github.com/Matysh/houseplan-card/issues/369
- Этап: ТЗ на ревью (PROCESS.md §2.4), полный трек (владелец назвал критерий «одна поверхность» §5 как не выполненный — семь несвязанных поверхностей)
- Артефакт:
docs/specs/369-audit-lows.md - Материал ревью: дельта
cbf9318e..c50d9e42(«ревизия 2» документа,docs: #369 spec revision 2 per SPEC-REVIEW-369-r1) — тот же единственный файл, 3 хунка (+11/-7 строк),User-Visible: no, корректно для docs-коммита - Заход: r2 · блокирующих циклов израсходовано 1 из 4 (лимит для полного трека — 4)
Несовпадение номера раунда в заголовке задачи — зафиксировано, не находка по ТЗ
Заголовок этой задачи ревью объявлял «Заход: 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→- Ревизия: 2 ... — по SPEC-REVIEW-369-r1 (M1–M3)(метаданные, не содержательно).- Контракт (ж): список файлов расширен
docs/FURNITURE.md:41(M1). - AC1: доказательство переформулировано с «check-docs зелёный» на «код-ревью читает три файла» (M2).
- AC8: добавлен мутант для (д) — «attach выброшен → смок AC5 красный по free-флагу и счётчику слушателей» (M3).
Ни рекомбейза на ушедший вперёд dev, ни смены контракта поведения, ни
новой подсистемы — дельта локальна классически. Разбор этого раунда
ограничен M1–M3 и тем, не сломала ли точечная правка что-то из уже
подтверждённого в r1 (правки чисто аддитивны: добавлено имя файла, снята
формулировка доказательства AC1, добавлен один пункт списка мутантов —
ни один не пересекается текстуально с AC2–AC7 или разделами «Риски»,
«Release-артефакты», «Вне скоупа», «Откат»).
Как проверялось
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/**не тронуты ни разу.
Дешёвые гейты (typecheck/test/build/check-docs) на этом заходе не
запускал — тот же довод, что в r1: диапазон дельты не содержит ни одного
файла класса A/B (PROCESS.md §1), гейты нечего было бы доказать. Смоки,
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 из r1 закрыты предметно (текст ТЗ, не заявление автора).
Унаследовано из r1
Документ: docs/reviews/SPEC-REVIEW-369-r1.md, разобран на SHA cbf9318e.
Дельта r2 не касается ничего из перечисленного ниже — принимается без
повторной построчной проверки:
- Сценарий («до/после», персона 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 «либо правится, либо снимается с записью» — уже снята.
Находки (этот раунд)
Low — AC7 не станет буквально «grep по репо пуст» даже после точечной правки; положительная проверка не покрывает добавленный файл
docs/specs/369-audit-lows.md, AC7 (строка 88-91): «(ж) grep «Matyushin» по
репо пуст; pack.json/LICENSE.md/README.md несут «Sergey Matyunin»…».
Два самостоятельных нюанса одной находки:
- Позитивная часть AC7 («несут «Sergey Matyunin»») по-прежнему называет
только три исходных файла и не упоминает добавленный
docs/FURNITURE.md— асимметрично контракту (ж), который теперь называет четыре. Негативная часть («grep пуст») это транзитивно покрывает, так что асимметрия не создаёт дыру в доказательстве, только небольшую редакционную рассогласованность. - Буквально пустой 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), переписывать его задним числом бессмысленно и запрещено духом канона.
Почему не блокирует: цель AC7 — отсутствие живого расхождения имени в
активных ассетах/документации (assets/furniture/houseplan-0.3.0/**,
docs/FURNITURE.md), а не буквальный ноль совпадений во всём git-дереве
включая архив ревью. Это то же различие буквы и духа AC, что и в #269.
Снимается без правки, с записью: код-ревьюер этой задачи должен читать
AC7 как «grep -rn Matyushin пуст вне docs/specs/** и docs/reviews/**»
— не нужно заводить эту находку заново на код-ревью, ссылка на этот раздел
и на прецедент #269 достаточна.
High: 0. Medium: 0 (у обеих Medium из r1 — M1, M2, M3 — закрытие подтверждено выше построчно).
Что проверено и корректно
- Все три 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).
Чего не проверял
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 из r1 (M1, M2, M3) закрыты предметно текстом документа, новых Medium/High не найдено. Одна Low-находка этого раунда (AC7: буквально недостижимый repo-wide grep, асимметрия позитивной проверки) снята без правки, с записью и ссылкой на прямой прецедент #269. Расхождение номера раунда в автоматике (задача звала себя «r1/0», фактически это «r2/1») зафиксировано отдельно выше — не находка по ТЗ, но стоит сообщить в процесс.