Files
houseplan-card/docs/reviews/SPEC-REVIEW-385-r2.md
T
2026-08-30 07:48:57 +00:00

134 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SPEC-REVIEW-385-r2
- Issue: https://github.com/Matysh/houseplan-card/issues/385
- Этап: ТЗ на ревью (PROCESS.md §2.4)
- Артефакт под ревью: `docs/specs/385-audit-lows.md`, ревизия 2 (2026-08-30),
коммит `687b2966` ("docs: #385 spec revision 2 per SPEC-REVIEW-385-r1")
- Заход: r2 · блокирующих циклов израсходовано 1 из 4 (до этого вердикта)
- Предыдущий раунд: `docs/reviews/SPEC-REVIEW-385-r1.md`, вердикт жёлтый на
ревизии 1, коммит `c28b2f2d` ("docs: specify #385 audit-lows batch")
## Скоуп раунда
Дельта — `git diff c28b2f2d..687b2966 -- docs/specs/385-audit-lows.md`: правка
текстовая, ровно по требованиям вердикта r1 (M1 + Low L2/L3). Код продукта не
менялся ни в r1, ни в r2 — стадия ТЗ. Единственный изменённый файл:
`docs/specs/385-audit-lows.md` (+23/-9 строк), затронуты четыре места:
строка «Ревизия», раздел «Проблема / Контракты» пункт (в), «DoR-примечания»,
«Release-артефакты». Разбор по дельте, не заново (PROCESS.md §2.9): полный
повторный разбор ТЗ, продуктовой рамки и AC1–AC6 не требуется — дельта
локальна, новую подсистему не задевает, ребейза не было.
## Как проверялось
По каждой находке r1 — построчное сравнение старого и нового текста (`git
diff`) плюс сверка новых утверждений с источником истины (кодом), а не с
заявлением автора о том, что правка внесена.
### Закрытие раунда r1
| Находка (r1) | Чем закрыта | Где это видно |
|---|---|---|
| **M1** — контракт (в) называет только первый дизъюнкт `isRelease`, риск ложного отказа CI на бета-коммитах приёмки эталонов | Абзац «Контракт» переписан: назван **весь** предикат (`(/^Release v\d/...) \|\| Boolean(one('Release'))`), явно оговорено «НЕ пересказ по памяти и НЕ только первый дизъюнкт», приведён конкретный контрпример-коммит и путь отказа через `evaluateCommit`; реализация явно требует одну функцию, используемую и `makeCommit`, и гейтом в `parseRecords`, AC4 привязан к переиспользованию | `docs/specs/385-audit-lows.md:45-59`. Выражение сверено дословно с `scripts/process-gate.mjs:133-135` — совпадает посимвольно (проверено `sed -n '125,136p' scripts/process-gate.mjs`). Контрпример `5f6ee657` перепроверён заново командой `git show -s --format='%s%n---%n%B' 5f6ee657`: subject `test: accept explicit value source golden` не матчит `/^Release v\d/`, трейлер `Release: v1.69.0-beta.5` присутствует — вторым дизъюнктом `isRelease` действительно становится `true`. Утверждение точное |
| **L2** — DoR-примечания не называют влияние на производительность | Добавлена третья фраза: «производительность — (в) сокращает работу pre-push/CI-гейта на длинных диапазонах (только выигрыш, бенч не требуется)» | `docs/specs/385-audit-lows.md:134-136` |
| **L3** — «(б)–(г) — мелкие уточнения» в Release-артефактах двусмысленно относительно changelog | Переписано прямо: changelog получает запись только про (а); (б)–(г) явно исключены из changelog («видимого поведения не меняют… НЕ входят»), с явной привязкой к `User-Visible: no` | `docs/specs/385-audit-lows.md:140-143` |
| **L1** — «план автотестов» ссылается на несуществующий тестовый паттерн `_valueBadgeForBinding` | Не требовала правки — в r1 снята решением ревьюера без возврата («технический вопрос — домен автора, не блокирует») | Текст не менялся, `docs/specs/385-audit-lows.md:115-117` — по-прежнему присутствует нетронутым; закрытие r1 было «оставляю как есть», а не «поправить», так что отсутствие правки — ожидаемо, не регресс |
M1 и L2/L3 закрыты по существу и корректно. Однако при сверке дельты нашёл
остаточную несогласованность текста — новая находка ниже.
## Находки
### Low (правится или снимается решением ревьюера — не блокирует)
**L4. Абзац-обоснование перед «Контрактом» (в) сохраняет старую неточную
формулировку предиката, которую r1 требовал заменить.**
`docs/specs/385-audit-lows.md:41-44`:
> `parseRecords` зовёт дорогую проверку (2×`git show` на каждый src-файл) для
> КАЖДОГО коммита, хотя потребляется она только для стабильных релизных
> (`/^Release v\d/` без beta/candidate, :134).
Это почти дословно та же фраза, которую вердикт r1 (M1, «Требуется на этом
раунде») просил заменить на точную — и она действительно заменена, но только
в следующем абзаце («Контракт: …»). Абзац-обоснование перед ним остался
нетронутым и по-прежнему называет лишь первый дизъюнкт, без трейлера
`Release:`. Формально в документе сейчас два соседних утверждения о том, при
каких коммитах включается проверка: неточное (проблема) и точное (контракт).
Почему это не Medium: нормативная часть — именно «Контракт», не «Проблема»;
контракт сформулирован недвусмысленно, с конкретным контрпримером и
файл:строка, и явно предупреждает «это не то же, что первый дизъюнкт». Риск,
из-за которого M1 был возвращён (реализатор напишет упрощённую версию,
прочитав только описание проблемы) кода не создаёт критического пути, потому
что реализатор будет реализовывать по «Контракту» и AC4, а не по абзацу
«Проблема». Но самопротиворечие в тексте ухудшает читаемость и не помешало бы
поправить заодно, раз уж абзац переписывался.
Не блокирует переход в `S5-ready`; снимаю записью, правка на усмотрение
автора при следующей правке этого файла (не стоит отдельного раунда).
## Унаследовано из r1
Без повторной проверки в r2 приняты факты, установленные в
`docs/reviews/SPEC-REVIEW-385-r1.md` на коммите `c28b2f2d` — дельта их не
затрагивает:
- Обоснование полного трека (критерий «одна поверхность» §5 не выполняется,
прецедент #369 / SPEC-REVIEW-376-r1 H1).
- Точность описаний дефектов (а), (б), (г) — построчная сверка с
`houseplan-editor-runtime.ts:12252-12312`, `devices.ts:868-892`,
`import_export.py:504-519` соответственно; текст этих пунктов в дельте r2
не менялся.
- Наличие всех обязательных разделов §7.1, однозначность и доказуемость
AC1, AC2, AC3, AC5, AC6 (AC4 перепроверен в r2 отдельно — см. ниже),
реалистичность плана автотестов и мутантов (кроме отмеченного L1),
корректность отката, отсутствие незаявленных догадок, обоснованный отказ
от эскалации продуктовых вопросов владельцу.
- Ссылка контракта (а) на букву `docs/specs/378-value-face-source.md:85`.
- Единственность пути записи `value_source`/`value_badge` через
`_valueBadgeForBinding` (два вызова, :12260/:12308, третьего нет) —
проверено в r1 через `grep`, риск в разделе «Риски» не менялся дельтой.
- Отсутствие задвоенности AC5 относительно существующих pytest-тестов.
- Неприменимость гейтов `typecheck`/`test`/`build`/`check-docs`/`invariants`/
смоков/`golden:verify` на этой стадии — код продукта не существует; в r2
подтверждено, что диапазон `c28b2f2d..687b2966` тоже не касается кода
(`git show --stat` — единственный файл, `docs/specs/385-audit-lows.md`).
## Что проверено заново в r2 (сверх таблицы закрытия)
- **AC4 остаётся согласован с новым текстом контракта.** AC4 говорит
«классификация релизности — та же функция, что в гейте (юнит сверяет
идентичность/переиспользование предиката)» — это не изменилось и корректно
описывает исправленный контракт (полное выражение, а не первый дизъюнкт).
Расхождения между новым текстом (в) и AC4 нет.
- **Точность нового текста контракта (в) против кода.** Выражение
`(/^Release v\d/.test(subject) && !/-(beta|rc|alpha)\.|candidate/i.test(subject)) || Boolean(one('Release'))`
сверено с `scripts/process-gate.mjs:133-135` — совпадает дословно.
- **Точность контрпримера `5f6ee657`.** Перепроверено заново (не полагался на
заявление r1): `git show -s --format='%s%n---%n%B' 5f6ee657` — subject не
матчит regex, трейлер `Release: v1.69.0-beta.5` присутствует, значит
`isRelease` истинно вторым дизъюнктом. Пример в спеке верен.
- **Файловый скоуп дельты.** `git show --stat 687b2966` — единственный
файл `docs/specs/385-audit-lows.md`; других изменений в этом коммите нет.
## Чего не проверял
- Полный повторный разбор AC1, AC2, AC3, AC5, AC6, разделов «Сценарий», «Что
человек увидит», «Скоуп/не-скоуп», «UX», «Модель данных», «i18n», «Риски»
кроме их незатронутых дельтой частей — они не менялись между r1 и r2,
наследую вывод r1 (раздел «Унаследовано из r1» выше).
- Гейты `typecheck`/`test`/`build`/`check-docs`/`invariants`/смоки/
`golden:verify` — неприменимы, код продукта не существует (стадия ТЗ),
дельта r2 тоже не код (подтверждено `git show --stat`).
- Реальные числовые издержки `2×git show` на типичный диапазон коммитов — не
требуется AC4, только факт отсутствия лишних вызовов.
## Вердикт
Зелёный: находка M1 предыдущего раунда закрыта по существу и корректно
(текст контракта точен, сверен с кодом заново), L2 и L3 закрыты полностью.
Новая находка L4 — Low, самопротиворечие соседних абзацев — не блокирует и
снимается записью на усмотрение автора. High нет, Medium нет. ТЗ готово к
переходу в `S5-ready`.