diff --git a/plugin-designs/my-upg-100-list/data/adm0/PROVENANCE.json b/plugin-designs/my-upg-100-list/data/adm0/PROVENANCE.json index bff75663b..1ba181905 100644 --- a/plugin-designs/my-upg-100-list/data/adm0/PROVENANCE.json +++ b/plugin-designs/my-upg-100-list/data/adm0/PROVENANCE.json @@ -7,9 +7,9 @@ "adm0_features": 162, "_duty": "130 of the 162 countries carry a duty that travels with any redistribution of boundaries/world-adm0*.geojson; only 32 are duty-free. The 130 split TWO ways and the split matters more than the total: 65 are attribution-only, and 65 are SHARE-ALIKE CLASS (58 ODbL + 7 explicit ShareAlike), which can constrain how a derivative is licensed rather than merely how it is credited. See _duty_classes. This matters because the repo is intended to be given away: these obligations are not discharged by shipping the file. See data/boundaries/ATTRIBUTION, which references this table by path.", "_duty_classes": { - "_why": "THREE CLASSES, NOT TWO — corrected 2026-09-28 after regions-plugin's challenge, which was right. I first gave only the 7 explicitly-named ShareAlike countries their own field on the reasoning that share-alike is a stronger duty than attribution. By that same reasoning the field should hold 65: Open Data Commons ODbL 1.0 is itself a SHARE-ALIKE licence for databases — alongside attribution it requires a Derivative Database be offered under ODbL, and it has a keep-open provision. Separating 7 from 58 buried exactly the thing the field existed to surface.", - "_precedent": "THIS REPO ALREADY TREATS ODbL AS CONSEQUENTIAL, which is the evidence rather than my reading of the licence: library/scripts/posters/data/README.md:36-50 records that Natural Earth's 1:10m ROADS were requested and DELIBERATELY NOT SHIPPED because of an ODbL attribution obligation. Someone here dropped a dataset over this class of duty.", - "_open": "NOT A LEGAL CONCLUSION. Whether a redistributed boundary file is a 'Derivative Database' under ODbL is exactly the clause a giveaway needs a real answer on, and neither regions-plugin nor I is qualified to give it. Recorded here, and raised with the licensing items, so the question is visible rather than settled by omission.", + "_why": "THREE CLASSES, NOT TWO — corrected 2026-09-28 after a review challenge, which was right. The first version gave only the 7 explicitly-named ShareAlike countries their own field on the reasoning that share-alike is a stronger duty than attribution. By that same reasoning the field should hold 65: Open Data Commons ODbL 1.0 is itself a SHARE-ALIKE licence for databases — alongside attribution it requires a Derivative Database be offered under ODbL, and it has a keep-open provision. Separating 7 from 58 buried exactly the thing the field existed to surface.", + "_precedent": "THIS REPO ALREADY TREATS ODbL AS CONSEQUENTIAL, which is the evidence rather than a reading of the licence: library/scripts/posters/data/README.md:36-50 records that Natural Earth's 1:10m ROADS were requested and DELIBERATELY NOT SHIPPED because of an ODbL attribution obligation. Someone here dropped a dataset over this class of duty.", + "_open": "NOT A LEGAL CONCLUSION. Whether a redistributed boundary file is a 'Derivative Database' under ODbL is exactly the clause a giveaway needs a real answer on, and nobody on this project is qualified to give it. Recorded here, and raised with the licensing items, so the question is visible rather than settled by omission.", "duty_free": { "count": 32, "iso3": [ diff --git a/plugin-designs/my-upg-100-list/data/apply-grouping-proof.mjs b/plugin-designs/my-upg-100-list/data/apply-grouping-proof.mjs index 0fab5545d..246b9ce7f 100644 --- a/plugin-designs/my-upg-100-list/data/apply-grouping-proof.mjs +++ b/plugin-designs/my-upg-100-list/data/apply-grouping-proof.mjs @@ -56,7 +56,7 @@ const TRACKED = [ 'gb-IND-ADM1.geojson', 'gb-CHN-ADM1.geojson', ]; // ★ MOVED TO data/tables/. groupings.json is now in the shared asset pool the tree copies into -// public/dx-maps/assets/tables/, because gospel's legend renders IN THE BROWSER and needs it at +// public/dx-maps/assets/tables/, because the gospel legend renders IN THE BROWSER and needs it at // runtime — a build-time import path would not reach the bundle. The name stays relative so P() // still resolves it against this directory; only the prefix changed. const GROUPINGS = '../../../data/tables/groupings.json'; diff --git a/plugin-designs/my-upg-100-list/data/apply-grouping.mjs b/plugin-designs/my-upg-100-list/data/apply-grouping.mjs index ae5b0dd64..25b145037 100644 --- a/plugin-designs/my-upg-100-list/data/apply-grouping.mjs +++ b/plugin-designs/my-upg-100-list/data/apply-grouping.mjs @@ -63,7 +63,7 @@ const readJSON = (f) => JSON.parse(readFileSync(P(f), 'utf8')); // ── canonical paths ─────────────────────────────────────────────────────────── // ★ MOVED TO data/tables/. groupings.json is now in the shared asset pool the tree copies into -// public/dx-maps/assets/tables/, because gospel's legend renders IN THE BROWSER and needs it at +// public/dx-maps/assets/tables/, because the gospel legend renders IN THE BROWSER and needs it at // runtime — a build-time import path would not reach the bundle. The name stays relative so P() // still resolves it against this directory; only the prefix changed. const GROUPINGS = '../../../data/tables/groupings.json'; diff --git a/plugin-designs/my-upg-100-list/data/generate-region-shades.mjs b/plugin-designs/my-upg-100-list/data/generate-region-shades.mjs index d0ea215e5..2a94afab4 100644 --- a/plugin-designs/my-upg-100-list/data/generate-region-shades.mjs +++ b/plugin-designs/my-upg-100-list/data/generate-region-shades.mjs @@ -33,7 +33,7 @@ import { dirname, join } from 'node:path'; const HERE = dirname(fileURLToPath(import.meta.url)); const STORE = join(HERE, 'zone-colors.json'); // zone-regions.json moved to data/tables/ (the shared asset pool the tree copies into -// public/dx-maps/assets/tables/) because gospel's legend renders IN THE BROWSER and needs it at +// public/dx-maps/assets/tables/) because the gospel legend renders IN THE BROWSER and needs it at // runtime. HERE is still this plugin's data dir, so the path walks up to the repo root. const REGIONS = join(HERE, '..', '..', '..', 'data', 'tables', 'zone-regions.json'); const LOCKS = join(HERE, 'color-locks.json'); // optional diff --git a/plugin-designs/my-upg-100-list/data/legend-tree.js b/plugin-designs/my-upg-100-list/data/legend-tree.js index a12417499..b6cc163e1 100644 --- a/plugin-designs/my-upg-100-list/data/legend-tree.js +++ b/plugin-designs/my-upg-100-list/data/legend-tree.js @@ -259,9 +259,8 @@ export function buildLegendNodes(clusters, opts = {}) { // ── REGIONAL GROUPING — the SAME sections the poster page uses ───────────── // The legend used to emit 14 LOOSE LEAVES at top level (West Africa, Sudan, // Brazil, Laos, …) beside two odd parents, "Asia (admin-1)" and "Frontier Asia - // (uncovered)". Brief: "the legend itself is not really well grouped — it says - // Asia and it mentions other groups… find the sections on the poster page and - // use those as the legend sections." + // (uncovered)". That grouping read poorly beside the poster page, so the legend + // now uses the poster page's own sections. // // So the same 28 zones now group into the poster page's nine regions. The // mapping is duplicated from poster-wall.vue rather than imported because this @@ -309,10 +308,10 @@ export function buildLegendNodes(clusters, opts = {}) { const node = { // ★ FOLD DIACRITICS BEFORE STRIPPING, or the mark is DELETED and the id silently becomes a // different id: Gujarāt -> 'region-gujar-t', not 'region-gujarat'. Today's labels are the - // fixed ASCII set from regionFor(), so nothing is broken — but the brief's whole point is that + // fixed ASCII set from regionFor(), so nothing is broken — but the whole point is that // a fork brings its OWN people-group set and names its own regions, and the first accented - // label would split one region into two with no error and no empty state. Same class gospel - // measured joining admin-to-list.json: a naive fold matched 514 of 1009 rows and lost THREE + // label would split one region into two with no error and no empty state. Same class as a measured + // join of admin-to-list.json: a naive fold matched 514 of 1009 rows and lost THREE // whole zones, while every surviving zone still looked populated. Fix the class, not the six // spellings we happen to know. id: 'region-' + label.normalize('NFD').replace(/\p{Mn}/gu, '').toLowerCase().replace(/[^a-z0-9]+/g, '-'), diff --git a/plugin-designs/my-upg-100-list/data/region-hue-proof.mjs b/plugin-designs/my-upg-100-list/data/region-hue-proof.mjs index 2057e8827..3f984d619 100644 --- a/plugin-designs/my-upg-100-list/data/region-hue-proof.mjs +++ b/plugin-designs/my-upg-100-list/data/region-hue-proof.mjs @@ -33,7 +33,7 @@ import { dirname, join } from 'node:path'; const HERE = dirname(fileURLToPath(import.meta.url)); const STORE = join(HERE, 'zone-colors.json'); // zone-regions.json moved to data/tables/ (the shared asset pool the tree copies into -// public/dx-maps/assets/tables/) because gospel's legend renders IN THE BROWSER and needs it at +// public/dx-maps/assets/tables/) because the gospel legend renders IN THE BROWSER and needs it at // runtime. HERE is still this plugin's data dir, so the path walks up to the repo root. const REGIONS = join(HERE, '..', '..', '..', 'data', 'tables', 'zone-regions.json'); const GENERATOR = join(HERE, 'generate-region-shades.mjs'); diff --git a/plugin-designs/my-upg-100-list/data/visual-gate.mjs b/plugin-designs/my-upg-100-list/data/visual-gate.mjs index b8f04fb80..d7f66527c 100644 --- a/plugin-designs/my-upg-100-list/data/visual-gate.mjs +++ b/plugin-designs/my-upg-100-list/data/visual-gate.mjs @@ -484,7 +484,7 @@ async function main() { // booted dark, so the first move used to be dark→light). This proves nothing // assumed the boot theme: handleToggleTheme flips isDark false→true → setStyle // dark-v11 → style.load re-adds tapestry/pins/isolation. The ThemeToggleButton - // is the .mcb control with data-control="theme" (studio L54) — untranslatable, + // is the .mcb control with data-control="theme" — untranslatable, // unlike the "Switch to …" title this used to match, which is localized AND dynamic. const themeBtn = page.locator(`${EL} button.mcb[data-control="theme"]`); let toggled = false; @@ -639,7 +639,7 @@ async function main() { await clearFilter(page); // ── (4) controls present in DOM (zoom, theme, fullscreen) ────────────────── - // ★ QUERY data-control, NEVER THE TITLE (studio L54). Each wrapper writes + // ★ QUERY data-control, NEVER THE TITLE. Each wrapper writes // data-control="zoom-in|zoom-out|fullscreen|theme|location|help|share" on // MapControlButton; it is not a declared prop, so it falls through onto the // rendered