Commit graph

2187 commits

Author SHA1 Message Date
Doxa Maps
13cf20eccf PPLR maps: the ready counts use the library's count formatter
Two status lines formatted their counts with an inline en-US; they now call
formatCount, the one place counts are formatted (fixed en-US while numerals are
held for the Driver), so the only remaining LOC-ENUS site is the library's own.
2026-09-28 00:20:34 +00:00
Doxa Maps
a37a4e9c12 The LOCALE column clears for Big Picture: the held numerals decision is allowed at its one site
check:universal-props showed LOCALE 'warn' on research-dashboard and people-groups-grid, both inside Big
Picture. Neither bundle has an en-US of its own any more — the fold put every count through
formatCount(), so both warns cited the SAME line, library/utils/formatCount.js:26, COUNT_LOCALE = 'en-US'.

That line is not a bundle ignoring the reader; it is the held decision written down. NUMERALS ARE HELD —
counts do not follow the locale — so 'ok' is not available here without breaking the policy and the gate
that asserts it. This allows it the way regions-dashboard's popup is allowed, at the SITE.

The site is shared, which is the one thing regions' precedent did not cover. A `bundle:RULE:file` key
would need one entry per importer, so the LOCALE column would warn afresh every time a bundle adopted the
shared helper — the column punishing the fold that made the policy auditable in one line instead of eight
call sites. A `*:RULE:file` key is honoured for every bundle that compiles the file, and ONLY for a path
under library/. That restriction is the whole guard: a bundle's own source can never be wildcarded, so
this cannot be used to clear a column broadly.

Measured on main: 4 LOC-ENUS warns -> 2, both remaining pplr-data-maps' and not mine. research-dashboard
and people-groups-grid read 'allowed', regions-dashboard unchanged.

Negative-tested in both directions, because an exemption that is wider than it reads is the failure here:
a planted toLocaleString('en-US') inside research-dashboard's own composable warns again, and a planted
one in library/composables/useDashboardData.js — shared, imported, but not the allowed file — warns too.
A self-test now also refuses a `*:` entry outside library/, which the lookup would silently never honour.
2026-09-28 00:20:33 +00:00
Doxa Maps
82e05018ee composes speaks three vocabularies, and unresolved refs now fail
The capability gate reported five composes refs as "resolve to no known bundle/profile" —
bp-research-header, cities-internet-map, gospel-resources-map, my-upg-100-list-map,
research-dashboard-map. All five were correct data. `composes` accepts a third form besides
'<bundle>/<profile>' and a bare '<bundle>': a registered ELEMENT TAG. Nothing needed renaming and no
author's meta.json was wrong; the resolver was short. 5 unresolved -> 0.

Two things the element form forced, both measured:

  · A SELF-REFERENCE is an internal child, not a nested plugin. big-picture composes
    bp-research-header, its own element, which resolved back to big-picture (cap-4) and promoted the
    bundle to cap-5. Excluding self keeps "nests other plugins" from meaning "has parts".

  · A name covering several profiles resolves to the HIGHEST tier among them, and both non-slashed
    forms now resolve the same way. A bare bundle name and that bundle's element tag both mean "this
    bundle", so taking the first profile for one and the highest for the other made the answer depend
    on discovery order. gospel-resources shows it: four single leaves and one cap-4 composite in one
    bundle, and losing the 4 silently demotes whoever composes it.

The rule now lives in internal/_composed-tiers.mjs, imported by the generator that WRITES the tier and
the gate that CHECKS it. It was duplicated, and a rule this fiddly does not stay identical in two files;
the drift would have shown up as a gate passing a manifest the generator would refuse to write. The
data stays independent — the gate rebuilds the edges from the <profile>.meta.json files on disk and
checks the published manifest against them.

With the count at 0, an unresolved ref FAILS in both. While five were outstanding a warning was right:
they were correct data the resolver could not read, and failing would have blamed five authors for a
gap in the tooling. At zero, a typo and a genuine plain child still look identical from here, so the
one thing that must not happen is quietly reading one as the other.

