poster cards: assert the preview's alt, which is the card's only name
Some checks are pending
build-gate / build (push) Waiting to run
Some checks are pending
build-gate / build (push) Waiting to run
MEASURED while sweeping my own gates for the count-only pattern: a poster card's
TEXT reads "116 UPG · Show on map" — a count and an action, no zone. The
identity lives entirely in the image's alt ("Northwest India — prayer poster…").
So the wall is CORRECT AS BUILT — all 27 previews carry a descriptive alt, and
sighted and screen-reader readers both learn which poster is which. No defect.
But that alt was doing load-bearing work nothing asserted: remove it and the
wall becomes 27 anonymous pictures for a screen-reader user while every
geometry, clipping, hover and reachability assertion here stays green.
★ I ALMOST ASSERTED THE WRONG THING. The obvious move on seeing "no zone name in
the card text" is to require one. That would have been me inventing a
requirement nobody stated — the same line I drew on the card-stock labels and
the UUPGs header. Measuring first showed the identity was already there, in the
attribute rather than the text, so the right assertion protects what exists
instead of mandating what I would have preferred.
MUTATION-TESTED: emptying the alt binding fails all 15 width x locale
combinations with "27 poster preview(s) have no alt text", exit 1. Restored,
gate green, SRI consistent.
This commit is contained in:
parent
4046abd551
commit
e32034039d
7 changed files with 23 additions and 11 deletions
|
|
@ -202,7 +202,7 @@ async function measure(width, lang) {
|
|||
const cards = all.filter((e) => (e.className||'').toString().split(' ').includes('card')).filter(vis)
|
||||
const boxes = cards.map((c) => ({ c, b: c.getBoundingClientRect() }))
|
||||
let intrusions = 0, overflowing = 0, worst = 0, coveringPreview = 0, worstY = 0
|
||||
let previewsPainted = 0, previewsBroken = 0, noPreview = 0
|
||||
let previewsPainted = 0, previewsBroken = 0, noPreview = 0, unnamedPreview = 0
|
||||
for (const { c, b } of boxes) {
|
||||
const row = c.querySelector('.pfs')
|
||||
if (!row) continue
|
||||
|
|
@ -227,6 +227,12 @@ async function measure(width, lang) {
|
|||
// one 3926px down an 844px viewport, and ZERO failing HTTP responses. A first version of this
|
||||
// assertion called that 18 broken images. Deferred is not broken; only an in-viewport image
|
||||
// that never painted is.
|
||||
// ★ THE ALT IS THE CARD'S ONLY NAME. MEASURED 2026-09-25: a card's TEXT reads
|
||||
// "116 UPG·Show on map" — a count and an action, no zone. The identity lives in the image's
|
||||
// alt ("Northwest India — prayer poster…"), which all 27 carry. So the wall is correct as
|
||||
// built, and that alt is doing load-bearing work NOTHING asserted: remove it and a
|
||||
// screen-reader user meets 27 anonymous pictures while every check here stays green.
|
||||
if (img && !(img.getAttribute('alt') || '').trim()) unnamedPreview++
|
||||
if (!img) noPreview++
|
||||
else {
|
||||
const ib2 = img.getBoundingClientRect()
|
||||
|
|
@ -288,7 +294,7 @@ async function measure(width, lang) {
|
|||
}
|
||||
return { cards: cards.length, rows: cards.filter((c) => c.querySelector('.pfs')).length,
|
||||
overflowing, worst, intrusions, coveringPreview, worstY,
|
||||
previewsPainted, previewsBroken, noPreview, clipped: clipped.length,
|
||||
previewsPainted, previewsBroken, noPreview, unnamedPreview, clipped: clipped.length,
|
||||
controls: ctrls.length, tiny: tiny.length, perRow, cardW }
|
||||
})()`)
|
||||
await page.close()
|
||||
|
|
@ -346,6 +352,12 @@ for (const r of results) {
|
|||
// THE PREVIEW MUST ACTUALLY BE THERE. A card with no image passes every geometry assertion
|
||||
// above trivially — nothing can overlap what does not render. Driver 2026-09-24: "it is supposed
|
||||
// to show the previews".
|
||||
if (r.unnamedPreview) {
|
||||
fails.push(`${at}: ${r.unnamedPreview} poster preview(s) have no alt text — the card's own text `
|
||||
+ 'is a count and an action ("116 UPG · Show on map"), so the alt is the ONLY thing naming '
|
||||
+ 'which poster this is. Without it a screen-reader user meets an anonymous picture, and '
|
||||
+ 'every geometry assertion here still passes.')
|
||||
}
|
||||
if (r.previewsBroken) {
|
||||
fails.push(`${at}: ${r.previewsBroken} preview image(s) failed to load (naturalWidth 0) — `
|
||||
+ 'a broken preview is not something the geometry checks can see')
|
||||
|
|
|
|||
2
public/doxa-maps/index.html
generated
2
public/doxa-maps/index.html
generated
File diff suppressed because one or more lines are too long
8
public/doxa-maps/manifest.json
generated
8
public/doxa-maps/manifest.json
generated
|
|
@ -681,7 +681,7 @@
|
|||
"bundle": "my-upg-100-list",
|
||||
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
|
||||
"output": "doxa-maps/my-upg-100-list/my-upg-100-list.js",
|
||||
"integrity": "sha384-U/2QjOxuZgh3qDjndls1kpI2DfYMCsQODBSgXYhWMFrt6kACquiu6+ZXja0Okr0J",
|
||||
"integrity": "sha384-ep76LkuPyJeFgArqsscDmCVlXnx4efDXp7txdVkBRXp74sT89dr+Tgdv/HUKsI/F",
|
||||
"elements": [
|
||||
"my-upg-100-list-map"
|
||||
],
|
||||
|
|
@ -701,7 +701,7 @@
|
|||
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./my-upg-100-list/poster-wall/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-U/2QjOxuZgh3qDjndls1kpI2DfYMCsQODBSgXYhWMFrt6kACquiu6+ZXja0Okr0J\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-ep76LkuPyJeFgArqsscDmCVlXnx4efDXp7txdVkBRXp74sT89dr+Tgdv/HUKsI/F\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -715,7 +715,7 @@
|
|||
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./my-upg-100-list/upg-100-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-U/2QjOxuZgh3qDjndls1kpI2DfYMCsQODBSgXYhWMFrt6kACquiu6+ZXja0Okr0J\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-ep76LkuPyJeFgArqsscDmCVlXnx4efDXp7txdVkBRXp74sT89dr+Tgdv/HUKsI/F\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -729,7 +729,7 @@
|
|||
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
|
||||
"embed": {
|
||||
"iframe": "<iframe src=\"./my-upg-100-list/upg-100-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-U/2QjOxuZgh3qDjndls1kpI2DfYMCsQODBSgXYhWMFrt6kACquiu6+ZXja0Okr0J\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
|
||||
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-ep76LkuPyJeFgArqsscDmCVlXnx4efDXp7txdVkBRXp74sT89dr+Tgdv/HUKsI/F\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <my-upg-100-list-map> custom element. -->
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-U/2QjOxuZgh3qDjndls1kpI2DfYMCsQODBSgXYhWMFrt6kACquiu6+ZXja0Okr0J" crossorigin="anonymous"></script>
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-ep76LkuPyJeFgArqsscDmCVlXnx4efDXp7txdVkBRXp74sT89dr+Tgdv/HUKsI/F" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <my-upg-100-list-map> custom element. -->
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-U/2QjOxuZgh3qDjndls1kpI2DfYMCsQODBSgXYhWMFrt6kACquiu6+ZXja0Okr0J" crossorigin="anonymous"></script>
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-ep76LkuPyJeFgArqsscDmCVlXnx4efDXp7txdVkBRXp74sT89dr+Tgdv/HUKsI/F" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
|
||||
<!-- Bundle IIFE — registers the <my-upg-100-list-map> custom element. -->
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-U/2QjOxuZgh3qDjndls1kpI2DfYMCsQODBSgXYhWMFrt6kACquiu6+ZXja0Okr0J" crossorigin="anonymous"></script>
|
||||
<script src="../my-upg-100-list.js" integrity="sha384-ep76LkuPyJeFgArqsscDmCVlXnx4efDXp7txdVkBRXp74sT89dr+Tgdv/HUKsI/F" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
Loading…
Reference in a new issue