doxa-maps/library
doxa-maps-88655c70 159acac940 Point the app-tables guard at pages that exist, and let it count rows it can see
verify:full runs two browser guards that `bun run verify` skips, and both were
failing. Neither was a product defect; both had rotted unnoticed precisely
because verify-all.mjs marks them `browser: true` and skips them unless --full is
passed, so the build chain has never run them.

verify-app-tables was broken four ways, each of which alone made it useless:

Its default port was 8917, which nothing in this repo has ever bound. Now 4173,
the port `bun run serve` binds, so it runs with the same server as every other
browser gate. APP_BASE still overrides.

It navigated to `index.html#key-city-posters` and two sibling fragments,
resolved against the PROFILES object in layouts/app-wrapper-material. That shell
is not what `/` serves — as of 2026-09-22 the root page mounts <plugin-studio>,
and the built root contains ZERO of those three keys. The list is now three real
profile paths taken from manifest.json. key-city-posters is dropped rather than
renamed to something that merely looks similar: no such profile ships.

Its "are we on our page" check matched the shell title "Doxa Maps". A leaf
titles itself "<profile> · <bundle>". My first replacement matched an absolute
script path and was equally wrong, because a leaf references its bundle
relatively (src="../gospel-resources.js") — measured, on a page that was fine.
It now matches the SRI integrity attribute, which this build guarantees by
construction and no other server emits.

Its row counter only counted rows ONE level inside a shadow host, with no seen
set. A row in the light DOM, or one shadow level deeper, counted zero. Now walks
every depth.

The last defect is the one worth reading twice. The app header printed near the
END of the loop body, after the row check, so every verdict appeared ABOVE the
app it described and the whole report was offset by one. That made a PASSING app
(gospel-resources/data-tables, 40 rows) look like the failure and the real
failure look like it had rendered rows. I chased the wrong app through three
rounds of instrumentation before reading the output in order. A report that is
correct but misordered costs a wrong diagnosis, not just time.

Read correctly, the guard now says: cities-internet/data-tables 40 rows and 1
table fetched; gospel-resources/data-tables 40 rows and 1 table fetched; and
gospel-resources/resources-list fetches NOTHING and renders nothing. That last
one is the already-carded gospel-resources data gap, waiting on the three Driver
decisions — the component is built and correctly showing an empty result for
data it was never given. So the guard is reporting one real, known, Driver-gated
absence, which is what it is for.

Everything else in it was already sound and is untouched: the recursive
shadow-root walk for row counting, fail-closed on zero fetches, and third-party
request detection, which the file rightly calls a persecution risk rather than a
performance note.
2026-09-23 09:19:20 +00:00
..
api consolidate docs into documentation/ and deployment shells into deployment/ 2026-09-21 23:23:23 +00:00
colors Land the swarm's dashboard work: colour, rails, cascade, scroll 2026-09-22 18:57:39 +00:00
components Show the eighth filter, and wrap the row instead of scrolling it 2026-09-23 02:49:38 +00:00
composables Give fitBounds a duration, because FLY_CONFIG alone leaves it instant 2026-09-23 05:01:53 +00:00
constants doxa-maps — portable bundler for embeddable JAMstack maps 2026-09-10 01:53:07 +00:00
data docs: simplify all folder READMEs (what's here + graphic + link); migrate complex reference to docs/architecture/{data-sources,i18n,components,app-wrappers,poster-generation}.md 2026-09-11 18:50:31 +00:00
i18n consolidate docs into documentation/ and deployment shells into deployment/ 2026-09-21 23:23:23 +00:00
layouts Match the tab radius to the rest of the app, and open on the tab you were last on 2026-09-23 01:03:15 +00:00
maps Load the RTL text plugin from one place, and in the composite too 2026-09-22 19:55:58 +00:00
scripts Point the app-tables guard at pages that exist, and let it count rows it can see 2026-09-23 09:19:20 +00:00
stores fix(spa): make embedded maps survive the sandboxed plugin iframe 2026-09-12 21:07:26 +00:00
styles Move the eight CARTO basemap styles to OpenFreeMap 2026-09-22 02:27:48 +00:00
utils Land the prayer facet and the scrim helper 2026-09-22 21:50:32 +00:00
index.js Brand-neutral shared VerticalTabsLayout with lazy nested-element hosting; fix cap-5 prayer tab leaf path; neutralize library identifiers; add Forgejo CI build-gate workflow 2026-09-19 17:24:30 +00:00
ProfileLoader.vue Land the swarm's dashboard work: colour, rails, cascade, scroll 2026-09-22 18:57:39 +00:00
README.md Complete app-profiles->plugin-designs sweep across comments/docs; build green; layouts kept at root (load-bearing) 2026-09-17 18:18:19 +00:00

library/ (@map) — the shared map template

The other half of the architecture (see ../plugin-designs/README.md): every map in plugin-designs/<your-map>/ composes the reusable, parameterized pieces that live here. Fix something here and every map benefits on the next build; break something here and every map breaks — read components/WARNING.md before touching shared pieces.

Folder What lives there
ProfileLoader.vue The root of every bundle: parses profile-config, loads the profile, provides the stores + config
components/ Shared UI — map, legends, controls, popup (PeopleGroupDetail), tables, charts, hints (README)
composables/ Shared logic — map engine (useMapInstance), provider switch, shadow-DOM styles, theming
stores/ Per-instance Pinia stores (ui / map / data) — provided by ProfileLoader, injected by children
api/ Data-source registry (sources.json) + fetch layer — the JAMstack runtime wiring
colors/ Color sets maps opt into via profile-config.colorSet
i18n/ The shared string catalogs (all maps speak the same languages)
data/ Small shared datasets baked at build time (big served data lives in ../data/)
constants/ Shared constants
scripts/ Maintainer pipelines (posters, research) — not part of any bundle

The rule of thumb (same as WARNING.md): custom code in your app-profile, reusable code here — and things only move from the first to the second once they've earned it.