Commit graph

1006 commits

Author SHA1 Message Date
Doxa Maps
8105b1e76a Prayer packet: point 4 prints a short reading list, and the 12 points are larger
Point 4 (READ THE WORD) printed Mark 5:1-20 in full at 14px, the longest
and smallest text in the packet. It now prints THE HEAVENLY FATHER'S
HEART: one heading, one framing line and seven short readings (Noah,
Lot, Rahab, the Gerasene, Cornelius, Lydia, the jailer), each a
household the Father saved through one person. The names come from each
locale's block; the addresses stay canonical English in the data and the
book is named in the packet's language, like every other reference
(Genesis and Joshua added to the 11 books tables).

That room goes to the twelve points: body 17 -> 22px, heading 19 -> 24px,
references 14 -> 17px, and 13 -> 16px between points. The page still fits
one sheet in all 11 locales (the tightest, de, ends 59px above the
bottom).

The gates that asserted the full passage (packet-render, packet-browser,
poster-prints) now assert the list: a .p4-heart block with its seven
readings. Rebuilt: my-upg-100-list, country-posters, regions-dashboard,
doxa-research-map, upg-neighbor; the tree and SRI regenerated.
2026-09-30 08:29:54 +00:00
Doxa Maps
757779d519 check:selection-kinds: resolve REAL tapped features, not hand-made keys
The gate began from keys like 'adm0:IND', so it never ran resolveTerritory
on what the map hands the click handler, and it passed while every tapped
country resolved as a province. Section 4 feeds the resolver three real
tapestry shapes: a country (shapeName + iso3, no listId), an India state
(listId + shapeName + iso3), and a country drawn inside an Asia zone
(zone.adm0).

Two-sided: on the previous resolver it fails three ways (Sudan and Nepal
filed adm1 with null counts); on the fixed one it passes.
2026-09-30 05:47:04 +00:00
Doxa Maps
16dca4d266 Posters drawn at the click use the SPARSE layout, like their stored thumbnails
The bold header on a poster -- the UPG count and population set large, a
bigger map, and no "Jesus' Strategy to Feed the 5000" / "What is a Prayer List"
columns -- is the SPARSE layout, the "thumbnail-worthy" design. The `posters`
script generates with SPARSE=1, so every stored thumbnail has it. But the env
handed to the generator in the browser carried only FORMAT and POSTER_DATE, so
EVERY sheet drawn at the click -- UPG-100 and country alike -- fell back to the
dense layout.

MEASURED on FINAL (two UPG-100 zones, Northwest and South-Central India): the
thumbnail shows the SPARSE header; the print the reader actually gets shows the
small facts table, both vision columns and a smaller map. That is the reported
"the country poster looks worse than the UPG-100 poster" -- the comparison was a
SPARSE thumbnail against a dense sheet.

(a) posterSheets.js passes SPARSE for every POSTER format and NOT for 'packet'.
    That is exactly the split the two build scripts make: `posters` sets
    SPARSE=1, `packets` does not. The renderer's formats are 3x4, 3x3, letter and
    packet, so 'packet' alone keeps the full layout its pages were built around.

(b) check:poster-browser-equiv's poster case now runs the Node side with
    SPARSE=1 as well. It used to compare dense with dense, so it passed while no
    reader ever saw that layout on a card. The packet case stays dense on both
    sides. PASS: country-npl 909026 bytes on each; asia-india-gujarat (packet)
    835047 on each.

The stored UPG-100 thumbnails are untouched by this. What changes is the PRINT,
which now matches them.
2026-09-30 02:53:15 +00:00
Doxa Maps
baa60ba647 Merge remote-tracking branch 'origin/development' into regions/country-sheet-onedef
# Conflicts:
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/manifest.json
#	public/dx-maps/regions-dashboard/region-dashboards/index.html
#	public/dx-maps/regions-dashboard/regions-dashboard.js
#	public/dx-maps/regions-dashboard/regions-list/index.html
#	public/dx-maps/regions-dashboard/regions-mfe/index.html
2026-09-29 22:59:27 +00:00
Doxa Maps
f42444ec8c Pass the region in check-poster-render-pinned's test zone
Found in the max-effort re-read of 1ab8524cf. countryZone now colours the sheet
from the region, and this gate's zone omitted it -- so it rendered the FALLBACK
teal and logged '[posterSheets] region undefined is not in POSTER_REGIONS' on
every run. The gate still passed, because what it pins is the served generator's
integrity rather than the colour, but it was exercising the path that does not
ship and shouting about it.

