14 KiB
CODE-REVIEW-425-r1
- Issue: https://github.com/Matysh/houseplan-card/issues/425
- Ветка:
issue/425-core-file-budget, материал:git diff origin/dev...HEADна SHAd4ecace6 - ТЗ:
docs/specs/425-core-file-budget.md(полный трек), спек-ревью зелёное на r2 (docs/reviews/SPEC-REVIEW-425-r2.md) - Заход: r1 · блокирующих циклов израсходовано 0 из 4
Скоуп
Диапазон origin/dev..HEAD — 5 коммитов:
4eae3398 docs: specify the core file budget gate (#425)
3df0f164 docs: review document for #425
84b5f63c docs: address the core budget spec review (#425)
f399ad54 docs: review document for #425
d4ecace6 test: cap the two frontend cores with a ratchet (#425)
Единственный коммит с продуктовым воздействием на гейты — d4ecace6:
docs/TESTING.md | 14 ++++++
scripts/mutation-gate.mjs | 13 +++++
test/core-file-budget.test.mjs | 109 ++++++++++++++++++++++++++++++
Остальные — спек-документы и ревью-документы предыдущего этапа (класс C), к
код-ревью не относятся содержательно. Диф не трогает src/**,
custom_components/**, demo/** — класс B (гейты и инструменты), issue
переиспользован как разрешено таблицей классов. User-Visible: no на каждом
коммите корректно: продуктовый код не менялся.
Как проверялось
| Гейт | Команда | Результат |
|---|---|---|
| typecheck | npx tsc --noEmit |
зелёный, 0 ошибок |
| unit (полный) | npm test |
1778 тестов, 1777 pass, 1 skip (issue 281 private exact fixture... — существующий условный skip, не связан с #425), 0 fail |
| build + сверка копии | npm run build && cmp dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js |
бандл собран, побайтовое совпадение; копия demo/srv/assets/** не коммитится (#255) и не сравнивается |
| целевой тест | node --test test/core-file-budget.test.mjs |
7/7 pass |
| мутант (штатный раннер) | node scripts/mutation-gate.mjs --id=core-budget-ignores-growth |
ok core-budget-ignores-growth: тест покраснел, как обязан — поймано 1 из 1 |
| проверка якорей мутанта | node scripts/mutation-gate.mjs --check |
ok core-budget-ignores-growth — патч применим к текущему коду |
| выбор браузерных смоков | node scripts/smoke-select.mjs --base origin/dev --head HEAD |
«Исполняемого frontend-диффа нет (src/**/*.ts не тронут). Browser-smoke этим диффом не выбираются — выбирать нечего.» |
| process-gate (офлайн) | node scripts/process-gate.mjs --base origin/dev --head HEAD |
«гейт пройден, предупреждений 0» |
| фактические размеры ядер | node -e "…split('\n').length" на обоих файлах |
houseplan-card.ts = 13659, houseplan-editor-runtime.ts = 14323 — совпадает с CAPS в тесте |
Чего не проверял и почему
node scripts/check-docs.mjs— не запускал: диф не трогаетsrc/**, условие «любой diff поsrc/**требует check-docs» не выполнено.- Полный прогон
node scripts/mutation-gate.mjs(все мутанты) — не гонял: дорогой прогон, задача трогает ровно один новый мутант, который проверен адресно через--id. Попутно замечено (не находка этой задачи): полный прогон в этом окружении падает на несвязанном бэкенд-мутанте из-за отсутствующегоpytest(No module named pytest) — окружение без Python- венды, не регрессия #425. golden:verify,smoke_*.mjs,pytest tests_backend, performance-профили — диф не меняет визуал, DOM, Python-код или производительность; AC их не называют.smoke-select.mjsнезависимо подтвердил «выбирать нечего».node scripts/model-invariants.mjs— диф не касается геометрии, толщины стен,layout,marker.space,open_spans.- Ручное тестирование в браузере — задача не создаёт видимого поведения
(
User-Visible: no, продуктовый код не тронут), пункт неприменим по определению задачи.
Разбор по AC
- AC1 (рост ядра выше потолка роняет
npm testс числом). Доказано исполнением, не чтением: мутантcore-budget-ignores-growth(scripts/mutation-gate.mjs:936-948) добавляет 400 строк вsrc/houseplan-card.tsпередexport class HouseplanCard, что больше люфта (250). Прогонnode scripts/mutation-gate.mjs --id=core-budget-ignores-growthдал «тест покраснел, как обязан» — тест реально умеет падать, а не только умеет проходить. Текст сообщения называет файл, потолок и превышение (test/core-file-budget.test.mjs:41-47), проверено юнитом «рост выше потолка становится нарушением с числом» (строки 67-72). - AC2 (уменьшение больше чем на 250 строк тоже роняет тест, с требованием
опустить потолок). Доказано юнитом «заметное уменьшение требует опустить
потолок» (
:74-79): проверяетkind==='shrank',under===300, текст содержит «Опустите потолок». Чтением подтверждено, что тот же путь исполнения используется и на реальных ядрах (measureвызывается один раз в верхнем тесте,coreBudgetViolations— чистая функция без ветвления по источнику данных). - AC3 (изменение в пределах люфта тест не трогает). Доказано юнитами
«изменение в пределах люфта не трогает никого» и «границы включительно»
(
:81-92) — отдельно проверены точкиcap,cap-slack,cap+1,cap-slack-1, то есть обе границы включительно и оба соседних шага исключительно. - AC4 (потолки — числа в тесте, не вычисление от текущего размера).
Доказательство по ТЗ — «ревью кода плюс юнит на то, что функция принимает
потолки аргументом». Юнит «потолки — числа в этом файле…» (
:99-109) парсит блокconst CAPSиз исходника теста и проверяет regex-отсутствиеmeasure|readFileSync|process.envвнутри блока — то есть механически исключает как раз тот способ обмана, который ТЗ называет неприемлемым (потолок, вычисленный от текущего размера). Прочитано чтением:CAPS(:21-24) — действительно литерал из двух чисел,coreBudgetViolations(:33-57) получаетcapsиslackпараметрами и не читает файлы иenvсама; чтение файлов инкапсулировано в отдельнойmeasure(:59), вызываемой только в интеграционном тесте верхнего уровня. Проверено чтением, не исполнением, в части «архитектурного» инварианта (что функция не может прочитать файл сама), исполнением — в части regex-проверки текста. - AC5 (гейт судит только два ядра, остальные файлы не ограничены). Доказано
юнитом «потолки заданы для двух ядер и ни для чего больше» (
:94-97), сверяющим точный список ключейCAPS. Чтением подтверждено, что других мест вsrc/**, ссылающихся наCAPS/coreBudgetViolations, нет (единственный потребитель — сам файл теста).
Все пять AC доказаны: AC1 — мутантом, исполненным лично (не на слово автора); AC2/AC3/AC5 — юнитами, прогнанными лично; AC4 — комбинацией юнита и чтения кода с явной пометкой, какая часть доказана как.
Соответствие ТЗ и процессу
- Числа
CAPS(13659,14323) совпадают с фактическим размером файлов на этом SHA, измеренным независимо (split('\n').length), что и есть мера, описанная в комментарии надCAPS(:14-16) и совпадающая с мерой вmeasure()(:59) — единственный источник числа, нет второго измерения той же величины другим способом (правило «одно число — один источник» неприменимо буквально, т.к. величина инженерная и не видна пользователю, но принцип соблюдён: потолок и измерение используют одну и ту же функцию подсчёта строк). docs/TESTING.mdдополнен разделом с объяснением, что делать при красном гейте — соответствует Release-артефактам ТЗ (толькоTESTING.md, changelog не требуется приUser-Visible: no).- Расхождение чисел в теле issue (таблица «dev: 13658») с
CAPS(«13659») — не дефект: таблица в issue используетwc -l(мера issue), тест — мераsplit('\n').length; автор явно проговорил это расхождение в хендофф- комментарии и держит одну меру в коде, что и требовалось. Само число в тексте issue — историческая иллюстрация, не контрактное значение. - Скоуп ТЗ («один тест с потолками и храповиком, мутант, строка в
docs/TESTING.md») выдержан ровно, попутных правок нет. - SCOPE.md: задача инженерная,
User-Visible: no, не обязана закрывать Core user job — прецедент (#337 bundle-budget, #85 mutation-gate) уже принят ревью ТЗ на r1, не переоткрываю.
Находки
Нет находок High или Medium. Low не обнаружено сверх уже снятого на этапе ТЗ.
Одна стилистическая заметка, не являющаяся дефектом (не заводится ни как Low,
ни как issue): пункт docs/TESTING.md:3593 оформлен чек-боксом - [ ], хотя
проверка полностью автоматическая и уже входит в npm test — соседние
чек-боксы в этом файле смешивают ручные и автоматические проверки, так что
формат не расходится с текущей конвенцией документа.
Материал раунда
- Ветка:
issue/425-core-file-budget - SHA на момент вывода:
d4ecace6(сверено непосредственно перед подведением итогов, см.git rev-parse HEADв начале сессии — совпадает сHEADдиапазонаorigin/dev..HEAD, использованного во всех командах выше) - Дерево материала: полный диф
origin/dev...HEAD, 6 файлов изменено (см. таблицу выше)
Материал раунда
- Ветка:
issue/425-core-file-budget, коммитd4ecace64c51— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
226386b38b1cb661fcb45b2c8f01a568b954a70agit log --all --format='%H %T' | grep 226386b38b1c - ТЗ
docs/specs/425-core-file-budget.md, блоб0469a1eec26759469cf469c87136556935a1f629git log --all --find-object=0469a1eec26759469cf469c87136556935a1f629 -- docs/specs/425-core-file-budget.md