docs: review document for #425

Issue: #425
User-Visible: no
This commit is contained in:
claude[bot]
2026-09-02 21:17:29 +00:00
parent 4eae3398a6
commit 3df0f1646b
+212
View File
@@ -0,0 +1,212 @@
# 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
```