Verified on the tree as it stands: 37 profiles, 25 bundles, 10 declaring composes edges — 10 agree,
0 disagree, 0 unresolved. Each fail arm negative-tested: a one-letter typo in a ref fails; a published
tier that disagrees with its own edges fails; the same composes shape pointing at another bundle's
cap-4 instead of its own element fails, which is what proves self-exclusion is load-bearing rather
than incidental.
2026-09-28 00:20:33 +00:00
Doxa Maps
3d64bcad41 README: link the guide to working from a laptop alongside the team
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 00:13:45 +00:00
Doxa Maps
26f3fdd321 Cloud container: the router no longer cuts quiet streams after 10 s
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
PocketBase's realtime stream sits quiet while someone signs in in the popup; Bun's default idle timeout
closed it before the sign-in result arrived.
2026-09-28 00:04:18 +00:00
Doxa Maps
caccc893a4 HOWTO: join the table from a laptop — follow a shared branch and run PocketBase with bun run dev
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-27 23:54:30 +00:00
Doxa Maps
b919371b26 Follow a remote: DX_SYNC_REMOTE also takes a repo URL, and checks every 5 s by default
One switch makes a laptop hot-reload what someone pushes elsewhere (e.g. cloud agents): a URL needs no
`git remote add`. Credentials in a https://user:token@ URL are never shown in the log or /api/dev-sync.
2026-09-27 23:54:30 +00:00
Doxa Maps
7b49aef938 bun run dev runs PocketBase at /api/pb, or uses a shared one
The first run downloads the pinned PocketBase (the cloud container's version) for this platform, checks its
SHA-256 and extracts it in-process into backend/bin (gitignored). It serves .pb/dev (gitignored) with the
migrations in git and hooks off, as in the cloud. DX_PB_URL proxies /api/pb to a shared PocketBase instead;
DX_PB_PORT moves the local one, and a port already in use is reported once instead of crash-looping.
2026-09-27 23:54:30 +00:00
Doxa Maps
de004b3703 bun run dev can follow a shared branch: fast-forward only, never over local edits
Opt-in with DX_SYNC_REMOTE (plus DX_SYNC_BRANCH, default main, and DX_SYNC_INTERVAL, default 15 s) in
.env.local. Every interval the dev server fetches the branch and fast-forwards when this checkout is on it
with no modified tracked files and no local commits, so Vite hot-reloads what teammates landed. Otherwise
it never merges, stashes or resets: it logs once and reports "main is N commits ahead, pull when ready" at
/api/dev-sync for a Studio badge.
2026-09-27 23:54:30 +00:00
Doxa Maps
a9e742697d Rebuild upg-neighbor 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-27 23:52:30 +00:00
Doxa Maps
0a52bb15e3 Cities with Internet: the Women / Men toggle is a 24px touch target
It was 21px tall, under the AA minimum (rega, cell A at 390).
2026-09-27 23:52:08 +00:00
Doxa Maps
fc05faa90e UPG Neighbor: the start view shows the unreached dots
When the data arrived while the map was still loading tiles, the paint was skipped
and never retried, so Mobilize opened on an empty map (and Campaigns could miss its
dots the same way). A skipped paint now retries once the map is idle.
2026-09-27 23:52:08 +00:00
Doxa Maps
392ce11e20 UPG Neighbor: hovering a dot names its group
About 7,300 red dots were anonymous until clicked. Hovering a red or green dot now
shows the group, its country and its language.
2026-09-27 23:52:08 +00:00
Doxa Maps
384d164ee6 Cloud container: a one-click page to check the team PocketBase sign-in
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
/admin/pb-signin-check (behind the site sign-in) signs in to pb-dev through the team account, with the
same realtime flow as the PocketBase SDK, and shows the email and groups it sees, or the exact refusal.
The token is never stored.
2026-09-27 23:50:07 +00:00
Doxa Maps
71d4c1817c Cloud container: pb-dev as the team's shared PocketBase, signed in through the team OIDC provider
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Laptops reach pb-dev's API without the site sign-in; PocketBase signs people in itself through the same
OIDC provider (its own client), members of OIDC_ALLOWED_GROUPS only, password sign-in off. The group check
is ONE hook baked into the image and pinned by SHA-256; hooks from the pulled repo still never run. The
dashboard, _superusers and system collections stay behind the site sign-in for admins. It fails closed:
without the baked gate or a working OIDC setup, /pb/ stays behind the site sign-in as before.
2026-09-27 23:41:53 +00:00
Doxa Maps
1d4ce570e4 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
my-upg-100-list
research-dashboard
rudder-voice. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
2026-09-27 23:30:44 +00:00
Doxa Maps
bac8a1048c Rudder with RUDDER_ENGINE=0 never starts the engine, and a page on another machine never offers to record the server's mic
A server where Rudder is laptop-only (RUDDER_ENGINE=0) no longer starts a
leftover engine binary. If an engine that records its own machine's microphone
is reached from another machine anyway, Rudder shows the laptop notice and
disables Record instead of recording the server.
2026-09-27 23:24:08 +00:00
Doxa Maps
9b150b902d Square panel: no child brings its own outline
ShareButton is not a .mcb. It wraps its button in a .share-wrap div carrying
border-radius:50% and a conic-gradient ring on ::before at inset:-2px, so the
button rules missed it and it kept a round rainbow halo inside the square
panel -- breaking the single-card illusion at the corner the eye lands on.

rega measured it at 390 and asked whether square should flatten it. It
should: in this variant the panel owns the outline, so a child may not bring
its own. The round default is untouched.

Gated, with a control asserting ShareButton really does carry a 50% radius,
so the two rules are not decorative.
2026-09-27 23:23:42 +00:00
Doxa Maps
ddb2b77971 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: cities-internet
country-posters
doxa-research-map
doxa-simple-map
my-upg-100-list
plugin-studio
rudder-voice. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
2026-09-27 23:18:33 +00:00
Doxa Maps
e994877984 Legend progress bar draws no empty segments, so its left end is rounded again
A zero-width segment button was still rendered: an invisible tab stop, and the
first child that took the bar's rounded left end. Segments with no width are
now left out.
2026-09-27 23:14:15 +00:00
Doxa Maps
55573df1d2 Rudder learns whether this server should have an engine even when its event stream is buffered; the legend bar keeps its rounded ends
The dev backend answers /status with the same offline status as /events, and
Rudder reads it on mount and whenever the event stream drops, so a proxy that
buffers the stream no longer leaves it saying "Runs on your computer" on a
server that should run the engine. The local-microphone notice no longer shows
off this computer. The legend progress bar paints its grey band as a rounded
strip and rounds the first and last segment, which the 24px touch targets had
squared off.
2026-09-27 23:14:15 +00:00
Doxa Maps
8e267b0ce5 Rudder on a server that should run the engine says it is not running yet, not that it only runs on your computer
The dev backend reports expected=true while an engine the server is set up to
run is down (RUDDER_ENGINE=1 or RUDDER_AUDIO=browser). Rudder then reads "Not
running yet" and says the engine is starting or failed to set up; "Runs on
your computer" remains for a server with no engine at all.
2026-09-27 23:14:15 +00:00
Doxa Maps
b347310ef4 Legend progress bar segments are 24px touch targets while the bar still paints 10px
Each segment was a 10px-tall button, under the 24px minimum (WCAG 2.5.8). The
track is now 24px with a centred 10px painted band, the segment buttons clip
their colour to that band, and negative margins keep the legend's layout
unchanged.
2026-09-27 23:14:15 +00:00
Doxa Maps
8afea17c6b Capability is derived from what a plugin composes, and the preset-plugin standard is written down
generate-tree derives each profile's tier from its composes edges (composing
anything is capability 4; composing a capability-4 plugin is capability 5). An
explicit type is checked against the derivation and a contradiction fails the
build naming both. check:capability-derived asserts every profile is 1-5 and
agrees. documentation/PRESET-PLUGIN-STANDARD.md describes the one
*.instances.json file a preset plugin declares.
2026-09-27 23:14:15 +00:00
Doxa Maps
13dfe63a1f Clear the regions locale column without going blind
check:universal-props showed regions-dashboard LOCALE = warn on a single
site: the map popup's fixed en-US population. That is a HELD decision, not
an oversight -- their own site renders en-US numerals, it is carded, and
_chk-numerals-held-format-does-not-vary-by-locale ASSERTS it does not vary
by locale, so making it locale-derived would break a gate that exists to
keep it fixed.

