doxa-maps/internal/check-mapbox-drew.mjs
Doxa Maps 7d1ed8a4fc Assert that MAPBOX drew, which nothing measured
RT8 goal (b). Two gates already touch the engine and neither asserts this:
check-leaf-engine-per-provider proves MAPLIBRE purity (zero *.mapbox.com
requests under ?provider=maplibre) and that a map still draws, but never forces
Mapbox; check-provider-switch does load ?provider=mapbox — with a FAKE token, so
the engine LOADING was measured and a tile RENDERING never was, on one leaf.

So "Mapbox works" was unmeasured across the seven production tabs. This measures
it, and refuses to pretend when it cannot.

WHAT IT READS, and why each is the stronger property:
  · THE ENGINE off the canvas that drew — .mapboxgl-canvas vs .maplibregl-canvas
    — never from which globals exist. A leaf asked for Mapbox that quietly draws
    with MapLibre looks identical to success in a screenshot and passes every
    paint check; a peer script that merely loaded Mapbox proves nothing.
  · THAT IT DREW via queryRenderedFeatures() > 0. A canvas at the right size is
    not a map: this repo already had a country map render fully blank while "a
    real GL canvas exists at 1200x780" passed.

THREE EXIT STATES, BECAUSE TWO WOULD FORCE A LIE. On this sandbox the Mapbox
/v4/ composite raster endpoint and country-boundaries both 403 — proven outside
the browser with no Referer, with 127.0.0.1 and with localhost, so it is tileset
ENTITLEMENT, not the embed (PRODUCTION-MATRIX:235). Failing on that would
manufacture work for every owner; passing on it would be false. It exits 75 NOT
MEASURED and names the endpoint. No token, or a non-pk. token, is also 75 — a
fake token is exactly the false green this gate exists to refuse.

THE NEGATIVE ARM is in the same file: ?provider=maplibre must draw with MapLibre.
If it does not, the engine check cannot tell the engines apart and every pass
above it is unfalsifiable.

★ TARGETS COME FROM THE MANIFEST, AND SELECTING ON isMap ALONE LOST A TAB.
Measured: it found 6 of the 7 curated tabs. research-map-plus-grid (Simple
Research) is a nested-elements-mfe with isMap:false whose CHILD holds the map, so
it would have been skipped in silence — the exact class of miss this gate is
meant to catch. A composed tab now counts if it is isMap ITSELF or composes a
profile that is: 7 of 7.

Registered in package.json (script + description) and in verify-browser-all's
GATES array — deliberately NOT gates:pre, because it needs the browser seat.
Verified by re-reading the parsed package.json, and check:no-orphan-gates names
only the pre-existing check-gospel-whiteboard.mjs, not this.
2026-09-29 00:26:56 +00:00

175 lines
10 KiB
JavaScript

