Оба файла исполняются из ветки по умолчанию: process.yml — по событию
`issues`, mutation-gate.yml — по расписанию. Приводятся к версии dev после
#556 (SHA-пины сторонних Actions, права по job, job-scoped токен у стадии
модели). Гейт workflow_sync в Validate сверяет оба.
Issue: #556
User-Visible: no
Замер по AC5 #392 изменил решение. Я собирался заморозить набор на том, что
резолвилось (HA 2026.2.3, февральский), и вынести обновление в отдельную
задачу «на потом» — потому что шесть месяцев дрейфа API вслепую в dev не
отправляют.
Проверил на ветке experiment/392-py314: Python 3.14, phcc 0.13.357,
homeassistant 2026.8.3 — `450 passed, 2 skipped`. Ровно то же, что на старом
наборе, ни одного падения. Обновление оказалось бесплатным, и держать гейт на
февральском HA после такого замера нельзя.
Взята 0.13.357, а не последняя: она последняя, которая пинует стабильный
2026.8.3, дальше пинуются беты. Гейт на бете невоспроизводим — бету могут
перевыпустить под тем же номером.
pytest не закреплён намеренно: phcc задаёт совместимый диапазон сам, жёсткий
пин с ним конфликтует (ResolutionImpossible на 9.0.0, проверено).
Issue: #392
User-Visible: no
Два независимых хвоста из разбора #389, оба про то, что «зелёный» значит не
то, что читается.
#392. Оба места, где поднимается HA-харнесс, ставили зависимости без единой
версии. Python при этом закреплён на 3.13, а pytest-homeassistant-custom-
component с 0.13.348 требует 3.14 — резолвер молча уезжал на 0.13.316, а та
тянет homeassistant 2026.2.3. Интеграция полгода проверялась против
февральского HA, и состав окружения мог измениться без нашего коммита.
Версии закреплены в tests_backend/requirements.txt ровно те, что резолвились
30.08; шаг печатает установленное в лог. Это остановка дрейфа, а не
обновление: переход на 3.14 и свежий phcc — отдельная задача с отдельным
измерением.
#393. test_trails.py клал каталог пакета в sys.path при коллекции — на всю
сессию, включая HA-харнесс. Модули интеграции становились импортируемыми ещё
и как модули верхнего уровня, то есть один файл мог оказаться в sys.modules
дважды. Вставка при этом не работала ни на что: TrailBook берётся чтением
текста и exec среза, а не импортом. Убрана вместе с мёртвым spec.
Гейт статический, по исходникам: он ловит намерение, а рантайм поймал бы
последствие и только при сегодняшнем порядке тестов.
Issue: #392
User-Visible: no
Four independent cuts into the 2-4 hour full run, none touching the contract
"a mutant must turn its guard red":
- guardNeedsBundle: rollup runs only for guards that open the built bundle
(demo/ smokes, golden captures, bundle:sync) — 68 of 253 registry entries.
Unit and backend guards never read dist/ as a build artifact (verified
against every test that mentions dist/**: they read the git checkout or
synthetic files), so 185 mutants skip the most expensive step entirely.
- seedTestBuild + incremental tsc: the mutant worktree starts from the main
tree's warm test-build/ and .tsbuildinfo; tsc compares file hashes, not
mtimes, so the fresh checkout stays warm and only the mutated delta is
recompiled. This also speeds up the long guards that run tsc themselves.
- --changed[=range]: run only mutants whose patch files are touched by the
diff (origin/dev..HEAD by default). An empty selection is an honest success
with an explicit message — the full registry remains the pre-release
contract, per the workflow comment.
- --shard=i/n: deterministic interleaved slices; the workflow runs a 4-way
matrix, and a warm test-build step feeds every shard. Interleaving spreads
the expensive browser mutants across shards instead of clumping them.
Measured per mutant on this machine: unit 12-13 s (was ~50-70 s), backend
6 s, browser 32 s (unchanged — the bundle is genuinely needed there). Full
run estimate drops to ~70 sequential minutes, ~20 on four shards.
Unit coverage: guard classification on real registry shapes, a floor on both
classes so the split cannot silently collapse, changed-selection semantics,
and shard completeness/disjointness with an anti-clumping bound.
Issue: #332
User-Visible: no
Owner decision (chat, 2026-08-27): the running check's name must say what it
does, in Russian. Scripts locate workflows by file name (release-gate.mjs ->
validate.yml), so display names are free; job ids and needs are untouched.
The same content is cherry-picked to main because release workflows execute
from the default branch and process.yml must stay identical in main and dev.
Issue: #327
User-Visible: no
Five times in this project a green test meant nothing was checked. The
continuity smoke stayed green after the entire mechanism it guards was cut out.
The golden scene created to protect doorway light was empty — 1,177 warm pixels
against 107,119, all of them icons. The shadow smoke passed while no shadow was
drawn. Each time the test had been written alongside the code, went green at
once, and nobody ever asked whether it could go red.
The gate makes that question routine. Each mutant is a few lines of patch that
reproduce a known breakage, plus the name of the test that must fail on it. A
worktree is patched, the bundle rebuilt, the guard run — and a guard that stays
green fails the gate. Six mutants cover the holes documented in #85; the anchors
are exact strings from today's source, so the registry cannot silently drift —
a unit test that runs with the ordinary suite refuses a stale anchor.
The full run rebuilds the bundle per mutant, so it lives in its own workflow,
before a stable release and on a weekly schedule, not in Validate. The rules for
new tests are written at the top of docs/TESTING.md, and the sixth of them is
the cheapest: an assertion that reads back the property the code just set is
not written at all.
Issue: #85
User-Visible: no