Commit graph

1773 commits

Author SHA1 Message Date
Doxa Maps
376ecaee25 Prayer as a move at the grain a team is sent to
A country is not where anyone is sent; a state is. Each province now carries the
same two prayer numbers the country sheet does and ends in the same move — the
largest group there with nothing and nobody praying, one tap from its prayer page,
ranked need-first so drilling from country to province never hands the reader a
second answer. Andhra Pradesh: 64 of its 76 groups with a prayer page have nobody
praying, 3.8M people.

Always N of M. doxa.life publishes a page for 1,723 of the roster, so nobody-praying
can be said of the groups that HAVE one and never of the province; both numbers
ship together so no surface can quote the first alone.

The join here is name+country, not language — you pray for a people in a place, and
that is doxa.life's own key. It is the one join in this build where a name match is
correct rather than forbidden, and the slug is always theirs: pray.doxa.life answers
200 for any path, so a constructed one would look valid and be empty.

The doctrine screen now scans the province table too. It is the SIXTH place a URL
lives in this bundle, and a table added after the scan was written is exactly how
the access table went unscreened for weeks — read from disk, so it is checked even
when the province layer was never opened.
2026-09-26 17:54:39 +00:00
Doxa Maps
a76eb43419 Arunachal Pradesh is no longer offered Telugu
This table carried its own worst case as a caveat: the ways in were chosen for the
COUNTRY, so Arunachal Pradesh — in the far north-east — was offered TELUGU, a South
Indian language, because the curated bridge table is keyed by country and a curated
bridge outranks a computed one. Manipur and Kerala got Telugu too.

The province answers for itself now. Candidates are the languages of groups
STANDING IN IT that already have Scripture AND film, ranked by the people here who
already hold them. Arunachal Pradesh gets Hindi and Assamese, Manipur gets Meitei,
Kerala gets Malayalam — each one a measured neighbour rather than a national
average. 41 of 46 provinces can answer locally; the other 5 keep the country answer
and the new Basis column says which is which, because "no language here has both
Scripture and film" is itself worth reading. The country-level answer stays in its
own column so the two can be compared rather than swapped silently.

It is a NEIGHBOUR, not a recommendation: whether a group actually speaks it is a
question for someone on the ground, and the table says so.
2026-09-26 17:46:32 +00:00
Doxa Maps
b493f5e1b1 Wire the two strategic strings, English until their keys arrive
The fold's summary is a CONTROL — a reader in Arabic could not tell what was behind
it — and "This is a sign language." is the sentence that stops eBible's silence
being read as an absence of Scripture for 150 sign languages and 84.2M people.
Both go through tOr(), so they render today's English until exp-shepherd's keys
land and switch to the catalogue with no further change here.
2026-09-26 17:30:48 +00:00
Doxa Maps
f98bfa746d The embed contract, written down for partners
?codes, ?country, ?code and ?view=zero are what a partner puts in an iframe and
never touches again, so they are documented where the other embed material lives —
including the two things that decide whether a link is right: the denominator is
Doxa's 2,107, not the 12,379-group corpus, and a link matching nothing shows an
empty map reading "0 / 2,107" rather than pretending a broken list works.

Also says what the map does NOT promise: no zoom or centre parameter, placement is
approximate, and an unknown parameter is ignored rather than fatal.
2026-09-26 17:24:55 +00:00
Doxa Maps
5739818ecc Never hand a keyless page the engine that needs a token
resources-map resolved its engine as `engineGlobal(provider) || window.mapboxgl`.
engineGlobal already defaults to mapbox, so that fallback could only ever fire for
provider 'maplibre' — and then it returned MAPBOX. A page that chose the keyless
engine silently got the one that needs a token, and because the profile only
assigns accessToken when the provider is not maplibre, the substitute had no token
either: it would have 401'd on every tile. The fix is the deletion. The requested
engine or a named failure, with a console warning for whoever is debugging and the
reader's line through messages.* (English kept inline until the key lands).

check:engine-contract measures it: two providers across engine present, engine
blocked and both blocked, with the CDN blocked by request routing the way a proxy
or an offline kiosk does it. Three of those six arms first failed for reasons that
were mine, not the product's, and each is written down in the gate: Mapbox cannot
mount at all on a static tree without a token, 11s was not long enough for a leaf
that fetches 4 MB before the map exists, and engine attribution read from a debug
handle scored Mapbox-with-a-bad-token as "engine null" — the canvas class cannot
lie about who drew it.

Also in this landing: the pin caveat is translated in 11 locales from the shared
pins.* area, read through this leaf's own guarded t() rather than by mounting
library ApproxPinNote.vue — that component calls useI18n() unguarded, and this
bundle is embeddable in hosts that never called app.use(i18n), where an unguarded
call throws during setup and the shadow boundary swallows it. Same wording either
way. Both "Show all groups" buttons now use the key that already exists in 11
locales, and the engine's own control labels get the provider arm.
2026-09-26 17:21:22 +00:00
Doxa Maps
56c2da26c5 Merge branch 'main' of https://git.nuxtbase.app/doxa-life/doxa-maps into bundler-3/work
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
2026-09-26 16:46:48 +00:00
Doxa Maps
c51233182d Merge branch 'main' of https://git.nuxtbase.app/doxa-life/doxa-maps into bundler-3/work
# Conflicts:
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/gospel-resources/charts/index.html
#	public/dx-maps/gospel-resources/data-tables/index.html
#	public/dx-maps/gospel-resources/gospel-dashboard/index.html
#	public/dx-maps/gospel-resources/gospel-resources.js
#	public/dx-maps/gospel-resources/resources-list/index.html
#	public/dx-maps/gospel-resources/resources-map/index.html
#	public/dx-maps/manifest.json
2026-09-26 16:43:37 +00:00
Doxa Maps
12a76cc985 Rebuild country-posters, and regenerate the tree
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
2026-09-26 16:42:34 +00:00
Doxa Maps
2195b2aceb Country posters: a partner's dataSource and tokenUrl reach the panes
country-posters-mfe forwards the host's page keys to its two panes by an
explicit list, and dataSource and tokenUrl were not on it. The same gap regions
fixed in f0aa5ab3, found by dx-shepherd on this composite.
- dataSource was LIVE: countries-map reads it from its own profile-config
  (countries-map.vue:392, :622), nothing pinned it, and nothing publishes it
  page-wide, so <country-posters-mfe profile-config='{"dataSource":…}'> fell
  back to sources.json's activeSource.
