Commit graph

2468 commits

Author SHA1 Message Date
Doxa Maps
ef3590fbbc 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-28 13:01:37 +00:00
Doxa Maps
55cc694fdd Pplr Data Maps: tab and legend labels follow a language change instead of keeping the one they started with 2026-09-28 13:01:16 +00:00
Doxa Maps
439bea6754 Use the keys that landed for three strings the map still said in English
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
L56 published the catalogue keys these three sites were waiting for, so the template now asks for
them instead of carrying the English:

  the gap list's "related:" label            -> gospel.gapList.relatedLabel
  the legend's "Show all N" clear button     -> gospel.filter.showAll, with the count as a placeholder
  the detail panel's "Nothing in X itself"   -> gospel.related.nothingInItself

Each was chosen because the swap costs no markup: the <em> and <b> wrap the whole phrase, so they
stay outside the call and the emphasis survives. The sites where a <b> sits INSIDE the sentence --
"Showing only <b>…</b>." above all -- are deliberately not in this commit, because the key is one
whole sentence and using it would silently drop the emphasis that distinguishes the filter's value
from its label. That needs a markup-preserving form, not a quiet visual regression on a production
map.

Measured, not assumed: hardcoded-english for this plugin 147 -> 144, and every one of the 72 keys
the leaf now references resolves in the catalogue. That last check caught a mistake in this very
change -- a fallback I wrote as t('gospel.state.thisVariety'), which does not exist and would have
rendered the key name to a reader. It is back to its literal until a key exists for it.

i18n parity and never-translated both pass; gospel's own render gate passes in ar, zh, ru and hi.
Rebuilt this bundle only, then fix:sri; check:sri is green at 64 leaves.
2026-09-28 12:57:56 +00:00
Doxa Maps
8a6e5543c0 Localise the region link's screen-reader label
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
The new hardcoded-English gate found this in its first run over the production
plugins: an aria-label built by concatenation, so a screen-reader user on a
non-English locale heard "Open the" and "dashboard" in English around a region
name in their own language.

It uses the key the regions list already uses for the same sentence, which is
translated in all eleven locales, so the label now reads as one sentence rather
than two languages spliced together.

Found by the gate in the plugin that wrote it, which is the argument for making
it shared rather than private.
2026-09-28 12:51:28 +00:00
Doxa Maps
eb8d1f699e UPG-100: bind the user-visible strings to the catalogue (studio L56 keys)
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Ten strings that rendered to a reader in English whatever locale they chose.
Found by check:hardcoded-english; keys landed by studio L56.

STATUS OVERLAY (renders in .upg-status): noMapboxToken, loadingBoundaries (one
key, both call sites), fetchingUupgs {n}, mapStatusCounts {polys}{zones}{total}
{pins}. The "⚠ " prefix stays in the template, per the key spec. :2084 right
beside these was ALREADY t('messages.engineNotLoaded') — this makes the
neighbours consistent with it rather than introducing a new pattern.

MAP ERROR: noMapboxTokenDetail. It renders immediately after a translated
<strong>, so English sat literally adjacent to localized text.

LEGEND TABS: bound, not added — tabs.upg100Region / upg100Zone and
legend.tabInfo.* already existed in all 11 with exactly this text. ★ LEGEND_TABS
becomes a COMPUTED: t() is destructured at :391, BELOW the old const, so a plain
array could not call it; and even hoisted it would freeze the labels at the
locale active when the module evaluated. The host switches language at runtime,
so the labels have to re-evaluate on access. Both consumers are in the template,
where a ref auto-unwraps, so the call sites are unchanged.

THE PLURAL, deliberately a LABEL form: territor{{ n === 1 ? 'y' : 'ies' }} ->
t('messages.territoriesSelected', { count }). I had proposed a vue-i18n plural
key; studio was right that it would be worse, and I tested it — with no
pluralRules registered, v9 applies an English-shaped choice (count===1 ? 0 : 1)
to EVERY locale, so ru with 3 forms supplied picks wrong at 1, 2 and 21.
Confidently wrong grammar that LOOKS translated is worse than honest English.

