Commit graph

1448 commits

Author SHA1 Message Date
doxa-maps-88655c70
d1af039ac4 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: big-picture
country-posters
dashboard-plus-grid
gospel-resources
my-upg-100-list
research-map-plus-grid; also rebuilt: regions-dashboard. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
2026-09-25 21:29:35 +00:00
doxa-maps-88655c70
bd75f609da Arabic: their people-group vocabulary, and the list leaf reads ?lang= too
Two defects, both invisible to an English diff because both sides were English.

1. THE LIST LEAF NEVER GOT THE ?lang= FIX. I repaired languageCode in
region-dashboards.vue and stopped; regions-list.vue has the same computed and the
same comment block describing the same defect, and it still read only props and
profile-config. So a shared /regions-list/?lang=ar link rendered "المناطق" as its
heading and then listed all 41 countries as "Angola", "Benin", "Cameroon".

2. OUR ARABIC WAS NOT THEIRS. Ten strings used vocabulary doxa.life does not use:
"مجموعة بشرية" where they say "مجموعة شعبية" for a people group, "مُخْدُومَة"
where they vowelise it "مَخْدُومَة", and for unengaged an invented
"غير مبشرة" / "الهدف هو القضاء على…" where they simply say "غير مَخْدُومَة".
Each replacement is a string read off their live /ar/ pages in this session, with
our placeholders re-inserted where their rendered page carried the values —
copied, not translated, which is what the brief asks for and what I can defend.

MEASURED, by the census in Arabic: 190 unaccounted additions and 8 omissions
before, 9 and 8 after the leaf fix, 0 and 0 after the vocabulary. The English
census reported a perfect clone throughout, which is exactly why the locale
dimension was worth running.

The sanctioned list now resolves through our own catalogue, so a permission
granted in English is the same permission in Arabic: "عرض ملصقات الدولة" is
recognised as the Driver's country-poster toggle instead of being reported as an
invention. Hardcoding its Arabic would only have moved the problem to zh.

Also repaired every probe URL for the dx-maps rename — 180 paths across 153 files
were still pointing at /doxa-maps/, which now 404s, so the whole measurement
apparatus was aimed at a tree that no longer exists. Replaced only the
slash-delimited segment, leaving doxa-maps-spa and the repo URL untouched, and
proved the repair by re-running the English census to its known-good baseline
before trusting anything else.

Built ONLY regions-dashboard (rule 5: studio owns the full build). This touches
library/i18n/locales/ar/regions.json, so other bundles need a consumer rebuild —
messaging studio with the sha.
2026-09-25 21:22:44 +00:00
doxa-maps-88655c70
9006a8eabd Merge main into bundler-2/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/index.html
2026-09-25 21:14:43 +00:00
doxa-maps-88655c70
d1f9264016 The dashboard's search header follows the engine it was given
It fetched the Mapbox geocoder from api.mapbox.com whatever the provider, and
never passed `provider` to the GeocoderComponent it mounts — so a partner who
chose MapLibre, the keyless engine picked precisely so that no Mapbox key and no
Mapbox traffic is involved, still sent every visitor's IP to Mapbox and still
got the Mapbox geocoder. It now resolves the provider through the usual ladder
and, under MapLibre, preloads nothing: GeocoderComponent already fetches the
MapLibre plugin itself, so the right amount of work here is none.

★ AND THIS DOES NOT FIX THE LEAK THAT WAS REPORTED, WHICH IS WORTH SAYING PLAINLY.
The audit named this file, and this file was wrong. But research-dashboard.vue:23
says in as many words that DashboardSearchHeader "remains available in the kit
but is not mounted here" — so nothing this dashboard renders was ever affected by
it. Measured on the built leaf at ?provider=maplibre, the four requests it makes
to api.mapbox.com are all tags in the GENERATED LEAF PAGE:

    mapbox-gl.css · mapbox-gl.js · mapbox-gl-geocoder.css · mapbox-gl-geocoder.min.js

The leaf ships Mapbox GL and the Mapbox geocoder to every visitor regardless of
the engine asked for. That belongs to the leaf generator, not to this plugin,
and it has gone to studio as a finding.