Clearing it had only two mechanisms and both were wrong. Changing the code
reverses a Driver-backed ruling. A bundle-wide ALLOW silences every FUTURE
en-US anywhere in regions-dashboard -- clearing a column by going blind.

So ALLOW is now site-scopable: a `bundle:RULE:file` key exempts the one file
that earned it, falling back to the old `bundle:RULE` form. The entry records
the card and the reason.

Verified in both directions: the column reads `allowed` instead of `warn`,
and planting a new operative en-US in regions-list.vue puts it straight back
to `warn` naming that file. The exemption is one file wide, not one bundle.

`allowed` is the honest terminal state here, not `ok`. `ok` would mean the
numerals follow the locale, and they deliberately do not.
2026-09-27 23:14:15 +00:00
Doxa Maps
5ca125ad23 Plugin Studio: a top-level row names its capability like its nested rows do 2026-09-27 23:14:15 +00:00
Doxa Maps
7d3cfca897 Plugin Studio: every plugin sits under its capability 1-5; no Experimental section
Every plugin is capability 1 to 5, so the rail files each bundle under its
highest capability again. A bundle not yet in production says Experimental on
its own rows. check:studio-rail now asserts there is no section outside 1-5.
2026-09-27 23:14:14 +00:00
Doxa Maps
22440899d5 Plugin Studio: the Experimental section no longer reads CAP 0, and clicking a plugin no longer unfolds it
The Experimental section is a stage, not a tier, so its heading showed CAP 0
and the Research Gallery (capability 5) looked like a capability-0 plugin. The
heading now reads EXP and each of its rows names its own capability. Clicking a
plugin opens it without unfolding its folder or its parts; only the twisty
folds and unfolds, and a closed folder that stands for the plugin stays closed.
2026-09-27 23:14:14 +00:00
Doxa Maps
b03c8d4bd4 Cloud container: Rudder accepts every host the container serves, not only the sign-in host
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
With two domains on one container, the engine answered the second one 403 "forbidden host", so Rudder
showed offline there. The allowed list now defaults to the hosts Coolify gives the container
(COOLIFY_FQDN), then the OIDC redirect host; always an explicit list, never a wildcard.
2026-09-27 23:08:21 +00:00
Doxa Maps
8ef7d337d2 Cloud container: a rebuilt Rudder engine replaces the running one once nobody is dictating
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
The pull loop rebuilt the engine when its source changed, but the old process kept running until the
next container start. Now, when the engine reports it is not in use, the old process is stopped by its
own PID and the dev server starts the new binary.
2026-09-27 22:45:22 +00:00
Doxa Maps
55e56bea6f Rudder keeps the last words spoken before Stop
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
The streaming model holds back the last fraction of a second until more audio
or a pause arrives, and the commit alone did not flush it, so a Stop
mid-sentence lost its final words. The engine now sends 1.2 s of silence before
the commit, and keeps reading after the commit until the final text or 6 s of
quiet. Measured: a stream cut at 6 s of the test clip now ends "...ask not what
your" instead of "...ask not".
2026-09-27 22:36:07 +00:00
Doxa Maps
18152f0387 Cloud container: the site serves at once while Rudder sets up, and its model is in the image
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Rudder's setup ran before Vite and the sign-in proxy, so the whole site answered 502 for minutes on every
start while the engine built and ~742 MB downloaded; on the first start the download was reset mid-file and
Rudder stayed offline. Now the runtime and pinned model are baked into an early image layer (SHA-256
checked, resumed and retried on a stall), setup runs in the background, /api/rudder answers "starting"
meanwhile, and the dev server restarts once when setup ends so the engine starts.
2026-09-27 22:32:22 +00:00
Doxa Maps
f3d89f8c10 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: none; also rebuilt: rudder-voice plugin-studio. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
2026-09-27 22:14:32 +00:00
Doxa Maps
27fb396590 Rudder in browser-audio mode hides the engine's microphone-list error
The engine's local device list does not apply when the page's own microphone is
used, so a server without pactl no longer shows its error above the draft.
2026-09-27 22:10:35 +00:00
Doxa Maps
524f0dbc73 Rudder is idle the moment you press Stop, and a new recording can start while the last words arrive
On a loaded server the last words can land seconds after Stop, and the widget
read "Stop" until they did. Stop now releases the mic and returns to idle at
once while the session's socket stays open for the tail. Each engine session
sends its events to its own reader, so a session still draining never writes
into the next one, and Record again simply lets go of the old tail.
2026-09-27 22:10:35 +00:00
Doxa Maps
cf0b23a4d1 check:mjs-parses parses with node even when the gates run under bun
Under bun, process.execPath is bun, and bun --check runs the script instead of
parsing it; a cloud build hung inside check-link-rot-sample.mjs. The gate now
uses node under bun and fails plainly if node is missing.
2026-09-27 22:10:35 +00:00
Doxa Maps
4e94e92160 Rudder's corner is a pill that shows it is hearing you, and its draft scrolls like a message thread
Collapsed, the pill reads "Rudder · voice to text". While recording it drops the
label for a red dot, a mic that lights only while speech is detected, and the
last few words on one truncated line, so a closed panel still shows the reader
is being heard. Rudder reports this through an `activity` event. Open, the
panel no longer scrolls: the draft fills it and scrolls on its own, stays
editable while recording, and notices sit above it; with settings or info
open the panel scrolls so they stay reachable.
2026-09-27 22:10:35 +00:00
Doxa Maps
533ef04a9f Rudder transcribes on a server: the page streams its own microphone to the engine
With RUDDER_AUDIO=browser the engine records no local microphone. The page
captures the reader's mic, converts it to 16 kHz mono PCM in an AudioWorklet,
and streams it over a WebSocket at /api/rudder/stream into the same speech
session a local recorder feeds. The words come back on that socket to that
reader only, never on the shared event stream. One session at a time; a second
reader is told the engine is busy. The engine honours RUDDER_HOME, accepts the
public host named in RUDDER_ALLOW_HOST, and refuses a socket from another
origin. The dev proxy now carries WebSockets to backends.
2026-09-27 22:10:35 +00:00
Doxa Maps
744c3be317 Cloud CDN build: real Node in the image, the build steps without the gates, and no python3
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
The first build in the container hung for 18+ minutes: the image had only bun's node shim, and
`node --check` under that shim runs each script instead of parsing it. The gates also already
passed before a commit reaches main, so the container now runs clean, token, bundles, tree and
check:sri only. The public exclusions and the refuse-the-swap check still run on every build.
runtime-config.js was written with python3, which the image does not have; bun writes it now.
The build's PID goes to /tmp/build-cdn.pid so it can be stopped without touching the container.
2026-09-27 22:00:35 +00:00
Doxa Maps
a5759491d0 Cloud container: RUDDER_ALLOW_HOST (the public host Rudder's engine accepts), defaulting to OIDC_REDIRECT_URL's host; 2 vCPUs advised
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
The engine now refuses non-loopback Host headers and Vite's proxy passes the public host through, so
without this every /api/rudder call is 403 (studio, RUDSRV-STU2). entry.sh derives it from
OIDC_REDIRECT_URL when unset; the README documents it and the CPU need (it ran ~1.5x behind real time
on a loaded box).
2026-09-27 21:53:03 +00:00
Doxa Maps
c0487bb39d Cloud container: Rudder's engine inside (RUDDER_ENGINE=1), fed by the browser's microphone
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Go 1.22 in the image; on start, backend/rudder-engine/setup-runtime.sh fetches its pinned runtime and
model (SHA-256 checked, skipped when present) into RUDDER_HOME (default /data/rudder, meant for the
persistent volume) and builds the engine; RUDDER_AUDIO=browser. The pull loop rebuilds the untracked
engine binary when backend/rudder-engine changes. /api/rudder stays behind the sign-in: it is served
by Vite on the gated / route, and the only public routes remain /cdn/ and /api-prod/api/. README:
the flag, and 3.5 GB with it on.
2026-09-27 21:43:30 +00:00
Doxa Maps
14a25b6b59 README: Security controls (bundle integrity with the real manifest fields; the v1 backend posture), and PocketBase hooks switched off
Bundle integrity: all 25 bundles carry bundles[].integrity (sha384) and every profiles[].embed.script
already includes integrity + crossorigin=anonymous (checked on main); the section shows the snippet,
what the browser does with it, the CORS header it needs, and check:sri. The container's PocketBase:
locked-by-default collections, the prod dashboard blocked and the dev one admin-only, and hooks OFF,
now true in code: both instances get --hooksDir pointing at a path that never exists, so a pb_hooks/
folder added to the repo can't run. Per-plugin locks and isolated edge functions are stated as not
built.
2026-09-27 21:43:05 +00:00
Doxa Maps
9e59157b89 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: none; also rebuilt: rudder-voice. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
2026-09-27 21:38:33 +00:00
Doxa Maps
dab3980fc2 Rudder served from a remote host says it runs on your own computer, not that the engine is broken
The engine records the microphone of the machine it runs on, so a cloud dev
server has none by design. Off loopback (and not the desktop app), an absent
engine now reads "Runs on your computer" with where to open Rudder instead,
rather than build instructions for a missing binary.
2026-09-27 21:35:12 +00:00
Doxa Maps
3f8790ffce Cloud container v1: PocketBase dev + prod, a public CDN of the last good build, and an admin-only build trigger
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
deployment/cloud: PocketBase (pinned, sha256-checked) as dev (/pb/, signed in; its /_/ dashboard for
OIDC_ADMIN_GROUPS only) and prod (/api-prod/api/ public, dashboard never exposed), with the schema
as migrations in backend/pocketbase/pb_migrations and data on the /data volume; superuser from env.
admin.mjs routes /cdn/, /api-prod/, /pb/ and /admin/ behind oauth2-proxy (public: /cdn/ and
/api-prod/api/ only). build-cdn.sh: flock (409 on a second build), a snapshot of the pulled commit,
the public exclusions applied BEFORE the build, a heap-capped build, a check of the output that
REFUSES the swap if anything excluded remains (proved with planted fixtures: a field-access file,
'Visa Requirements' content, and key-cities one level down each fail; clean passes), then an atomic
swap; runtime-config.js carries the public API URL. public-exclusions.txt is the ONE list the
giveaway export and the CDN build share. Any git host via REPO_URL/BRANCH/GIT_TOKEN.
2026-09-27 21:32:46 +00:00
Doxa Maps
306178f0a2 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; also rebuilt: rudder-voice plugin-studio. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
2026-09-27 21:17:36 +00:00
Doxa Maps
cffb914a97 gospel.res: drop the unused newTestament and fullBible, and word nParts in ar without plural agreement
The Scripture chip reads gospel.charts.newTestament and fullBible, so the two
gospel.res copies had no reader. In Arabic the count now follows a label
("number of parts: {n}"), which is correct for every n.
2026-09-27 21:11:33 +00:00
Doxa Maps
3ae2390536 Rudder in the Studio corner is a chat-style bubble with a compact panel
Collapsed, the corner is a round bubble that turns red, pulses and shows a dot
while Rudder listens. Open, it is a 360px panel (a 60vh bottom sheet on a phone)
with a one-line header, the draft as the main element, and record and copy under
it; language, microphone, clear and debug sit behind a settings button.
Collapsing only hides the panel, so a recording keeps going and the draft stays.
2026-09-27 21:06:58 +00:00
Doxa Maps
4415519a83 Correct c18d4ffb's claim about the bundle
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
c18d4ffb says "the built bundle no longer contains the inline English". One of those eleven
strings IS still in the bundle: "The {engine} map engine did not load." is the en CATALOGUE's
value for messages.engineMissing, which every bundle compiles in. What changed is that the
SOURCE no longer carries a copy of it — that was the point of the commit, and the sentence
overstated it.

An empty commit rather than an amend, because the commit is already on the remote branch and
--force is not available here. A wrong sentence in the record is what the next reader trusts, so
it is corrected in the record rather than left for them to disprove.
2026-09-27 20:34:58 +00:00
Doxa Maps
c18d4ffb71 Drop eleven English fallbacks now their keys have landed
tOr() rendered English while a key was in flight. All eleven keys it guarded are on main, so it
is gone and every call site reads the catalogue: nParts, engineMissing, sheet.loading,
guide.wayInAll/wayInSome/wayInWhat, legend.hnrTip, guide.howNumbersMade, guide.isSignLanguage,
sheet.linkCopied, sheet.share.

I compared each default against the catalogue before deleting it, rather than assuming they
matched — deleting a fallback silently changes what a reader sees. Ten were identical. The
eleventh was not: gospel.sheet.share held my "Share this card" against the catalogue's "Share".
The catalogue wins, because it is translated in eleven locales where my phrase was not and a
button inside a card need not restate its container, so THE SHARE BUTTON NOW READS "Share" —
a visible change, deliberate, and the shorter label suits the 390px screen where those tap
targets were just fixed.

The four parameterised calls needed doing by hand: my regex for tOr(key, english, params)
stopped at the first ")" inside fmt(...), so it silently converted seven of eleven and left
four. Counted the remainder instead of trusting the count it printed.

gates:pre 11/11, ENGLISH-LEAKS PASS, and the built bundle no longer contains the inline English.
2026-09-27 20:33:29 +00:00