From 1208fdce712a40934fc36b2bde6b45b69d2623c4 Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Tue, 29 Sep 2026 13:38:14 +0000 Subject: [PATCH] The production Country Map honours the host's people-group list country-map.vue fetched /api/people-groups/list and mapped the posts straight to points, without applyPeopleGroupList(). Every other consumer of that endpoint calls it -- DataSourceManager, useDashboardData, useCsvExport, peopleGroupRecords and the people-groups grid. So a host that asked for one curated list got the WHOLE endpoint drawn on its country map, and nothing said so: the pins looked like data rather than like the wrong list. The list is applied to the raw posts, before they become points, which is where every other consumer applies it. That is what keeps this element and a dashboard showing the same country from disagreeing about which groups are in it -- the same reason the country filter beside it is client-side. The default list returns the rows untouched and makes no fetch, so an unconfigured host pays nothing. A list whose membership cannot be loaded yields NO groups rather than the wrong ones: applyPeopleGroupList's own contract, and the safer failure for a prayer surface. Measured three ways, with a temporary copy of check:universal-props that adds country-map to its BUNDLES list (the reason the gate never saw this: 19 bundles listed, this one absent): - RED on development: BYPASS country-map LIST-FETCH country-map.vue:98, exit 1; - GREEN here: 20 bundles read engine, token, locale and list through the library, exit 0, the gate's 9 planted-bypass self-tests still caught; - a real list value changes the drawn count, through the shipped applyPeopleGroupList and the served membership files: Nepal draws 34 points on the default list, 29 on "frontier", 0 on "frontier-500k". Rebuilt, tree regenerated, SRI refreshed. The list-membership URL is present in the built bundle; the manifest diff is integrity hashes only, 0 other lines. --- plugin-designs/country-map/country-map.vue | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugin-designs/country-map/country-map.vue b/plugin-designs/country-map/country-map.vue index fe1ebf3c1..52ffbc794 100644 --- a/plugin-designs/country-map/country-map.vue +++ b/plugin-designs/country-map/country-map.vue @@ -31,6 +31,7 @@ import { computed, inject, ref, onMounted, watch } from 'vue' import RegionCountryMap from '@map/components/maps/RegionCountryMap.vue' import { toNumber, PEOPLE_GROUP_LIST_FIELDS } from '@map/utils/countries-meta.js' import { peopleGroupPoints, PEOPLE_GROUP_POINT_FIELDS } from '@map/utils/peopleGroupPoints.js' +import { applyPeopleGroupList } from '@map/lists/peopleGroupList.js' import { useRegionsI18n } from '@map/i18n/useRegionsI18n.js' const props = defineProps({ @@ -99,7 +100,20 @@ async function loadPoints() { const response = await fetch(url) if (!response.ok) throw new Error(`HTTP ${response.status}`) const data = await response.json() - const all = peopleGroupPoints(Array.isArray(data.posts) ? data.posts : [], toNumber) + // ★ THE HOST'S LIST IS APPLIED TO THE RAW POSTS, BEFORE THEY BECOME POINTS. `list` is a + // profile-config prop every other consumer of this endpoint honours — DataSourceManager, + // useDashboardData, useCsvExport, peopleGroupRecords and the people-groups grid all call + // applyPeopleGroupList on the rows they fetched. This element did not, so a host that asked for + // one curated list got the WHOLE endpoint drawn on its country map and nothing said so: the pins + // looked like data rather than like the wrong list. Applying it here, on data.posts rather than + // on the mapped points, is what keeps this element and a dashboard showing the same country from + // disagreeing about which groups are in it — the same reason the country filter below is + // client-side. + // The default list returns the rows untouched and makes no fetch, so an unconfigured host pays + // nothing; a list whose membership cannot be loaded yields NO groups rather than the wrong ones, + // which is applyPeopleGroupList's own contract and the safer failure for a prayer surface. + const posts = await applyPeopleGroupList(Array.isArray(data.posts) ? data.posts : [], cfg.value) + const all = peopleGroupPoints(posts, toNumber) // Filter HERE rather than asking the API for one country: the endpoint returns the whole list // and every other consumer in this repo filters client-side, so a country page and a dashboard // showing the same country cannot disagree about which groups are in it.