reconcile the 5-caps representatives against the manifest; cap-1 was sampling a cap-2 bundle

This commit is contained in:
doxa-maps-88655c70 2026-09-20 07:46:29 +00:00
parent a456a0fcd2
commit 97085f05cd

View file

@ -10,7 +10,9 @@
* ★ THE MODEL, grounded not remembered: capability = 5 - PROFILE_TIER, where PROFILE_TIER lives in
* internal/plugin-gallery/discover.mjs:
* nested-mfe-spa 0 · nested-elements-mfe 1 · monolithic 2 · parameterized 3 · single 4
* One representative bundle per level. If a bundle's declared type changes, update REPS here.
* One representative bundle per level. REPS is reconciled against manifest.json at startup, so a
* bundle whose declared type changes makes this gate FAIL LOUDLY rather than silently certify a
* level it is no longer sampling — you no longer have to remember to update it by hand.
*
* ★ TWO MEASUREMENT TRAPS THIS ENCODES (both cost real debugging time):
* - SHADOW DOM DOES NOT PIERCE. A cap-4/cap-5 composite mounts CHILD elements with their OWN shadow
@ -34,12 +36,59 @@ const GL=['--use-gl=swiftshader','--enable-unsafe-swiftshader','--ignore-gpu-blo
const B=(process.env.BASE || 'https://nuxtbase.app/plugin-assets/doxa-maps/').replace(/\/?$/,'/')
// capability = 5 - PROFILE_TIER (discover.mjs). One representative per level.
const REPS=[
['cap-1 single', 'doxa-vision-card/doxa-vision-card/index.html', 'single'],
// ★ CORRECTED 2026-09-20 by the manifest reconciliation added below, on its FIRST RUN.
// This slot used to be doxa-vision-card — which ships doxa-vision-card.instances.json with 2
// instances, so discover.mjs types it PARAMETERIZED (cap-2), not single. The gate has therefore
// been reporting '5/5 capability levels' while sampling cap-2 TWICE and cap-1 NEVER. Exactly the
// drift the reconciliation exists to catch, found the moment it was switched on.
['cap-1 single', 'all-people-groups/all-people-groups/index.html', 'single'],
['cap-2 parameterized', 'people-groups-grid/people-groups-grid/index.html', 'preset-element'],
['cap-3 monolithic', 'doxa-research-map/research-map/index.html', 'monolithic'],
['cap-4 nested-elements', 'dashboard-plus-grid/dashboard-plus-grid/index.html','nested-elements-mfe'],
['cap-5 nested-mfe-spa', 'doxa-maps-spa/doxa-maps-spa/index.html', 'nested-mfe-spa'],
]
// ★ RECONCILE THE HARDCODED REPS AGAINST THE MANIFEST BEFORE TRUSTING THEM.
// The REPS table above asserts each representative's declared type as a STRING LITERAL, and the
// header says "if a bundle's declared type changes, update REPS here" — i.e. it relies on a human
// remembering. That makes the EXPECTATION and the thing it describes corruptible by the same event:
// change a bundle's meta.json and this gate keeps claiming the old tier while still passing, so it
// would certify a matrix it is no longer actually sampling. (Live risk, not hypothetical: on
// 2026-09-20 research-dashboard moved single -> monolithic. It is not a REP, so nothing desynced —
// but only by luck.) Read the manifest and FAIL LOUDLY on any drift.
// Local-tree runs only: the manifest sits next to the leaves at the same BASE.
try {
const mfUrl = B + 'manifest.json'
const res = await fetch(mfUrl, { signal: AbortSignal.timeout(10000) })
if (res.ok) {
const mf = await res.json()
const byProfile = new Map()
for (const bundle of (mf.bundles || [])) {
for (const p of (bundle.profiles || [])) byProfile.set(`${bundle.bundle}/${p.profile}`, p.type)
}
const ALIAS = { 'preset-element': 'parameterized', 'composite-element': 'nested-elements-mfe',
'multi-view-element': 'monolithic', 'app-shell': 'nested-mfe-spa', 'single-element': 'single' }
const drift = []
for (const [name, path, claimed] of REPS) {
const key = path.split('/').slice(0, 2).join('/')
const actual = byProfile.get(key)
const want = ALIAS[claimed] || claimed
if (actual && actual !== want) drift.push(`${name}: REPS says "${claimed}" (=${want}) but the manifest says "${actual}" for ${key}`)
}
if (drift.length) {
console.error('5-CAPS: FAIL — the REPS table has DRIFTED from the manifest:')
drift.forEach((d) => console.error(' ' + d))
console.error(' Update REPS in internal/verify-5-capabilities.mjs. Until then this gate is')
console.error(' certifying capability levels it is no longer actually sampling.')
process.exit(1)
}
console.log(`5-CAPS: REPS reconciled against ${mfUrl} — all ${REPS.length} declared types match.`)
} else {
console.log(`5-CAPS: NOTE — manifest not readable at ${mfUrl} (${res.status}); REPS types UNVERIFIED this run.`)
}
} catch (e) {
console.log(`5-CAPS: NOTE — manifest check skipped (${String(e.message || e).slice(0, 60)}); REPS types UNVERIFIED this run.`)
}
const b=await chromium.launch({headless:true,args:GL})
let bad=0
for(const [name,path,type] of REPS){