Chad is Africa in library/data/country-posters.json. The warn-once is doing
exactly its job here: it found a caller that had not been updated.
2026-09-29 21:23:23 +00:00
Doxa Maps
fcbb7bbf8e sync-dropin: a build config that won't parse fails loudly, even under --if-present
From studio's review of 87f10ceda. configDest swallowed a JSON parse error, so with a malformed
vite.doxa-maps-build-config.json (one trailing comma from a hand edit), --if-present read it as "no
destination configured" and exited 0. The build went green and never refreshed the site. The parse
error is now recorded when the file EXISTS. Under --if-present or --from-config the command exits 1
with "build config unreadable: <file>: <error>", even with DOXA_DROPIN=off. A config file that is
absent, or one with no dropin.dest, still skips.
Tested 7 ways:
1. dest configured, host absent: skip, exit 0.
2. host present: 1,208 files copied, exit 0.
3. no dest key: skip, exit 0.
4. no dest key, plain --from-config: exit 1.
5. trailing comma: exit 1, "build config unreadable".
6. trailing comma with DOXA_DROPIN=off: exit 1.
7. no config file: skip, exit 0.
The config was restored byte for byte (cmp).
2026-09-29 21:03:15 +00:00
Doxa Maps
87f10ceda0 sync-dropin --if-present: no configured destination is a skip too, not a failed build
Found re-reading 2a4c3ddb3. With dropin.dest removed from the config (a site that doesn't use DX Life)
and no DOXA_DROPIN_DEST, the full build's last step printed the usage line and exited 1, after a build
that had passed. The host is optional, so --if-present now skips there as well. Without --if-present a
missing destination is still refused.
Tested: no dest configured with --if-present skips (exit 0); the plain command still exits 1; a configured
but absent host still skips (exit 0). The config was restored byte for byte after the test.
2026-09-29 21:00:07 +00:00
Doxa Maps
7795eba447 The knows-Christ totals come from the unrounded share
Only the printed percentage rounds. A large list at 0.004% is tens of
thousands of people, which printed as 0 when the total was computed from
the rounded figure; a share below the last printed digit now reads
"<0.01%" beside its real total. check:evangelical-share asserts it.
2026-09-29 20:20:02 +00:00
Doxa Maps
588e28e10c Merge remote-tracking branch 'origin/development' into upg100/christian-page 2026-09-29 20:15:02 +00:00
Doxa Maps
d78e485643 "Who among them knows Christ" counts people, not weeks
The page reused the life calendar's grid and counted its shaded boxes in
weeks ("0.61% · 32 weeks"), under a week axis and a year axis, with a lede
calling it "one human life in weeks". On this page a box is an equal share
of the list's PEOPLE, so the same 5,200 boxes are now drawn with no week or
year axis, and the legend states each side in people: how many follow
Jesus and how many do not yet, each with its share (the two percentages
sum to 100 as printed), plus how many people one box stands for. Numbers
are formatted in the reader's locale.

The labels become "Followers of Jesus" / "Not yet following Jesus" and the
lede drops the weeks, in all eleven languages; the served strings file is
re-pinned. check:evangelical-share asserted the weeks figure; it now
asserts the people totals, the bare percentage and the absence of weeks
and axes, with the life page (which keeps its axes) as the negative
control. check:packet-variants found the grid by an exact class string
and now matches the class prefix.
2026-09-29 20:08:55 +00:00
Doxa Maps
fa69209035 The gallery's published section order: Prayer Progress before the UPG-100 List
The Deep Research page publishes the rail as Dashboards (Big Picture, Simple Research, Regions),
Prayer Mobilization (Prayer Progress, UPG-100 List), Gospel Research (Cities with Internet, Gospel
Resources), then the Experimental folder. Only the Prayer Mobilization pair moves. Big Picture now
says "desktop only" on every width, not only once a phone has disabled it.

check:spa-tab-order asserted the old four-name order with UPG-100 first; it now asserts all seven
published rows in order (still relative, with tab 1 positional). It needs a browser: rega runs it.
2026-09-29 20:00:36 +00:00
Doxa Maps
2b210b78f0 Merge remote-tracking branch 'origin/development' into regions/country-map-refetch
# Conflicts:
#	package.json
2026-09-29 19:36:16 +00:00
Doxa Maps
656503a28d Merge remote-tracking branch 'origin/development' into regions/pane-config-land
# Conflicts:
#	package.json
2026-09-29 19:12:46 +00:00
Doxa Maps
e643e8a30e country-map: key the refetch by value, let only the newest response win, show the wait
Three defects on country-map/country-map, which is production -- DX Life's
country pages. Found by auditing the element rather than from a report.

1. ANY profile-config change refetched all 2,106 records. The watch getter
   returned a NEW ARRAY literal, and Vue compares a watch value with Object.is,
   so a fresh array always reads as changed; both computeds read the injected
   cfg, so the effect re-ran on every config change and the callback then fired
   unconditionally. MEASURED with real Vue: flipping isDark refetched the whole
   endpoint and redrew the map, and so did a host adding pinHint. A joined
   STRING compares by value, so only a real language or country change refetches
   -- which must still refetch, because the API localises the names.
   This was latent waste until the composite re-forward made config writes
   routine. It is now on every upstream locale switch, so the two changes are
   complementary rather than independent.

2. A SLOW EARLIER RESPONSE OVERWROTE A NEWER ONE. loadPoints is async and had no
   sequencing at all -- 0 abort or generation tokens in the file -- so two runs
   could be in flight and the one that STARTED first could FINISH last. Both
   assigned points, so the map showed the previous country's pins with no error
   and nothing for the reader to notice. Every run now takes a ticket and a stale
   ticket writes nothing: not the points, not loadFailed, not the spinner the
   current run is still using. fetch is left to complete rather than aborted,
   because the response is cached for the next switch back.

3. `loading` WAS WRITE-ONLY: assigned in three places and read in none, zero
   template references. A reader on a country page waited on an empty map -- no
   outline, no pins, no message -- which is indistinguishable from a country that
   genuinely has no people groups, and this element fetches the whole list before
   it can draw one pin. "Loading results..." was already in the catalogue in all
   eleven locales, so saying so cost no new string and no parity debt.

check:country-map-refetch guards all three. It drives the REAL reactive chain
with real Vue and takes the watch key expression OUT OF THE SHIPPED SFC, because
bug 1 is entirely a question of what Vue considers changed and is invisible to
any test that fakes reactivity or re-types the watch.

Mutation-tested, 5 mutations, all caught by name. The first version of the gate
MISSED one: a bare /if \(!current\(\)\) return/ grep matched the guard in the
catch block, so removing only the guard before the points write still passed.
The assertions are positional now -- the guard must sit immediately before the
assignment it protects -- and the catch guard is asserted separately. That hole
existed because the behavioural half of the test reproduced the guard's shape
inside the gate instead of reading the component, which is the self-consistent
oracle this repo's other geometry gate explicitly warns against.

Registered in scripts and gates:pre, verified by re-parsing: one key, 107
checks. Bundle rebuilt (BUNDLE=country-map), then tree, then fix:sri.
2026-09-29 19:11:37 +00:00
Doxa Maps
e7962e4ef7 Merge origin/development into studio/hygiene 2026-09-29 18:47:01 +00:00
Doxa Maps
7d816f5eab Four more gates:post reds, hidden until a failed gate printed why
- research-map.vue's openPacket read and wrote _packetBusy, a name 8ab3dc0f5 replaced with the
  reactive packetBusy ref. Reading an undeclared name throws, so the packet export threw a
  ReferenceError on every click, in doxa-research-map and in research-map-plus-grid, the production
  map that compiles it. It uses packetBusy.value now (check:no-free-identifiers).
- check:list-prop-unit and check:optional-t-equivalence read every entry of library/i18n/locales as
  a locale, and the folder has held a README.md since bba33e783. They read locale FOLDERS now.
- people-groups-grid's regions-look instance previewed two props (filters-toggle, backdrop) of a grid
  merge that is not on development, so the page showed nothing different and
  check:instance-config-keys failed. It returns with that merge.
2026-09-29 18:40:27 +00:00
Doxa Maps
2a4c3ddb3d The full build also copies the maps into the sibling DX Life site, when it is there
`bun run build` now ends with `sync-dropin --from-config --if-present`. It copies public/dx-maps into the
ONE configured host path (vite.doxa-maps-build-config.json dropin.dest, default ../doxa-life/public, or
DOXA_DROPIN_DEST). No site at that path: it prints "skipped" and exits 0. Nothing else on the filesystem
is searched for repos or sites. DOXA_DROPIN=off skips it even when the site is there. Without
--if-present, a missing host is still an error, as before.
Tested: no host skips (exit 0); a host gets 1,209 files; DOXA_DROPIN=off copies nothing; the plain
command still refuses a missing host. The container's /cdn build (build-cdn.sh) does not run this chain.

On this box ../doxa-life does not exist beside the doxa-maps checkouts (DX Life lives in root-dx-life), so the step is a no-op for the fleet's builds.
2026-09-29 18:39:36 +00:00
Doxa Maps
cc65f40c1e Gate hygiene: three gates:post reds on development, and two things that hid failures
- check:no-orphan-gates stopped at internal/check-grid-merge-defaults.mjs, which had no script. It
  asserts defaults of three grid props that are not on development (the grid merge has not landed),
  so it is registered ON DEMAND with that reason, not chained red. Past that first arm, its chain arm
  found check:grid-image-loading and check:retry-fetch run by no chain; both depend only on code and
  pass in under 300 ms, so they join gates:pre.
- A tracked vite.config.js.timestamp-*.mjs (395 KB, eight absolute paths) failed check:no-abs-paths.
  Removed, and ignored at the source: vite writes one beside its config while it bundles it.
- check:library-index: documentation/reference-library-index.md regenerated for retryFetch.js.
- run-parallel printed a failed step's output only with --verbose: the unbraced else bound to the
  inner if. Braced; a failing step now prints why.
- The Pages workflow ran bun run build without BUILD_ALLOW=1, so build-lock refused it with exit 75
  and the workflow ran no gate at all. A CI runner is the only builder on its machine; it opts in.
2026-09-29 18:35:37 +00:00
Doxa Maps
9ccec24d29 Generalise the pane re-forward to attribute-configured panes, and gate it
sr asked to adopt usePaneConfig for research-map-plus-grid rather than write a
second fix, and found the one shape it did not cover: people-groups-grid takes
its filters as THREE separate attributes (wagf-region, religion-family,
primary-language) instead of one profile-config blob, so that composite has one
pane of each kind. The helper hardcoded 'profile-config' and gave the grid
nothing.

registerAttrs is the sibling for that shape. It shares the same entries list,
the same watchEffect, the same prune and the same write-only-on-change -- one
mechanism for all four composites rather than a fork per adopter. A helper with
a single caller has not been shown to generalise at all; this is the second
shape that showed it.

Two decisions worth recording. Each attribute is compared and written
independently, so a getter whose region changed does not rewrite the two that
did not and re-trigger the child. And the attribute NAME LIST is pinned at
registration: a later getter that omits a key CLEARS that attribute rather than
leaving a stale filter silently narrowing the grid, which is the same class of
lie as the frozen config this helper exists to fix.

The gate runs the shipped helper with real Vue, not a re-typed copy, because the
dependency-tracking hole found in review is invisible to any test that fakes
reactivity. 28 cases over both shapes. Its subject is the measurement on
development 92ca8b6e6: the outer element reached locale ar by +1.5s while every
nested host carried NO locale key at boot and still none at +15s, across four
composites -- so case 1b asserts that an ABSENT key is still a change.

Case 7 is the adopter's property rather than mine: a re-forward triggered by a
LOCALE change must produce the SAME primary-language string. gridLanguage() can
fall back to a display label, and the grid compares whole normalised values, so
a name fetched in one language matches no row in another. It does not bite today
because the surviving fallback is a value the grid itself produced, but the gate
asserts the class, not today's instance.

Mutation-tested, 7 mutations, all caught: plain array, no write-on-change guard,
skip-instead-of-prune, escaping getter throw, no per-attribute compare, omitted
key left stale, and the label-instead-of-code regression. The first two crashed
rather than naming a case, so cfgOf is null-safe now -- a gate that dies reports
"something went wrong" instead of naming the pane that stopped following.

Registered in package.json scripts and in gates:pre, verified by re-parsing the
file: one key, 104 checks. gates:pre PASS 103 FAIL 0 NM 1.
2026-09-29 18:34:49 +00:00
Doxa Maps
83fa4da4f4 Drop the region-paint gate's on-demand entry now that it is chained
The entry was marked temporary, to be deleted when the gate joined
gates:post. 6a1860539 chained it; the entry stayed behind.
2026-09-29 17:42:45 +00:00
Doxa Maps
99816626af Every shadow stylesheet gets its own label, and a gate keeps it that way
useShadowStyles keys its <style> by the label and overwrites an existing
tag with the same key, so two components sharing a label keep only the
last one's CSS in a shared shadow root. The regions list lost its sheet
this way to the region card, which had kept the list's label when it was
extracted.

check:shadow-style-labels-unique (gates:pre) fails any label two calls
share, globally rather than per shadow root, so a copied or forked
component is caught when it is copied. It reads the real parsers,
classifies every reference to the function (a rebinding, .call, a
re-export or a namespace import fails instead of hiding a call),
cross-checks the AST against the token stream, and covers the other
ways two calls share a key: unlabelled calls under the dev server's
per-component key, and a fixed label over CSS that varies per caller.

countries-map.vue, a fork of research-map.vue, carried the same label;
it is now 'countries-map', with the country-posters bundle rebuilt and
the tree regenerated. The composable's JSDoc called the label a
debugging name; it now says it is the key.
2026-09-29 17:42:44 +00:00
Doxa Maps
494a529e09 Merge origin/development into studio/integration 2026-09-29 16:50:13 +00:00
Doxa Maps
de6d60378e Merge origin/development into studio/integration 2026-09-29 16:38:05 +00:00
Doxa Maps
57671ca465 Merge remote-tracking branch 'origin/development' into regions/handoff-integration
# Conflicts:
#	public/dx-maps/cities-internet/cities-internet.js
#	public/dx-maps/cities-internet/connectivity-list/index.html
#	public/dx-maps/cities-internet/connectivity-map/index.html
#	public/dx-maps/cities-internet/data-tables/index.html
#	public/dx-maps/country-map/country-map.js
#	public/dx-maps/country-map/country-map/index.html
#	public/dx-maps/country-posters/countries-map/index.html
#	public/dx-maps/country-posters/country-poster-wall/index.html
#	public/dx-maps/country-posters/country-posters-mfe/index.html
#	public/dx-maps/country-posters/country-posters.js
#	public/dx-maps/demo-map/demo-map.js
#	public/dx-maps/demo-map/demo-map/index.html
#	public/dx-maps/demo-map/demo-map/maplibre/index.html
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/doxa-research-map/doxa-research-map.js
#	public/dx-maps/doxa-research-map/research-map/index.html
#	public/dx-maps/doxa-research-map/research-map/maplibre/index.html
#	public/dx-maps/doxa-simple-map/doxa-simple-map.js
#	public/dx-maps/doxa-simple-map/doxa-simple-map/adoption/index.html
#	public/dx-maps/doxa-simple-map/doxa-simple-map/engagement/index.html
#	public/dx-maps/doxa-simple-map/doxa-simple-map/index.html
#	public/dx-maps/doxa-simple-map/doxa-simple-map/prayer/index.html
#	public/dx-maps/gospel-internet/board/board/index.html
#	public/dx-maps/gospel-internet/board/index.html
#	public/dx-maps/gospel-internet/board/india-china/index.html
#	public/dx-maps/gospel-internet/board/language-tree/index.html
#	public/dx-maps/gospel-internet/board/platforms/index.html
#	public/dx-maps/gospel-internet/board/project-700/index.html
#	public/dx-maps/gospel-internet/board/zero/index.html
#	public/dx-maps/gospel-internet/gospel-internet.js
#	public/dx-maps/manifest.json
#	public/dx-maps/regions-dashboard/region-dashboards/index.html
#	public/dx-maps/regions-dashboard/regions-dashboard.js
#	public/dx-maps/regions-dashboard/regions-list/index.html
#	public/dx-maps/regions-dashboard/regions-mfe/index.html
2026-09-29 16:33:55 +00:00
Doxa Maps
e21c4a5d57 Merge remote-tracking branch 'origin/development' into regions/handoff-integration
# Conflicts:
#	public/dx-maps/country-posters/countries-map/index.html
#	public/dx-maps/country-posters/country-poster-wall/index.html
#	public/dx-maps/country-posters/country-posters-mfe/index.html
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/manifest.json
#	public/dx-maps/regions-dashboard/region-dashboards/index.html
#	public/dx-maps/regions-dashboard/regions-list/index.html
#	public/dx-maps/regions-dashboard/regions-mfe/index.html
2026-09-29 16:12:45 +00:00
Doxa Maps
2ff7d2f17b Merge origin/development into studio/integration 2026-09-29 16:01:38 +00:00
Doxa Maps
0417e46fbd Merge remote-tracking branch 'origin/development' into bundler-2/handoff
# Conflicts:
#	internal/check-poster-layout.mjs
#	library/composables/poster/useMapPoster.js
#	package.json
2026-09-29 16:00:18 +00:00
Doxa Maps
212ec20816 Merge remote-tracking branch 'origin/development' into bundler-2/handoff
# Conflicts:
#	package.json
2026-09-29 15:54:16 +00:00
Doxa Maps
14096e19c2 Merge remote-tracking branch 'origin/development' into upg100/merge
# Conflicts:
#	package.json
2026-09-29 15:54:05 +00:00
Doxa Maps
7f08a74784 Revert "The map engine loads from the tree it was served from" for the handoff (unverified, now conflicting)
The same-origin engine copy collided with the CDN preloads that landed meanwhile: map
leaves now preload https://cdn.jsdelivr.net/.../maplibre-gl.js (leaf hints), and composite
snippets preload the same URL. With the engine loaded from <tree>/vendor/ instead, those
preloads would never be reused and every map page would download the engine twice.
Re-pointing the preloads is design work, which the handoff does not start. The change
stays in history (fc7259e06, studio/vendor-maplibre 275cdc807), and it belongs to the
HANDOFF-BRANCHES-RECORDED-AS-MERGED-WITHOUT-THEIR-CONTENT card.
2026-09-29 15:38:28 +00:00
Doxa Maps
8eccda7752 Merge origin/development into studio/integration 2026-09-29 15:37:45 +00:00
Doxa Maps
0757b38f88 Merge remote-tracking branch 'origin/development' into regions/handoff-integration 2026-09-29 15:35:44 +00:00
Doxa Maps
b1173d48ab Merge remote-tracking branch 'origin/development' into upg100/merge 2026-09-29 15:27:41 +00:00
Doxa Maps
0450da266c Merge remote-tracking branch 'origin/development' into regions/handoff-integration 2026-09-29 15:24:53 +00:00
Doxa Maps
decdf31ed5 Merge remote-tracking branch 'origin/development' into dx-base/handoff-integration 2026-09-29 15:24:30 +00:00
Doxa Maps
01706a4e39 generate-tree's engine comment keeps the reason and drops the speaker 2026-09-29 15:22:27 +00:00
Doxa Maps
62afbdcdf3 check:ported-globals-identical compares only the ported rules, not the whole stylesheet
The gate hashed each component's entire emitted CSS, so any unrelated style change
in these four files (Regions giving three :host rules position:relative) failed it,
and could pass only by re-baselining a guard that exists to prove something else.
It now hashes what library/styles/portedGlobals.js emits, found in the executed CSS:
each cyrillicHeading and strongMedium rule with the selectors in front of it, and
each scrollbar-gutter declaration with its rule's selector.

Re-baselined on the tree the old gate passed on. Proven both ways: re-scoping
GoalCard's strong rule, changing the module's Cyrillic letter-spacing and dropping
a file's ported rules each fail it; --write refuses to baseline an empty block.
2026-09-29 15:03:05 +00:00
Doxa Maps
fc7259e06d The map engine loads from the tree it was served from, with the CDN as fallback (unverified)
UNVERIFIED: carried into the handoff without a browser run on this base.

MapLibre GL came from cdn.jsdelivr.net: a second origin to connect to before a
map could start. generate-tree now copies the pinned maplibre-gl JS and CSS from
node_modules into <tree>/vendor/maplibre-gl@5.24.0/ and stops the build if their
bytes do not match the integrity pin. A built bundle loads the engine from its
own tree with that same pin, one cached copy for every bundle, and falls back to
jsdelivr if the copy is missing. Mapbox GL stays on api.mapbox.com.
2026-09-29 14:56:52 +00:00
Doxa Maps
8eb4e498fc check:composite refuses a verdict built from files no commit has (unverified)
UNVERIFIED: written, not yet run end to end; the handoff stopped it here.

The rebuild runs in the working tree, so it can read what no commit carries: an
untracked locale a glob picks up, a VITE_* key from an untracked root .env that
the code reads (apiBaseUrl.js reads VITE_API_BASE_URL), a build env var such as
DOXA_QA. Bytes built from those prove nothing about freshness, and the landing
precondition caches a PASS per tree id. Build env vars are now scrubbed from each
rebuild; vite.config.js writes down every file a build read when DOXA_BUILD_INPUTS
is set (only this gate sets it); a bundle whose rebuild read an untracked file or
such a key is NOT MEASURED (exit 75), naming the files.

Measured before the stop: an untracked .env.local with an unreferenced VITE_ key
leaves all-people-groups byte-identical (cf536c63), so only keys the code reads
are held against a bundle.
2026-09-29 14:56:52 +00:00
Doxa Maps
f8d0a7d9c0 check:ported-globals-identical compares only the ported rules, not the whole stylesheet
The gate hashed each component's entire emitted CSS, so any unrelated style change
in these four files (Regions giving three :host rules position:relative) failed it,
and could pass only by re-baselining a guard that exists to prove something else.
It now hashes what library/styles/portedGlobals.js emits, found in the executed CSS:
each cyrillicHeading and strongMedium rule with the selectors in front of it, and
each scrollbar-gutter declaration with its rule's selector.

Re-baselined on the tree the old gate passed on. Proven both ways: re-scoping
GoalCard's strong rule, changing the module's Cyrillic letter-spacing and dropping
a file's ported rules each fail it; --write refuses to baseline an empty block.
2026-09-29 14:56:52 +00:00
Doxa Maps
9d00aa3db4 check:snippets-draw: every published snippet, pasted verbatim on another origin, must draw (awaiting its first run)
Ported from rega's snipgate and mbxcheck probes (card GATE-EVERY-PUBLISHED-SNIPPET-DRAWS-A-MAP). Two scripts so the keyless arm never waits on a token: check:snippets-draw pastes each production embed.script and requires a MapLibre map to draw (a hooked instance with its style loaded via a setter trap on the engine global, a sized canvas, tiles 2xx, no failure note, 0 page errors); check:snippets-draw:mapbox does the same over embed.scriptMapbox with only the token filled from MAP_TOKEN, NOT MEASURED without one and never printing it. Composites that open on a list (regions-mfe, upg-100-mfe) are pressed to their map view under the settle rule first, since a hidden pane still draws a canvas. The browser slot is checked before any server starts, and the tree server is spawned --exit-with-parent. Registered and declared on demand until rega's first run; it joins verify-browser-all after.
2026-09-29 14:56:52 +00:00
Doxa Maps
7c99d1a06c A gate's tree server dies with its gate: serve-strict --exit-with-parent, passed by every spawning gate
On 2026-09-29, 41 serve-strict processes had outlived the gates that started them: 279 MB resident,
the oldest 5.3 days, spread across eight worktrees. A gate that crashes, is killed, or is refused by the
browser-slot guard's process.exit cannot run its own srv.kill(), and _serve-reaped's handlers cover
signals and normal exit but not a SIGKILLed parent.

serve-strict takes --exit-with-parent: it records the pid that started it and exits within 2 s once
that process is gone. Opt-in, so a server someone deliberately left running is never taken down.
Every internal/ gate and tool that spawns it now passes the flag (14 files, plus _serve-reaped, the
shared helper). Proven: a parent that spawns the server with the flag and exits abruptly (as the
guard does) leaves it alive for a moment and gone within 3 s.

The orphans already running belong to other worktrees' runs and are left to their owners; plugin-local
scripts that spawn serve-strict should pass the flag too.
2026-09-29 14:56:38 +00:00
Doxa Maps
d3cdc2c3bc Two gates the branch backlog turned red
Seven Driver citations came back with the merged branches. Each keeps its
engineering reason and its date, and loses the speaker: the overlap report, the
poster's legend rule, the network-change defect, the chart's provenance.

check:plural-forms crashed rather than failed. It built its locale list by
listing the catalogue directory, so a README.md moved in beside the locale
folders became a 'locale', passed the exists check because a file does exist,
and crashed readdirSync on a non-directory. It now filters to directories. The
gate on development has the same line and only survives because that README is
not there yet -- so this is a fix for development, not a merge artefact.

Both found by running the full 103-gate chain; the shortened chain the merge
produced ran neither.
2026-09-29 14:55:35 +00:00
Doxa Maps
ca11b7b361 Merge remote-tracking branch 'origin/development' into regions/handoff-integration 2026-09-29 14:55:26 +00:00
Doxa Maps
4dd858fb9a Merge upg100/list-pattern into development (handoff)
# Conflicts:
#	internal/check-ported-globals-identical.mjs
#	internal/fixtures/ported-globals-baseline.json
2026-09-29 14:54:21 +00:00
Doxa Maps
7869f28ebc Merge branch 'regions/grid-merge' into regions/handoff-integration
# Conflicts:
#	package.json
#	plugin-designs/people-groups-grid/people-groups-grid.vue
#	public/dx-maps/doxa-maps-spa/manifest.json
#	public/dx-maps/manifest.json
#	public/dx-maps/people-groups-grid/people-groups-grid.js
#	public/dx-maps/people-groups-grid/people-groups-grid/driven/index.html
#	public/dx-maps/people-groups-grid/people-groups-grid/index.html
#	public/dx-maps/people-groups-grid/people-groups-grid/people-groups-grid/index.html
2026-09-29 14:53:55 +00:00
Doxa Maps
844fc60d0e Merge upg100/group-set-standard into development (handoff)
# Conflicts:
#	library/scripts/posters/packet.mjs
2026-09-29 14:53:36 +00:00
Doxa Maps
bdb74ff69f Merge remote-tracking branch 'origin/development' into bundler-2/handoff 2026-09-29 14:50:51 +00:00
Doxa Maps
4d65d399b1 Merge origin/development into the handoff integration 2026-09-29 14:50:47 +00:00
Doxa Maps
6156895e54 Merge branch 'bundler-2/driver-1650' into bundler-2/handoff
# Conflicts:
#	internal/check-embed-url-absolute.mjs
#	internal/check-legend-top-offset.mjs
#	internal/check-map-menu-anchor.mjs
#	internal/check-mercator-slice.mjs
#	internal/check-one-scroll-container.mjs
#	library/components/map-controls/MapControlMenu.vue
#	library/composables/poster/useMapPoster.js
#	library/composables/usePosterPrints.js
#	library/maps/mercator-slice.js
#	library/utils/embedBase.js
#	package.json
#	plugin-designs/doxa-research-map/research-map.vue
2026-09-29 14:50:44 +00:00