First palette migration from SPEC-LIBRARY-CURATION.md. Source only; studio rebuilds (rule 5B — library/ plus four other owners' plugins). WHY THIS ONE FIRST: the duplication was not idle. doxa-research-map's affinity-block.js carried A018 'Tibetan Peoples' and A019 'Himalayan Peoples' — live on the pray-tools API — with colours measured to WCAG 1.4.11's 3.0:1 non-text floor (A013 5.28 unchanged, A018 7.69, A019 3.53; sibling separations 2.61/1.46/1.79). country-posters' copy covered only A001–A017, so 134 rows (6.4% of 2,107) fell to the grey fallback #95a5a6 — the "bunch of grey colours" report. exp-shepherd confirmed that code path headlessly. So the correct copy wins with no judgement call, and the move FIXES country-posters rather than changing it. FOUR CONSUMERS, NOT THE TWO THE SPEC COUNTED, and finding that is the sharpest argument for the migration: research-dashboard/index.js and dashboard-plus-grid/index.js each imported `../doxa-research-map/src/colors/affinity-block.js` — a cross-plugin RELATIVE import into another plugin's PRIVATE folder. Both now import @map/colors/. Only the build found this; no gate names cross-plugin reach. THE GLOB STAYS in both plugins' index.js, deliberately, and is documented there: resource.js is still plugin-local pending C1b, so deleting the glob would unregister it and colour those pins by the soft fallback — the same silent wrong-colour class being fixed here. Deleting the two STALE FILES is what stops the stale copy winning. THE REJECTED-CANDIDATE NOTE MOVED ABOVE `export const PALETTE`, and this is a real constraint rather than tidying: check:one-palette slices from that export to END OF FILE and matches every hex, despite its own comment claiming it reads "only the PALETTE export". #AF7AC5 was rejected for A019 at 2.95 — under the accessibility floor — and mentioned below the export it would have been DEMANDED of every consumer bundle. The note keeps the reasoning without creating the obligation; the gate bug itself is reported separately since internal/ is not mine to edit. The legend needed no change and that is by design: useAffinityBlockLegendData resolves via getColorStrategy(COLOR_MODES.AFFINITY_BLOCK) — the same strategy the pins use — and reads labels from the data, so map and legend gain A018/A019 together. Its comments claiming the strategy lives in a plugin folder were corrected; they now describe where it actually is. GATES: check:one-palette PASS — 8 strategies, 16 bundle/palette pairs (baselined at 6 and 12 before the move, so a red would have been mine). check:library-index PASS after regenerating the derived menu. check:no-free-identifiers PASS. All four consumer bundles build; their artifacts reverted for studio. |
||
|---|---|---|
| .. | ||
| api | ||
| colors | ||
| components | ||
| composables | ||
| constants | ||
| data | ||
| i18n | ||
| layouts | ||
| lists | ||
| maps | ||
| packet | ||
| scripts | ||
| stores | ||
| styles | ||
| utils | ||
| index.js | ||
| ProfileLoader.vue | ||
| README.md | ||
library/ (@map) — the shared map template
The other half of the architecture (see ../plugin-designs/README.md):
every map in plugin-designs/<your-map>/ composes the reusable, parameterized pieces that live here.
Fix something here and every map benefits on the next build; break something here and every map
breaks — read components/WARNING.md before touching shared pieces.
| Folder | What lives there |
|---|---|
ProfileLoader.vue |
The root of every bundle: parses profile-config, loads the profile, provides the stores + config |
components/ |
Shared UI — map, legends, controls, popup (PeopleGroupDetail), tables, charts, hints (README) |
composables/ |
Shared logic — map engine (useMapInstance), provider switch, shadow-DOM styles, theming |
stores/ |
Per-instance Pinia stores (ui / map / data) — provided by ProfileLoader, injected by children |
api/ |
Data-source registry (sources.json) + fetch layer — the JAMstack runtime wiring |
colors/ |
Color sets maps opt into via profile-config.colorSet |
i18n/ |
The shared string catalogs (all maps speak the same languages) |
data/ |
Small shared datasets baked at build time (big served data lives in ../data/) |
constants/ |
Shared constants |
scripts/ |
Maintainer pipelines (posters, research) — not part of any bundle |
The rule of thumb (same as WARNING.md): custom code in your app-profile, reusable code here — and things only move from the first to the second once they've earned it.