mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-04 05:41:34 +00:00
213 lines
17 KiB
Markdown
213 lines
17 KiB
Markdown
# 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
|
||
```
|