From 5fd97169060163b5a75f7ed0e7057934bac71c5b Mon Sep 17 00:00:00 2001 From: Matysh Date: Sat, 22 Aug 2026 01:46:39 +0300 Subject: [PATCH] fix: verify demo bundle freshness for smokes too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Golden runs, benchmarks and documentation captures each called assertFreshDemoBundle; the smoke launcher never did, so all ~128 smokes could silently test a stale demo/srv/assets bundle. On #234 that cost a round of analysis: three assertions went red and a fourth went green, because the old code was wrong in two places that agreed with each other, and a mixed result reads as a logic defect rather than a stale artefact. launch() now runs the check once for every smoke, against the repository root rather than the serving root — demo/srv has no src/** to fingerprint. HP_ALLOW_STALE_BUNDLE=1 skips it for debugging and warns out loud, because a guard that says nothing when it steps aside is the silent success this project keeps removing. A mutation entry proves the call cannot quietly disappear. Issue: #236 User-Visible: no --- demo/serve.mjs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/demo/serve.mjs b/demo/serve.mjs index 0b33df68..88a0af64 100644 --- a/demo/serve.mjs +++ b/demo/serve.mjs @@ -1,10 +1,14 @@ // Shared launcher for demo captures: starts headless Chromium serving demo/srv/ // via request interception (no HTTP server needed). Usage: const {page,browser}=await launch(); import { chromium } from 'playwright'; +import { assertFreshDemoBundleUnlessAllowed } from './bundle-freshness.mjs'; import { readFileSync, existsSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { dirname } from 'node:path'; const ROOT = dirname(fileURLToPath(import.meta.url)) + '/srv'; +// Корень репозитория, а не каталог раздачи: фингерпринт считается по +// src/** и demo/fixtures, которых внутри demo/srv нет (#236). +const REPO_ROOT = dirname(dirname(fileURLToPath(import.meta.url))); const CT = { '.html': 'text/html', '.js': 'text/javascript', '.svg': 'image/svg+xml' }; // ---- assertion harness (audit T1) -------------------------------------- // Until 2026-07-27 the smokes printed booleans and always exited 0: a broken @@ -64,6 +68,14 @@ export async function launch( }); await page.goto('http://demo.local/demo.html', { waitUntil: 'domcontentloaded' }); await page.waitForFunction(() => window.__card?._model?.length > 0, { timeout: 9000 }); + // Свежесть бандла проверяется здесь, а не в каждом смоке (#236). Смок читает + // demo/srv/assets/houseplan-card.js; если туда не скопирован свежий dist, + // проверяется прежняя версия карточки — и результат выглядит осмысленным, + // потому что часть проверок краснеет, а часть зеленеет. На #234 это стоило + // круга разбора: три проверки упали, четвёртая ложно прошла, поскольку старый + // код одинаково врал в двух местах, которые сверялись друг с другом. + // golden и бенчмарки эту защиту имели с самого начала, смоки — нет. + await assertFreshDemoBundleUnlessAllowed(page, REPO_ROOT); // HP-1552: the first-open boot veil hides the plan (visibility:hidden) until // the stage height settles — real pointer interaction cannot hit a hidden // plan, so every smoke starts where the user does: with the plan revealed.