40 console.log calls (fetch progress, grid sizes, sample rows, API stats) ran on every
load; public-hygiene flagged them. Warnings and errors are kept.
check:composite-freshness found stale on main: all-people-groups
cities-internet
country-posters
dashboard-plus-grid
demo-map
doxa-research-map
doxa-simple-map
gospel-internet
key-cities
my-upg-100-list
plugin-studio
pplr-data-maps
prayer-walk-planner
regions-dashboard
research-dashboard
template-bundle
upg-neighbor. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
70a9ce16 gave the cleared state a data-driven shape and stopped there, which was half a fix. The pins
layer is ADDED with a constant "circle-opacity": 1, and applyPinOpacity is otherwise first reached from
a legend click — so the new expression was only ever the CLEARED state, and the first selection was
still the moment MapLibre needed a new shader variant. The 3.2-3.5 s freeze rega profiled would have
survived the fix meant to remove it.
One line: applyPinOpacity(map.value) in the map-ready path, right after the layer is added. matchExpr is
left UNDEFINED on purpose — "re-apply what is current" — so a selection already restored from a
share-link hash is preserved rather than cleared at boot.
★ HOW IT WAS FOUND, because the method is the point: reading the BUILT bundle, not the source. The
addLayer call with its constant opacity is right there in the shipped JS, next to the pre-warm
expression I had just added — two facts that cannot both be true of a working fix. I had been about to
hand rega a tree to measure and would have read a still-slow first click as "the engine folds the
expression away", which is the wrong lesson and a day of chasing it.
Verified: gates:pre 12/12. Unchanged: this is still zero visual difference — both branches of the
boot-time expression are the same alpha.
rega's contact sheet showed what no gate could: page 3 read as ONE SOLID GREEN BAR. 32 contiguous cells
fill most of row 1 of 52, so the page said "a big green block" where the Driver's intent is "32 boxes lost
in 5,200". Rarity is the whole message and a bar cannot carry it.
⚠ AND THE COMMENT I DELETED SAID THE OPPOSITE, WHICH IS THE PART WORTH KEEPING. It read: "Row-major, so the
shaded run reads as a contiguous block from the top — a scattered shading of the same COUNT would be honest
arithmetic and an unreadable picture." I wrote that reasoning about a picture I had never looked at, and it
was exactly backwards. Scattering is what makes the eye hunt for them, which IS the point.
DETERMINISTIC, NEVER Math.random(): a 32-bit FNV-1a hash of the ZONE ID feeds a mulberry32 PRNG, so the
same packet prints identically every time — two copies of one zone must not disagree — while different
zones get different constellations, so a print run is not 28 sheets wearing the same pattern. Verified: two
consecutive renders produce byte-identical files (md5 febafc1813c6 both times).
Partial Fisher-Yates over the index space rather than shuffling all 5,200, so a large share degrades into
an even spread rather than clumping.
★ AND THE NEW ASSERTION IS THE ONE THAT WOULD HAVE CAUGHT THIS. check-packet-render now measures the shaded
cells' VERTICAL SPREAD as a fraction of the grid height, at the RENDERED layer via getBoundingClientRect —
because a COUNT cannot tell a scatter from a bar. 32 shaded is 32 shaded either way, which is precisely why
every existing assertion stayed green on a broken page.
POISON-TESTED rather than trusted: rebuilding the same 32 cells as a contiguous run makes it FAIL with
"span only 0% of the grid height". The real packet measures 95% (32 cells across 26 distinct rows). The 50%
floor is deliberately loose — a genuine scatter spans nearly the whole page, a bar spans ~1%, and anything
between deserves a human look.
⚠ The poison test first ran on a copy in /tmp and the gate REFUSED it — "outside any checkout, so which
build produced it cannot be checked". A sensible guard, and it meant my first poison run proved nothing;
re-ran inside the tree.
en and ar both PASS at 9 sheets. Page 2 (the empty life grid reading as blank graph paper) is UNTOUCHED and
held for the Driver with the page-order question — shading a reader's life we do not know would be a guess
presented as a fact, which is a product decision, not mine.
English readers got the style's own bilingual labels, native script under every name,
so an English page fetched a glyph range for every script at world view: Prayer
Progress loaded 18 font/sprite requests (777 KB) in English against 5 (185 KB) in
Arabic. English now gets the same single-language labels as every other locale.
The Driver: on Simple Research the research map is not connecting with the legend. It was connecting —
two seconds later, which a reader correctly reads as "nothing happened".
I was wrong about the cause twice, and both wrong answers were cheap to discard because they were
measured. First guess: a late echo through applyDimFilter's 80ms dedupe, whose toggle branch would read
the echo as a second click and clear the highlight. rega instrumented the pin layer every frame for 2 s:
ZERO 'legend:highlight' events on every click and no apply-then-revert anywhere. Second guess: the JS
filter scan in zoomToLegendRow, which walks 2,106 features evaluating ['in',['get','uniqueId'],
['literal', ~700 ids]] linearly. Benchmarked at the real shapes: 13.9 ms per full scan, 4.4 ms with a
memoised Set. Two orders of magnitude short, so nothing there was "optimised".
rega's CPU profile named it. ONE task of 3.2-3.5 s, self time getShaderParameter 3,583 ms +
getProgramParameter 551 ms: the GPU compiling a NEW SHADER VARIANT. The click was the first moment
circle-opacity stopped being a constant and became a per-feature expression, and a data-driven paint
property needs a different program. The second click on the same map costs 205 ms — the program is
cached — which is the signature of a one-time compile and not of anything in our logic. The legend's DOM
was never involved: 34 rows before the click, 34 after.
So the fix is not a smaller expression. It is that the first SELECTION must not be the moment the
variant is first needed. With nothing selected the value is now ['case',['has','uniqueId'], a, a] —
both branches identical, so not one pixel changes — and circle-opacity is data-driven from the first
paint. The program compiles during boot beside every other one, and a selection afterwards only
re-uploads attribute values.
The trade, stated rather than hidden: boot compiles one more program. On a real GPU that is tens of
milliseconds; rega measured seconds only because that box rasterises on the CPU through SwiftShader.
Paying it at load beats freezing the map mid-gesture, and the variant was going to be compiled on the
first interaction anyway.
Second finding from the same profile, fixed here too: circle-opacity was being rewritten 4-8 times for a
single click (+1.52, +1.57, +1.94, +5.17 s) because the selection handler, the glow sync and the slider
watcher all end up in this one function, and every write re-uploads the per-feature attribute. It now
writes only when the value actually differs — asked of the MAP rather than of a remembered key, so a
layer that gets torn down and re-added cannot leave the skip holding a dim that is no longer painted.
Verified: gates:pre 12/12 (check:setup-order included, since this touches module-scope state next to a
function that reads it). Needs eyes: rega, the same affinity click — expect the dim at the first frame
and one long task at BOOT instead.
rega, ?lang=ar on landing 38: "People's Republic of China" and "Lao People's Democratic Republic" were
still English in the top-countries chart. The API labels some countries with their FORMAL name, and
library/data/countries.json does not carry those — it says "China" and "Laos" — so reversing the English
name missed precisely the countries whose names are longest. Measured: both miss the name table, and
both resolve through the row (CHN -> CN -> الصين, LAO -> LA -> لاوس).
Every row already carries both halves: the label the chart aggregates on, and the alpha-3 in
country_code.value — the same accessor the choropleth joins on. Reading the pair out of the data is
exact and needs no alias table. The name table stays as the fallback, so a label whose rows are
currently filtered out still resolves, and a synthetic key ("Other") resolves to neither and renders as
itself.
Deliberately NOT a looser text match. "Democratic Republic of the Congo" and "Republic of the Congo" are
two countries, so stripping formal prefixes is how one would silently become the other — the failure
countryName.js's own header warns about, and the reason that file refuses to guess.
Still English, and not fixable from CLDR: the regions "Middle East" and "North America & Non-Spanish
Caribbean". M49 145 is "Western Asia" and 021 is "Northern America"; neither means the region we draw,
so naming them from CLDR would redraw the region rather than translate it. They need a translation
source, which is the Driver's call — the same class as the affinity blocs and language families.
Verified: check:sfc-parse PASS. Needs eyes: rega, ?lang=ar top-countries.
Driver decision 2026-09-28: the prayer is kept word for word. The
operational-vocabulary rule now removes exactly the prayer text at
packet-strings.json <locale>.points[0].text (every locale, raw and as a string
literal) from a scanned file before it looks; the same word anywhere else is
still reported. Measured: 4 warnings to 0, and a planted file using the word
is still flagged.
The copyable script snippet 404'd on bun run dev for every production map, while
the iframe snippet worked through leafRewrite. /<b>/<b>.js and /<tree>/<b>/<b>.js
now serve the built IIFE from public/<tree>/; a bundle not built yet gets a plain
404 that says to build it, never the HTML fallback.
rega's load waterfall: the engine was requested only after the component tree
had rendered, and the dashboard's 384 KB country boundaries only after the whole
basemap style had loaded, so each waited on the other. The engine download now
starts when the map composable is set up, and the boundaries when the dashboard's
map panel mounts; the style handler awaits that same download.
The rail showed Gospel x Internet as "board": a row's name fell back to its
profile id unless a hand-kept DISPLAY_NAME table had an entry. The manifest now
carries each profile's .meta.json label (or title / displayName), and the rail
shows it without a trailing aside in parentheses; with no label it shows a name
made from the ids ("Gospel Resources · Charts"). DISPLAY_NAME is an override
only and is empty. check:studio-rail fails if any row would show a bare id.
The engine did not compile outside Linux: Pdeathsig (kill children with the
engine) is Linux-only. It now sits behind a build tag, with a no-op elsewhere
where the desktop shell owns the engine's lifetime. The default speech-server path
names this platform's NeMo-Speech.cpp release folder instead of the Linux one.
The /stream WebSocket accepts the Tauri origins (tauri://localhost,
http://tauri.localhost) and RUDDER_ALLOW_ORIGIN as well as the page's own host,
and still refuses any other site. Cross-compiled for darwin/arm64, darwin/amd64
and windows/amd64.
Laptop (bun run dev, zero config); a shared cloud dev server (Docker or Coolify, with a persistent /data);
public embeds from /cdn or any static host; the built folder inside a site's public/, as DX-life does.
Each with the command, what you get, and the detailed doc.
check:composite-freshness found stale on main: big-picture
country-posters
dashboard-plus-grid
doxa-research-map
gospel-internet
regions-dashboard
research-dashboard. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
upg100-plugin caught it: my THIRD-PARTY.md row 17 stated their licences table
was EMPTY on the very commit where it held all 162. Our landings crossed and
neither of us could see the other's tree. Worse than they framed it -- my own
two files disagreed, since data/boundaries/ATTRIBUTION already carried the 162
and the three duty classes.
Row 17 now records what is true: 162 licences established, 32 duty-free, 65
attribution-only, 65 share-alike class (58 ODbL + 7 explicit ShareAlike), with
the ODbL "Derivative Database" question marked OPEN and legal rather than
measurable. The "unverified, someone should look" paragraph drops from four
rows to three, because world-adm0's provenance is answered.
★ AND THE STRUCTURAL FIX, WHICH MATTERS MORE THAN THE ROW. The counts are
asserted in two files, so that is the one place these records can silently
disagree. The register now names their PROVENANCE.json as the AUTHORITY and
says plainly that if the two disagree, it wins -- drift becomes resolvable
instead of invisible. Their phrase for the failure is the right one: a register
that still reads "unestablished" after the work is done is settled-by-omission
in reverse, the absence of an update reading as the absence of the work.
The Driver, 2026-09-28: an export-poster button must open the PRINT DIALOG with a poster preview,
never a direct download. Simple Research was doing exactly the forbidden thing — render a PNG, hand it
to a download helper — so a reader got doxa-prayer-poster.png in their downloads folder with no
preview, no paper size, and no way to print it without opening it somewhere else first.
The dialog IS the preview. printImageBlob() puts the rendered poster on a sheet of exactly the spec's
size (@page 8.5in x 11in, margin 0 — the renderer already composed the margins in) and raises the
dialog over the map. It goes in library/composables/printInPlace.js, which is THE print mechanism here
and already carries the Driver's earlier ruling that killed the pop-up path: an iframe cannot be
blocked and needs no user gesture, so the same call works for a human click and for an agent.
The ellipsis comes back on the label. It was stripped while the button handed over a file directly,
and an ellipsis promises a dialog — which is now what happens.
★ AND THE GATE ASSERTED THE OLD RULING, which is the part worth naming. check-export-one-click passed
while the button did the thing the Driver has now ruled against: it waited for a download and checked
the PNG's dimensions. A gate that encodes a superseded ruling does not just miss the defect, it defends
it — the next person to "fix" this button would have had to break a green gate to do it. It is replaced
by check-export-poster-prints, same four cases (leaf and gallery, en and ar), asserting the new
contract: one click, some frame calls window.print() within 120s, the printing document is the
1700x2200 poster on an 8.5in x 11in sheet, and NO download arrives. window.print is stubbed in every
frame — the native dialog is modal and would hang the run — so this measures everything up to the
dialog and not the browser's own chrome, which is the right boundary for a headless gate.
Why the download half is asserted separately: a button that opens the dialog AND saves a file still
breaks the rule, and a download that lands late is still a download, so it is judged over the whole run
rather than at a moment.
Verified: gates:pre 12/12, check:doc-scripts and check:no-credentials-omit PASS with the rename.
NOT verified here: the new gate needs a browser, and this agent does not start one — rega runs it.
rega's ?lang=ar pass (KA3, 3d64bcad) found English on a localized map in four places, and the census
behind it explains why no gate saw them. Catalogue coverage is COMPLETE: of the 760 keys my bundles
name across the 21 areas they reach, ZERO are missing from any of the ten non-English locales, and the
per-locale English-identical values are numerals, acronyms and cognates rather than debt. Everything
rega actually read was a string no catalogue ever held.
· THE PROJECTION PILL said "🌐 Globe" / "▭ Flat" in all eleven locales. The icon is now the label.
Neither word has a catalogue entry and authoring ten new strings for a two-state toggle to say what
a glyph already says is the wrong trade — but mapui.enableGlobe / mapui.disableGlobe DO ship in all
eleven, as the ACTION, which is what a button should announce. They become the accessible name and
the tooltip. min-width joins min-height on the pill: the 24px used to come free from the text.
· THE TABLE FOOTER said "Σ 2,107 groups". dashboard.groups has shipped in eleven locales all along
(ar "مجموعة") and this one call site never read it. Written with the same singular/plural test as
the header count so the two cannot disagree at one row.
· THE REGION CHART labelled its bars with the prayer API's English region names. Seven regions is a
closed set, so they are now CATALOGUED — five generated from vendored CLDR by
internal/generate-wagf-region-names.mjs, which is the same data countryName.js already trusts.
Generating is what keeps seventy translations out of my hands. middle_east and
north_america_&_non-spanish_caribbean stay English: M49 145 is "Western Asia" and 021 is "Northern
America", and neither means the region we draw. An English label a reader can match to the map beats
a localized one that names the wrong territory. --check verifies the catalogue against CLDR.
· TOP COUNTRIES labelled its bars with the API's English country names. By aggregation time the
alpha-3 is gone, so countryName.js gains iso3ForEnglishName() — reversing its OWN table, exact where
it matches and silent where it does not — which is precisely the ✓ case its header describes.
One thing found while wiring those: the BAR label was the only chart surface still printing the raw
facet key. The donut, its legend and both tooltips already went through legendLabel(); the bar list did
not, which is why these labels stayed English after the donut was fixed for rega's earlier survey. Both
new facets are projected there, so the two charts cannot disagree about a name again.
English is left EXACTLY as authored. Both projections return the key untouched at locale 'en', which
also keeps the 42 countries whose CLDR name differs from ours reading as they do today. Nothing
localizes a VALUE: data-key, isActive() and every click and filter path still carry the canonical
English, the rule the religion donut already followed.
Verified: gates:pre 12/12, check:i18n-keys-exist / parity / never-translated PASS, and the generator's
own --check PASS. Rendering on ?lang=ar goes to rega.
check:public-hygiene reports role nouns in doxa-maps-spa/manifest.json.
studio guessed a meta.json description; it is neither that nor the SPA's.
The manifest generator extracts each element's @description from its SFC
header, and both leaking entries are my files: region-dashboards.vue and
regions-mfe.vue.
Rewritten to describe the element rather than who asked for it. Verified by
regenerating the tree: doxa-maps-spa/manifest.json goes 2 occurrences to 0.
Found the same way as the last two: match the shipped text back to source
rather than reason forward from the bundle name.
upg100-plugin ran the per-country fetch (304a4c120): 162 queries against the
geoBoundaries endpoint, values recorded verbatim, 0 failures, one spot-check
re-verified live. 130 of 162 countries carry a duty; only 32 are duty-free.
ATTRIBUTION now says the world-adm0 duties are DISCHARGEABLE and points at the
single authority for them -- their PROVENANCE.json -- rather than copying the
table, because one table in two places drifts. Their words.
★ THE DUTIES ARE RECORDED AS CLASSES, NOT AS ONE THING. They separated the 7
explicit ShareAlike countries because share-alike is a stronger duty than
attribution, which is right; by the same reasoning the class holds 65, because
Open Data Commons ODbL 1.0 also requires a derivative database to be offered
under ODbL. 58 ODbL + 7 CC-SA. This repository already acted on that reading:
Natural Earth's 1:10m roads were deliberately not shipped over an ODbL
obligation. Whether "licensed alike" binds a giveaway is a legal question, not
a measurement, and it is recorded as open rather than resolved here.
The CCK line is gone. It read as an outstanding gap; CCK is absent from
world-adm0 entirely, so that 404 was a fetch for a country that never shipped.
The India ADM1 boundary is Creative Commons Attribution (CC BY 2.5 IN,
sourced from DataMeet and the Election Commission of India), so the credit
has to reach whoever receives the data. It did not: 6.1 MB of boundary
GeoJSON shipped with no human-readable attribution, and a sidecar for one
file of eight.
data/boundaries/ATTRIBUTION now ships beside the data. Every licence value in
it is verbatim from the geoBoundaries API, queried per boundary -- CC BY 2.5
IN for India, Public Domain for China. No licence wording is ours.
★ IT TOOK TWO ALLOWLIST EDITS, and the first one silently did nothing. The
boundary staging is TWO-STAGE: a pair list gathers into the build pool, and a
separate path list decides what reaches the tree. I added the file to the pair
list, rebuilt, and it still did not ship. An entry in one stage of a two-stage
pipeline is not an entry.
WORLD-ADM0 IS CORRECTED, not closed. This register first guessed Natural
Earth, public domain. It is geoBoundaries gbOpen assembled per country: its
features carry geoBoundaries' own iso3/shapeGroup/shapeName, and the plugin's
data/adm0/PROVENANCE.json names the source and endpoint. That file also states
the real problem -- gbOpen passes each country's UPSTREAM licence through, so
one file carries up to 162 licences and up to 162 attribution duties -- and
its licences table is EMPTY. Which of the 162 are CC BY is unestablished.
Stated in ATTRIBUTION as an undischarged duty rather than papered over.
pplr's row is exp-shepherd's evidence: the PPLR ArcGIS org aggregating IMB,
Joshua Project, ROP and WCD identifiers, publishing no licence at all, and
WCD is a proprietary Brill database.
regions-plugin challenged the record I had just written, and they were right. I gave the 7 explicitly-named
ShareAlike countries their own field because share-alike is a stronger duty than attribution — and 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 carries a
keep-open provision. So my 58 ODbL countries are the same class as my 7, and separating them buried exactly
what the field existed to surface.
★ WHAT CONVINCED ME WAS THIS REPO, NOT THE LICENCE TEXT. regions pointed at
library/scripts/posters/data/README.md:36-50, and I read it: Natural Earth's 1:10m ROADS were requested and
DELIBERATELY NOT SHIPPED because of an ODbL attribution obligation. Someone here already dropped a whole
dataset over this class of duty. An argument from the licence would have been my reading of a clause; an
argument from a decision already taken in this tree is evidence.
THE RECORD NOW SPLITS THREE WAYS, with the iso3 lists so each is checkable:
32 duty-free (28 Public Domain + 4 CC0)
65 attribution-only
65 SHARE-ALIKE CLASS (58 ODbL 1.0 + 7 explicit ShareAlike)
That is a materially different picture from "130 need attribution, 7 are stronger": it says HALF the
duty-bearing countries may constrain how a derivative is licensed, not merely how it is credited.
⚠ AND IT IS EXPLICITLY NOT A LEGAL CONCLUSION. Whether a redistributed boundary file is a "Derivative
Database" under ODbL is precisely the clause a giveaway needs a real answer on, and neither regions-plugin
nor I is qualified to give it. The record says so in _duty_classes._open and the question goes up with the
other licensing items — visible rather than settled by omission, which is the same failure the empty
`licences: {}` was.
The table stays here as the single source of truth; regions' data/boundaries/ATTRIBUTION references it by
path rather than copying it, because one table in two places drifts.
upg100-plugin ran the per-country fetch (304a4c120): 162 queries against the
geoBoundaries endpoint, values recorded verbatim, 0 failures, one spot-check
re-verified live. 130 of 162 countries carry a duty; only 32 are duty-free.
ATTRIBUTION now says the world-adm0 duties are DISCHARGEABLE and points at the
single authority for them -- their PROVENANCE.json -- rather than copying the
table, because one table in two places drifts. Their words.
★ THE DUTIES ARE RECORDED AS CLASSES, NOT AS ONE THING. They separated the 7
explicit ShareAlike countries because share-alike is a stronger duty than
attribution, which is right; by the same reasoning the class holds 65, because
Open Data Commons ODbL 1.0 also requires a derivative database to be offered
under ODbL. 58 ODbL + 7 CC-SA. This repository already acted on that reading:
Natural Earth's 1:10m roads were deliberately not shipped over an ODbL
obligation. Whether "licensed alike" binds a giveaway is a legal question, not
a measurement, and it is recorded as open rather than resolved here.
The CCK line is gone. It read as an outstanding gap; CCK is absent from
world-adm0 entirely, so that 404 was a fetch for a country that never shipped.
regions-plugin's third-party register (their ATTRIBUTION landing) flagged this row as mine, and they were
right: my own PROVENANCE.json already said "gbOpen passes through each country UPSTREAM licence — this
collection is MIXED-LICENCE with per-country attribution duties" and then left `licences: {}` empty. The
duty was NAMED and not DISCHARGED, which is the worst of both — it reads as handled.
★ THE NUMBERS ARE WHY THIS MATTERED, and I did not expect them to be this lopsided:
130 of 162 countries carry an ATTRIBUTION or SHARE-ALIKE duty
32 are duty-free (Public Domain 28 + CC0 4)
58 Open Data Commons ODbL · 44 CC BY 4.0 · 13 CC BY 3.0 IGO · 7 ShareAlike · 2 OGL v3 · …
The repo is meant to be given away, so those duties travel with boundaries/world-adm0*.geojson. Shipping
the file does not discharge them; naming the source does.
⚠ THE 7 SHARE-ALIKE COUNTRIES GET THEIR OWN FIELD (AGO GAB GEO GIN MMR NER TUR) because ShareAlike is a
STRONGER duty than attribution — a derivative may have to be licensed alike — and a blanket "mostly CC BY"
summary would hide exactly the ones that constrain a giveaway.
METHOD: one query per country against the endpoint the file already documents,
https://www.geoboundaries.org/api/current/gbOpen/<ISO3>/ADM0/, throttled at ~3/s, recording
boundaryLicense / licenseSource / boundaryID / boundarySource verbatim. 162 fetched, 0 failures.
Spot-checked SDN against the live API after writing: byte-identical. No licence is inferred — regions'
point that "guessing a licence is worse than recording none" is exactly right, and every value here came
off the wire.
⚠ THE OLD "CCK: meta HTTP 404" GAP IS RESOLVED AS OBSOLETE, NOT FIXED, and the distinction is recorded in
the file. CCK is not in world-adm0.geojson at all — 0 features, absent from the ISO list — so that 404 was
a fetch for a country that never shipped. It took three checks to establish: `.get('CCK',{})` returned None
and I read it as "null licence", then as "failed fetch", before asking whether the key was there at all.
The gaps list is now genuinely empty rather than empty-because-unmeasured.
repo's zero-config .env.example is on main (8c529c031), verified before writing about it: every DX_* and
VITE_* line is present and empty, empty meaning the local default. That is the follow-up patch I held back
rather than documenting a file whose contents had not landed.
"Every line in it is optional" is a better opening than the list I had, because it IS the zero-config
promise in five words — a reader who copies the file and fills in nothing has a working setup, which is
exactly what the Driver asked the default to be.
Also states what happens if the Mapbox token is left empty: the Mapbox-backed maps do not draw, and the
keyless MapLibre provider is the alternative. My previous wording implied the token was required to get
anywhere, which is not true and is discouraging at exactly the wrong moment.
The India ADM1 boundary is Creative Commons Attribution (CC BY 2.5 IN,
sourced from DataMeet and the Election Commission of India), so the credit
has to reach whoever receives the data. It did not: 6.1 MB of boundary
GeoJSON shipped with no human-readable attribution, and a sidecar for one
file of eight.
data/boundaries/ATTRIBUTION now ships beside the data. Every licence value in
it is verbatim from the geoBoundaries API, queried per boundary -- CC BY 2.5
IN for India, Public Domain for China. No licence wording is ours.
★ IT TOOK TWO ALLOWLIST EDITS, and the first one silently did nothing. The
boundary staging is TWO-STAGE: a pair list gathers into the build pool, and a
separate path list decides what reaches the tree. I added the file to the pair
list, rebuilt, and it still did not ship. An entry in one stage of a two-stage
pipeline is not an entry.
WORLD-ADM0 IS CORRECTED, not closed. This register first guessed Natural
Earth, public domain. It is geoBoundaries gbOpen assembled per country: its
features carry geoBoundaries' own iso3/shapeGroup/shapeName, and the plugin's
data/adm0/PROVENANCE.json names the source and endpoint. That file also states
the real problem -- gbOpen passes each country's UPSTREAM licence through, so
one file carries up to 162 licences and up to 162 attribution duties -- and
its licences table is EMPTY. Which of the 162 are CC BY is unestablished.
Stated in ATTRIBUTION as an undischarged duty rather than papered over.
pplr's row is exp-shepherd's evidence: the PPLR ArcGIS org aggregating IMB,
Joshua Project, ROP and WCD identifiers, publishing no licence at all, and
WCD is a proprietary Brill database.
A fresh clone needs no .env. .env.example lists each local setting with its default, and an empty value
means the default: DX_SYNC_REMOTE empty = hot reload of local edits only; DX_PB_URL empty = a local
PocketBase. Rudder's settings are marked as shell-environment only, since the dev server reads them there.
Both are MIT, which asks for the permission notice to be included with the
software. Tabulator's minified .js carried only "(c) Oliver Folkerd 2025" and
its .css carried nothing; Vue's banner names @license MIT but omits the
permission text. Each now has its upstream LICENSE vendored verbatim beside
it -- fetched, not authored, with the URL and sha256 recorded.
★ AND THE ALLOWLIST IS WHY IT WOULD NOT HAVE WORKED. generate-tree stages
vendor/ by an explicit PATH LIST, so the licences sat in data/vendor and never
reached the tree: staged count 0. Vendoring a notice the staging step drops is
not compliance, it is paperwork. Both LICENSE paths are now listed.
documentation/THIRD-PARTY.md is the register the sweep produced: every
non-original thing dx-maps ships, its source, its licence, whether the licence
or attribution actually travels, and the gap. Compiled by inspecting the
SHIPPED tree rather than the source lists, because the question is what a
recipient receives.
Four rows are left OPEN and marked as such. Two are unverified and need a look
(world-adm0's provenance, the pplr upstream). Two need a decision, not a fetch:
people-groups and the 304 derived tables carry data whose redistribution terms
are not established, 36 MB of it. Attaching a licence I have not confirmed
would be worse than the gap, so those go to the Driver. geoBoundaries is
closable by work rather than judgment -- CC BY needs attribution, and the
.meta.json sidecar pattern already exists here for one file of eight.