- tokenUrl was LATENT: the outer ProfileLoader already publishes the fetched
  token page-wide, but the panes never got the URL itself.

Both join INHERITED_PAGE_KEYS. profile and instanceId are still never inherited
(pane.config is spread last).

Headless: replaying paneElement's forwarding on a partner config, main passes
{provider, lang} and drops dataSource and tokenUrl; after, the map pane gets
dataSource and tokenUrl too, and profile stays countries-map. Build OK;
no-free-identifiers, universal-props and composites-mount pass.
2026-09-26 16:42:10 +00:00
Doxa Maps
1a76174166 Rebuild the consumers main left stale (build owner, README rule 5)
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
check:composite-freshness found stale on main: all-people-groups
big-picture
cities-internet
country-posters
dashboard-plus-grid
demo-map
doxa-research-map
doxa-simple-map
gospel-resources
key-cities
my-upg-100-list
pplr-data-maps
regions-dashboard
research-dashboard
research-map-plus-grid
template-bundle
upg-neighbor
wall-of-people-groups. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
2026-09-26 13:41:21 +00:00
Doxa Maps
6273ae18e6 P8: a partner's own list is an address
This map ships Doxa's roster, and the point of a public corpus is that other lists
can stand on it. A partner could already embed the map; their reader then had to
go hunting for their own people among 2,107 dots.

  ?codes=kfr,cmn,npi   draw only those languages, framed on them
  ?country=IND         open that country's sheet — this did NOTHING before unless
                       a ?code came with it, so the brief's second requirement had
                       no address, which is exactly what a partner embeds
  ?view=zero           unchanged

The join is ISO 639-3, so a partner's list needs no agreement with ours — only the
codes their own data already carries. It filters and never invents: the notice
reads "74 / 2,107" and is itself the button back to the whole map, labelled with a
key that already exists in 11 locales. A link matching nothing shows an empty map
reading "0 / 2,107", because showing the full map instead would tell a partner
their broken list works.

check:embed-contract gates the promise. Written against the pin index first, it
demanded "12 / 12,379" of a map correctly saying "0 / 2,107" — the gate was wrong
and the map was right, so its numbers and its probe codes now come from the file
the leaf itself reads.
2026-09-26 13:36:15 +00:00
Doxa Maps
e87db2b0a5 Library index: list ApproxPinNote, which landed without a regeneration
check:library-index failed on main after dee9f9c9 added legends/ApproxPinNote.vue; bun run library-index
regenerates the derived menu.
2026-09-26 13:35:57 +00:00
Doxa Maps
8048c3b900 Fourteen accessible names that never reached the catalogue
The dashboard's five resize handles are role="separator" widgets with arrow-key
operation and live aria-valuenow — properly built, and four of them already read
their names through T(). None of the six keys they asked for existed. aria.json
held eleven keys and not one of them was a resize key, so every handle fell back
to its English default in all eleven locales: a screen reader in Arabic
announced "Resize filters rail" over an otherwise Arabic board. The T() call
sites were right the whole time; the catalogue simply never caught up, which is
the quiet half of this defect class and the half no gate was watching.