POSTER-WALL headings translate at render; REGION_OF keeps its English values as
grouping identity (studio's split). ⚠ TWO OF THE SEVEN HEADINGS HAVE NO KEY:
'India' and 'Other'. The gate reported five because its header states it cannot
see single-word strings — this is that documented blind spot materialising, not
an oversight in the spec. They fall through to English text (never a raw key)
until poster.region_india / region_other exist; raised with studio.

Bundle rebuilt + fix:sri. The manifest churn is the same old->new hash for this
bundle; doxa-maps-spa's manifest changes only because it references it.
2026-09-28 12:48:42 +00:00
Doxa Maps
a7d7a984b9 Rebuild cities-internet doxa-simple-map, 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-28 12:41:59 +00:00
Doxa Maps
050f031e56 Prayer Progress: note the accessibility work due before the help modal or a second tab is switched on 2026-09-28 12:41:10 +00:00
Doxa Maps
cb8b2857a0 Cities with Internet: the AI-notice dismiss button meets the 24px target minimum 2026-09-28 12:41:10 +00:00
Doxa Maps
5dc161daa9 Cities with Internet: its load and engine errors speak the reader's language
The engine-missing message read the shared messages.engineMissing through this file's
connectivity-prefixed t(), so it always missed and showed English in every locale.
Shared keys are now read qualified with tStatic: engineMissing, engineNotLoaded, and
couldNotLoadNamed for a data table that fails to load (naming the tab in the reader's
language, not 'table not found (404)'). Four unused English tab labels are removed.
2026-09-28 12:41:10 +00:00
Doxa Maps
c9905dd9db UPG-100 gate: query data-control, drop the i18n shim and the last title matches
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
studio landed data-control on the map controls (L54 3ed7d8d0c), so the gate can
name a control by untranslatable identity instead of its displayed text. Each
wrapper writes data-control="zoom-in|zoom-out|fullscreen|theme|…" onto
MapControlButton; it is not a declared prop, so it falls through onto the
rendered <button>.

REMOVES A CROSS-OWNERSHIP DEPENDENCY. Check (4) resolved its expected strings out
of library/i18n/locales/en/buttons.json — locale-correct, but it made a check in
MY gate depend on a key name in STUDIO's catalogue, so a rename there would have
failed a test here. data-control removes that coupling entirely.

THE THEME BUTTON GAINS THE MOST, and it had two more sites I had not fixed:
:488 (check 5's toggle) and :1502 (17b cold-load) both matched
[title^="Switch to"]. That title is LOCALIZED and DYNAMIC ("Switch to dark" /
"Switch to light"), so no i18n key ever resolved it and a prefix match on English
prose was the only option. All three sites now use data-control="theme", and the
`theme === 1` assertion finally means what it says.

Zero English-literal attribute selectors remain in the gate; every control query
is now a class or data-control. The one surviving `[title="…"]` string is inside
a comment recording why the pattern was abandoned.
2026-09-28 12:36:10 +00:00
Doxa Maps
4dd4d7328e UPG-100: delete the orphaned copy-to-clipboard path and its red gate
fc93847bb ("Batch selection builds a packet, instead of recolouring regions")
replaced copy-to-clipboard with packet-building and left four pieces behind: the
button's handler, its execCommand fallback, the window global they wrote, and the
gate check that read it. This removes all four.

copySelection had exactly ONE reference in the file — its own definition — and
legacyCopy was called only from it, so both were unreachable. The minifier was
already dropping them: __UPG_LAST_CLIPBOARD__, which copySelection set
unconditionally, appears 0 times in the built bundle.

THE GATE HALF MATTERED MORE. visual-gate check (15) asserted the Copy payload,
guarding on .upg-hud-btn.copy existing — a button that no longer exists. But the
guard skipped only the MEASUREMENT: copyOk was initialised false and check() ran
unconditionally, so it reported FAIL ("no .upg-hud-btn.copy in HUD") on every run
since the button went. A permanently red assertion for a deliberately deleted
feature teaches readers to ignore red, which is worse than no check at all.

formatClipboard SURVIVES — 3 references, and one is live: __UPG_SELECT__
.clipboardText, the headless probe surface the gate still uses. Deleting the
"clipboard code" wholesale would have broken it.

Also corrects the D-8 comment, which still named "Copy + Clear" as the HUD
buttons; they are Prayer List / Poster Map / Clear.

VERIFIED BY THE BUILD NOT MOVING: rebuilt after deleting 43 lines of source and
the bundle is byte-identical to its parent (sha 3dda630d5cf5e647, 992356 bytes).
That is the test of the claim — if the output had changed, the code was not dead.
2026-09-28 12:36:10 +00:00
Doxa Maps
02230d3eb8 UPG-100: the lazy-panel comment named the wrong API and a moved line
Two stale claims in one comment. It said `defineAsyncComponent` while the code
below it calls `retryableAsyncComponent` (:56), and it pointed at
research-map.vue:152 for the pattern — which is now a tStatic import; the real
lazy-load moved to :193.

Not cosmetic. Auditing card BUG-LAZY-PLUGIN-DEATH-ON-A-SINGLE-FAILED-IMPORT, the
census of components bypassing the retry wrapper is a grep for raw
`defineAsyncComponent`, and this comment made my own file read as a bypass. The
one real bypass (pplr-data-maps.vue:46, six lazy views) is exp's and routed. A
comment that names the wrong API costs the next reader the same detour.

Says why the wrapper is used rather than only naming it: Vue caches a REJECTED
loader promise, so one dropped chunk request kills the panel for the life of the
page. That is the defect the card exists for, and the reason not to "simplify"
this back to the raw API.

Comment-only, so the build is byte-identical — the strip-shadow-css-comments
pass drops it. Rebuilt and re-ran fix:sri anyway to prove it: 124 hashes already
agreed, 0 rewritten, the committed .js unchanged.
2026-09-28 12:36:10 +00:00
Doxa Maps
b235203064 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-internet
gospel-resources
key-cities
my-upg-100-list
people-groups-grid
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-28 12:29:13 +00:00
Doxa Maps
bee8d7182c A DOM query argument is a selector, not prose
gospel's diff of a hand triage against the checker found this: a selector
listing two custom elements was reported as user-visible English, because it
reads as English only where the tag names happen to be English words. The
single-tag rule matched neither, since it is a comma-separated list.

Exempt by call site rather than by content, as with developer strings. No
content rule can reliably tell a tag list from a sentence, and the site is a
fact about what the string is for. Covers querySelector, querySelectorAll,
closest, matches and the getElementBy* family.

The self-test plants gospel's own case and a second list of custom elements
from another plugin, since the pattern is not theirs alone.
2026-09-28 12:19:23 +00:00
Doxa Maps
66765053d2 Catalogue keys for gospel-resources' and UPG-100's remaining English, in eleven locales
gospel: 15 whole-sentence keys from its card (search, filter, gapList, province) with
placeholders each locale may move, 9 standalone strings, and 8 sentences that the template
assembles from fragments (prayer-page link, macrolanguage note, video titles, the largest-N
line), each now one key. UPG-100: map status and token messages, the territory hint, a
label-form territory count that needs no plural rules, and the poster wall's five region
headings. The templates switch to these keys in the owners' own commits.
2026-09-28 12:19:23 +00:00
Doxa Maps
32dfe88d48 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-internet
gospel-resources
key-cities
my-upg-100-list
pplr-data-maps
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-28 12:13:14 +00:00
Doxa Maps
7b5887ef3f check:hardcoded-english's note: 179 with cross-area keys, 28 self-test assertions 2026-09-28 12:04:36 +00:00
Doxa Maps
41f66f0ce9 Catch a key that can never resolve, not just a string never translated
A namespaced translator qualifies every key with its own area, so a key from
another area can never resolve and the English fallback becomes the normal path
in every locale. The reader sees English exactly as if it had been hardcoded,
which is why it belongs here rather than in a separate check.

Nothing caught it before. The existing key check reads the key as written,
which does exist; it is the key as qualified that misses. exp-shepherd hit it
twice in one day, in two different plugins.

Detected by shape -- qualified key absent while the unqualified one is present
-- so it cannot fire on an ordinary missing key, which is the other check's job.

The first version found only one of the two real cases, because the other
declares its translator through a wrapper that takes no argument and carries
the namespace one indirection away. Wrappers are now resolved from source, and
both historical defects are reproduced from the code as it stood before each
fix, with the qualified key named in the message.

Self-test now makes twenty-eight assertions, including a planted wrapper.
2026-09-28 12:04:36 +00:00
Doxa Maps
d589edb3a2 check:hardcoded-english's note records the tuned count, 178 2026-09-28 12:04:36 +00:00
Doxa Maps
ac2556cc8a Hardcoded-English gate: three agents' triage of its first run
gospel, upg100 and exp-shepherd triaged 300-odd hits between them, and most of
what they found was the gate being wrong rather than the code.

False positives removed, each from a real hit: class and id suffixes built by
interpolation, relative URLs, custom-element tag names, and empty matches.
Developer strings are now exempt by CALL SITE rather than by content, because
the site is the fact and the wording is not. A split template literal is one
finding reported as its whole string with its holes marked, instead of one hit
per fragment -- that alone was turning single defects into three.

Text inside a dir="ltr" island is DELIBERATE English, the marker these plugins
already use for content ruled to stay English. It is listed but not counted, so
nobody is asked to undo a decision.

The header gains a second blind spot, found the same day by exp-shepherd: a
guarded fallback is judged by its shape, not by whether the lookup it guards
works. A key read with the wrong prefix misses every time, making the English
arm the normal path in every locale while this stays quiet. I had triaged
exactly that line as "not a leak" because the key existed -- existing and being
found are different things.

Self-test is twenty-three assertions: every leak shape seen, every correct form
silent, both blind spots pinned.
2026-09-28 12:04:36 +00:00
Doxa Maps
198fd0f090 check:hardcoded-english's note records today's count, 373, with interpolations scanned 2026-09-28 12:04:36 +00:00
Doxa Maps
11e2d7eaaf Hardcoded-English gate reads interpolations and two more fallback idioms
Interpolation expressions carry the same defect as bound attributes: a literal
the reader sees, assembled in an expression a template walker skips. Added
before the gate lands, so the count each owner triages is the real one. It rose
by twenty-nine.

Two more shapes are fallbacks rather than leaks, both found by triaging real
hits. A proxy translator whose member read misses, and the idiom that asks
whether the translator handed the key back, which is what a missing key looks
like in vue-i18n. The second is matched on the key's shape -- dotted, no spaces
-- so an ordinary comparison against a word is not mistaken for one.

Both directions are planted in the self-test, which now makes seventeen
assertions: every leak shape must be seen, and every correct form must be
silent.
2026-09-28 12:04:36 +00:00
Doxa Maps
ca1dc11565 check:hardcoded-english runs on demand; its self-test runs in gates:pre
Not in gates:post: it reports 346 today, most of them gospel-resources prose. It joins when
that reaches zero or every hit is carded.
2026-09-28 12:04:36 +00:00
Doxa Maps
b51a8a6402 One hardcoded-English gate instead of four private scanners
sr, upg100, gospel and regions each wrote a scanner for user-visible English
that never reaches a translator, and each found real defects. Four copies means
four sets of blind spots and four allow-lists drifting apart, so this merges
them. Every rule earns its place from a defect one of those scanners caught.

Templates and script blocks are parsed, never matched with a regex: a regex for
string literals matches from the closing quote of one to the opening quote of
the next, which produced 137 phantom findings before this was parsed properly.
Translator aliases are read out of each file, because `const t2 = t` defeats a
check that knows only the base names. Guarded fallbacks are not leaks, in both
shapes that exist here: an existence check around the call, and a proxy whose
member read misses. Bound attributes are parsed too, in either quote style,
which is the blind spot every one of the four scanners shared.

The self-test plants a leak of each kind and requires the gate to see it, then
plants the correct forms and requires silence. It also asserts the fixtures are
valid Vue first, because a malformed fixture and a blind scanner produce the
same silence.

The header records what this cannot see: single-word strings. A bare 'Other'
used as a fallback label is user-visible English and will not be reported. That
trade keeps the signal readable, and the self-test pins it so that closing the
gap forces the header to be corrected rather than left stale.
2026-09-28 12:04:36 +00:00
Doxa Maps
7a0305ee94 The research dashboard's table and chart chrome is translated
Five bound English strings no locale could reach, now catalogue keys in all eleven locales:
the column sort tooltip (dashboard.sort_by_column_hint, {column}), the full-screen button's
title and label (fs_*), the export tooltip (export_*_hint, a label form with {n} so no plural
rule is needed), and the donut's accessible name (aria.donutChart, {title}), which read a
translated title followed by the English word "donut". English stays the fallback argument.
2026-09-28 12:04:36 +00:00
Doxa Maps
8adafe952b Two controls announced themselves as buttons and could not be pressed
Accessibility audit of my production surfaces, headless from source, scan negative-tested before I
trusted its zeros. Four hits, two real.

  · THE PROJECTION PILL (DashboardMapPanel) carries role="button" and tabindex="0" and had no key
    handler. A keyboard reader tabs to it, hears "button", presses Enter, and nothing happens — the
    role and the tabindex promise an activation that was never wired (WCAG 2.1.1). It is a span rather
    than a button because the pill sits inside the map chrome, so the promise has to be kept by hand.
    I touched this element earlier today to give it a translated accessible name and did not notice it
    could not be operated; naming a control and making it usable are separate jobs.

  · THE SORTABLE COLUMN HEADERS (DashboardDataTable) carry role="columnheader" and aria-sort and were
    click-only. Screen-reader users were told the sort state of a control they could not reach. Now
    focusable with Enter and Space, and shift+Enter still adds a second column, because onSort reads
    shiftKey off the event it is handed and a KeyboardEvent carries it the same way.

.prevent on space so the page does not scroll under the press.

TWO HITS WERE FALSE POSITIVES and are recorded so the next sweep does not re-raise them: the facet
rail's .fr-body and the chip bar's .rd-chips both take @click on a container, which looks like a
click-handler on a non-focusable div. They are DELEGATION: the facet rows carry their own
:tabindex/:role and the container has @keydown for parity, and every chip is a real <button> with an
aria-label. The control is the row and the chip, not the box around them.

Verified: check:sfc-parse PASS, and the scan reports 0 on both files afterwards. Not landed — the quiet
window is on; this waits for studio.
2026-09-28 12:04:35 +00:00
Doxa Maps
3ed7d8d0c3 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-internet
gospel-resources
key-cities
my-upg-100-list
people-groups-grid
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-28 11:53:20 +00:00
Doxa Maps
e0092a4317 Nine raw region writes were undoing the pre-warm the moment a highlight cleared
Found by cross-reading exp-shepherd's country-posters port, not by anything failing here. Their
73438b43b routes all eighteen of that map's region clears through a regionIdle() wrap. Mine still wrote
NINE raw constants — fill-opacity 0.20 and 0.7, line-color rgba(60,60,80,0.35), line-width 0.6 — across
clearCountryHighlight, the deselect path and the dim path.

A raw value makes the property CONSTANT again. So the first time a reader cleared a highlight, or ran a
country search and dismissed it, the three region paints stopped being data-driven and the next
highlight recompiled the shader variant that b5894ec3 exists to have compiled at layer-add. rega
measured 0 ms on the row click and that measurement was honest — it was taken on a fresh tab, where no
clear had run yet. The path nobody exercised is the one that pays.

Every region paint write now goes through regionIdle(v) — ['case', ['has','iso_3166_1_alpha_3'], v, v],
both branches the value it already had, so nothing looks different and the property stays data-driven.
Nine sites, no behaviour change, and the pre-warm now survives a clear.

★ DEFINED ABOVE ITS FIRST USE, deliberately. The first caller sits four hundred lines above where the
other idle constants live, and a const read before its declaration line has executed is the TDZ this
file has already shipped twice this week (_lastFitKey, then _lastPinOpacityKey). Its callers only run
after mount, so it would probably have been fine — "probably fine" is what the gate exists to stop me
saying. check:setup-order PASS.

Verified: check:sfc-parse and check:setup-order PASS. Needs eyes: rega — clear a region highlight, then
click another region row, and the compile should still be 0 ms. That is the case no run has covered.
2026-09-28 11:42:54 +00:00
Doxa Maps
726b11ae79 A lazy view that fails to load says so and offers Retry; map controls carry data-control
retryableAsyncComponent: after the three retries the pane rendered blank. It now shows
"This view couldn't load." with a Retry button (messages keys, 11 locales). Retry swaps in a
fresh async component, since Vue keeps a rejected load for the life of the page.

Each map control wrapper passes data-control (zoom-in, zoom-out, fullscreen, theme, location,
help, share) to its button: an untranslated hook for probes, where title and aria-label are
localised.
2026-09-28 11:42:54 +00:00
Doxa Maps
3c2277046c 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-internet
gospel-resources
key-cities
my-upg-100-list
pplr-data-maps
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-28 11:31:35 +00:00
Doxa Maps
20de4c457b Translate the three strings that were built from fragments or hardcoded
Regions: the country and region counts under the dashboard title were English
template literals; they are now label keys ('Countries: %count%') in all eleven
locales, which also sidesteps plural forms.
Gospel: the Zume chip joined 'in' + a language name, which reads backwards in
Hindi; it is now one phrase key with a {language} placeholder.
UPG-100: the Batch Select button title comes from legend.title.batchSelect.
2026-09-28 11:24:16 +00:00
Doxa Maps
7d8335575e 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-28 11:14:35 +00:00
Doxa Maps
01b142eb27 PPLR maps: a failed view import no longer kills that tab until a reload
The six lazy views were built with raw defineAsyncComponent, which caches a rejected
loader, so one network blip left that tab dead until a full reload. They now use the
library's retryableAsyncComponent, which retries the import.
2026-09-28 11:13:33 +00:00
Doxa Maps
73438b43b2 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-28 10:59:44 +00:00
Doxa Maps
db7cc16907 Country posters: clearing a highlight keeps the region paints data-driven
The load-time pre-warm made the regions fill and border paints data-driven, but every
clear (clearCountryHighlight, clearAllHighlights and the reset branches) wrote the
plain constants back. All 18 writes now use regionIdle(v), the same identical-branch
case the pre-warm uses, so the property never returns to its constant variant and a
second highlight cannot re-pay a variant switch. Nothing changes on screen.
2026-09-28 10:59:19 +00:00
Doxa Maps
ad822c0f31 UPG-100 gate: find controls by class, assert the localized title separately
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
The (G-rail) probe queried `.upg-rail-batch[title="Batch Select"]`. Once the
title becomes a bound `:title="BATCH_SELECT_TITLE"` (studio L53) that selector
matches under `en` and nowhere else, and the gate reports "button not in the
toolbar" — a PRODUCT failure for what is really a broken query. The class is
already proven unique by the railBtns === 1 assertion in the same probe, so it
is the identity; the title is still checked, as the property that actually
matters for a11y: NON-EMPTY, which holds in every locale. That also catches a
regression the equality missed — a :title binding resolving to '' or undefined.

The (4) map-controls check had the same coupling, three times. Those titles are
ALREADY bound (ZoomInButton.vue: :title="t('buttons.zoomIn')"), but the page is
pinned to en-US at newPage({ locale }) — L4/LESSON-03 — so they are not failing
today. The expected strings now come from the same i18n source the component
reads (library/i18n/locales/en/buttons.json) rather than being hardcoded, so the
gate survives being run in another locale. Verified the three keys resolve to
the literals they replace, so this asserts exactly what it asserted before.

The theme button cannot use that shim: its title is DYNAMIC ("Switch to dark" /
"Switch to light"), so there is no single key to resolve, and it stays a prefix
match on English prose. Its assertion moves from `> 0` to `=== 1` (studio's
call): that does not remove the coupling, but it stops 0 and 2 both collapsing
into "not > 0", and the failure line already prints the count.

Those four .mcb buttons share one class with no stable per-control hook, and
aria-label mirrors the localized title, so the title is the only identity
available to a query. The durable fix is data-control="zoom-in|zoom-out|
fullscreen|theme|location" on library/components/map-controls/MapControlButton
— studio's under 5B. They are riding it on the next landing that rebuilds the
17 consumers anyway rather than spending a rebuild on it alone; this shim comes
out when that lands.
2026-09-28 10:53:37 +00:00
Doxa Maps
fc6dd4ac19 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-28 10:47:52 +00:00
Doxa Maps
824298ff1b Country posters: a region highlight has no holes, and pin dimming writes once
A region legend row painted the country polygons twice: from the region dataset (every
member country, via selectRegion -> applyDimFilter) and from the legend's own list,
which holds only countries WITH PINS, so whichever ran last left holes. region: rows
now leave the polygons to the dataset; block: and country: rows still paint from the
legend. The 18 raw pin-opacity writes go through one read-before-write setPinOpacity,
so a family click no longer rewrites the same value 4+ times, and the undimmed value is
data-driven from load, so the first dim does not stop for a shader compile.
2026-09-28 10:47:30 +00:00
Doxa Maps
3c988b30c8 Rebuild gospel-internet: the map mounts on first show
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-28 10:40:25 +00:00
Doxa Maps
ab65c370e9 Gospel x Internet mounts its geographic map on first show, not on open (the board opens on the tree) 2026-09-28 10:40:03 +00:00
Doxa Maps
3d2c16a707 check:facet-shape tests the facet gate's injected helper headlessly and runs in gates:pre
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
The WALK string the facet gate injects into the page moves to a browser-free
module, internal/lib/facet-walk.mjs; the gate imports it, and
internal/check-facet-shape.mjs imports the same string and evaluates it on both
engines' source shapes without a browser. check:facet-shape ran from the browser
gate's own file, so the runner routed it to the browser slot; now it is headless
and joins gates:pre. Poisoned (the { geojson } unwrap disabled) it reports 4/5.
2026-09-28 10:27:43 +00:00
Doxa Maps
39b3285f55 The composed grid's locale depends on a spelling neither file mentions
Auditing Big Picture for goal (d) I read this as a live defect: big-picture threads the host's locale into
each child's profile-config as `lang`, while the grid's prop is `languageCode`. On a profile-config embed
that would leave a composed grid in the wrong language — exactly the failure 8b40f6c58 was written to fix.

It is not a defect. people-groups-grid.vue accepts three spellings — languageCode || locale || lang — and
`lang` is the third. Two greps settled it, and the near-miss is the point: nothing at either end said so.

Both ends now do. The writer records that the spelling is load-bearing and which fallback it lands on; the
reader records that `lang` has a caller and why that caller cannot reach it any other way — getRuntimeLocale
is module state, and a separately-built child bundle gets its own copy, so threading the config is the only
channel big-picture has.

★ WHY A COMMENT AND NOT A GATE. The failure is invisible in the obvious place: ?lang= embeds keep working,
because the grid falls through to localeFromUrl(). Only a host passing profile-config sees it, which is the
smaller and quieter half of the traffic. A gate for that would have to stand up a composed embed with a
profile-config locale and read rendered text — which is rega's browser run, not a headless check — so the
honest guard is to make the coupling legible to whoever next tidies either list.

No behaviour change. Verified: check:sfc-parse PASS.
2026-09-28 10:26:43 +00:00
Doxa Maps
4f3858eab8 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: doxa-research-map. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
2026-09-28 10:19:30 +00:00
Doxa Maps
5ae7d31b04 useMapFly's zoomToLegendRow comment names readSourceFeatures, not the engine-private _data
The comment still said the code reads map.getSource()._data, which invites a copy
of the private field back in; the code reads through the shared helper that knows
both engines' source shapes.
2026-09-28 10:13:29 +00:00
Doxa Maps
f5a9ee40b7 The packet cover said "50 of 214" in every language, because I wrote it that way today
Found auditing my own map for goal (d), in code I added this morning. The cover note is the one string on
that document a reader in Arabic or Hindi cannot read, on a document whose entire purpose is that they
can pray from it in their own language.

The slash needs no translation and is not a guess: zh's professional translation of legend.progress.short
renders exactly this relationship as "{covered} / {total}". The WORD is available per locale in that same
key — ar "من", ru "из", fr "sur" — but it carries "· {pct}%" with it, so reusing it would mean either a
wrong suffix on the cover or slicing a translated string on a separator I cannot guarantee survives
translation. Ten invented translations for one connector is the worse trade.

Wrapped in U+2066/U+2069 isolates, which is the convention the Arabic catalogue already uses five times
for numeric ranges ("⁦30–59%⁩"). Without them the pair reorders against the Arabic label beside it and a
reader sees "214 / 50" — the numbers held but the meaning inverted. NUMERALS ARE HELD, so the digits
themselves are untouched.

CENSUS BEHIND IT, on current main, reusing the existing gates rather than adding one: check:i18n-parity,
check:i18n-never-translated and check:i18n-keys-exist all PASS; and of the 766 catalogue strings the three
Simple Research bundles ship across 21 areas, ZERO fall back to English in any of the ten locales. The
English still visible to a non-Latin reader is five or six items and every one was already classified:
two external resource names (Open Bible Stories, Scripture Earth), one pure format string, two acronyms
(DPI, MST), and UUPGs, which is the Driver's deferred ruling. This cover note was the only NEW leak, and
it was mine.

Verified: check:sfc-parse and check:i18n-keys-exist PASS. Needs eyes: rega — the packet cover at ?lang=ar.
2026-09-28 10:13:29 +00:00
Doxa Maps
4fbe44ce17 Rebuild upg-neighbor, 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-28 10:09:00 +00:00
Doxa Maps
beb82f2e2e UPG Neighbor Campaigns: hovering a dot names its group
After a language was picked, its believer (green) and unreached (red) dots were
anonymous until clicked, and a green dot could not be clicked at all. Hovering either
now shows the group and its country, as Mobilize does.
2026-09-28 10:08:43 +00:00
Doxa Maps
77c7b16fef UPG-100: the HUD band follows the reading direction
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
.upg-hud-band used margin-left:auto to push itself to the trailing end of the
flex row .upg-hud-head. That end is the LEFT in Arabic, so the band sat on the
wrong side. margin-inline-start:auto, the same class as the legend and table
conversions. No consumer overrides .upg-hud-band, so nothing can defeat it.

Found by a localization audit of this bundle (upg-100-mfe + poster-wall +
upg-100-list). The rest of the audit came back clean, and both scans were
NEGATIVE-TESTED before their zeros were believed:
  - hardcoded English in templates: a planted sentence IS found, so the zeros in
    poster-wall.vue and upg-100-mfe.vue mean something. The only template hits in
    upg-100-list.vue were `{{ LEGEND_TITLE }}` (a translated computed, a false
    positive of the regex) and one real one, below.
  - script-side user-visible English: none.
  - key coverage: 23 keys used, 0 missing across all 11 locales. A planted
    nonexistent key reports missing in 11/11 and a real key resolves in 11/11, so
    the checker is neither blind nor vacuous.

ONE FINDING IS NOT MINE TO FIX: upg-100-list.vue:2786 has a literal
title="Batch Select" where its siblings at :2811 and :2833 use a translated
:title. The fix needs a new key, and the catalogues live in library/i18n/locales/
— the build owner's under rule 5B. Sent to dx-shepherd rather than landed here.
2026-09-28 10:00:37 +00:00
Doxa Maps
8e13477340 Remove the superseded headline-tiles computed
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
`tiles` built four stat objects that nothing rendered. The commit which cloned
DX-life's region dashboard replaced its template block with `stats` and the
shared StatCard, and removed the .rd-tile styles with it, but left the computed
behind.

It was not merely unused: it carried four bare English labels, so a localisation
scan reports it as hardcoded English every time. It cost this audit the time to
prove it harmless, and would have cost the next one the same. `stats` renders
the same four figures and puts every label through t().

Verified superseded rather than unfinished before deleting: the template usage
and the computed were added by one commit and the usage removed by the next, the
styles are already gone, and nothing in the plugin refers to it. Behaviour is
unchanged.
2026-09-28 09:55:30 +00:00
Doxa Maps
b2142ac0b0 DataTable + StackLayout: physical left/right -> logical, where the rule mirrors
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Six conversions, one deliberately kept physical. Same method as the legends.

CONVERTED
  DataTable.vue:238  .tabulator-cell border-right -> border-inline-end. A per-cell
    trailing border is the COLUMN SEPARATOR between adjacent cells; in RTL the
    separator has to sit on the other side or it draws on the table's outer edge.
  DataTable.vue:269  .dt-actions   margin-left:auto -> margin-inline-start:auto
  DataTable.vue:293  .dt-close     margin-left:auto -> margin-inline-start:auto
    Both are "push me to the trailing end of a flex row", which is the left in RTL.
  DataTable.vue:299  .dt-dl ul padding-left -> padding-inline-start. A list's
    marker indent follows the reading direction.
  StackLayout.vue:161,305  .stl-meta margin-left:auto -> margin-inline-start:auto
    (twice: the light and dark theme blocks).

★ KEPT PHYSICAL, AND IT WOULD HAVE BEEN A REGRESSION TO CONVERT
  DataTable.vue:245  '.dt:dir(rtl) … .tabulator-cell{text-align:right}'
  It is already SCOPED TO :dir(rtl), so right IS the trailing edge wherever it
  applies. More importantly the cells carry unicode-bidi:plaintext, which makes
  `end` resolve PER CELL from that cell's own first strong character -- which is
  the exact behaviour this line exists to override (English cells left-aligning
  inside an rtl table and clipping at its left edge, rega L20). text-align:end
  would silently undo the fix. Comment added at the site so the next reader does
  not "correct" it.

No consumer overrides any of the four classes: .dt-actions, .dt-close, .dt-dl and
.stl-meta appear in no other file in library/ or plugin-designs/, so a physical
override cannot defeat the logical rule and produce a half-mirrored table.

LTR is unchanged: inline-start/inline-end resolve to left/right under dir=ltr.
check:sfc-parse PASS. 13 plugin files use DataTable, 9 use StackLayout.

library/ is the build owner's under rule 5B -- source sha to studio; rega eyeballs ar.
2026-09-28 09:48:45 +00:00