So what lands here is a component made correct for whoever mounts it, and a gate
that names the real cause. The gate is deliberately NOT in gates:post: it cannot
pass until the leaf stops shipping those four files, and a red gate about another
lane's file teaches everyone to ignore it. Run it by name.
2026-09-25 21:14:19 +00:00
doxa-maps-88655c70
94f0e55444 README screenshots retaken on the dx-maps 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-25 21:07:11 +00:00
doxa-maps-88655c70
f67735bbb2 Languages: a host sets the language in profile-config
A page that embeds the Research Gallery or a single map sets its language with profile-config
{"locale":"ar"} ("lang" works too) and can switch it live. With profile-config only the map's
own box mirrors for Arabic; a ?lang=ar address mirrors the whole page. The example is the
gallery, <doxa-maps-spa profile-config='{"locale":"ar"}'>, which takes its locale from the
language prop or profile-config and hands it to every tab.
2026-09-25 21:07:10 +00:00
doxa-maps-88655c70
a3f50075a6 check:element-census-vs-live: sanctioned PAIRS, so an allowed difference leaves no phantom omission
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
A sanctioned entry only excused OUR string, so the other half of the same control — their "Show
Filters" beside our sanctioned "Hide Filters" (our panel is open on load) — still counted as an
omission. An entry may now carry `theirs` (+ `theirsFlags`): their string for the same control, under
the same Driver citation. It is excused only while OUR half is on the page; if our control vanishes,
their string is an omission again, so a pair can never hide a real gap.

Measured on the live research page with simpleresearch's preset (people-groups-grid): as committed,
THEIRS-ONLY 12 including "Show Filters"; with `"theirs": "^Show Filters$"` added to the Hide Filters
entry, THEIRS-ONLY 11 and "Show Filters" reported as the other half of the sanctioned pair. The preset
itself is simpleresearch's to update.
2026-09-25 20:57:39 +00:00
doxa-maps-88655c70
da016d8b1d The tree-identity guard can check the DATA a gate judges, not just the bundles
servesThisTree fingerprints manifest.json, which describes BUNDLES. MEASURED 2026-09-25 (gospel):
verify:gospel-map adopted another worktree's server and reported PASS, reading 16,867 links, 93
short of this tree — the manifests were byte-identical because the change under test was a data
asset (doxa-gospel-access.json); a planted jw.org link went undetected.

- servesThisTree(base, repo, { assets }) / requireThisTree(base, repo, label, { assets }): a gate
  declares the tree-relative data files it judges, and their served bytes must equal disk too.
  A mismatch or a missing file is a DIFFERENT build -> requireThisTree exits 75 NOT MEASURED,
  naming the file.
- verify-gospel-map converges onto it (its per-gate copy of the check is gone): the tables are
  declared in its adopt check, so a same-manifest/different-data server is not adopted and its own
  server is started instead; a server you NAMED that is another tree is now NOT MEASURED (75), not
  "SKIP — nothing served" (exit 0).

Negative-tested: a copy of this tree with an identical manifest and one planted link in
doxa-gospel-access.json — without assets the guard says "same build" (the incident); with assets it
refuses, naming the file; requireThisTree exits 75; this tree passes; verify:gospel-map named at the
copy exits 75.
2026-09-25 20:57:39 +00:00
doxa-maps-88655c70
405db45f19 browser-slot: a disk floor, and an infrastructure crash is NOT MEASURED, not a red gate
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-25 20:52:19 +00:00
doxa-maps-88655c70
42b3105fed 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: dashboard-plus-grid; also rebuilt: plugin-studio. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
2026-09-25 20:49:01 +00:00
doxa-maps-88655c70
134b6e484e Plugin Studio: the header's menus stay on top of every plugin
Driver, 2026-09-25: "the Mapbox token menu is not z-index on top … it is underlapping the plugins". The
header row and the pane area were siblings with no stacking context of their own, so a menu at z-index 30
lost to plugin chrome (a filter bar at 55, a drawer at 1000). The header now stacks above the content and
the pane area is isolated (isolation:isolate), so no plugin's z-index can rise over the studio's header.
Measured in a browser with a plugin open: the Settings panel and the engine menu are the topmost element at
3 of 3 sampled points.
2026-09-25 20:44:24 +00:00
doxa-maps-88655c70
db92d79d0a Landing precondition: judge public/ as COMMITTED, and point stale consumers at the build owner
- Check 2 read public/ from the filesystem, so a gitignored, untracked leftover (a pre-rename public/assets/
  in an older worktree) REFUSED repo's clean README-only landing. It now reads the commit being landed
  (git ls-tree HEAD public/). Tested: an ignored leftover passes; a committed extra folder is still refused.
- The stale-consumer refusal now states README rule 5 (dx-shepherd, 2026-09-25): one agent owns the full
  build. A change that touches library/ or anything compiled into other plugins is handed to studio to land
  with the consumer rebuild; a change stale only in the author's own plugin rebuilds just that bundle.
2026-09-25 20:40:31 +00:00
doxa-maps-88655c70
c53367f920 Merge main into bundler-2/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-25 20:31:17 +00:00
doxa-maps-88655c70
6d919169c9 A landing is refused unless the commit is fresh, one-folder and SRI-consistent
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 SEVEN composites stale on main (the committed bundle was not what its
source builds). Cause: d49b6c80 rebuilt all 25 bundles in a worktree that had not merged the dx-maps
rename — it wrote the OLD folder and left dx-maps/ stale — and every landing involved passed its own
checks. A check BESIDE the push can be skipped; this makes it a PRECONDITION of the push.