Ten resize keys (each handle's accessible name plus its tooltip hint) and
aria.removeFilter for the kit's chip strip, all eleven locales.

Three dashboard keys for the shell's new polite live region: results_live,
filters_live, search_live. They are the sentence a screen-reader user gets when
a brush changes the row count — "693 of 2,107 groups shown · Filters: Religion".
The counts arrive already formatted by the shell, so numerals are untouched here
and the placeholders pass straight through.

Keys are appended, never reordered: a catalogue diff that reshuffles is a diff
nobody can review. check:i18n-parity and check:english-leaks pass, and
check:i18n-never-translated finds none of these fourteen identical across
locales. (It still reports poster.json:dpi, tables.json:csv and tables.json:json
from before this branch.)
2026-09-26 13:35:57 +00:00
Doxa Maps
c683d49716 The dashboard now says out loud what a filter just did
Cross-filtering is the one interaction whose whole point is that acting on ONE
control changes a number somewhere ELSE. Pick "Islam" in the left rail and 2,107
becomes 693 across the KPI strip, the map, the table and the charts. A sighted
user watches that happen. A screen-reader user heard nothing at all: this
element carried exactly one role="status" (the table's selection pill) and zero
aria-live regions. The filter worked; the feedback did not exist.

ONE polite live region in the shell, not one per panel. Six surfaces change on
every brush, and polite announcements QUEUE — six regions would make the user
wait through five repeats before reaching the next control. It is always
rendered and starts empty, because a live region inserted already holding its
text is routinely not announced; it is visually hidden rather than display:none,
which would take it out of the accessibility tree along with the pixels. It is
debounced at 700ms for the same reason the selection camera is debounced: typing
re-derives the row set per keystroke, and an un-debounced region would queue one
announcement per character. It stays silent on arrival and only ever reports a
change. It names the count, the total, the active facets and the search term,
formatted by the shell's own formatter so it can never read as a different
number from the KPI strip beside it.

ONE RESIZE HANDLE ANNOUNCED ITSELF IN ENGLISH in all 11 locales. Four of the five
read their title and aria-label through T(); the map/table one held raw string
literals. It survived review because each half looks correct on its own — the
ternary is right, the strings are right, only the missing T( is wrong. Both now
resolve through the catalogue. (The keys themselves are on
sr/dashboard-a11y-strings: aria.json held eleven keys and not one was a resize
key, so ALL five handles have been falling back to English. The T() call sites
were right the whole time.)

THE CHIP ✕ IS NOW BIG ENOUGH TO HIT. The live strip's remove button was a
~13x16px glyph — the smallest control in the product, and the only way out of a
narrowed board, where a miss costs the reader the whole view. The row height
cannot grow: three comment blocks above it record a measured layout-shift bug and
the Driver's "a lot more subtle" instruction that pinned it to 16px. So the HIT
AREA grows and the BOX does not, via an absolutely-positioned 24x24 ::after that
contributes nothing to the flex row's intrinsic size. Nothing moves by a pixel.
2.5.8 is a TARGET SIZE criterion, not a touch one, so it is unconditional. A
focus-visible ring too, since the chips live in an overflow-x strip where being
scrolled into view is not the same as being visible.

The kit's own DashboardFilterChips were spans with click delegation — not
focusable, no click from Enter or Space. They are buttons now, with an aria-label
naming the ACTION rather than the filter ("Religion: Islam" is a good name and a
useless action), type="button" so a partner's form is not submitted by a chip, a
focus ring and a 24px floor. The reset-all chip deliberately gets NO aria-label:
its visible words already are the action, and overriding them breaks voice
control.

Recording what this does NOT fix, because the measurement that prompted it named
the wrong file. DashboardFilterChips is exported from the kit and mounted by
NOBODY — round 1 of BUG-DUPLICATE-FILTER-BADGES removed it, and the strip on
screen belongs to SearchFilterHeader, whose remove button was already a real
<button type="button"> with a localized aria-label. So the keyboard half was a
latent defect closed before the next dashboard mounts it, not a live one. The
live defect in that same control was its size, above.

check:dashboard-filter-a11y guards all of it, on the kit component AND the strip
that actually ships. It walks the parsed template AST rather than grepping,
because grep cannot tell a bound :aria-label from a literal one, cannot tell a
button from a span named like one, and cannot see a live region hiding inside a
v-show'd cell. It also reads the built bundle, since source-correct plus
bundle-stale is a real repeat failure here. Fourteen mutants were run against it;
every one fails, naming the file and the reason. No browser — that is rega's.

STUDIO: needs a rebuild of research-dashboard and dashboard-plus-grid (the
composite bakes the shell in). Part D of the gate fails until you do, by design.
2026-09-26 13:35:57 +00:00
Doxa Maps
f3fcce9386 "Arabic" emptied the grid, because no people group speaks "Arabic"
rega, on MapLibre, in BOTH locales: Languages > Language > "Arabic" sent
map-filtered with {language:"Arabic", languageCode:""}, the composite handed the
grid an empty code, and 2,107 rows became 0. An empty grid reads as "no
results" — the worst shape a wiring bug can take, because the reader believes
the data.

ONE LINE, AND IT WAS MINE. The emitter looked for a row whose language LABEL
equalled the selected name. A language tier's label is not a label any row
carries: the legend builds family > language > dialect and derives the language
tier by splitting the API label at the comma. Measured on the live source —
2,107 rows, every one carrying primary_language as {value,label} — there is NO
row whose label is "Arabic". There is "Arabic, Sudanese", "Arabic, Levantine",
"Arabic, Gulf", twenty-two codes in all. The exact match could never hit, in any
locale, which is why it failed identically in en and ar and why the locale fix
that prompted this code was right about the disease and wrong about this line.

This is the derived-value trap one tier down from where I last wrote it up: a
value that crosses a component boundary has to exist on a row. "Arabic" is a
grouping the legend invented; primary_language.label is a field.

So the rows are now matched the way the legend's own node matches pins — base,
"base," prefix, " base" suffix — rather than by a fourth hand-typed spelling of
a rule that already exists in two places. 61 tiers resolved an empty code
before; "Arabic" was one of them.

AND ONE CODE ONLY WHEN THERE IS ONE. "Arabic" means 22 ISO codes, so no single
value expresses it. Emitting one would filter the grid to a fraction of the
selection while looking correct; emitting the tier NAME is what showed zero. The
honest answer is to emit nothing for that axis and leave the grid unfiltered —
the map is narrowed, the grid is not, and the reader can see both. languageCodes
carries the whole set alongside, so this becomes a real narrowing the day
filterSet goes multi-value (SPEC-DASHBOARD-KIT D1) rather than a rewrite.
Measured on the fixture: 764 tiers now resolve one code and filter the grid; 41
cover several and abstain.

A DIALECT IS A LANGUAGE SELECTION TOO, and it emitted nothing at all — the
watcher never observed selectedDialect, so drilling from "Arabic" to "Arabic,
Sudanese" changed the map and left the grid reporting the tier above. Its
originalLabels are exact API labels, so it is the one unambiguously resolvable
case.

check:language-code-link, headless, no network at run time. It LIFTS the
emitter's match rule and the composite's gridLanguage() out of the shipping
source rather than carrying its own copy — a gate with its own copy of the rule
passes while the product is broken, which is exactly how this survived a green
check:linked-vocabulary. It proves the emitter's predicate and the legend's
filter expression agree on every (label, tier) pair, that every tier selects at
least one row, and that an ambiguous tier narrows nothing. The fixture is the
864 distinct label/value pairs from the live source, deduplicated rather than
sampled so the counts above are about the whole set. Four mutants; reverting the
emitter to the exact-label rule reproduces rega's finding exactly — 61 tiers
selecting zero rows, "Arabic" named first.

STUDIO: needs a rebuild of doxa-research-map and research-map-plus-grid.
2026-09-26 13:35:57 +00:00
Doxa Maps
f42daf2802 The geocoder check failed a contract it should have been reading
rega: "0 search bars on both engines". The product is right and the check was
wrong, twice, and both mistakes are mine.

UNDER MAPLIBRE, NO SEARCH BAR IS THE CONTRACT. research-map.vue says
`hasGeocoder = mapProvider === 'mapbox'`, and research-map.instances.json says it
in words: "Under maplibre the search bar is deliberately ABSENT —
GeocoderComponent's maplibre path still geocodes through Mapbox, so shipping it
would bill the very key this instance exists to avoid." The previous revision had
just been taught that a bar-less leaf is a hollow pass, and applied that lesson
to the one engine where absence is the point. An absent bar is in fact the
STRONGEST form of this gate's own assertion: a search that cannot be typed into
cannot send anyone's IP to Mapbox.
The rule is conditional now rather than hardcoded, because a keyless geocoder
may ship one day and this gate should not need rewriting when it does: no bar
under maplibre is recorded and passes; a bar under maplibre must work and still
make zero Mapbox requests. Either way the zero is what is asserted.

THE MAPBOX RUN WAS NEVER GIVEN A TOKEN, so it could not have rendered a bar
either. The leaf bakes BAKED_TOKEN = "" and nothing else supplies one, so
mapbox-gl cannot construct a Map, `map` stays null, and the bar's
`v-if="appReady && map && hasGeocoder"` never fires. Note the mechanism, because
it is not the obvious one: an explicit ?provider=mapbox does NOT fall back to
maplibre — explicitMapProvider reads the URL first — so the engine is Mapbox, it
simply has no key. A gate that fails a product for a key the gate did not
provide is measuring its own environment.
It takes MAPBOX_TOKEN from the env, or `token` from the build config — the same
ladder check:experimental-shelf uses — and injects it as window.MAP_TOKEN the way
check:auto-engine and check:a11y-button-names do. Only for the mapbox run: a
token present during the maplibre run is the very variable this gate holds at
zero. With no token the mapbox half is NOT MEASURED, reported through the SKIP
line run-parallel reads, so the wave prints it as unmeasured rather than counting
it as a pass. The maplibre half is measured either way, keyless being the whole
point of that engine.

Also separates "the bar was removed" from "the map never constructed" by probing
for a canvas, since those are different bugs with one symptom — and the second is
how this check misread itself.

The token is never printed, only its presence.
2026-09-26 13:35:57 +00:00
Doxa Maps
c377e19925 Drop my geocoder-check edit in favour of simpleresearch's contract-reading rewrite (7d3a2199) 2026-09-26 13:35:57 +00:00
Doxa Maps
c7d68dc3fa Four shared controls get a 24x24 target at every pointer, not only on touch (WCAG 2.5.8)
Their 24px floor sat only behind @media (pointer:coarse), so a desktop mouse still got the small target
(regions' finding; the phone probe runs with touch, so it measured the passing branch). 2.5.8 is a target-
size criterion, not a touch one. .mobile-collapse-caret (22x20 in a 20+4px slot), .stl-hdr-num (a 9px line
box), .rm-link-btn (11px, padding 0) and .pin-hint-x (16px) each get a 24x24 absolutely-positioned ::after
hit area at every width (the f29b8151 pattern). It adds a target without a box, so no row or slot
geometry moves; the coarse query still sizes the box on touch.
PosterWall's .pbtn, .pstock and .tape-h are HELD: their spacing is the Driver's sign-off.
The desktop verdict (2.5.8's spacing exception, an ancestor with overflow:hidden) needs a rendered layout,
so this is a needs-eyes item for rega.
2026-09-26 13:35:57 +00:00
Doxa Maps
1c63481832 Six entries hand-rolled the RTL text plugin; the library already installs it
Every one of these bundle entries carried its own copy of

    if (window.mapboxgl?.setRTLTextPlugin) { setRTLTextPlugin(url, null, true) }

which is a strict SUBSET of what library/maps/rtl-text.js already does, so the
copies could not be covering anything the library misses:

  - useMapInstance calls installRtlTextPlugin(gl) at line 450, before it builds a
    map at 537/567 -- registration still precedes construction, the one ordering
    Mapbox cares about.
  - the call is identical in effect: same v0.3.0 URL, same null callback, same
    lazy flag.
  - the block is mapboxgl-only. The library installs on MapLibre too, so every
    keyless embed was covered by the library and never by these blocks.
  - the single raw `new gl.Map` site (upg-100-list.vue:1894) installs for itself
    at 1835 and never depended on its entry.

I first justified this as deleting DEAD code, on the theory that the engine is
injected lazily so window.mapboxgl would not exist when an entry runs. That is
wrong and the measurement says so: every leaf index.html loads mapbox-gl.js as a
blocking <head> script while ./index.js is a deferred module, so the guard did
pass and the blocks were live. The reason to delete them is redundancy, which is
the weaker and truer claim.

A three-line pointer replaces each block so the next reader does not re-add a
Mapbox-only copy.
2026-09-26 13:35:57 +00:00
Doxa Maps
0f52e9ef08 gospel.legend.hnrTip in all 11 locales: the 'heard, not read' tooltip on the gospel map's legend
gospel-resources reads it through tOr() with the English inline as the fallback, so it switches to the
catalogue as soon as this key is on main, with no plugin change (gospel-plugin's request).
2026-09-26 13:35:57 +00:00
Doxa Maps
6c804159c3 Three browser gates stop passing hollow or racing (rega's gates:post run at ded4b3c1)
- check:dashboard-geocoder-provider: 0 search bars on BOTH engines. Its default leaf (research-map) hides
  the bar under MapLibre on purpose, and the tokenless Mapbox run could not draw. It now defaults to
  doxa-simple-map (a bar on both engines), and the Mapbox run gets a host token: TEST_MAPBOX_TOKEN, or a
  well-formed fake whose token-carrying requests are aborted, never sent.
- check:composite-embed-knobs: every tk case SKIPPED (no baked token since the auto engine), so every
  provider case went UNMEASURED and the gate still PASSed. It takes TEST_MAPBOX_TOKEN, and a run where no
  case measured anything exits 75 NOT MEASURED instead of PASS.
- check:linked-vocabulary: it attached its groups-filtered listener after goto and could miss the grid's
  first emit ("the grid never reported a total"). The totals are now recorded from page start
  (addInitScript).
Not browser-run here (browsers are rega's): rega's next gates:post pass is the proof.
2026-09-26 13:35:57 +00:00
Doxa Maps
3dddba0eeb Rebuild pplr-data-maps, and regenerate the tree
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
2026-09-26 13:24:23 +00:00
Doxa Maps
6bdfa59437 PPLR legend: its loading, empty and overflow lines speak the reader's language
PPLR's SemanticTreeLegend (a diverged copy of the library's; retiring it is card
RETIRE-PPLR-SEMANTICTREELEGEND) still typed in five strings: "Loading {label}…",
"Loading data…", "No data at this level", "Showing top {n} of {m}" and "use the
geocoder above to find the rest". The keys exist in all 11 locales since
d4359163 (legend.loadingRows / loadingData / noDataAtThisLevel / showingTop /
useGeocoderHint), which the library copy uses.

They now go through the component's existing guarded translator (ta), with the
English added to its fallback table, so a host without i18n still reads
English, never a key. Numbers keep their current toLocaleString (numerals held).

Headless: build OK, and check:no-free-identifiers, i18n-parity and
profiles-mount pass. (check:ui-strings-have-keys, which found this, is not on
main yet.)
2026-09-26 13:24:08 +00:00
Doxa Maps
85a4172644 Merge APPROXPIN and rebuild against the library it moved
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
studio's APPROXPIN (dee9f9c9) moved library/ — legends, PinHint, useMapInstance,
i18n — so the rebuild was certain rather than conditional this time. Checked, as
always, with `git diff --name-only <base> <main> | grep '^library/'` rather than
assumed: that test was EMPTY on one earlier merge and NON-EMPTY on the next two,
and it is the only thing that decides whether the bundle must follow.

All conflicts were DERIVED artifacts again — my two leaf HTMLs and the manifests,
zero source conflicts. Resolved to main's fresh build, then regenerated from the
merged source, because picking a side of a generated file is meaningless.

VERIFIED BY HASHING, the step whose absence shipped a blank page: fix:sri rewrote
the two manifests, and I then recomputed sha384 over the actual bundle —
upg-100-list, upg-100-mfe and poster-wall all MATCH, whole-tree sweep 57 integrity
attributes with 0 mismatches. fix:sri, not tree: studio had already regenerated the
pages and the gate itself warns that tree re-reads .vue source on a shared branch.
2026-09-26 13:20:45 +00:00
Doxa Maps
dee9f9c9b3 Rebuild the consumers main left stale (build owner, README rule 5)
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
check:composite-freshness found stale on main: all-people-groups
cities-internet
country-posters
dashboard-plus-grid
demo-map
doxa-maps-spa
doxa-research-map
doxa-simple-map
gospel-resources
key-cities
my-upg-100-list
plugin-studio
pplr-data-maps
prayer-walk-planner
regions-dashboard
research-dashboard
template-bundle
upg-neighbor
wall-of-people-groups. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
2026-09-26 13:14:13 +00:00
Doxa Maps
420c36a405 ui-strings baseline: gospel's resources-map types the pin note's first sentence, which now has a key
The shared approximate-pin note (pins.approximate) turned gospel-resources' own hardcoded copy of the
same sentence into 'has a key but typed in'. Recorded as known debt for gospel-plugin to switch to
ApproxPinNote; no string was added.
2026-09-26 13:04:16 +00:00
Doxa Maps
fef8c7b0fd The last of the shared-library English: legend, poster preview and tab loading states
Third and final batch of the shared-library strings, in the shepherd's order:
SemanticTreeLegend (4), PosterPreview (2), PosterWall (2) and
VerticalTabsLayout (2), plus PosterWall's "people groups" which already had a
key and was still typed in.

These are all LOADING and OVERFLOW states — "Loading data…", "Showing top 500 of
2,107", "use the geocoder above to find the rest", "Loading map snapshot…",
"preview unavailable", "Could not load X". Text a reader meets exactly when
something is slow or has gone wrong, which is the worst moment to be handed a
language they do not read. PosterWall's own source called one of them "i18n
DEBT" in a comment; it is paid now.

The counted ones take a placeholder rather than being split around an
interpolation — legend.showingTop is "Showing top {n} of {m}" — so a translator
can move the numbers within the sentence. Languages do not agree about where a
count goes, and a sentence assembled from fragments cannot be reordered at all.

VerticalTabsLayout needed a different shape: it is an options-API component, so
a module-level helper compiles fine and then renders nothing, because its
template can only see what the component returns. T is exposed from setup().

★ THE NEW GATE CAUGHT SOMETHING I WOULD HAVE MISSED, on its first real batch.
Adding these keys flipped two strings in
plugin-designs/pplr-data-maps/src/components/SemanticTreeLegend.vue from "no
catalogue entry" to "has a key and is still hardcoded" — that file is a COPY of
the library component I just fixed, carrying the same debt. It is another lane's
plugin so I have not touched it, and it is reported rather than quietly
baselined away. The baseline is refreshed to today's truth so the gate guards
the new line: 285 → 273 without a key, and the two copies recorded as known debt
rather than as a regression.
2026-09-26 13:04:16 +00:00
Doxa Maps
36ad9ae73c The engine logo's label follows the reader's language, on both engines
rega's row 34 (map controls in ar) found the engine logo's label English: "Mapbox homepage" /
"MapLibre logo" — one engine key with two meanings. engineUiLocale(lang, provider) now takes the engine
and sets LogoControl.Title from mapui.mapboxHomepage or mapui.maplibreLogo (11 locales). gospel-resources
and cities-internet build their maps RAW; engineUiLocale is documented as exported for them. (PinHint's
close button was already translated on main as aria.dismissHint.)
2026-09-26 13:04:16 +00:00
Doxa Maps
1f77810450 check:share-policy: record the template-bundle, which became a map
22b92ae0 made the starter's first screen a real map (CRITIC-11), so the gate
found a map bundle with no share decision. It is recorded as 'none': the starter
is not published, and a copy adds a ShareButton when it becomes a real map. The
gate enforces that assumption: if template-bundle is ever published, 'none'
fails it. Now PASS, 12 map bundles.
2026-09-26 13:04:16 +00:00
Doxa Maps
1228cd1f1a check:facet-cascade: read the facet rail by brace depth, so getter titles stop blinding it
The gate reads facetRail out of dashboard.config.js with /\{[^{}]*\}/, which
matches only objects with no braces inside. 53e2c662 translated the rail titles
as getters (get title() { return tStatic(...) || 'People' }), so the four drill
sections stopped parsing. The bus was then built with no hierarchy, and the gate
reported 21 'orphaned child' failures in a dashboard that cascades correctly
(the real one reads the live config object, never this parser). Red on main
since 53e2c662 (bisected by swapping the gate's only two inputs: 7f700935 OK,
53e2c662 FAIL).

The parser now splits the array into top-level objects by brace depth, skipping
quoted strings, and throws if a section has neither a drill nor a facet. So a
parse miss is an error, never a false pass or a false fail.

Headless: it passes on main's real files. With a poisoned bus (configureHierarchy
installs no hierarchy) it FAILS; restored, it passes.
2026-09-26 13:04:16 +00:00
Doxa Maps
9888c4bcc9 gates:post reports three buckets, PASS / FAIL / NOT MEASURED, and exits non-zero only on FAIL
A skipped or unmeasurable gate and a failing one shared one exit code, so real reds hid among skips
(regions measured 15 of 67 red at d3d3c3f8, mixed with gates that simply could not look).
- Exit 75 (EX_TEMPFAIL) from ANY step is NOT MEASURED, as is a gate that exits 0 announcing SKIP or NOT
  MEASURED. Only any other non-zero exit is a FAIL. The summary line is
  "PASS n · FAIL n · NOT MEASURED n", then the unmeasured by name, then each failure in full.
- Browser gates run only on the browser seat (DOXA_BROWSER=1; the project rule that browsers are one
  agent's). Elsewhere they are NOT MEASURED without being started, instead of failing to launch.
- `verify` is graded static: verify-all runs its browser guards only with --full, so the plain step
  no longer goes through the browser slot, where it printed "ALL GUARDS PASS (browser guards skipped)"
  and still exited non-zero.
2026-09-26 13:04:15 +00:00
Doxa Maps
e9f5edf79d A gate for English typed into a template, so the ground we have won stays won
check:composite-locale-leaks asks a good question — "does the catalogue
translate this string, and is the page showing English anyway?" — but its
criterion is that the catalogue already HOLDS the string, so a string nobody
ever added is invisible to it by construction. And it runs in a browser, so it
only ever sees what happens to be on one screen.

That blind spot was measured, not guessed. After both composites passed the leak
gate with zero findings, a source audit of the same two trees found 31 more
user-visible strings. Most were aria-labels, titles and tooltips: text only a
screen-reader user or a hovering mouse ever meets. Our localization verification
had been "what can I see", and the blind spot was exactly the readers who most
need the words.

TWO CLASSES, because they are different defects with different fixes:
  NO KEY      wording must be written and translated — sometimes the Driver's call.
  HAS A KEY   the translation already ships in eleven locales and the reader is
              shown English anyway. The cheapest defect in the catalogue: the
              work was done and wasted. Nobody was looking for this one; it only
              appeared because the report was split in two.

★ WARN-ONLY AGAINST A BASELINE, DELIBERATELY. Failing on the whole backlog — 285
without a key, 29 hardcoded-with-a-key across 126 components — would make it
unlandable and it would be switched off within a day. It fails on what is NEW, so
the count can only fall; --update refreshes the baseline when a batch lands.

QaCorner is excluded BY NAME, with the reason in the file: an opt-in developer
widget that studio is making host-neutral or removing. Eleven locales for a
corner only we open is not worth the translations, and a judgement like that is
better written down than left as a silent gap.

NEGATIVE-TESTED ON BOTH CLASSES, because a gate never seen to fail is not
evidence: a new text node and a new title attribute are both caught and named;
an aria-label hardcoded to "Reset all" — which already ships in every locale — is
caught as the second class with the fix stated. Restored, it passes.
2026-09-26 13:04:15 +00:00
Doxa Maps
1ac32fe3d0 People-group pins say what they are: one shared note, and the groups that share a point are named
A people-group pin is a representative point, not an address, and some pins ARE the same point: on the
Doxa roster 2,107 groups sit on 2,048 coordinates, 108 of them on a point shared with another (gospel-
plugin's measurement). Every map with people-group pins must say so, in one wording.

- library/components/legends/ApproxPinNote.vue: "The dot marks where this people is found, not a town or a
  boundary." always; when the selected pin's point is shared, "It sits on the same point as <names> — <n>
  groups share this coordinate…". Never prints the raw coordinate. Wording: gospel-plugin's P5 proposal,
  in a new pins catalogue (11 locales).
- library/utils/colocation.js: the co-location index, built from the roster THE MAP draws (rows or
  GeoJSON features), never a hardcoded count.
- LegendDesktop and LegendMobile (research map, simple map, country posters, cities, UPG-100) show the
  note under the legend, and under the detail card with the shared names.
- check:approx-pin-note (headless, gates:post): the index, the two sentences, no coordinate, Arabic.
2026-09-26 13:04:15 +00:00
Doxa Maps
29feabb9a0 Rebuild cities-internet, and regenerate the tree
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
2026-09-26 12:54:38 +00:00
Doxa Maps
bb7a6d869f Cities with Internet: the map's own labels speak the reader's language
The connectivity map is built raw (new gl.Map), not through useMapInstance, so
it never handed the engine a UI locale: the canvas's "Map" name, "Zoom in",
"Toggle attribution" and the gesture hints stayed English under ar on both
engines (rega, row 34, _qa-cycle/rega/rows31-34-0f136d25/).

It now passes locale: engineUiLocale(readerLang(), provider) at construction,
with the same reader-language ladder useMapInstance uses (ProfileLoader's lang,
profile-config, ?lang=, <html lang>). The provider argument is ready for
studio's per-engine logo label; today's engineUiLocale ignores it.

Headless: the bundle builds and carries the engine key map (Map.Title...), the
ar catalogue has mapui.map = "الخريطة", and check:no-free-identifiers,
profiles-mount and universal-props pass. Not rendered in a browser.
2026-09-26 12:54:15 +00:00
Doxa Maps
49992a5ddd Merge branch 'main' of https://git.nuxtbase.app/doxa-life/doxa-maps into bundler-3/work
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
# Conflicts:
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/gospel-resources/charts/index.html
#	public/dx-maps/gospel-resources/data-tables/index.html
#	public/dx-maps/gospel-resources/gospel-dashboard/index.html
#	public/dx-maps/gospel-resources/gospel-resources.js
#	public/dx-maps/gospel-resources/resources-list/index.html
#	public/dx-maps/gospel-resources/resources-map/index.html
#	public/dx-maps/manifest.json
2026-09-26 12:50:53 +00:00
Doxa Maps
1f1edb6c4d The engine's own controls speak the reader's language
This leaf calls `new gl.Map` directly rather than going through useMapInstance, so
it never inherited the locale map the shared composable passes: under Arabic every
string we own was Arabic and the engine's own were not — "Toggle attribution", and
the canvas's accessible name, which is what a screen reader announces the map as.

The strings were already in the bundle; nothing was handing them to the engine.
Measured that way: the Arabic mapui catalogue is present in the built bundle both
before and after, while ENGINE_UI_KEYS — the map from the engine's key names to
ours — appears only after. Set at construction, the only time either engine reads
it. Needs eyes to confirm on screen.

The one English legend tooltip now goes through t(), with the English kept in the
template as the fallback so it renders exactly as it does today until the key
lands, rather than showing "gospel.legend.hnrTip" in a tooltip.
2026-09-26 12:50:05 +00:00
Doxa Maps
a6273dc905 Merge studio/mirror and rebuild: library/ changed, so the bundle had to follow
studio/mirror (c85eeee7) rebuilt every bundle and touched library/ —
PinHint, LegendDesktop, LegendTools, MapControlMenu, ShareButton, PosterDialog
and others — so unlike the previous merge this one genuinely required rebuilding
my bundle rather than just re-hashing it. Checked rather than assumed: the
decision of whether to rebuild turns on `git diff --name-only <base> <main> |
grep '^library/'`, and last time that was empty and this time it is not.

ALL SIX CONFLICTS WERE DERIVED ARTIFACTS — my bundle, my three leaf HTMLs and the
two manifests — and ZERO source files conflicted. Resolved to main's freshly built
versions and then regenerated from the merged source, because picking a side of a
generated file is meaningless: neither side is authoritative, the source is.

VERIFIED BY HASHING, which is the step whose absence shipped a blank page three
commits ago. fix:sri rewrote files this time (it reported nothing to do last time
only because `tree` had already fixed them), so the summary alone would have been
even less informative. Recomputed sha384 over the actual bundle: upg-100-list,
upg-100-mfe and poster-wall all MATCH, and a whole-tree sweep is 57 integrity
attributes with 0 mismatches.
Used fix:sri and NOT tree, per the gate's own advice — tree re-reads .vue source
and on a shared branch can bake in another agent's half-finished work. studio had
already regenerated the pages, so there was nothing to regenerate.

BLAST RADIUS: the only bundle differing from main is mine. Pins-first source
confirmed intact after the merge (boundaryPromises, paintPinsEarly, the deferred
boundary await).
2026-09-26 12:38:51 +00:00
Doxa Maps
c85eeee783 Rebuild the consumers main left stale (build owner, README rule 5)
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
check:composite-freshness found stale on main: all-people-groups
big-picture
cities-internet
country-posters
dashboard-plus-grid
demo-map
doxa-maps-spa
doxa-research-map
doxa-simple-map
gospel-resources
key-cities
my-upg-100-list
plugin-studio
pplr-data-maps
prayer-walk-planner
regions-dashboard
research-dashboard
template-bundle
upg-neighbor
wall-of-people-groups. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
2026-09-26 12:30:43 +00:00
Doxa Maps
205a871d44 check:i18n-never-translated: CSV and JSON are file-format names, the same in every locale by design 2026-09-26 12:23:49 +00:00
Doxa Maps
83fc3f5029 Share, export, clusters and the pin hint stop being typed in English
Second of the shared-library batches, in the shepherd's order: ShareButton,
DataTable, LegendTools, and PinHint's dismiss label.

★ THE ONE THAT MATTERS MOST IS THE PARAGRAPH A PARTNER READS. ShareButton's
embed tab explains where to paste the snippet — "WordPress, Squarespace, Wix, or
any site that accepts HTML widgets" — and it was English on every locale of a
product whose whole pitch is that a partner can drop it into their own page. The
two tab labels beside it likewise.

Also wired: the data table's CSV and JSON buttons, its row-detail hint and
dialog label; the legend's Clusters button and the Minimum Spanning Tree option
with its explanation; and the pin hint's Dismiss.

★ SIX SITES NEEDED NO NEW WORDING AT ALL — they already had translations in all
eleven locales and were still typed into the template: four "Close" buttons
(buttons.close) across PosterDialog, DataTable, MapControlMenu and the QA
corner, "Expand legend" (aria.expandLegend) and PosterWall's "people groups".
Those are the cheapest defect in the whole catalogue: the work was done, the
reader just never saw it.

CSV and JSON are keyed but identical in all eleven, like DPI in the poster
batch. A format acronym is not an untranslated string; the key exists so a
language that does translate it can, without anyone editing a component.

★ LIBRARY CHANGE — studio's to land under rule 5B. I have NOT rebuilt anything.
Until it lands, every string falls back to the English it reads today.

Measured with the source audit: shared-library strings with no catalogue entry
go 32 → 21, and the has-a-key-but-hardcoded class goes 6 → 2. Remaining, in
order: QaCorner (10, a developer tool), SemanticTreeLegend (4), PosterPreview,
PosterWall and VerticalTabsLayout (2 each).
2026-09-26 12:23:49 +00:00
Doxa Maps
1795fb4740 Plugin Studio rail laid out like plugin-designs/: one folder per bundle, its elements inside
The Driver's ask: one folder per BUNDLE with its ELEMENTS inside, bundles sorted by capability, highest
first. The rail listed every element flat under its own capability, so a bundle's elements were
scattered (gospel-resources' five screens sat in three sections). Now each capability section (5 → 1)
holds the bundles whose HIGHEST capability it is, in name order; a bundle with several elements is one
folder (country-posters, gospel-resources, my-upg-100-list, regions-dashboard, cities-internet), and a
single-element bundle is shown as its element. Composites keep their folded composition trees.

StudioTree identifies a plugin's row by a `canonical` flag rather than "depth 0", so auto-reveal opens
the bundle folder above an element chosen by URL or restored tab. New folder icon; 'elementsCount' and
'elements' in all 11 studio catalogues.
check:studio-rail (headless, gates:post) runs the studio's real rail code on the built manifest and
asserts the layout and one canonical node per plugin (21 bundles, 33 elements); it fails on the previous
rail. Also: poster.json:dpi is declared identical on purpose in check:i18n-never-translated (a unit
symbol kept as-is by project decision), which had turned that gate red on main.
2026-09-26 12:23:49 +00:00
Doxa Maps
ded4b3c105 how-to: hosting the dx-maps folder — caching, compression and CORS
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
From exp-shepherd's web-boundaries report, checked against main (afb34488): no file in dx-maps/ is
content-hashed today, so everything takes public, max-age=86400, stale-while-revalidate=604800
with an ETag, and immutable only once names are hashed. The boundary file is 1,866 KB raw / 597 KB
gzipped (measured); the smaller -web copies are not on main yet, so not cited. Script embeds need
ACAO * because every embed.script carries integrity + crossorigin=anonymous. The first-paint
figures are rega's cold loads of the UPG-100 list (9.5-16.5 s) and studio's bundle/engine split.
2026-09-26 12:19:02 +00:00
Doxa Maps
fa7aee343b Rebuild upg-neighbor pplr-data-maps, and regenerate the tree
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
2026-09-26 12:15:28 +00:00
Doxa Maps
ff99c2d27e PPLR data maps: the map boots in the projection its button says
The three map views ask for projection:'mercator' at construction, but on
Mapbox the style's own projection (globe) wins, so the map booted as a globe
while the view's state and button said Mercator, and the first "Switch to
Globe" click did nothing (rega, C2 at 0f136d25: pre/post-mapbox logs, "proj
globe -> globe"). The existing setProjectionFor ran only after a basemap
switch, never at boot.

Each view's 'load' handler (religion, rop-tree, language-families) now applies
the state's projection first; the style is ready there on both engines.
Headless, against a map whose style projection is globe: before, the map is
globe while the state is mercator; after, both are mercator.
2026-09-26 12:14:42 +00:00
Doxa Maps
64568ba685 My UPG Neighbors: the flat projection is applied on MapLibre too
Four lenses (send-map, lang-cluster, the cockpit's MapCell and FlowerClusters)
called setProjectionOn(m, 'mercator') straight after initializeMap(). MapLibre
throws "Style is not done loading" from setProjection before the style loads;
setProjectionOn swallows it and returns false, so on MapLibre the projection was
never set (rega, C2 at 0f136d25). Mapbox accepts it early, which is why only
one engine showed it.

A small plugin helper, src/whenStyleReady.js, runs the call at once if the style
has loaded, else on 'style.load'. Headless, against a MapLibre-shaped map that
throws before load, with the real setProjectionOn: before, it returns false and
the projection stays null; after, it is mercator, both when the style loads
later and when it is already loaded.
2026-09-26 12:14:41 +00:00
Doxa Maps
afb34488cc A country click ends in a move you can make now
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Every number on the country sheet is work for somebody else to fund, staff or
translate. The one thing the reader can do before closing the tab was reachable
only by guessing which pin to tap, so the sheet now names it: the largest group in
this country with nothing and nobody praying, one tap from its prayer page.

Need first, then size, and India shows the cost of that order — of its 601 groups
with nobody praying only five have nothing at all, so it offers Malai Pandaram at
8,700 people ahead of Badhai at 851,000, who already have Scripture and film. The
sub-label says which rung the reader was handed.

The count above it reads "601 / 779", never a bare 601: doxa.life publishes a page
for 1,723 of the 12,379 groups here, so nobody-praying can be said of the groups
that HAVE a page and never of the country. Zero still means zero on doxa.life's
counter, not a claim about the world.

Costs 1.05 kB: the prayer pages and the tabs catalogue were already shipped.
2026-09-26 11:54:39 +00:00
Doxa Maps
91d9edba72 Merge main and rebuild through the whole recipe, not just the first step
MY LAST THREE COMMITS SHIPPED A PAGE THAT COULD NOT RUN, and rega caught it: the
committed bundle hashed to sha384-k1mPDt9L… while every leaf's integrity attribute
still pinned sha384-GEhDNkbg… — the PREVIOUS bundle. The browser refuses the script
outright, so 6 of 6 of their runs loaded only the html and the js and never created
a map. A blank page.

I RAN `vite build` FOUR TIMES AND NEVER RAN THE OTHER TWO STEPS. dx-shepherd's
recipe is build -> tree -> fix:sri, and I ran the first third of it and reported
success each time because vite exited clean. It did — the BUILD was fine. What was
broken is the ARTIFACT PAIR: index.html and my-upg-100-list.js are two files that
must agree about a hash, and "vite exited 0" says nothing about whether they do.
That is the same measure-the-artifact-not-the-property mistake I have spent this
whole session finding in other places, committed four times in a row in my own
build step.

FIXED PROPERLY THIS TIME:
  · merged main (d3d3c3f8). rega also flagged the stale base — the branch was on
    c2af6b16 and missing main's catalogue trimming, which is why the bundle was
    1,026,943 B against main's 811,632. After the merge it builds to 792 kB.
  · the ONLY merge conflict was public/dx-maps/my-upg-100-list/my-upg-100-list.js,
    a DERIVED artifact — so neither side is authoritative and picking one would be
    wrong on principle. Regenerated it from the merged source instead.
  · then `bun run tree`, then `bun run fix:sri`.

VERIFIED BY HASHING, not by trusting the tool's own summary. fix:sri reported "115
already agreed, rewrote 0", which is only reassuring if `tree` had already fixed
them — so I recomputed sha384 over the actual bundle and compared it against every
leaf that loads it: upg-100-list, upg-100-mfe and poster-wall all MATCH. Then swept
the whole tree: 57 integrity attributes checked, zero mismatches.
AND CHECKED THE BLAST RADIUS, because `tree` regenerates every leaf's HTML: the
other bundles under public/ (all-people-groups.js, big-picture.js) are byte-identical
to main — the merge brought main's versions, my rebuild did not touch them. Only my
own bundle differs, as it should.

NOT SIMPLIFIED YET, for the record: the merge brought gb-IND-ADM1-full.geojson
(1,796 KB) as an ADDED higher-detail variant. The SERVED files are unchanged
(world-adm0 1,866 KB, gb-IND-ADM1 1,628 KB), so the 3.6 MB parse cost still stands
and the boundary-simplification work is still pending elsewhere.
2026-09-26 11:46:13 +00:00
Doxa Maps
0f136d2513 Merge branch 'main' of https://git.nuxtbase.app/doxa-life/doxa-maps into bundler-3/work
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
# Conflicts:
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/gospel-resources/charts/index.html
#	public/dx-maps/gospel-resources/data-tables/index.html
#	public/dx-maps/gospel-resources/gospel-dashboard/index.html
#	public/dx-maps/gospel-resources/gospel-resources.js
#	public/dx-maps/gospel-resources/resources-list/index.html
#	public/dx-maps/gospel-resources/resources-map/index.html
#	public/dx-maps/manifest.json
2026-09-26 11:42:26 +00:00
Doxa Maps
d3d3c3f8fb Rebuild the consumers main left stale (build owner, README rule 5)
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
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-resources
key-cities
my-upg-100-list
prayer-walk-planner
regions-dashboard
research-dashboard
template-bundle. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
2026-09-26 08:57:11 +00:00