#!/usr/bin/env node
/**
* check-mapbox-drew — the Mapbox engine actually DREW, on every production leaf.
*
* ★ THE HOLE THIS FILLS (regions, RT8 goal b). Two gates already touch the engine and neither
* asserts this one thing:
* check-leaf-engine-per-provider proves MAPLIBRE purity (zero *.mapbox.com requests under
* ?provider=maplibre) and that a map still draws. It never forces
* Mapbox.
* check-provider-switch does load ?provider=mapbox — but with a FAKE token, so it proves
* the ENGINE LOADS, not that a single tile rendered. One leaf.
* So "Mapbox works" was never measured on the seven production maps. This measures it.
*
* ★ A SILENT FALLBACK IS THE FAILURE WORTH CATCHING. A leaf asked for Mapbox that quietly draws with
* MapLibre looks perfect in a screenshot and passes every paint check. So the ENGINE is read off the
* canvas that drew (.mapboxgl-canvas vs .maplibregl-canvas), never from which globals exist — a peer
* script that merely loaded Mapbox proves nothing.
*
* ★ AND A CANVAS AT THE RIGHT SIZE IS NOT A MAP. This repo learned that the hard way: a country map
* rendered fully blank while "a real GL canvas exists at 1200x780" passed. So drawing is asserted
* with queryRenderedFeatures() > 0 on the leaf's own rendered features, not by canvas geometry.
*
* ★ THREE EXIT STATES, BECAUSE TWO WOULD FORCE A LIE. On this sandbox the Mapbox /v4/ composite
* raster endpoint and country-boundaries both 403 — proven outside the browser with no Referer, with
* 127.0.0.1 and with localhost, so it is TILESET ENTITLEMENT, not the embed (PRODUCTION-MATRIX:235).
* Counting that as a failure would manufacture work for every owner; counting it as a pass would be
* false. It exits 75 NOT MEASURED instead, and says which endpoint.
*
* USAGE MAP_TOKEN=pk.… node internal/check-mapbox-drew.mjs [--dir <tree>] [--only a/b,c/d]
* Run through internal/browser-slot.sh — it needs the browser seat.
* @browser-slot-max-hold 1800
* EXIT 0 every measured leaf drew with Mapbox · 1 a real failure · 75 no token, or only
* entitlement 403s (nothing could be judged).
*/
import { chromium } from './lib/playwright-guarded.mjs'
import { createServer } from 'node:http'
import { spawn } from 'node:child_process'
import { readFileSync, existsSync } from 'node:fs'
import { resolve, dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { TREE_NAME } from './_tree-name.mjs'
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const argv = process.argv.slice(2)
const arg = (k, d) => { const i = argv.indexOf(k); return i >= 0 && argv[i + 1] ? argv[i + 1] : d }
const DIR = resolve(arg('--dir', resolve(ROOT, 'public')))
const ONLY = arg('--only', '') ? new Set(arg('--only', '').split(',')) : null
const TOKEN = process.env.MAP_TOKEN || ''
// ── 3. NO REAL TOKEN -> NOT MEASURED, never a pass and never a fail ───────────────────────────
if (!/^pk\./.test(TOKEN)) {
console.log('MAPBOX-DREW: NOT MEASURED — set MAP_TOKEN to a real pk.… token. A fake token loads the'
+ ' engine and renders nothing, which is exactly the false green this gate exists to refuse.')
process.exit(75)
}
const manifestPath = join(DIR, TREE_NAME, 'manifest.json')
if (!existsSync(manifestPath)) { console.log(`MAPBOX-DREW: NOT MEASURED — no ${manifestPath}`); process.exit(75) }
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
// ── 2. TARGETS FROM THE MANIFEST, never hardcoded: the curated production tabs ─────────────────
// The seven are whatever doxa-maps-spa composes. Reading it here means adding a production tab
// cannot silently escape this gate.
const spa = (manifest.bundles || []).find((b) => b.bundle === 'doxa-maps-spa')
const composed = new Set(((spa?.composes) || []).map(String))
const leaves = []
// ★ isMap IS FALSE ON A COMPOSITE WHOSE CHILD HOLDS THE MAP, and skipping on it would have lost a
// production tab silently. research-map-plus-grid (Simple Research) is type nested-elements-mfe with
// isMap:false and composes ['doxa-research-map', 'people-groups-grid'] — the MAP is the child. So a
// composed tab counts as a map leaf if it is isMap ITSELF or it composes a profile that is. Measured:
// selecting on isMap alone found 6 of the 7 curated tabs.
const profileIsMap = new Map()
for (const b of manifest.bundles || []) for (const p of b.profiles || []) profileIsMap.set(`${b.bundle}/${p.profile}`, !!p.isMap)
const composesAMap = (b, p) => ((b.composes || []).some((ref) => {
const r = String(ref)
return profileIsMap.get(r) || [...profileIsMap.keys()].some((k) => k.startsWith(`${r}/`) && profileIsMap.get(k))
}))
for (const b of manifest.bundles || []) for (const p of b.profiles || []) {
const id = `${b.bundle}/${p.profile}`
if (!composed.has(id)) continue // only the curated tabs
if (!p.isMap && !composesAMap(b, p)) continue // …that draw a map, directly or via a child
if (ONLY && !ONLY.has(id)) continue
if (existsSync(join(DIR, TREE_NAME, id, 'index.html'))) leaves.push(id)
}
if (!leaves.length) { console.log('MAPBOX-DREW: NOT MEASURED — no composed map leaf matched'); process.exit(75) }
async function serve(dir) {
const port = await new Promise((ok) => { const s = createServer().listen(0, '127.0.0.1', () => { const n = s.address().port; s.close(() => ok(n)) }) })
const srv = spawn(process.execPath, [resolve(ROOT, 'internal/serve-strict.mjs'), '--port', String(port), '--directory', dir], { stdio: 'ignore' })
await new Promise((r) => setTimeout(r, 600))
return { port, stop: () => { try { srv.kill() } catch (_) {} } }
}
// The endpoints known to 403 on the sandbox token. Entitlement, not the owner's bug.
const ENTITLEMENT = [/\/v4\//, /country-boundaries/]
async function measure(page, url, provider) {
const errs = []
const forbidden = []
page.on('pageerror', (e) => errs.push(String(e.message || e)))
page.on('response', (r) => { if (r.status() === 403 && /mapbox\.com/.test(r.url())) forbidden.push(r.url()) })
await page.addInitScript((tk) => { window.MAP_TOKEN = tk }, TOKEN)
await page.goto(`${url}?provider=${provider}`, { waitUntil: 'load', timeout: 45000 })
// Give the engine a real chance to paint before judging; a slow tile server is not a failure.
const drew = await page.waitForFunction(() => {
const deep = (root, out = []) => {
for (const el of root.querySelectorAll('*')) {
if (el.tagName === 'CANVAS') out.push(el)
if (el.shadowRoot) deep(el.shadowRoot, out)
}
return out
}
const c = deep(document).find((x) => x.width > 0 && x.height > 0)
if (!c) return null
const engine = c.classList.contains('mapboxgl-canvas') ? 'mapbox'
: c.classList.contains('maplibregl-canvas') ? 'maplibre' : 'other'
// The map instance this repo already publishes for gates to read.
const m = window.__rcmMap || window.__rdashMap || null
let features = -1
try { if (m && m.queryRenderedFeatures) features = m.queryRenderedFeatures().length } catch (_) { features = -1 }
return { engine, features }
}, { timeout: 30000 }).then((h) => h.jsonValue()).catch(() => null)
return { drew, errs, forbidden }
}
const cur = await serve(DIR)
const browser = await chromium.launch({ args: ['--use-gl=swiftshader', '--enable-webgl', '--ignore-gpu-blocklist'] })
const base = `http://127.0.0.1:${cur.port}/${TREE_NAME}`
const fails = []
const notMeasured = []
const passes = []
for (const id of leaves) {
const page = await browser.newPage()
const { drew, errs, forbidden } = await measure(page, `${base}/${id}/`, 'mapbox')
await page.close()
const entitlement = forbidden.filter((u) => ENTITLEMENT.some((re) => re.test(u)))
const otherForbidden = forbidden.filter((u) => !ENTITLEMENT.some((re) => re.test(u)))
if (!drew) { notMeasured.push(`${id}: no sized canvas appeared within 30s`); continue }
// ── 4. THE ENGINE. A silent fallback is the failure worth catching. ──
if (drew.engine !== 'mapbox') { fails.push(`${id}: asked for ?provider=mapbox and the canvas that drew is ${drew.engine.toUpperCase()} — a silent fallback`); continue }
if (otherForbidden.length) { fails.push(`${id}: 403 on ${otherForbidden[0]} — not the known entitlement endpoints`); continue }
// ── 5/6. DREW, or an entitlement 403 that makes it unjudgeable. ──
if (drew.features > 0) { passes.push(`${id}: mapbox canvas, ${drew.features} rendered feature(s)`); continue }
if (entitlement.length) { notMeasured.push(`${id}: 0 features and an entitlement 403 (${entitlement[0].replace(/\?.*/, '')}) — tileset, not the embed`); continue }
if (errs.length) { fails.push(`${id}: 0 rendered features, page error: ${errs[0].slice(0, 90)}`); continue }
fails.push(`${id}: mapbox canvas drew 0 rendered features, and no 403 explains it`)
}
// ── 8. THE NEGATIVE ARM. If the engine assertion cannot fail, a green above means nothing. ─────
let armOk = false
{
const page = await browser.newPage()
const { drew } = await measure(page, `${base}/${leaves[0]}/`, 'maplibre')
await page.close()
armOk = !!drew && drew.engine === 'maplibre'
}
if (!armOk) fails.push('NEGATIVE ARM BROKEN: ?provider=maplibre did not draw with MapLibre, so the engine'
+ ' check cannot distinguish the engines and every pass above is unfalsifiable')
await browser.close(); cur.stop()
for (const p of passes) console.log(` ✓ ${p}`)
for (const n of notMeasured) console.log(` · NOT MEASURED ${n}`)
for (const f of fails) console.error(` ✗ ${f}`)
// ── 9. THREE STATES ──
if (fails.length) { console.error(`MAPBOX-DREW: FAIL — ${fails.length} of ${leaves.length} leaf/leaves`); process.exit(1) }
if (!passes.length) { console.log(`MAPBOX-DREW: NOT MEASURED — nothing could be judged (${notMeasured.length} leaf/leaves blocked)`); process.exit(75) }
console.log(`MAPBOX-DREW: PASS — ${passes.length} of ${leaves.length} composed map leaf/leaves drew with Mapbox`
+ `${notMeasured.length ? `, ${notMeasured.length} not measurable on this token` : ''}; negative arm holds.`)