13 KiB
Код-ревью #596 — заход r1
Материал: 337d85ea4c40db8308e35caac4303254c0874306 (ветка issue/596-merge-candidate-maxbuffer, один коммит).
Класс B: scripts/merge-candidate.mjs, test/merge-candidate.test.mjs, scripts/mutation-registry.mjs. Файлов класса A нет.
Трейлеры коммита: Issue: #596, User-Visible: no — верно, изменение внутреннего инструмента конвейера, продуктового поведения не касается.
Скоуп задачи
sh() в scripts/merge-candidate.mjs вызывал spawnSync без maxBuffer (умолчание 1 МиБ).
Шаг слияния считает patch-id материала и кандидата через git diff --full-index, когда dev
сдвинулся за время ревью; дифф задачи, пересобирающей бандл, несёт три копии
houseplan-card.js — воспроизведено на #594 (7 103 616 байт). Процесс убивался по ENOBUFS,
status становился null, а status: r.status ?? 1 выдавало это за «git вернул 1» — с
усечённым stdout в сообщении об ошибке (must() берёт stderr || stdout, stderr был пуст).
Задача — issue #596, инфраструктурная, класс B, входит в флоу на S7-code-review сразу (#562).
Как проверялось
Дешёвые гейты (npx tsc --noEmit, npm test, npm run build) на этом SHA уже зелёные —
Validate https://github.com/Matysh/houseplan-card/actions/runs/35429741728, повторно не гонял.
node scripts/check-docs.mjs не нужен: diff не трогает src/** (только scripts/** и
test/**). Инварианты модели не нужны: diff не трогает геометрию, layout, marker.space,
open_spans, толщину стен. Браузерные смоки не нужны: смоки исполняют собранный бандл и DOM
(src/**/demo/**), а диффа там нет — смок-раздел smoke-select.mjs рассчитан на связь с
изменённым исполняемым символом фронтенда, здесь такого символа нет в принципе (правка Node-скрипта
CI, не фронтенда). golden:verify, pytest tests_backend, перф-профили — не применимы,
не тронуты соответствующие пути.
Ручная проверка (то, что Validate не покрывает и что специфично для этой задачи):
- Прочитал итоговый
scripts/merge-candidate.mjs:sh()теперь передаётmaxBuffer: MAX_COMMAND_OUTPUT_BYTES(256 МиБ) первым в объекте опций,optsможет его переопределить (порядок спреда{ encoding, maxBuffer, ...opts }корректен — опции вызова, если есть, побеждают дефолт, как и раньше для остальных полей).r.errorтеперь читается: причина (ENOENT,ENOBUFS, таймаут) уходит вstderrрезультата, и при её наличииstatusпринудительно1(не полагается наr.status ?? 1, которое для провала запуска всегдаnull). - Прогнал целевые тесты изолированно:
node --test --test-name-pattern="#596" test/merge-candidate.test.mjs→ 2/2 pass. - Дисциплина «тест умеет падать» — не поверил заявлению автора, воспроизвёл мутацию вручную
импортом модуля и вызовом
sh()сmaxBuffer: 1024*1024(то же, что делает мутантmerge-candidate-truncates-the-candidate-diffвscripts/mutation-registry.mjs) на 3 МиБ вывода:Тест AC1 (status 1 stderr "…/node не выполнился: ENOBUFS" stdoutLen 1114112assert.equal(r.status, 0, …)) в этом состоянии красный, как и заявлено. Причём само сообщение об ошибке называетENOBUFS, а не отдаёт усечённыйstdout— это и есть AC2 в действии на конкретном сценарии дефекта. - Проверил, что
scripts/mutation-registry.mjsсинтаксически корректен и грузится (node -e "import('./scripts/mutation-registry.mjs')"→ ok), новый элемент массива не ломает соседние (declared-baseline-review-run-never-checkedидёт следом без искажений),idуникален по файлу. - Проверил, что экспорт
shне используется больше нигде вscripts/*.mjsза пределамиmerge-candidate.mjs— расширение публичного API файла не создаёт скрытых потребителей и не меняет поведениеrealOps(сигнатураshне поменялась, только опции по умолчанию и структураstderr). - Просмотрел
must():stderr || stdout— при заполненномstderr(наш случай после исправления) в исключение уходит причина, а не дифф. Логика согласована с текстом AC2.
AC — построчно
- AC1 (вывод >1 МиБ доезжает целиком,
status: 0) — доказано автотестомtest/merge-candidate.test.mjs:397-404, тест реальный (гоняет процесс, не заглушку), падение при откате правки подтверждено вручную (см. п.3 выше). Выполнено. - AC2 (сбой запуска называет причину в
stderr,must()печатает её) — доказано автотестомtest/merge-candidate.test.mjs:406-413и чтениемmust()(scripts/merge-candidate.mjs:134,${what}: ${r.stderr || r.stdout}). Выполнено. - AC3 (существующие тесты остаются зелёными, подмена
execне ломается) — сигнатураsh(cmd, args, opts)и форма возврата{status, stdout, stderr}не изменились, только дефолтmaxBufferи заполнениеstderrприr.error;realOpsконструируетgit/execчерез тот жеshпо умолчанию, тестовые фикстуры подменяютexecцеликом и его не затрагивают. Подтверждено прогоном Validate на этом SHA (2775/2776, 1 skip — без регрессии) и точечным прогоном новых тестов. Выполнено. - AC4 (мутант снимает
maxBuffer, AC1 краснеет) — мутантmerge-candidate-truncates-the-candidate-diff(scripts/mutation-registry.mjs:9940-9951) возвращаетmaxBufferк1024*1024; воспроизвёл эффект вручную (п.3) — AC1 действительно краснеет, и вдобавок причина в этом состоянии верно называетсяENOBUFS, а не молчит. Выполнено. - AC5 (
npm test,npm run typecheck,npm run buildзелёные) — покрыто Validate на этом же SHA (ссылка выше), повторный прогон не требовался. Выполнено.
Продуктовое рассуждение (docs/SCOPE.md)
Задача не создаёт и не меняет пользовательского поведения; это инструмент самого ревью- конвейера (§2.4/§2.9 PROCESS.md, класс B). К Core user jobs (J1–J7) прямого отношения нет — она инфраструктурная и входит в флоу по отдельному правилу (#562), что и отражено в issue. Ничего в SCOPE.md эту работу не ограничивает и не блокирует.
Находки
Нет ни одной находки уровня High или Medium. Мелочей уровня Low, которые стоило бы отметить, тоже не нашёл: код лаконичен, комментарии по существу объясняют «почему», тесты целенаправленные и действительно проверяют регрессию, а не пересказывают код.
Что проверено и корректно
- Причина исходного дефекта (ENOBUFS на 1 027 868 байт, тот же обрыв, что в комментарии о
сбое #594) устранена явным
maxBufferс большим запасом (256 МиБ) — обоснование запаса («переживает рост бандла и задачу, которая трогает бандл и эталоны одновременно») разумно для CI-скрипта, не тянет памяти сверх нормы для однократного вызоваgit diff. - Вторая половина дефекта (сокрытие
r.error) устранена:must()теперь получает причину, а не огрызок диффа, который «уводит разбор в сторону» — именно то, что случилось на #594. shэкспортирован и используется в тестах напрямую (не только черезrealOps), так что оба AC имеют исполнимого свидетеля, а не рассуждение автора.- Мутационный тест зарегистрирован по тем же соглашениям, что и соседние записи в файле
(
guard,because,patches), синтаксис файла не нарушен. - Скоуп изменения не выходит за пределы заявленных трёх файлов, продуктовый код не тронут.
Чего не проверял и почему
npx tsc --noEmit,npm test(полный),npm run buildсо сверкой бандла — не гонял повторно: зелёный Validate уже есть на этом точном SHA (ссылка выше), диффа не по бандлу и не по типам, что подтверждается локальным точечным прогоном тестов файла.node scripts/check-docs.mjs— diff не трогаетsrc/**, гейт не устареет от этой правки.npm run invariants— diff не трогает геометрию/толщину стен/layout/marker.space.- Браузерные смоки (
demo/smoke_*.mjs) — diff не трогает фронтенд/бандл/DOM, смоки его в принципе не исполняют;smoke-select.mjsне запускал, так как предмет диффа (Node-скрипт CI-инструмента) вне домена, который инструмент оценивает. npm run golden:verify— diff не может изменить видимый рендер.python -m pytest tests_backend -q—custom_components/**/*.pyне тронут.- Перф-профили — не названы в AC, чувствительные к перфу пути не тронуты.
node scripts/process-gate.mjs --issues— автор отметил недоступностьghв песочнице; это гейт публикации/CI, а не код-ревью, отдельно не гонял.
Вердикт
Все пять AC выполнены и доказаны исполнимыми тестами, один из которых (мутационный) я воспроизвёл вручную и убедился, что он действительно ловит регрессию, а не просто существует. Скоуп не нарушен, продуктовый код не затронут, трейлеры корректны. Находок нет.
Зелёный.
Материал раунда
- Ветка:
issue/596-merge-candidate-maxbuffer, коммит337d85ea4c40— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
24ca27d21d24b5d66aba292f22d8e5aafd51c074git log --all --format='%H %T' | grep 24ca27d21d24 - Тело issue:
9b589ac902b977dac360fa27b962cac1d90e89020e3987a38de00c4aae14c2df - Вердикт конвейера:
green· High 0