Prove the grid-under-map link on both engines, not just the one we happened to run

BUILD-INTEROP-CONTRACT-GRID-UNDER-MAP-BOTH-PROVIDERS asks for a provider matrix:
the same assertions, once per engine, with identical counts. Interoperability
that holds on one provider and not the other is not interoperability.

It is not a formality here. The map half of this link resolves a religion family
through its own legend, and the legend is drawn by the map engine — MapLibre
drops an entire layer in silence for one misplaced paint property, which would
surface as a link delivering nothing while the Mapbox run stayed green.

So the gate now runs the whole measurement under ?provider=mapbox and
?provider=maplibre, and then asserts the two agree: the same starting total, the
same rows for the same family, and the same rows over the composite's wire. A
per-engine pass with different numbers would mean the same choice narrows to
different peoples depending on which engine a partner embedded.

MEASURED, identical to the row on both:

    mapbox     2,107 groups · Buddhism 83 direct · 83 linked · mutant 0
    maplibre   2,107 groups · Buddhism 83 direct · 83 linked · mutant 0

The mutant still runs first on each engine, so a green here still means the gate
can tell a right mapping from a wrong one — twice over now.
This commit is contained in:
Doxa Maps 2026-09-25 22:35:48 +00:00
parent 60477a29b1
commit 29fc335b00

View file

@ -82,9 +82,18 @@ await requireThisTree(TREE, ROOT, TAG)
const browser = await chromium.launch({ args: ['--enable-unsafe-swiftshader', '--use-gl=angle', '--use-angle=swiftshader'] })
const fails = []
const lines = []
// ★ THE PROVIDER MATRIX. The same assertions, run once per engine, because interoperability that
// holds on one provider and not the other is not interoperability
// (BUILD-INTEROP-CONTRACT-GRID-UNDER-MAP-BOTH-PROVIDERS). It is not a formality: the map half of
// this link resolves a religion family through its own legend, and the legend is drawn by the map
// engine — a MapLibre-only paint or layout mistake drops a whole layer silently, which would show
// up here as a link that delivers nothing while the Mapbox run stays green.
const PROVIDERS = ['mapbox', 'maplibre']
const results = {}
try {
for (const engine of PROVIDERS) {
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } })
await page.goto(LEAF, { waitUntil: 'domcontentloaded', timeout: 60000 })
await page.goto(`${LEAF}?provider=${engine}`, { waitUntil: 'domcontentloaded', timeout: 60000 })
// Everything below runs in ONE evaluate: the totals have to be read from the same live page, and
// a `groups-filtered` listener installed from Node would miss events fired between round trips.
@ -186,19 +195,38 @@ try {
return { unfiltered, family, letter, direct, linked, mutant, mapVocab, gridVocab: gridVocab.slice(0, 12) }
})
if (out.skip) { await browser.close(); cleanup(); skip(out.skip) }
if (out.fail) fails.push(out.fail)
else {
lines.push(` · vocabulary — the map names ${out.mapVocab.length} religion families, the grid names ${out.gridVocab.length}+; '${out.family}' is shared`)
lines.push(` · direct — religion-family="${out.family}" set on the grid itself: ${out.direct} of ${out.unfiltered}`)
lines.push(` · linked — the same family over the composite's wire: ${out.linked}`)
lines.push(` · mutant — the legend KEY '${out.letter}' over the same wire: ${out.mutant}`)
await page.close()
if (out.skip) { await browser.close(); cleanup(); skip(`${out.skip} (under ${engine})`) }
results[engine] = out
if (out.fail) { fails.push(`[${engine}] ${out.fail}`); continue }
if (out.mutant === out.direct) {
fails.push(`NO TEETH — sending the legend key '${out.letter}' narrowed the grid to the same ${out.direct} rows as the family name '${out.family}'. This gate cannot tell a right mapping from a wrong one, so its pass would mean nothing.`)
lines.push(` ── ${engine}`)
lines.push(` vocabulary — the map names ${out.mapVocab.length} religion families, the grid names ${out.gridVocab.length}+; '${out.family}' is shared`)
lines.push(` direct — religion-family="${out.family}" set on the grid itself: ${out.direct} of ${out.unfiltered}`)
lines.push(` linked — the same family over the composite's wire: ${out.linked}`)
lines.push(` mutant — the legend KEY '${out.letter}' over the same wire: ${out.mutant}`)
if (out.mutant === out.direct) {
fails.push(`[${engine}] NO TEETH — sending the legend key '${out.letter}' narrowed the grid to the same ${out.direct} rows as the family name '${out.family}'. This gate cannot tell a right mapping from a wrong one, so its pass would mean nothing.`)
}
if (out.linked !== out.direct) {
fails.push(`[${engine}] the link does not deliver the facet — '${out.family}' set on the grid gives ${out.direct} rows, the same family over the composite's wire gives ${out.linked}.`)
}
}
// ★ AND THE TWO ENGINES MUST AGREE. Each run above only proves the link works within one engine;
// identical COUNTS is what proves the contract is the same product on both. A per-engine pass with
// different numbers would mean the two builds narrow to different peoples for the same choice.
const [a, b] = PROVIDERS
if (results[a] && results[b] && !results[a].fail && !results[b].fail) {
if (results[a].unfiltered !== results[b].unfiltered) {
fails.push(`the two engines start from different data — ${a} lists ${results[a].unfiltered} groups, ${b} lists ${results[b].unfiltered}.`)
}
if (out.linked !== out.direct) {
fails.push(`the link does not deliver the facet — '${out.family}' set on the grid gives ${out.direct} rows, the same family over the composite's wire gives ${out.linked}.`)
if (results[a].family === results[b].family && results[a].direct !== results[b].direct) {
fails.push(`'${results[a].family}' narrows to ${results[a].direct} rows under ${a} and ${results[b].direct} under ${b} — the same choice gives different peoples on the two engines.`)
}
if (results[a].linked !== results[b].linked) {
fails.push(`the link delivers ${results[a].linked} rows under ${a} and ${results[b].linked} under ${b} — interoperability that holds on one provider and not the other is not interoperability.`)
}
}
} catch (err) {
@ -217,4 +245,4 @@ if (fails.length) {
console.log(' NAME per row. Both halves must speak the NAME on the wire.')
process.exit(1)
}
console.log(`${TAG}: PASS — the composite's religion link delivers exactly the facet the grid delivers on its own, and a wrong mapping does not.`)
console.log(`${TAG}: PASS — on BOTH providers the composite's religion link delivers exactly the facet the grid delivers on its own, a wrong mapping does not, and the two engines agree to the row.`)