Files
claude[bot] 59f0e49c6e
Проверка (CI) / Классификация изменённых файлов (push) Failing after 20m18s
Проверка (CI) / Предполёт: документация, провенанс, процесс (push) Failing after 21m11s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Skipped
Проверка (CI) / HACS: валидация репозитория (push) Skipped
Проверка (CI) / Hassfest: манифест интеграции (push) Skipped
Проверка (CI) / Мутанты по диффу (1/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (2/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Skipped
Проверка (CI) / Мутанты по диффу (3/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (4/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (5/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (6/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Skipped
Проверка (CI) / Смоки: все шарды зелёные (push) Skipped
Проверка (CI) / Golden-кадры против принятых эталонов (push) Skipped
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Skipped
Проверка (CI) / Геометрия: TS/Python parity исполнена (push) Skipped
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Skipped
Проверка (CI) / Доказательство выполненных проверок (push) Failing after 17m53s
docs: review document for #646
Issue: #646
User-Visible: no
2026-09-25 01:07:05 +00:00

13 KiB
Raw Permalink Blame History

CODE-REVIEW-646-r1

Issue: #646 — temp dirs are removed even when a test fails; lint guards it. Материал: fa91f3a7311145e9c3f6e2d22d55aca07f844ef1 (ветка issue/646-temp-dir-hygiene, ребейз на origin/dev @ 524908b2), один коммит. Дерево и блобы из блока «Материал раунда» сверены с git ls-tree HEAD — совпадают побайтово. Трек: инфраструктурный, класс B. Issue: #646, User-Visible: no — оба трейлера на коммите присутствуют; изменений в src/** нет, changelog не требуется.

Скоуп

Симптом: test/golden-capture-provenance.test.mjs's accept() создавал mkdtemp(hp-golden-571-baselines-*) (~20 МБ) и не удалял его ни при успехе, ни при ожидаемом падении — 433 копии за сутки параллельной работы агентов, 8,5 ГБ, ENOSPC. Ещё три места (bundle-assets, docs-accept, rebase-generated) протекали так же.

Правка:

  1. Четыре реальных утечки закрыты — очистка в finally или t.after.
  2. Новый статический lint test/temp-dir-hygiene.test.mjs: AST-разбор (TypeScript) test/**/*.mjs, требует, чтобы каждый mkdtemp/mkdtempSync был связан с именем и убран rm*/rmSync/rmdir* в finally либо в хуке after/afterEach/t.after, с поддержкой цепочки именованных помощников (до 3 звеньев) и исключением // tmp-ok: <причина>.
  3. Два мутанта в scripts/mutation-registry.mjs, привязанные к guard'у node --test test/temp-dir-hygiene.test.mjs.

Какую работу из docs/SCOPE.md это обслуживает: не продуктовую строку J1–J7 напрямую — это внутренняя инфраструктура тестового прогона (гигиена CI/локальной песочницы), предмет AGENTS.md/PROCESS.md, а не пользовательский сценарий. Продуктового поведения дифф не меняет ни строкой — весь diff лежит в test/** и scripts/mutation-registry.mjs.

Как проверялось

Зелёный Validate уже подтверждён на этом SHA (https://github.com/Matysh/houseplan-card/actions/runs/36079627502) — typecheck, npm test, npm run build со сверкой бандла и check-docs (не по src/**, но прогоняется всегда) на этом прогоне не перегонялись.

Гейт Статус Результат
Validate на fa91f3a7 (typecheck/test/build/docs) Не перегонял, зачёл по ссылке success
npx tsc -p tsconfig.test.json Прогнал чисто, без вывода
node --test test/temp-dir-hygiene.test.mjs Прогнал 2/2 pass (реальное дерево — 0 нарушений; самопроверка правила — 7 плохих/7 хороших примеров)
node --test на четырёх изменённых файлах (golden-capture-provenance, bundle-assets, docs-accept, rebase-generated) Прогнал 73/73 pass
Замер TMPDIR вокруг того же прогона (свой пустой каталог /tmp/t-646-verify) Прогнал 0 записей до и после — независимое подтверждение AC1 на изменённых файлах
node scripts/mutation-gate.mjs --id=golden-accept-sandbox-leaks на fa91f3a7 Прогнал сам (автор гонял его на до-ребейзном 98d45838) поймано 1 из 1
node scripts/mutation-gate.mjs --id=temp-hygiene-accepts-cleanup-outside-finally на fa91f3a7 Прогнал сам поймано 1 из 1
node scripts/mutation-gate.mjs --check (полный реестр, 920 мутантов) на fa91f3a7 Прогнал сам rc 0, 920 ok — новые два мутанта не сломали ничего в остальном реестре
Ручной просмотр остальных ~55 сайтов mkdtemp в test/** (merge-candidate, process-gate и др.) Прогнал (выборочно) все используют распознаваемый паттерн try/finally — нет признаков, что lint слеп на реальном коде
grep .sandbox в golden-capture-provenance.test.mjs после удаления поля из возврата accept() Прогнал нет использований — поле убрано целиком и безопасно

AC · чем доказан · чем краснеет

AC Чем доказан Чем краснеет Проверено ревьюером
AC1. После полного юнит-набора в TMPDIR не остаётся тестовых каталогов Автор: ручной замер 6 частей полного набора, 0→0, контроль на origin/dev — 11 каталогов/160 МБ Возврат любой из 4 утечек → красный temp-dir-hygiene (AC2); мутант golden-accept-sandbox-leaks Частично исполнением: независимый прогон 4 изменённых файлов с чистым TMPDIR — 0 записей. Полный набор (все 3048 тестов) не перегонял — соразмерно объёму задачи, ссылаюсь на Validate + собственный частичный прогон
AC2. Lint ловит новый mkdtemp без очистки test/temp-dir-hygiene.test.mjs: тест 1 — реальное дерево (63 вызова, 0 нарушений, канарейка sites >= 20); тест 2 — самопроверка на 7 плохих/7 хороших примерах Мутант golden-accept-sandbox-leaks (снята очистка в accept()), мутант temp-hygiene-accepts-cleanup-outside-finally (правило принимает очистку вне finally) Исполнением: оба мутанта перегнаны на fa91f3a7 лично, оба пойманы (1 из 1 каждый)

Третий столбец не пуст ни в одной строке, и обе названные мутации перегнаны на материале ревью, а не только на коммите автора до ребейза — это закрывает главный риск раунда (--id=… гонялся автором на 98d45838, а не на fa91f3a7).

Что проверено и корректно

  • accept() в golden-capture-provenance.test.mjs: sandbox больше не покидает функцию — index/stdout/error читаются до finally, где rmSync(sandbox, { recursive: true, force: true }) исполняется всегда, включая путь expectFailure. Ни один вызывающий тест больше не читает поле .sandbox (проверено grep) и не делает собственный rmSync(from, …) в конце теста — заменено на artifact(t, …), снимающий каталог в t.after независимо от исхода assert'ов.
  • bundle-assets.test.mjs, docs-accept.test.mjs, rebase-generated.test.mjs: тот же класс дефекта (очистка отсутствовала или стояла после assert'ов вне finally) закрыт стандартным паттерном t.after/try…finally. Диффы точечные, смысл тестов не менялся — assert'ы и структура тестов совпадают до и после.
  • Lint сам себя не обманывает: правило отличает «очистка в finally» от «очистка после ассертов» (мутант 2 это буквально и проверяет), различает помощника, отдающего каталог целиком, от помощника, отдающего каталог полем объекта, которое вызывающий не забирает (ровно кейс старого accept() — предусмотрен намеренно), и требует непустую причину у tmp-ok:.
  • Мутанты интегрированы корректно: guard node --test test/temp-dir-hygiene.test.mjs — это тот же тест, который является доказательством AC2, оба мутанта поймал именно он на текущем материале; полный mutation-gate.mjs --check (920 мутантов) зелёный — новые два не конфликтуют с остальным реестром.
  • Трейлеры и changelog: Issue: #646, User-Visible: no на коммите — верно для чисто тестовой правки без видимого поведения; changelog не тронут и не должен быть.
  • Одно число, один источник: правка не вводит новых видимых пользователю чисел — нечего сверять по §8.

Находки

Нет ни High, ни Medium, ни Low.

Чего не проверял

  • Полный набор из 3048 тестов под наблюдаемым TMPDIR — не перегонял целиком (это дорогой гейт не по этому диффу); ссылаюсь на Validate (success) плюс собственный независимый прогон четырёх изменённых файлов с чистым TMPDIR, давший 0 записей, как частичное, но прямое подтверждение AC1 поверх слов автора.
  • hp-mutant-* worktree от оборванных прогонов мутантов — не читал scripts/mutation-execution.mjs; согласен с автором, что это отдельный дефект (утечка из скриптов, не из test/**/*.mjs, куда сфокусирован lint) и вне AC этой задачи, раз он явно назван в разделе «Чего не проверял» хендоффа, а не спрятан.
  • Windows-путь — не проверял; t.after/try…finally платформенно нейтральны, и это разумное необоснованное риском допущение для CI-only паттерна.
  • Полный ручной перебор всех ~63 сайтов mkdtemp — прочитал выборочно (merge-candidate.test.mjs, process-gate.test.mjs) и опёрся на канарейку sites >= 20 плюс собственный запуск lint-теста на реальном дереве вместо построчного аудита каждого из 63 сайтов.
  • scripts/check-docs.mjs — не гонял: диффа по src/** нет, репозиторий несёт независимо существующее предупреждение о протухшем скриншот-отпечатке (#479), не относящееся к этой правке.

Вердикт

Зелёный. Ни один AC не в скоупе не остался без доказательства, обе защитные мутации перепроверены лично на материале раунда fa91f3a7, независимая проверка AC1 на изменённых файлах подтвердила 0 утечек.


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

  • Ветка: issue/646-temp-dir-hygiene, коммит fa91f3a73111 — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: b96dc160827eec6840263e83a0ef2b761c21724a
    git log --all --format='%H %T' | grep b96dc160827e
    
  • Тело issue: 6f23efe32c765c152615c83303b8817f3690c5b1bfa19d5cb62475810575f839
  • Вердикт конвейера: green · High 0