gate the blank-basemap class: 7 of 10 map bundles draw geography from Mapbox tiles only

Reading the cap-2 screenshots found all three doxa-simple-map shots rendering data dots
on an empty dark field: no coastlines, no country fills, no labels. Every shot reported
OK, because the page loads, the element mounts, and the legend, controls and data layer
are all correct.

The reason no signal can see it: the Mapbox STYLE DOCUMENT returns 200 from every origin,
so the map genuinely boots. Only the TILESETS are restricted — mapbox-streets-v8, which
is the basemap itself, plus bathymetry-v2 and country-boundaries-v1, all 403 off
doxa.life and 200 with its referer. A booted map showing its own UI and its own data
looks like a working map; only the geography is absent.

This also explains a near-misdiagnosis. cap4-upg100-list paints perfectly beside four
blank maps, which looked like a per-bundle bug. It is not: my-upg-100-list ships its own
world-adm0.geojson and draws geography from self-hosted data. Three bundles do that and
survive; seven do not.

The dark basemap in those shots is deliberate, not a theme violation — useMapTheme's
lookForStrategy keeps prayer, adoption and engagement on the night preset by design.

Negative-tested: marking every affected bundle as self-hosted removes the finding, and
removing the markers brings it back.
This commit is contained in:
doxa-maps-88655c70 2026-09-21 11:46:36 +00:00
parent dfe6c3d1fa
commit 029cffc01f

View file

@ -110,9 +110,59 @@ function restrictedTilesetFiles() {
return out
}
/**
* Map bundles whose BASEMAP comes only from Mapbox tiles — i.e. that render a blank void when
* the token cannot fetch tilesets from this origin.
*
* ★ THE THIRD FIDELITY CLASS, and the widest (measured 2026-09-21 by looking at cap2-*.png).
* All three doxa-simple-map shots show data dots floating on an empty dark field: no coastlines,
* no country fills, no labels. `bun run shots` reported OK for every one — the page loads, the
* element mounts, the legend and controls paint, the data layer is correct.
*
* ★ WHY IT IS INVISIBLE TO EVERY OTHER SIGNAL: the Mapbox STYLE DOCUMENT returns 200 from every
* origin, so the map genuinely initialises. Only the TILESETS are restricted —
* mapbox-streets-v8 (the basemap itself), mapbox-bathymetry-v2, country-boundaries-v1 all return
* 403 off doxa.life and 200 with its referer. A booted map showing its own UI and its own data
* looks like a working map; only the GEOGRAPHY is absent.
*
* ★ AND IT EXPLAINS A NEAR-MISDIAGNOSIS worth keeping: cap4-upg100-list.png paints coastlines and
* country fills perfectly, which made the blank cap-2 maps look like a per-bundle bug. It is not —
* my-upg-100-list SHIPS ITS OWN world-adm0.geojson and draws geography from self-hosted data
* instead of tiles. Three bundles do that and survive; the other eight do not.
*
* NOTE the dark basemap in those shots is DELIBERATE, not a theme violation: useMapTheme's
* lookForStrategy() keeps prayer/adoption/engagement on the night preset by design ("light and
* darkness"), and only affinity/region/language go light. The missing TILES are the defect.
*/
function tileDependentMapBundles() {
const dir = join(ROOT, 'plugin-designs')
if (!existsSync(dir)) return []
const out = []
for (const e of readdirSync(dir, { withFileTypes: true })) {
if (!e.isDirectory() || /^[_.]/.test(e.name)) continue
const bdir = join(dir, e.name)
let usesMap = false, selfHosted = false
const scan = (d) => {
for (const f of readdirSync(d, { withFileTypes: true })) {
if (/^(node_modules|[_.])/.test(f.name)) continue
const p = join(d, f.name)
if (f.isDirectory()) { scan(p); continue }
if (!/\.(vue|js|mjs)$/.test(f.name)) continue
const src = readFileSync(p, 'utf8')
if (/useMapInstance|mapbox-gl|bootStyle/.test(src)) usesMap = true
if (/adm0/.test(src)) selfHosted = true
}
}
scan(bdir)
if (usesMap && !selfHosted) out.push(e.name)
}
return out
}
const bundles = emojiBundles()
const fonts = emojiFontCount()
const tilesetFiles = restrictedTilesetFiles()
const tileBundles = tileDependentMapBundles()
const findings = [] // every condition reports; no early exit hides a later one
console.log(`SHOT-FIDELITY: ${bundles.length} bundle(s) render emoji; emoji fonts on this box: ` +
@ -124,6 +174,23 @@ if (fonts === null) {
console.log(' i fc-list not available — cannot verify glyph coverage. Screenshots UNASSESSED.')
}
if (tileBundles.length) {
findings.push([
'',
'SHOT-FIDELITY: these map bundles draw their GEOGRAPHY from Mapbox tiles only, so they shoot',
'as a blank void when the token cannot fetch tilesets from this origin:',
` ${tileBundles.join(', ')}`,
'',
' Measured: the STYLE document returns 200 everywhere (so the map boots, the legend and',
' controls paint, the data layer is correct) while mapbox-streets-v8 / bathymetry-v2 /',
' country-boundaries-v1 all return 403 off doxa.life. A booted map showing its own UI and',
' its own data looks like a working map — only the coastlines and country fills are gone.',
'',
' Bundles that ship their own world-adm0.geojson are UNAFFECTED, which is why one cap-4 shot',
' looks perfect beside four blank ones. That contrast is a red herring, not a per-bundle bug.',
].join('\n'))
}
if (tilesetFiles.length) {
findings.push([
'',
@ -132,8 +199,8 @@ if (tilesetFiles.length) {
'',
' The shared pk. token is URL-restricted. Measured against country-boundaries-v1:',
' Referer doxa.life -> 200 (3/3) · 127.0.0.1 -> 403 · no referer -> 403',
' The STYLE endpoint returns 200 from every origin, so MOST maps paint here and only the',
' tileset-backed choropleth blanks — which is why this looked like "that surface has no map".',
' The STYLE endpoint returns 200 from every origin, so every map BOOTS and only the TILES are',
' missing — which is why this first looked like "that surface has no map".',
'',
' ★ It is NOT a missing tileset scope (re-tested with the doxa.life referer, which passes)',
' and NOT a code defect. Either shoot these panes from an allowed origin, or add the shot',