- internal/landing-preconditions.mjs, run through .main-capture/prepush on the exact commit about to
  land: (1) the working tree IS that commit, (2) public/ = README.md + the configured tree only — a build
  under another tree name writes another folder and is refused, (3) check:sri, (4) every composite
  rebuilds to its committed bytes.
- `main-capture scan` (the Driver's harness) runs a repo's .main-capture/prepush, when present, after its
  merge scan is clean; non-zero refuses the landing. Repos without the file are unaffected.

Proven with main-capture scan: (A) main as it was, 7 stale -> REFUSED naming all seven; (B) the rebuilt
main 7c96759d -> PASS; (C) a people-groups-grid string changed and committed WITHOUT a rebuild ->
REFUSED (big-picture, dashboard-plus-grid stale); (D) a public/doxa-maps/ folder beside dx-maps/ ->
REFUSED ("extra: doxa-maps"). Scratch commits were reset, never pushed.
2026-09-25 20:25:47 +00:00
doxa-maps-88655c70
a9add45656 Rebuild every bundle after resolving artifact conflicts
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-25 20:21:29 +00:00
doxa-maps-88655c70
ee46ff0610 Merge main into bundler-2/work
# Conflicts:
#	public/dx-maps/dashboard-plus-grid/dashboard-plus-grid.js
#	public/dx-maps/dashboard-plus-grid/dashboard-plus-grid/default/index.html
#	public/dx-maps/dashboard-plus-grid/dashboard-plus-grid/index.html
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/manifest.json
2026-09-25 20:16:05 +00:00
doxa-maps-88655c70
1ffbd3b584 Use library engineFor(map); the last local engine-resolution line is gone
exp-shepherd landed engineFor(map) in useMapProvider, so the expression I was
carrying can go. Theirs is stricter than mine: it instance-tests BOTH engines
rather than inferring the second from the first.

This closes a three-step path, and each step deleted something. It began as
glFor.js copied from pplr-data-maps; became one expression delegating to
useMapProvider's isMapboxMap once I found that already existed; and is now a
plain import. Nothing engine-related is left in this plugin.

Three implementations were compared before swapping, because a substitution I
have not measured is one I am guessing at: _chk-glfor-equivalence.mjs builds the
deleted copy, my interim expression and library engineFor, and runs all three
across every engine combination — mapbox map with both globals, maplibre with
both, either alone, and the case the whole fix exists for, a MapLibre map with no
Mapbox global at all. Identical in all of them.

Built on the POST-RENAME tree: 68 files under public/dx-maps/, none under the old
public/doxa-maps/. My previous all-bundle rebuild predated that rename in this
worktree and wrote orphans; confirming the tree name before building is now part
of the sequence. composite-freshness PASS on all 10, check:sri PASS.
2026-09-25 20:10:13 +00:00
doxa-maps-88655c70
7c96759d4e Rebuild every bundle on the dx-maps tree: seven composites were stale on main
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 failed on main for big-picture, country-posters, dashboard-plus-grid,
gospel-resources, my-upg-100-list, regions-dashboard and research-map-plus-grid: their committed bundles
were not what their source builds. Cause (dx-shepherd): d49b6c80 rebuilt all 25 bundles in a worktree
that had not merged the dx-maps rename, so it wrote the OLD folder and left dx-maps/ stale (the orphans
90910f32 removed). All 25 rebuilt here on current main with the dx-maps config, tree + SRI regenerated.
check:composite-freshness, check:sri, check:drop, check:public-hygiene PASS.
2026-09-25 20:08:30 +00:00
doxa-maps-88655c70
2590fe5eb1 Merge main into bundler-2/work 2026-09-25 20:00:13 +00:00
doxa-maps-88655c70
20e3d5f1e4 Rebuild the bundles the merge left behind in the renamed tree 2026-09-25 20:00:09 +00:00
doxa-maps-88655c70
90910f32f6 public/ is one folder again: drop the stale doxa-maps/ bundles a rebuild re-added, and make that a hard failure
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
d49b6c80 rebuilt four bundles under the OLD tree name after the rename to dx-maps (09014f8a), putting
public/doxa-maps/{big-picture,doxa-research-map,research-map-plus-grid,wall-of-people-groups}.js back
beside public/dx-maps/. Nothing references them (the live copies are under dx-maps/). Removed.

check:public-hygiene only WARNED about a root entry outside the drop-in contract unless run --strict, so
the build stayed green. public/ holding only the output folder + README.md is a Driver decision
(BUILD-OUTPUT-IS-ONE-FOLDER), so it is now always a finding. Proven both ways: with the orphans the gate
FAILS ('doxa-maps/ — outside the drop-in contract (dx-maps, README.md only)'); without them it passes.
2026-09-25 19:54:59 +00:00
doxa-maps-88655c70
a7c65c2bb9 check:experimental-shelf looks at the map: paint arm with its own poisons, and settled counts
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Every earlier assertion counted FEATURES, and queryRenderedFeatures answers happily over a white
rectangle (gospel's incident, 0574fe7f). Each map surface now also passes two looks:
  - COLOURS read off the map's own WebGL canvas inside its 'render' event (floor 40), so a legend
    or panel over the map cannot inflate the count and no per-plugin clip is needed;
  - FILL = the map's height over the plugin ELEMENT's (floor 70%), not canvas over container,
    which stayed 1.0 when a stylesheet collapsed both together.
Each arm has its own self-test poison and must be the one that catches it: 'blank' (every layer's
opacity 0) -> "only 1 colour(s) on its canvas ... while 12204 features still count as drawn";
'collapse' (container squeezed to 300px) -> "fills 38% of <all-people-groups>'s height".
Drawn counts are now read SETTLED (equal on two consecutive polls): a first-non-zero read took
1752 of 2107 mid-fit on Cities. The PASS line names only the surfaces that ran.
Measured: 7 bundles, 60 rows PASS, 3 n/a; lowest paint across the 40 map rows 264 colours, 92%.
2026-09-25 19:54:41 +00:00
doxa-maps-88655c70
01096d67d3 Integrate main into bundler-2/work 2026-09-25 19:50:05 +00:00
doxa-maps-88655c70
73fc1582ce Rebuild dashboard-plus-grid into the renamed tree
The tree is now published as dx-maps rather than doxa-maps, and the merge left
this composite's committed bundle behind its source under the new name.
Freshness and SRI are clean.
2026-09-25 19:49:57 +00:00
doxa-maps-88655c70
9fb4f8350a The leak gate proves its exclusions do not blind it
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
The numeric-sibling rule shipped last tick as a rider on the RTL commit
and was never confirmed by a run — both attempts returned RC=75. Live,
plausible and unmeasured is the riskiest state a change can be in, and
a GENERAL exclusion makes it worse: "an element whose own text sits
beside a sibling rendering a number is enumerating data" can go green by
excluding too much, which is the same thing as never checking.

So --self-test INJECTS a real chrome leak in the position the rule is
most likely to swallow: an English catalogue value in a label that HAS a
numeric sibling, plus a control with none. Both must still be caught.
The injected value is read from the catalogue rather than invented, so
the self-test exercises the same comparison the real run does.

  SELF-TEST: PASS — 6 of 6 injected leaks caught, including the one
  beside a number. The data, facet and enumerated-value exclusions
  narrow the population without blinding the gate.

  NORMAL: PASS — 8 of 8 combinations in ar/zh/ru/hi, 74-83 comparable
  keys each, so no combination was vacuous. dashboard-plus-grid is clean
  in all four locales, which closes Big Picture cell E.

⚠ THE SELF-TEST'S OWN FIRST RUN REPORTED NOT MEASURED, and that is worth
keeping: every non-flag argv is a target, so `--self-test` was consumed
as a leaf path and all four locales 404'd. The "no combination
rendered" guard caught my harness instead of reporting 0 leaks caught
out of 0 expected, which I could have read as a pass. Flags are now
filtered out of the target list.
2026-09-25 19:42:51 +00:00
doxa-maps-88655c70
c5cbaf4277 Integrate main into bundler-2/work
# Conflicts:
#	public/dx-maps/dashboard-plus-grid/dashboard-plus-grid.js
#	public/dx-maps/dashboard-plus-grid/dashboard-plus-grid/default/index.html
#	public/dx-maps/dashboard-plus-grid/dashboard-plus-grid/index.html
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/manifest.json
#	public/dx-maps/research-dashboard/research-dashboard.js
#	public/dx-maps/research-dashboard/research-dashboard/index.html
2026-09-25 19:41:21 +00:00
doxa-maps-88655c70
c727c87411 Plugin Studio header: language, map engine and Settings set the props every plugin gets
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Driver, 2026-09-25: "the studio at the top needs a localization dropdown, a map dropdown to swap
between Mapbox and MapLibre, and a settings button to add a Mapbox token or the URL it comes from…
the header needs to let you swap between props… so the studio becomes more functionally useful."

The header now reads: Language ▾ · 🗺 Map engine ▾ · ⚙ Settings.
- Map engine: Mapbox (needs a token) / MapLibre (no token needed) / each map's own default. The choice
  is handed to every pane as its profile-config provider and published as window.MAP_PROVIDER for
  maps nested inside composites; changing it re-mounts the maps.
- ⚙ Settings replaces the separate 🔑 button: the Mapbox public token (sk.… refused) or a token-service
  URL, with a status line that says which is in use — and that MapLibre needs none.
- Kept in this browser (localStorage); one menu open at a time. New labels in all 11 locales.

Browser-tested on the built dx-maps tree: the header shows the three controls; MapLibre sets the pane's
provider and window.MAP_PROVIDER and survives a reload; Settings then says no token is needed; Mapbox
plus a pasted token puts both on the pane; "each map's own" clears the provider.
2026-09-25 19:41:20 +00:00
doxa-maps-88655c70
2509a6e347 README: three outputs, not five methods; a Languages section; screenshot gates see every shot again
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
- Deployment is now organised around what the build makes: (1) one web
  folder (536 files, 76 MiB), embedded by iframe and JavaScript (proven) and
  WordPress (just for fun); (2) the mobile app (Capacitor, built); (3) the
  desktop app (Tauri, proof of concept). A hosting table says where the folder
  can go: dx-life's public/, Cloudflare Pages drag-and-drop (fits its 1,000-file
  / 25 MiB limits), GitHub + jsDelivr (JS embeds only: measured, jsDelivr serves
  HTML as text/plain), or any web server, with the one _headers line JS embeds
  need. No Docker. The diagram and the map-cruncher picture say three outputs.
- Languages: 11 locales via ?lang=, Arabic right to left, with an Arabic shot of
  UPG-100 (Big Picture still leaks English in Arabic; reported). The partner
  profile-config locale is deliberately not documented until it is fixed.
- check-shot-freshness and check-shot-distinctness parsed only '...' paths, so
  after 44ef31b2 turned them into `/${TREE_NAME}/...` templates they saw 2 of 26
  shots: distinctness failed, freshness passed vacuously and hid 22 stale shots.
  Both now accept either form and resolve TREE_NAME, and exit 75 (NOT MEASURED)
  unless every `await shot(` call is parsed (the one dynamic dx-life call is
  marked). Negative-tested. The 22 shots are retaken and checked by eye.
- how-to: the shell no longer overwrites the Studio (it now lives in the output
  folder); README serve line points at doxa-maps/index.html.
- Docs follow the rename to dx-maps (09014f8a): every output-folder path and URL in
  README, how-to, reference, CONTRIBUTING, the CLI section and the develop guide now says
  public/dx-maps/. The repo name, the config file name, the WordPress plugin folder and
  the doxa-* tag names are unchanged (tags are a separate landing).
- Hosting: a live example, the dx-life branch research-gallery, which drops the folder
  into dx-life public/ and fills /research with the Research Gallery.
2026-09-25 19:40:03 +00:00
doxa-maps-88655c70
a4a7ddd6fd Rebuild every bundle after resolving artifact conflicts
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-25 19:36:53 +00:00
doxa-maps-88655c70
d49b6c8093 Rebuild all 25 bundles: my own conflict shortcut had staled seven of them
I have been resolving artifact conflicts with `git checkout --theirs -- public/`
and then rebuilding only the bundles whose SOURCE arrived in the incoming diff.
That is wrong, and it put seven stale composites on main under 6cb61caa:
--theirs replaces my freshly built artifacts with whatever main happened to hold,
including bundles that nothing in the incoming diff mentions. big-picture,
country-posters, dashboard-plus-grid, research-map-plus-grid and my own
regions-dashboard were all committed as bytes their source no longer builds.

Worse, the gate TOLD me. My landing command printed
"research-map-plus-grid is STALE" and pushed anyway, because I ran freshness
next to the push instead of gating the push on it. A check whose output nobody
is obliged to act on is decoration.

Two changes, both in how I land rather than in the product:
  - after taking --theirs for public/, rebuild EVERY bundle, not the incoming
    subset: --theirs can import staleness into any of them, so the incoming diff
    is the wrong trigger here for the same reason it was the wrong trigger when
    regions-dashboard went stale this morning;
  - the push is now conditional on composite-freshness PASS, so this cannot be
    printed and ignored again.

All 25 rebuilt, check:sri PASS across every leaf, composite-freshness PASS.
2026-09-25 19:29:13 +00:00
doxa-maps-88655c70
b122009b96 Merge main into bundler-2/work 2026-09-25 19:27:30 +00:00
doxa-maps-88655c70
588a2a5d3c Translate the map legend's title, without inventing a word
Big Picture in Arabic still showed "UPGs / country" over its choropleth legend.
It is now composed from two catalogue entries that already ship in all eleven
locales — legend.columns.upgs and dashboard.country — so nothing new had to be
written in ten languages to fix it. The English shifts to "UUPGs / Country",
which is how this tree spells both words everywhere else.

It was the only one of the six remaining English strings on that view that
could be done this way. "Export CSV", "Full screen", the detail drawer's title
and empty state, and the legend's "heartbeat zone" bin all need wording that
does not exist yet, so they are on DECIDE-SR-CHROME-WITH-NO-CATALOGUE-WORDING
with one useful note: "Full screen" needs NO new wording either, because
buttons.toggleFullscreen already ships in every locale — only a decision to use
one toggle label instead of a two-state pair.

★ TWO OF THE REPORTED DEFECTS DO NOT REPRODUCE, and the measurement says why.
The table's last column header is neither English nor clipped on this tree: all
nine headers render Arabic and every one of them has scrollWidth equal to
clientWidth at 1440×900. The screenshot that reported "ent" predates the commit
that gave that column a catalogue getter.
2026-09-25 19:27:29 +00:00
doxa-maps-88655c70
09014f8a03 Rename the output folder to dx-maps
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Driver decision: no embeddable URL carries "doxa" in its folder. The tree's name is one line in
vite.doxa-maps-build-config.json ("name": "dx-maps"); everything else follows it.

- __DOXA_TREE_NAME__ (the vite define rega landed, from MFE_NAME = internal/_tree-name.mjs) bakes the name into the
  bundles for the runtime code that must recognise the tree in a URL. StackLayout.vue's
  resolveBundleSrc anchored on a literal /doxa-maps/ and would have broken every composite's nested
  bundles on a renamed tree; it now anchors on the define. The Research Gallery's dev fallback uses
  it (one reader: rega's define, not a second one).
- The native shells follow via internal/sync-app-shells.mjs: capacitor webDir public/dx-maps, Tauri
  frontendDist ../../public/dx-maps (its window url is tree-relative since the one-folder landing).
- The WordPress contract test reads the name from config instead of carrying three literals.
- check:locale-reachable extracted detectLocale alone and died with "localeFromUrl is not defined"
  after 09d03c60 factored a helper out; it now follows the calls it makes (already red on main).
- generate-tree removes its temp asset pool even when it crashes (a failed build leaked ~50 MB into
  /tmp each time; measured on a full disk).
- Capability exemplars regenerated for the new paths.

Proof: rm -rf public && bun run build -> public/ = README.md + dx-maps/; the 25 built bundles carry
zero 'doxa-maps/' paths (scanned); check:sri, check:drop, check:parse, check:public-hygiene PASS.
Tag names (doxa-* -> dx-*) are the next, separate landing.
2026-09-25 19:26:14 +00:00
doxa-maps-88655c70
cc5252b563 Rebuild Wall of People Groups with the offline notice, 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-25 19:24:09 +00:00
doxa-maps-88655c70
e31738762c Wall of People Groups: say so when the live API cannot be reached, and stop a render error
With pray.doxa.life unreachable (offline, or a local dev server whose 127.0.0.1 origin the API
refuses by CORS) the wall sat at "0 Groups Loaded" with nothing explaining why, and logged
"Cannot read properties of undefined (reading 'length')". That error was not the fetch at all:
SourceSelector's template read `sources`, which does not exist (its computed is
availableSources), so it threw on every render, online as well.
  - SourceSelector: availableSources.
  - PeopleGroupsWall: when nothing loaded and the store holds an error, an in-wall notice says
    what failed and offers Try again (inside the wall, never position:fixed over a host page).
  - The store logs the network failure as a warning: it is an expected state now shown on screen.
Measured with every pray.doxa.life request aborted: the TypeError is gone, the notice renders,
and the only console line left is the browser's own "Failed to load resource". Unblocking and
pressing Try again loads 2107 groups. Live (unblocked): 2107 groups, 0 console errors.
2026-09-25 19:20:48 +00:00
doxa-maps-88655c70
5e7ad5a409 Merge main into bundler-2/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-25 19:16:39 +00:00
doxa-maps-88655c70
4274ec45dd Rebuild the bundles the merge left behind, so no bundle ships an older copy
check:composite-freshness named seven by hash after integrating main. A build
artifact cannot be merged line by line, so they were rebuilt from the merged
sources; freshness and SRI are clean.
2026-09-25 19:16:37 +00:00
doxa-maps-88655c70
6cb61caa62 Merge main: rebuild what the incoming source requires
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-25 19:08:24 +00:00
doxa-maps-88655c70
57065889f6 Integrate main into bundler-2/work 2026-09-25 19:07:04 +00:00
doxa-maps-88655c70
82d7f21e85 The raw map shapes Arabic, Persian and Hebrew place names
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
upg-100-list builds its map RAW (`new gl.Map`) rather than through
useMapInstance, so it inherits none of the bundle entry's side effects —
including the RTL text plugin. It appeared to work only because the leaf
head PRELOADED the Mapbox peer, which let an entry-time registration
land in time. studio is removing that preload.

⚠ IT IS NOT A UI-LANGUAGE FEATURE, which is why it matters more than it
looks. A basemap draws each place in its OWN script, so over the Middle
East, Iran and Israel MOST labels are Arabic, Persian or Hebrew for
EVERY viewer in EVERY UI language. Unshaped they render reversed — a
WRONG NAME for exactly the groups this map is about — and it fails
silently: no error, no warning, just mirrored text that reads as a font
problem to anyone who does not know the script.

MEASURED with gospel's gate, which PANS to Arabia before judging because
the shaper registers lazily and reads 'deferred' at a world view:

  before   mapbox    ok    58/61 RTL labels shaped
           maplibre  FAIL  62 RTL labels on screen, shaper 'requested'
  after    mapbox    ok    58/61
           maplibre  ok    63/63 shaped

★ THE MAPBOX ARM PASSING BEFOREHAND IS THE FINDING. It is the preload
rescuing an entry-time call, so mapbox looks fine today and breaks the
moment that preload goes. MAPLIBRE ALREADY FAILED, with no preload to
rescue it — this was live for every keyless viewer, not only a future
regression. Measuring just the mapbox arm would have read "already
fine".

The install goes after the engine global resolves and before
new gl.Map: with the engine injected lazily, an index.js call runs
before `gl` exists and does nothing at all.

THE GATE IS PARAMETERISED, NOT FORKED. dx-shepherd routed it to the
other raw-map owners (cities-internet, key-cities, RegionCountryMap), so
it takes --leaf instead of hardcoding gospel's. Copying it would have
given each owner a drifting copy of the pan-first logic and the poison
arm — the two parts that needed corrections to get right.

Also carries the leak gate's third correction: the survivors of the
data and facet exclusions were in .rd-lt inside .rd-li and .rd-bl inside
.rd-bar — DashboardChartsRail renders `{{ s.key }}` beside `{{ s.value }}`
over chart.geometry, the same shape as a facet row. Chasing one class
name at a time is how that went wrong three times, so the rule is now
general: an element whose own text sits beside a sibling rendering a
NUMBER is enumerating data, not naming the UI. Section headings and
column titles have no numeric sibling and stay in scope.
2026-09-25 19:05:59 +00:00
doxa-maps-88655c70
86442aa4c0 The UPG-100 search placeholder speaks the reader's language
repo's Arabic screenshot of the list was clean except for one string:
the search box still read "Search people group, zone, or territory…" in
every locale. It was a hardcoded literal, the last English on an
otherwise localized screen.

NO NEW TERMINOLOGY — composed from wording this product already ships
and has already approved: search.kinds.peopleGroup for the group,
tabs.upg100Zone for what this plugin calls a "zone" (its own legend
names them "UPG-100 Lists" / "قوائم UPG-100" / "UPG-100 名单"), and
search.kinds.region for the territory. That is precisely why this one
could be translated while the UUPGs column header could not: there, no
source established any candidate acronym, and a wrong term looks
authoritative to a reader who cannot check it. Here the words were
already on the page.

⚠ A computed, and declared beside LEGEND_TITLE rather than at the
literal's old position, because t() is not initialised until later in
setup — a const at the original line would have captured the fallback
and never re-evaluated when the locale changed.
2026-09-25 19:05:59 +00:00
doxa-maps-88655c70
ac6347aa15 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/doxa-maps/doxa-maps-spa/manifest.json
#	public/doxa-maps/gospel-resources/charts/index.html
#	public/doxa-maps/gospel-resources/data-tables/index.html
#	public/doxa-maps/gospel-resources/gospel-dashboard/index.html
#	public/doxa-maps/gospel-resources/gospel-resources.js
#	public/doxa-maps/gospel-resources/resources-list/index.html
#	public/doxa-maps/gospel-resources/resources-map/index.html
#	public/doxa-maps/manifest.json
2026-09-25 19:04:56 +00:00
doxa-maps-88655c70
d6cdc2771e Rebuild cities-internet and key-cities with RTL shaping, 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-25 19:03:59 +00:00
doxa-maps-88655c70
ac66728a69 Gospel charts: the chart vocabulary comes from the catalogue
Every bar label, tab and legend key in the charts leaf was written inline in
English and never wired to i18n — a surface whose headings were translated while
the words inside the picture were not. Eight of them already had catalogue
entries and were simply not used; the other fourteen are new keys, translated in
all eleven locales from each catalogue's own vocabulary rather than invented
beside it.

The tab strip had to become computed. A plain array is evaluated once at setup,
so it would have kept whichever language the leaf first rendered in and never
followed a locale change; the legend arrays live in the template and already
re-evaluate on render.

Adding a key for "Full Bible" then exposed what the leak gate cannot tell apart.
It read table CELLS as if they were chrome, and a cell whose entire text equals
an English term is indistinguishable from a label by text alone. Both findings it
produced were the language being correct: Source cells carry organisation names —
JESUS Film, Faith Comes By Hearing, Door43 — and Scope cells describe what a
resource contains, one of whose 114 values is the words "Full Bible" while most
of the rest are already in the target language. Translating either would be the
defect. The boundary is structural, so the DOM now draws it.

That leaves the Type column, the one cell column carrying catalogue labels, with
its own arm. Asked the obvious way round it was wrong: requiring every translated
type to be present failed on Gospel audio in all four locales, because 1,027 rows
carry it and none was on the first page of fifty — pagination reported as a
translation defect. It asks instead that no cell equal one of the eight
enumerated type strings, which stays silent for a type that is off-screen and
fails for one that is on-screen and English.
2026-09-25 19:03:44 +00:00
doxa-maps-88655c70
d846af6f59 Rebuild all bundles: the merge brought new i18n catalogues 2026-09-25 19:00:51 +00:00
doxa-maps-88655c70
bd180fac82 Merge main into bundler-2/work
# Conflicts:
#	public/doxa-maps/dashboard-plus-grid/dashboard-plus-grid/default/index.html
#	public/doxa-maps/dashboard-plus-grid/dashboard-plus-grid/index.html
#	public/doxa-maps/doxa-maps-spa/manifest.json
#	public/doxa-maps/doxa-research-map/doxa-research-map.js
#	public/doxa-maps/doxa-research-map/research-map/index.html
#	public/doxa-maps/doxa-research-map/research-map/maplibre/index.html
#	public/doxa-maps/manifest.json
#	public/doxa-maps/research-dashboard/research-dashboard/index.html
2026-09-25 19:00:09 +00:00
doxa-maps-88655c70
ffef2b761e Raw maps shape Arabic, Persian and Hebrew place names: cities-internet and key-cities
These two maps build `new gl.Map` directly, so they never got useMapInstance's RTL install, and
their bundle entries registered nothing either. The basemap draws each place in its OWN script,
so over the Middle East most labels are Arabic, Persian or Hebrew for EVERY viewer: they were
drawn as disconnected glyphs in the wrong order. installRtlTextPlugin(gl) now runs after the
engine global resolves and before new gl.Map (an entry-time call cannot work once the engine is
injected lazily).

Gate: check:rtl-raw (+ :poison), gospel's check-gospel-rtl-shaping method (pan to Arabia first;
no RTL label on screen is NOT MEASURED; one defineProperty per global for hook + poison) over
cities-internet on both engines and key-cities (Mapbox-only, gated, no leaf: mounted on a
same-origin host page). The shared gate's --leaf argument can replace the cities rows once it
lands; the key-cities host page still needs this one.
Measured: before, cities-internet mapbox 58 RTL labels with the shaper 'unavailable' and maplibre
62 stuck at 'requested', both unshaped; after, shaper 'loaded' on both, and key-cities 56 RTL
labels shaped. Poison: 3/3 rows caught.
2026-09-25 18:59:31 +00:00
doxa-maps-88655c70
1828957f83 Rebuild every bundle that compiles in engineFor, 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-25 18:57:57 +00:00
doxa-maps-88655c70
7b9e88754b Merge main into bundler-2/work
# Conflicts:
#	public/doxa-maps/index.html
2026-09-25 18:41:40 +00:00
doxa-maps-88655c70
056942b33f engineFor(map): build markers, popups and poster maps with the map's OWN engine
Every generated leaf <head> preloaded mapbox-gl.js whatever the provider, so code that used the
bare `mapboxgl` global always found one, even on a MapLibre map. Removing that peer (it sends
every visitor's IP to Mapbox under provider=maplibre) turns each such site into an error.
engineFor(map), next to isMapboxMap in useMapProvider.js, asks the map which engine built it:
  - useSelectedPin: the selected-pin Marker
  - useMapEvents: the pin-fallback and region Popups
  - useMapPoster: main already builds the hidden map with the source map's engine (1cbfb3aa);
    its choice now goes through this one helper instead of a second inline sniff
  - pplr-data-maps: glFor is now this helper; the geocoder awaits ensureEngineScript first
  - key-cities: ensureEngineScript('mapbox') before reading the global
Measured with every api.mapbox.com tag stripped from the served leaf (no peer at all for
key-cities), before -> after:
  pin select under MapLibre, on cities-internet, country-posters, doxa-research-map and
  doxa-simple-map: "reading 'Marker'" -> marker drawn; country-posters region popup: none ->
  popup; PPLR search: no input -> suggestions (both engines); key-cities: "mapbox-gl not
  loaded" -> map loaded. Mapbox rows unchanged (they passed before and after).
The poster UI could not be driven: PosterDialog never opens in country-posters or
doxa-research-map (they pass props it does not declare and no modelValue/getMap), reported
separately. useMapPoster itself was rendered from a real map with only its engine on the page:
MapLibre "mapboxgl global not found" on the pre-1cbfb3aa library -> a 400x300 PNG with 88 colours.
2026-09-25 18:38:17 +00:00