From a9214695f4dae55a505f421d50667a4e49ee1ed0 Mon Sep 17 00:00:00 2001 From: doxa-maps-88655c70 <88627970+doxa-maps-88655c70@users.noreply.github.com> Date: Thu, 24 Sep 2026 04:03:47 +0000 Subject: [PATCH] test(packet): a declared @font-face must actually load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some languages need a face the system stack does not carry — Hindi renders as tofu boxes in Georgia/Palatino/serif. When the packet declares one, a failed @font-face is SILENT: the text is present, the strings compare equal, every other assertion stays green, and the page prints as empty rectangles. The gate now asserts every declared face reaches status "loaded". Confirmed to fire before being accepted: corrupting the inlined base64 reports 'Noto Serif Devanagari:error — text in that script will print as empty boxes'. ★ THIS ASSERTS THE MECHANICAL HALF ONLY, deliberately. A general tofu detector was attempted twice and abandoned, and the attempts are worth recording: - comparing shaped width against a deliberately-missing font FALSE-POSITIVES on every system-covered script, because Cyrillic, CJK and Arabic legitimately measure the same in both stacks when both resolve to the same system font; - an ink-column-profile heuristic scored CORRECTLY RENDERED Devanagari the same as tofu (3 vs 2 distinct column heights), because its baseline bar gives a uniform profile. Both would have blocked correct Arabic, Chinese, Russian and Hindi packets. A detector that fails working output is worse than no detector, so glyph correctness stays a human reading a screenshot, and the gate covers what it can check without lying. --- internal/check-packet-render.mjs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/internal/check-packet-render.mjs b/internal/check-packet-render.mjs index 6a0173efd..2291be92f 100644 --- a/internal/check-packet-render.mjs +++ b/internal/check-packet-render.mjs @@ -58,6 +58,24 @@ const lang = await page.evaluate(() => document.documentElement.lang || 'en') // the bug it is, and no other assertion here would notice. const RTL = new Set(['ar', 'he', 'fa', 'ur', 'ps', 'sd', 'yi']) const dir = await page.evaluate(() => document.documentElement.dir || 'ltr') +// SCRIPT FONT. Some languages need a face the system stack does not carry — Hindi +// renders as tofu boxes in Georgia/Palatino/serif. When the packet declares one, +// it must actually LOAD; a declared-but-failed @font-face is silent, and the page +// then prints as empty rectangles with every other assertion still green. +// +// ⚠ This asserts the FONT LOADED, not that glyphs are correct. A general tofu +// detector was attempted and abandoned: comparing shaped width against a missing +// font false-positives on every system-covered script (Cyrillic, CJK, Arabic all +// legitimately measure the same in both stacks), and an ink-profile heuristic +// scored CORRECTLY-RENDERED Devanagari the same as tofu, because its baseline bar +// gives a uniform column profile. A detector that blocks working packets is worse +// than none. Read the pixels for that; this covers the mechanical half. +const fontStatus = await page.evaluate(async () => { + await document.fonts.ready + const faces = [...document.fonts] + return { declared: faces.length, loaded: faces.filter((f) => f.status === 'loaded').length, + names: faces.map((f) => `${f.family}:${f.status}`) } +}) // The catalog sits beside the generator that produced this packet, so derive it // from the packet's own path rather than hardcoding a machine-specific location. const catalogPath = process.env.PACKET_STRINGS @@ -145,6 +163,10 @@ if (r.rhythms !== r.rhythmsTotal) fails.push(`only ${r.rhythms}/${r.rhythmsTotal if (!r.hasMark5) fails.push('Mark 5:1-20 is NOT printed in full (Driver requirement for point 4)') if (r.metacamp !== 2) fails.push(`${r.metacamp} metacamp.org attributions, expected exactly 2`) if (r.mapFaults.length) fails.push(`map: ${r.mapFaults.join('; ')}`) +if (fontStatus.declared && fontStatus.loaded !== fontStatus.declared) { + fails.push(`a declared @font-face did not load (${fontStatus.names.join(', ')}) — ` + + 'text in that script will print as empty boxes') +} if (RTL.has(lang) && dir !== 'rtl') fails.push(`lang="${lang}" is right-to-left but dir="${dir}"`) if (!RTL.has(lang) && dir === 'rtl') fails.push(`lang="${lang}" is not RTL but dir="rtl"`) if (translated === 0) { @@ -162,6 +184,7 @@ console.log(` Mark 5 in full : ${r.hasMark5}`) console.log(` metacamp.org : ${r.metacamp}`) console.log(` map : ${r.mapFaults.length ? r.mapFaults.join('; ') : 'palette resolves, not black'}`) console.log(` page size : ${boxes[0] ? boxes[0].join(' x ') : '?'} pt`) +console.log(` script font : ${fontStatus.declared ? fontStatus.names.join(', ') : 'system stack'}`) console.log(` language : ${lang} (dir=${dir}) (${r.rhythms}/${r.rhythmsTotal} rhythms in ${lang}` + `${translated === null ? '' : `, ${translated} strings translated`})`)