Files
houseplan-card/docs/reviews/SPEC-REVIEW-425-r1.md
T
2026-09-02 21:17:29 +00:00

213 lines
17 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-425-r1
- Issue: https://github.com/Matysh/houseplan-card/issues/425
- ТЗ: `docs/specs/425-core-file-budget.md`, ветка `issue/425-core-file-budget`,
SHA `4eae3398a6510ea19b403fd1ac33a5a3cc44881b` (единственный коммит поверх
`origin/dev`, класс C: `docs: specify the core file budget gate (#425)`,
`Issue: #425` · `User-Visible: no`).
- Заход: r1 · трек: полный (снят с `small` автором — «метка small конвейер не
запускает»; техническая причина смены трека вне моей компетенции, к
содержанию ТЗ отношения не имеет).
- Вердикт: **жёлтый**.
## Скоуп задачи
Ядро #425: заменить #34 узким, автоматизируемым ограничителем — гейт-храповик
на размер `src/houseplan-card.ts` и `src/houseplan-editor-runtime.ts` (растёт
выше потолка → красный тест; падает больше чем на 250 строк ниже потолка →
тоже красный, чтобы потолок опускали, а не забывали). Только тестовая
инфраструктура: один тест, один мутант, строка в `docs/TESTING.md`, закрытие
#34. Продуктового кода, UX, i18n, миграций конфига задача не касается
(`User-Visible: no`).
## Как проверялось
1. `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md` — прочитаны целиком.
2. Тело issue #425 и оба комментария (переход на `small`, затем откат на
полный трек) — прочитаны через `gh issue view 425 --json ...` (MCP-доступ к
`get_issue`/`get_issue_comments` не выдан в этой сессии).
3. Тело ТЗ прочитано целиком (`docs/specs/425-core-file-budget.md`, 103
строки).
4. Проверено по факту, а не на слово:
- `#34` существует, открыт, `S3-spec` — ссылка и статус в ТЗ не выдуманы;
- текущие размеры ядер: `wc -l src/houseplan-card.ts` → 13658,
`src/houseplan-editor-runtime.ts` → 14322 — совпадают с колонкой `dev` в
таблице ТЗ день в день;
- заявленные «42% всего TypeScript» — при подсчёте строками выходит 38.97%
(27980/71793), но при подсчёте байтами (как считает `bundle-budget.mjs`
— прецедент похожего гейта в этом же репозитории) — 42.66%
(1312569/3076509 Б по `src/**/*.ts` на `origin/dev`). Автор посчитал
байтами; расхождение с интуитивным «строками» — не ошибка, а другая
единица измерения, оставляю как проверенный факт;
- `scripts/mutation-gate.mjs`, `test/mutation-gate.test.mjs`,
`.github/workflows/mutation-gate.yml` существуют — приём «тест
сопровождается мутантом в `scripts/mutation-gate.mjs`» это не догадка, а
действующая конвенция репозитория (`docs/TESTING.md`, правило 4);
- `scripts/bundle-budget.mjs` — единственный похожий по духу гейт в
репозитории — проверен на предмет пересечения: он про initial-view gzip
бандла, не про строки исходника; дублирования функциональности нет;
- `test/*.test.mjs` — гейта на размер файлов исходников сегодня нет
(`grep` по «budget/потолок» ничего похожего не находит) — задача
действительно новая, а не повтор существующего.
5. `node scripts/process-gate.mjs` на диапазоне `origin/dev..HEAD` — «гейт
пройден, предупреждений 0» (класс C, трейлеры корректны, веткование верно).
6. Продуктового кода коммит не содержит (`git diff origin/dev...HEAD --stat`
— один файл, `docs/specs/425-core-file-budget.md`), поэтому дешёвые гейты
(`typecheck`/`test`/`build`) к материалу этого раунда неприменимы — они
отвечают на вопрос «работает ли код», а кода в этом раунде нет. Зелёный
Validate на `4eae3398` (ссылка в контексте задачи) это подтверждает
попутно.
## Находки
### Medium-1 — нет обязательных разделов «Сценарий» и «Что человек увидит до и после» (§7.1)
`docs/specs/425-core-file-budget.md`, весь документ.
PROCESS.md §7.1 называет эти два раздела первыми не случайно: «ТЗ, которое не
может ответить на эти два вопроса, описывает работу, а не изменение
продукта». В документе их нет вообще — ни в явном виде, ни как «не
применимо» (для секции «UX, модель данных, i18n» автор такую отметку сделал:
строка 62 — «Не применимо: продуктового кода задача не касается»; для
Сценария и «что увидит человек» — не сделал).
**Сценарий воспроизведения:** открыть файл и поискать заголовки «Сценарий» и
«Что человек увидит» — их нет; DoR-чеклист §2.5 требует полный набор разделов
§7.1 перед переводом в `S5-ready`.
Задача действительно не имеет пользовательской видимости (`User-Visible: no`,
гейт CI), поэтому по существу ответ тривиален — но именно поэтому его нужно
написать явно, тем же приёмом, что уже применён к UX-разделу: «Сценарий: не
применимо — персона отсутствует, единственный наблюдатель контракта —
разработчик, читающий вывод `npm test`». Без этой строки документ не проходит
формальный чеклист §2.5, хотя по сути вопрос закрыт.
Серьёзность: Medium, в скоупе — правится добавлением двух коротких абзацев,
без изменения контракта.
### Medium-2 — AC4 (и частично AC5) не называют способ доказательства
`docs/specs/425-core-file-budget.md:45-46`.
DoR (§2.5) требует у каждого AC «указано, чем он доказывается: unit / backend
/ smoke / golden / «ревью кода»». AC1–AC3 это делают явно («Доказательство:
мутант...», «Доказательство: тот же юнит»). AC4 — нет:
> **AC4**. Потолки записаны числами в самом тесте: любое их изменение видно в
> дифе и проходит ревью как решение, а не как побочный эффект.
Способ доказательства здесь по смыслу — «ревью кода» (структурное свойство:
константа лежит в тесте, а не читается из внешнего конфига), но текст этого
не говорит, и план автотестов (строки 70–75) AC4 не упоминает вовсе — только
AC1, AC2, AC3, AC5. AC5 хотя бы косвенно закрыт пунктом 5 плана
(«потолки заданы для обоих ядер и ни для чего больше (AC5)»); у AC4 такой
связи нет ни в тексте AC, ни в плане.
**Как проявится, если не поправить:** на код-ревью придётся решать самому,
чем считать AC4 доказанным — юнитом или чтением кода; при полном треке это
дало бы почву для расхождения между автором и ревьюером кода.
Серьёзность: Medium, в скоупе — правится одной строкой
(«Доказательство: ревью кода — константы `...` лежат в теле теста, изменение
видно в diff»).
### Low-1 — раздел «Откат» задублирован
`docs/specs/425-core-file-budget.md:48-50` и `:94-96` — два одинаковых
раздела `## Откат` с идентичным текстом «Удаление одного тестового файла и
одного мутанта.» (первый явно перенесён из тела issue, второй добавлен при
расширении до полного трека, старый не убран).
Содержательного расхождения нет, ambiguity не создаёт. Снимаю с записью:
чинится удалением одного из двух блоков при следующей правке ТЗ, отдельного
цикла не требует.
## Что проверено и корректно
- **Замена #34.** Ссылка живая, статус (`S3-spec`, открыт) соответствует
описанию «за 25 дней не сдвинулся»; заявление не выдумано.
- **Числа в таблице долга** (13658 / 14322 на `dev`) сверены с деревом
напрямую — точное совпадение день в день.
- **AC1–AC3, AC5** — однозначны, каждый привязан к конкретному проверяемому
условию и (кроме AC5 частично) к явному способу доказательства; план
автотестов на чистой функции `coreBudgetViolations(sizes, caps, slack)`
описывает все ветки, включая обе границы (строка 74: «границы
включительно») — асимметрия «рост без люфта / падение с люфтом 250 строк»
прочитана из контракта верно и без противоречий.
- **Мутант** соответствует действующей конвенции `docs/TESTING.md` (правило
4): 2–5-строчный патч в реальный файл, а не в тест, тест обязан покраснеть.
- **Не найдено ни одной догадки, выданной за факт.** Все технические
утверждения (существование `scripts/mutation-gate.mjs`, конвенция
мутантов, текущие размеры файлов, отсутствие похожего гейта) проверены по
дереву репозитория, а не приняты на слово.
- **Открытых продуктовых вопросов владельцу нет** — и не должно быть: задача
целиком техническая, ни одного вопроса о том, что видит или делает человек,
в ней нет.
- **`docs/USER-GUIDE.ru.md` и канонические документы подсистем** (`SUN.md`,
`LIGHT.md`, `CANVAS.md`, `WALL-THICKNESS.md`, `UX-MODES.md`,
`CONFIG-COMPATIBILITY.md`, `TOUCH-SUPPORT.md`) не относятся к этой задаче —
видимое поведение не меняется, интерфейсная терминология не используется;
проверено тем, что задача помечена `User-Visible: no` и раздел UX ТЗ прямо
это фиксирует.
- **`docs/SCOPE.md` / Core user jobs.** Задача не закрывает ни одну строку
J1–J7 — и не обязана: это не продуктовая фича, а инженерный гейт качества
(`User-Visible: no`, класс B/C по DoD), аналогичный уже принятым в этом же
репозитории `scripts/bundle-budget.mjs` (#337/#367) и самому
`scripts/mutation-gate.mjs` (#85). SCOPE.md ограничивает, что становится
видимой функцией продукта; техдолг разработки под этот ограничитель не
подпадает. Это не находка, а явно проверенное и подтверждённое отсутствие
конфликта.
- **Класс изменений и трейлеры коммита r1** — `process-gate.mjs` подтвердил
автоматически (см. «Как проверялось», п.5).
## Чего не проверял и почему
- **Дешёвые гейты кода** (`npx tsc --noEmit`, `npm test`, `npm run build`,
сверка бандла) — не прогонял: материал раунда не содержит продуктового или
тестового кода, только текст ТЗ; прогонять их не на чем.
- **Мутационный гейт, golden, смоки, инварианты модели, perf-профили,
бэкенд-тесты** — не прогонял: код гейта ещё не написан (это стадия ТЗ, не
`S6`/`S7`), диф не трогает `src/**`, геометрию, рендер, Python или touch.
Ни один из этих гейтов не относится к материалу этого раунда по diff'у или
AC.
- **`docs/specs/README.md`** — не требую внесения записи об issue #425/#34 в
этот индекс: свежие специфицированные задачи (#422, #416) там тоже не
зарегистрированы, реестр по факту не поддерживается синхронно (см. и
собственную пометку PROCESS.md §7.3 п.1 о его частичном устаревании), это
не критерий приёмки ни этой, ни соседних задач.
- **Точность исторических чисел** (18 файлов на v1.58, 20287 строк на
v1.66.0) — не перепроверял по тегам: это фон мотивации, не AC, ошибка в нём
не меняет проверяемость контракта.
## Материал раунда
- Ветка: `issue/425-core-file-budget`
- SHA: `4eae3398a6510ea19b403fd1ac33a5a3cc44881b`
- ТЗ: `docs/specs/425-core-file-budget.md` (единственный файл в диффе с
`origin/dev`)
## Вердикт
Жёлтый: обе находки Medium в скоупе задачи, High нет. Обе правятся точечно —
двумя короткими разделами и одной строкой доказательства у AC4 — без
изменения контракта, AC или объёма задачи. Low снят с записью, отдельного
действия не требует.
`Вердикт: жёлтый · заход r1 · блокирующих циклов 0/4 · High: 0 · Medium: 2 → в задаче · Документ: docs/reviews/SPEC-REVIEW-425-r1.md`
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/425-core-file-budget`, коммит `4eae3398a651` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `d37bea6a940c33f8197d96b008432931ad7edb8f`
```
git log --all --format='%H %T' | grep d37bea6a940c
```
- ТЗ `docs/specs/425-core-file-budget.md`, блоб `213aaf2a92ffc550f9fd87d2b4b81338a82359a6`
```
git log --all --find-object=213aaf2a92ffc550f9fd87d2b4b81338a82359a6 -- docs/specs/425-core-file-budget.md
```