From a2e6184d3b9629ac41ed145ae262b1f2ccd6fa59 Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Tue, 29 Sep 2026 12:22:04 +0000 Subject: [PATCH] check:poster-print-fallback asserts the outcome: the source loaded and a print frame opened A poison run answered 404 to posters/.html for the browser only, and the gate still PASSED. It counted the .html REQUEST, and its failure pattern (not available|failed|blank|error) never matched what the wall then shows, "poster not found (404)"; the HUD reader did not even collect that text. So it could not fail on the one path it exists for. It now requires the .html to ANSWER 200 and a print frame to actually OPEN (counted at creation with the appendChild hook the degrade gate already uses, since the frame removes itself after printing). "not found" is read as the failure it is, in the HUD reader, the poll and the verdict. Its output reports both outcomes. The browser runs are rega's: the positive arm must still pass, and the 404'd source must now fail. --- internal/check-poster-print-fallback.mjs | 38 ++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/internal/check-poster-print-fallback.mjs b/internal/check-poster-print-fallback.mjs index 968a13c3a..e2588595c 100644 --- a/internal/check-poster-print-fallback.mjs +++ b/internal/check-poster-print-fallback.mjs @@ -124,9 +124,18 @@ page.on('pageerror', (e) => errs.push(String(e).slice(0, 140))) // when that generator cannot load (a policy that refuses both the blob and the classic // script, a failed integrity check, a print while offline), so the generator is blocked // too, and the .html is the one way through. +// ★ ASSERT THE OUTCOME, NOT THE REQUEST (2026-09-29). A poison run answered 404 to posters/.html +// for the browser only, and this gate still PASSED: it counted the REQUEST, and its failure pattern did +// not match what the wall then says ("poster not found (404)"). So it could not fail on the one path it +// exists for. It now requires the .html to ANSWER 200, a print frame to actually OPEN (counted at +// creation, the degrade gate's technique), and reads "not found" as the failure it is. let webpBlocked = 0 let htmlServed = 0 +let htmlOk = 0 +let printFrames = 0 let generatorBlocked = 0 +page.on('response', (r) => { if (/\/posters\/[^/?]+\.html(\?|$)/.test(r.url()) && r.status() === 200) htmlOk += 1 }) +await page.exposeFunction('__notePrintFrame', () => { printFrames += 1 }) await page.route('**/posters/*.webp', (route) => { webpBlocked += 1; route.abort() }) await page.route('**/posters/*.html', (route) => { htmlServed += 1; route.continue() }) await page.route(/\/lib\/poster-render(\.global)?\.js(\?|$)/, (route) => { generatorBlocked += 1; route.abort() }) @@ -147,6 +156,18 @@ await page.waitForTimeout(8000) await page.evaluate(() => { window.__HUD = [] window.print = () => {} + // Count print frames AT CREATION: the frame self-removes on afterprint, so polling finds none. + const realAppend = Node.prototype.appendChild + Node.prototype.appendChild = function (n) { + const r = realAppend.call(this, n) + try { + if (n && n.tagName === 'IFRAME') { + window.__notePrintFrame() + try { n.contentWindow.print = () => {} } catch { /* cross-realm */ } + } + } catch { /* never break the page to observe it */ } + return r + } const walk = (root, out = []) => { for (const el of root.querySelectorAll('*')) { out.push(el); if (el.shadowRoot) walk(el.shadowRoot, out) } return out @@ -154,7 +175,7 @@ await page.evaluate(() => { window.__readHud = () => walk(document) .filter((e) => e.childElementCount === 0 && e.tagName !== 'SCRIPT' && e.tagName !== 'STYLE') .map((e) => (e.textContent || '').trim()) - .filter((t) => t && /generating|preparing|saving|not available|failed|blank|error/i.test(t)) + .filter((t) => t && /generating|preparing|saving|not found|not available|failed|blank|error/i.test(t)) setInterval(() => { for (const t of window.__readHud()) if (!window.__HUD.includes(t)) window.__HUD.push(t) }, 120) }) @@ -198,7 +219,7 @@ if (clicked.ok) { hud = await page.evaluate(() => window.__HUD || []) // Terminal states: an explicit failure, or "generating" seen AND no longer showing. const live = await page.evaluate(() => window.__readHud()) - const failing = hud.some((t) => /not available|failed|blank|error/i.test(t)) + const failing = hud.some((t) => /not found|not available|failed|blank|error/i.test(t)) const generated = hud.some((t) => /generating/i.test(t)) if (failing) { settled = true; break } if (generated && !live.some((t) => /generating|preparing|saving/i.test(t))) { settled = true } @@ -219,8 +240,8 @@ if (hud.some((t) => /Poster not available yet/i.test(t))) { fails.push('the print preview opened on "Poster not available yet" — the old behaviour: ' + 'the .webp 404ed and the rasterise fallback did not run') } -if (hud.some((t) => /not available|failed|blank|error/i.test(t))) { - fails.push(`the print path ended in an error state: ${JSON.stringify(hud.filter((t) => /not available|failed|blank|error/i.test(t)))}`) +if (hud.some((t) => /not found|not available|failed|blank|error/i.test(t))) { + fails.push(`the print path ended in an error state: ${JSON.stringify(hud.filter((t) => /not found|not available|failed|blank|error/i.test(t)))}`) } // With EVERY .webp aborted, a clean run is only possible via the rasteriser — so the // "generating the poster" phase MUST have been entered. Its absence means the preview @@ -238,13 +259,20 @@ if (webpBlocked === 0) { } if (htmlServed === 0) { fails.push('no posters/*.html was fetched — the rasterise fallback never ran') +} else if (htmlOk === 0) { + // THE OUTCOME, not the attempt: requested is not loaded, and a 404 source rasterises nothing. + fails.push(`posters/*.html was requested ${htmlServed} time(s) but never answered 200 — the fallback had no source to rasterise`) +} +if (clicked.ok && printFrames === 0) { + fails.push('no print frame opened — the print path never reached the dialog, so nothing was printed') } if (errs.length) fails.push(`${errs.length} page error(s): ${errs[0]}`) console.log('POSTER-PRINT-FALLBACK') console.log(` wall : ${WALL}`) console.log(` .webp requests : ${webpBlocked} (all aborted — the default-drop condition)`) -console.log(` .html requests : ${htmlServed}`) +console.log(` .html requests : ${htmlServed} (${htmlOk} answered 200)`) +console.log(` print frames : ${printFrames}`) console.log(` generator : ${generatorBlocked} request(s) aborted${generatorBlocked ? '' : ' (this wall generated nothing first)'}`) console.log(` print button : ${clicked.ok ? 'found and clicked' : 'NOT FOUND'}`) console.log(` HUD : ${hud.length ? JSON.stringify(hud) : '(nothing)'}`)