test(packet): a declared @font-face must actually load
Some checks are pending
build-gate / build (push) Waiting to run

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.
This commit is contained in:
doxa-maps-88655c70 2026-09-24 04:03:47 +00:00
parent 467b7f01a2
commit a9214695f4

View file

@ -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`})`)