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

17 KiB
Raw Permalink Blame History

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


Материал раунда

  • Ветка: 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