packet gate: a map one-pager with no map on it is not a map one-pager
Some checks are pending
build-gate / build (push) Waiting to run
Some checks are pending
build-gate / build (push) Waiting to run
Deleting the map svg from page 1 entirely left this gate reporting
"map: palette resolves, not black — PASS, map painted".
mapFaults queried `document.querySelector('.sheet svg')` — the first svg
ANYWHERE in the document. With page 1 empty the query silently retargeted to the
PRAYER WHEEL's svg two sheets later, and the wheel has no CSS variables to leave
unresolved and no black fills, so both checks passed vacuously. The sheet count
stayed 8 because the empty sheet still exists.
A fallback selector turns an absence into a pass: when the thing being asserted
about disappears, the query finds a different object that happens to satisfy the
checks — and here the gate printed a stronger claim than it had evidence for.
"page 1 = map one-pager" is the first line of the packet spec.
Now scoped to sheet 0, which the page order fixes as the map page. And it
asserts the map paints GEOGRAPHY, because palette-resolves and not-black are
both properties a map with zero country shapes satisfies perfectly. Geography is
paths whose `d` exceeds 200 chars — a coastline, not an icon. The floor of 5 is
set from a measured spread rather than guessed: laos 13, brazil 18,
middle-east-core 55, tibet 69, uncovered-scatter 74, varying with how many
countries a zone spans.
Mutation-tested in three shapes: no svg fails naming page 1; an svg present but
drawing nothing fails at "only 0 geography path(s)"; the good packet passes at
13. All 11 locales report 13 — the map is data, not text.
Syncing the gate surfaced a second thing. doxa-maps-plugin-studio ships 0 poster
html files against wt-packet's 28, and packet.mjs deliberately "still builds
(cover page without the map) rather than failing" when out/posters/<zone>.html is
absent. That soft-fail is intentional but it was invisible: the degraded packet
has 8 sheets, an <svg> present (the wheel's), and no marker at all, so it is
structurally indistinguishable from a good one while page 1 promises a map and
delivers an empty sheet. PACKET_EXPECT_MAP=0 follows the PACKET_EXPECT_PHOTOS
precedent — fail by default with the remedy named, pass when the degradation is
declared.
Also fixed the summary line, which read "map painted" unconditionally and so
described a declared map-less packet as having a painted map. It now reads
"NO map (declared)". The summary is the part a reader quotes.
i18n verified with a 2-key partial block: page 1 renders the translated keys,
falls back to English elsewhere, 0 blank runs. Wave 34/34, packets-all 11/11.
This commit is contained in:
parent
c4a6d628b4
commit
d561e35d33
1 changed files with 60 additions and 5 deletions
|
|
@ -163,9 +163,33 @@ const r = await page.evaluate(() => {
|
|||
|
||||
// Whole-map property, NOT one sampled element — see header note 2.
|
||||
const mapFaults = (() => {
|
||||
const svg = document.querySelector('.sheet svg')
|
||||
if (!svg) return ['no map svg found']
|
||||
// ⚠ SCOPE TO PAGE 1. This was `document.querySelector('.sheet svg')` — "the first svg
|
||||
// ANYWHERE" — which is a FALLBACK SELECTOR, and a fallback selector turns an absence
|
||||
// into a pass. Measured 2026-09-24: deleting the map svg from page 1 entirely left this
|
||||
// gate reporting "map: palette resolves, not black — PASS, map painted", because the
|
||||
// query silently retargeted to the PRAYER WHEEL's svg two sheets later. The wheel has no
|
||||
// CSS variables to leave unresolved and no black fills, so both checks passed vacuously
|
||||
// while page 1 — "the map one-pager", the first line of the Driver's packet spec — was
|
||||
// blank. The sheet count stayed 8 because the empty sheet still exists.
|
||||
// The packet's page order is the product spec and does not vary: sheet 0 IS the map page.
|
||||
const sheet0 = document.querySelector('.sheet')
|
||||
const svg = sheet0 ? sheet0.querySelector('svg') : null
|
||||
if (!svg) return ['no map svg on page 1 — the map one-pager rendered without its map']
|
||||
const faults = []
|
||||
// ⚠ AND ASSERT IT PAINTS GEOGRAPHY. Palette-resolves + not-black are both properties a
|
||||
// map with ZERO country shapes satisfies perfectly. Geography is counted as paths whose
|
||||
// `d` is long enough to be a coastline rather than an icon or a chart tick. MEASURED
|
||||
// across zones: laos 13, brazil 18, middle-east-core 55 — it varies with how many
|
||||
// countries a zone spans, so the floor is well under the smallest rather than an exact
|
||||
// count. Zones whose groups do not resolve are SKIPPED by the generator and never reach
|
||||
// this gate ("europe: no groups resolved — skipped"), so a zero here is a real fault.
|
||||
const geoPaths = [...svg.querySelectorAll('path')]
|
||||
.filter((e) => (e.getAttribute('d') || '').length > 200).length
|
||||
if (geoPaths < 5) {
|
||||
faults.push(`only ${geoPaths} geography path(s) on the map page — the map one-pager is `
|
||||
+ 'blank or drew nothing but furniture (a correct palette and no black fills are both '
|
||||
+ 'satisfied by a map with no countries on it)')
|
||||
}
|
||||
const names = [...new Set((svg.outerHTML.match(/var\((--[a-z0-9-]+)/g) || []).map((v) => v.slice(4)))]
|
||||
const cs = getComputedStyle(svg)
|
||||
for (const n of names) if (!cs.getPropertyValue(n).trim()) faults.push(`unresolved ${n}`)
|
||||
|
|
@ -235,6 +259,14 @@ const r = await page.evaluate(() => {
|
|||
})(),
|
||||
metacamp: (body.match(/metacamp\.org/g) || []).length,
|
||||
mapFaults,
|
||||
// Printed beside the verdict: a reader should see the number the assertion rests on,
|
||||
// not just the word "painted".
|
||||
mapGeoPaths: (() => {
|
||||
const sheet0 = document.querySelector('.sheet')
|
||||
const svg = sheet0 ? sheet0.querySelector('svg') : null
|
||||
if (!svg) return -1
|
||||
return [...svg.querySelectorAll('path')].filter((e) => (e.getAttribute('d') || '').length > 200).length
|
||||
})(),
|
||||
// The per-page "{from}-{to} of {count}" headers, as DIGIT TRIPLES rather than text.
|
||||
// Read from the rendered DOM (not the source template) so what is checked is what a
|
||||
// reader would see. Locale digits are normalised to ASCII first: several catalogs
|
||||
|
|
@ -329,7 +361,24 @@ if (r.points !== POINTS_EXPECT) {
|
|||
+ 'carries its "12 Prayer Points" heading')
|
||||
}
|
||||
if (r.metacamp !== 2) fails.push(`${r.metacamp} metacamp.org attributions, expected exactly 2`)
|
||||
if (r.mapFaults.length) fails.push(`map: ${r.mapFaults.join('; ')}`)
|
||||
// THE MAP PAGE IS OPT-OUT-ABLE, THE SAME WAY THE PHOTOS ARE — and for the same reason.
|
||||
// packet.mjs lifts the map from out/posters/<zone>.html and, when that file is absent,
|
||||
// deliberately "still builds (cover page without the map) rather than failing". That soft
|
||||
// fail is intentional, but it is also INVISIBLE: measured 2026-09-24, a packet built with
|
||||
// no poster sources has 8 sheets and an <svg> present (the prayer wheel's) and carries no
|
||||
// marker at all, so it is structurally indistinguishable from a good one while page 1
|
||||
// promises a map one-pager and delivers an empty sheet. doxa-maps-plugin-studio ships 0
|
||||
// poster html files against wt-packet's 28, so every packet generated there is degraded
|
||||
// this way and nothing said so.
|
||||
// Default to FAILING, so the degradation has to be DECLARED rather than discovered.
|
||||
const expectMap = process.env.PACKET_EXPECT_MAP !== '0'
|
||||
if (r.mapFaults.length && expectMap) {
|
||||
fails.push(`map: ${r.mapFaults.join('; ')}`
|
||||
+ (r.mapGeoPaths === -1
|
||||
? ' — build the poster sources first (node library/scripts/posters/generate.mjs), or set '
|
||||
+ 'PACKET_EXPECT_MAP=0 to declare this a deliberately map-less packet'
|
||||
: ''))
|
||||
}
|
||||
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')
|
||||
|
|
@ -478,7 +527,9 @@ console.log(` wheel segments : ${r.wheelSegs} (${r.wheelLabels}/${WHEEL_LABE
|
|||
console.log(` Mark 5 in full : ${r.mark5Len} chars`
|
||||
+ `${scriptureIsEnglish ? ' ⚠ UNTRANSLATED (English fallback)' : ''}`)
|
||||
console.log(` metacamp.org : ${r.metacamp}`)
|
||||
console.log(` map : ${r.mapFaults.length ? r.mapFaults.join('; ') : 'palette resolves, not black'}`)
|
||||
console.log(` map (page 1) : ${r.mapFaults.length
|
||||
? `${r.mapFaults.join('; ')}${expectMap ? '' : ' [declared deliberate: PACKET_EXPECT_MAP=0]'}`
|
||||
: `${r.mapGeoPaths} geography paths, palette resolves, not black`}`)
|
||||
console.log(` page size : ${boxes[0] ? boxes[0].join(' x ') : '?'} pt`
|
||||
+ `${boxes.length ? ` (all ${boxes.length} pages, asserted US Letter)` : ''}`)
|
||||
console.log(` layout : ${r.cards} cards / ${PER_PAGE} per page `
|
||||
|
|
@ -494,4 +545,8 @@ if (fails.length) {
|
|||
for (const f of fails) console.error(` - ${f}`)
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(`\nPACKET-RENDER: PASS — ${r.sheets} sheets, ${r.sheets} pages, portrait, map painted, content intact.`)
|
||||
// ⚠ THE VERDICT MUST NOT CLAIM MORE THAN WAS CHECKED. It read "map painted" unconditionally,
|
||||
// so a packet passing under PACKET_EXPECT_MAP=0 — one with NO map on page 1 — was summarised
|
||||
// as having a painted map. The summary line is the part a reader actually quotes.
|
||||
console.log(`\nPACKET-RENDER: PASS — ${r.sheets} sheets, ${r.sheets} pages, portrait, `
|
||||
+ `${r.mapFaults.length ? 'NO map (declared)' : 'map painted'}, content intact.`)
|
||||
|
|
|
|||
Loading…
Reference in a new issue