From ca0b318e5e56858fef5e886c978f2fac92026824 Mon Sep 17 00:00:00 2001 From: Matysh Date: Tue, 1 Sep 2026 23:20:09 +0300 Subject: [PATCH] ci: make the stability measurement a gate, not a printout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Замер сделал свою работу — теперь он остаётся как проверка. Если кадр снова начнёт зависеть от времени, шаг упадёт, а не напечатает число в лог. Стоит перед съёмкой набора: публиковать артефакт, снятый недетерминированной съёмкой, смысла нет. Issue: #410 User-Visible: no --- .github/workflows/docs-screenshots.yml | 12 ++++++++---- demo/docs/capture.mjs | 8 ++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs-screenshots.yml b/.github/workflows/docs-screenshots.yml index 6c5a8883..a58ecda8 100644 --- a/.github/workflows/docs-screenshots.yml +++ b/.github/workflows/docs-screenshots.yml @@ -89,10 +89,14 @@ jobs: # сравнить два прогона одного и того же SHA, нужен текст, который видно с # экрана. Именно так измеряется недетерминированность съёмки — и её # отсутствие после починки. - # ВРЕМЕННО на ветке замера #410: три снимка на сценарий в одном процессе, - # без правки состояния между ними. Отвечает на вопрос, плавает ли кадр - # внутри одного состояния страницы. - - name: "Замер стабильности (#410)" + # Съёмка обязана быть воспроизводимой, и это проверяется, а не + # предполагается (#410): три снимка на сценарий в одном процессе, без + # правки состояния между ними, обязаны совпасть побайтово. Шаг падает, + # если кадр снова начнёт зависеть от времени. + # + # Проверка стоит ПЕРЕД съёмкой набора: смысла публиковать артефакт, + # снятый недетерминированной съёмкой, нет. + - name: "Кадр не плавает внутри одного состояния (#410)" run: node demo/docs/capture.mjs --stability=3 - name: Хеши кадров run: | diff --git a/demo/docs/capture.mjs b/demo/docs/capture.mjs index 5fcb4701..8f1c0c3c 100644 --- a/demo/docs/capture.mjs +++ b/demo/docs/capture.mjs @@ -186,6 +186,7 @@ const DETERMINISTIC_ARGS = [ * * Ничего не пишет на диск и манифест не трогает: это измерение, а не съёмка. */ +const unstable = []; const stabilityArg = process.argv.find((arg) => arg.startsWith('--stability')); const STABILITY_SHOTS = stabilityArg ? Math.max(2, Number(stabilityArg.split('=')[1] || 3)) @@ -314,6 +315,7 @@ try { + (result.box ? `, bbox ${result.box.x0},${result.box.y0}` + `..${result.box.x1},${result.box.y1}` : '') + `, кадр ${result.size ? result.size.join('x') : '?'}`); + if (result.pixels || result.sizeMismatch) unstable.push(`${scenario.id} ${result.pair}`); } continue; } @@ -336,6 +338,12 @@ try { if (browserErrors.length) throw new Error(`browser errors: ${browserErrors.join(' | ')}`); if (STABILITY_SHOTS) { console.log(`\nзамер стабильности: ${STABILITY_SHOTS} снимка на сценарий, манифест не тронут`); + if (unstable.length) { + // Режим — не только диагностика, но и гейт: если кадр снова начнёт зависеть + // от времени, это должно останавливать съёмку, а не печататься в лог. + throw new Error(`кадр плавает внутри одного состояния страницы: ${unstable.join(', ')}`); + } + console.log('кадр не плавает ни в одном сценарии'); } else { const manifest = { version: DOC_SCREENSHOT_VERSION,