diff --git a/internal/check-gospel-embed-contract.mjs b/internal/check-gospel-embed-contract.mjs index 00dc3c6b..895beed7 100644 --- a/internal/check-gospel-embed-contract.mjs +++ b/internal/check-gospel-embed-contract.mjs @@ -165,7 +165,25 @@ try { else console.log(' ok ?tab=province (unknown)'.padEnd(34) + 'matches nothing and says so') } - /* 5 — the view that already existed, kept honest */ + /* 5 — THE FIELD CARD MUST RENDER, not merely fetch. Added after ?card= shipped BLANK: the sheet + reads selected.* and card mode had no country, so the render threw and the page was empty while + every byte-level check passed. A mount assertion is the only thing that would have caught it — + the data was right and the feature was dead. */ + const anySlug = (JSON.parse(readFileSync(resolve(PUBLIC, TREE_NAME, 'assets/tables/doxa-people-groups.json'), 'utf8')).rows || []) + .find((r) => r.slug && r.mapped)?.slug + if (!anySlug) fails.push('no slug in the roster — the ?card= arm would pass vacuously') + else { + const c = await read(page, `?card=${encodeURIComponent(anySlug)}`) + if (!c.mounted) fails.push(`?card=${anySlug}: the leaf did not mount`) + else if (c.text.length < 400) fails.push(`?card=${anySlug}: rendered ${c.text.length} characters — a blank card`) + else if (!c.text.includes(anySlug.split('-')[0])) fails.push(`?card=${anySlug}: the card rendered but does not name the group`) + else console.log(` ok ?card=${anySlug}`.slice(0, 33).padEnd(34) + `${c.text.length} chars rendered`) + const bad = await read(page, '?card=not-a-people-anywhere') + if (!bad.mounted) fails.push('?card=: the leaf did not mount — a bad slug must not blank the page') + else console.log(' ok ?card='.padEnd(34) + 'says so, still renders') + } + + /* 6 — the view that already existed, kept honest */ const d = await read(page, '?view=zero') if (!d.mounted) fails.push('?view=zero: the leaf did not mount') else if (!d.text.length) fails.push('?view=zero: the leaf rendered nothing') diff --git a/plugin-designs/gospel-resources/resources-map.vue b/plugin-designs/gospel-resources/resources-map.vue index f4ce7056..75910568 100644 --- a/plugin-designs/gospel-resources/resources-map.vue +++ b/plugin-designs/gospel-resources/resources-map.vue @@ -1576,7 +1576,15 @@ onMounted(async () => { const r = await fetch(`${assetsBase.value}/tables/card-${cardShard(cardSlug)}.json`) const shard = r.ok ? await r.json() : null const card = shard && shard[cardSlug] - if (card) selectedGroup.value = card + if (card) { + selectedGroup.value = card + /* ⚠ THE SHEET READS selected.* IN FOURTEEN PLACES, and card mode had no country at all, so + the first of them — the back button's selected.country — threw and the page rendered + BLANK. Guarding that one line would have left thirteen. The card knows its country, so + `selected` is populated from it: every existing read is satisfied, and the curated-analysis + block stays hidden on its own hasCurated test because a card carries none of those fields. */ + selected.value = { iso3: card._iso3 || '', country: card.countries || card._iso3 || '' } + } else err.value = `No card for "${cardSlug}".` } catch (e) { err.value = String(e.message || e) } return @@ -2496,7 +2504,7 @@ useShadowStyles(