The 14 bundles that import ShareButton (or read the share catalogue area), built
one at a time on the merged pilot cee32f273, then bun run tree + fix:sri. The
build-config key and define reach every bundle; the others are byte-identical
(the in-lock freshness check runs on every bundle).
The precondition's scope against the pilot (its own step-4 rule): every bundle
that imports ShareButton/MapControlMenu or reads the share catalogue area, plus
the P1 shells. Built one bundle at a time, then bun run tree + fix:sri.
gates:pre 141/0/1, gates:post 99/0/16.
The merge took the pilot's built files where both sides had rebuilt them; this rebuilds the landing's
freshness scope (22 bundles, now including bless-india-posters) on the merged source, then the tree and
SRI. Against the pilot's bundles, with data-v ids normalised and the old->new wording applied, eight are
identical, gospel-resources differs only by minifier renaming, and gospel-internet's one further change
is notice.pin no longer passing {country}. Pages and manifests differ from the pilot only in integrity
hashes.
The host page of every full-page map (and the Plugin Studio) sized the
element to the viewport in a way that tracks the phone's address bar:
- the built fixed-viewport leaf used position:fixed with inset:0, which
follows the DYNAMIC viewport, so the map and its legend sheet resized
on every scroll that moved the bar;
- the Plugin Studio page and the dev server's leaf and studio pages used
100vh, the LARGE viewport, taller than the view while the bar shows, so
the page itself scrolled by the bar's height and the app seemed to
resize.
All four now use height:100svh (100% first as the fallback where svh is
unknown), anchored top-left, and set --profile-min-h:0 so ProfileLoader's
100dvh floor cannot grow the element when the bar hides. On a desktop svh
equals the viewport, so nothing moves there. Scroll-page leaves (the
cap-4 stacks) are unchanged.
Regenerated the tree: 51 leaf pages and the Plugin Studio page change
only this rule and its comment; no bundle changes.
A host may move the engine's credit to the TOP of the map (a phone layout with the sheet flush at the
bottom). creditFloor() would then have used a credit near y=10 as the floor, and syncAttribClearance()
would have reserved the whole map height (capped at 120px), so the pill lifted itself for nothing. Now
a credit in the upper half of the pill's layout parent is not counted: no floor, and the 20px default
clearance. Every credit is at the bottom today, so this changes nothing yet.
Every bundle rebuilt (PinHint ships through ProfileLoader), composites after their children, then the
tree and SRI.
- It is dismissed when the reader taps a pin, the gesture it teaches. The signals are
uiStore.selectedPeopleGroup (the maps that select through uiStore.selectPeopleGroup) or a
'dxmaps:pin-selected' event inside the map's root (a map with its own selection). It was left
standing over the detail card that the tap had opened. A pan still does not dismiss it.
- Wide, the pill reached the gallery's round menu button (bottom-left). Its bottom now takes the
larger of the credit clearance and --map-fab-clearance, which the layout publishes only while the
button is rendered.
- Every bundle rebuilt (PinHint ships through ProfileLoader), composites after their children, then
the tree and SRI.
This branch changes five library files -- ProfileLoader.vue, LifeCalendar.vue,
packetCharts.js, RegionSectionCard.vue and packet/countrySheet.js -- and
ProfileLoader alone is carried by sixteen bundles. Built every one of those
sixteen, one at a time (memory is the limit on this box), then regenerated the
tree and refreshed SRI.
FIFTEEN CHANGED, which is the measurement that matters: all-people-groups,
cities-internet, country-map, country-posters, demo-map, doxa-research-map,
doxa-simple-map, gospel-internet, gospel-resources, my-upg-100-list,
pplr-data-maps, research-dashboard, template-bundle, upg-neighbor and
wall-of-people-groups. Only regions-dashboard was already current, because it was
rebuilt for the label fix.
A previous claim of mine that this tree was fresh rested on `bun run tree` and
`fix:sri` producing no diff. That proves neither: tree does not rebuild bundles,
and SRI only proves a leaf loads the bundle its integrity names. The test that
distinguishes the two is building the consumers and seeing whether their bytes
move -- and fifteen of them did.
The shadow-style label fix survives the rebuild: ,"regions-list") appears once
and ,"region-section-card") once in regions-dashboard.js.
The branch merges thirteen shared library files, including two new modules, so
every bundle that imports them was carrying older bytes than its source.
Found by building each of the twenty-two bundles the freshness step names, one
at a time: all twenty-two build cleanly in 8-24 seconds, none fails and none
hangs -- and twenty of them produce different bytes. Big Picture alone moves
510 bytes.
That also corrects a check I trusted earlier in this branch. `bun run tree`
reported zero changed files and I read it as "the consumers are fresh". It is
not: tree stages assets and regenerates leaf pages, and does NOT rebuild the
bundles, so it can report a clean tree over twenty stale ones. Only a build
answers that question.
Hashes rebaked and check:sri passes across every leaf.
BUNDLE=<name> bun x vite build for cities-internet, gospel-internet,
gospel-resources, plugin-studio and rudder-voice, then bun run tree and fix:sri.
Regenerated on this tip, never merged: the scan refused the previous sha with
gospel-internet stale (committed 7361a689e3a6 against a rebuild of ce15dd0ba73f).
dx-shepherd/rega: both production composites should get hints, but 37/27 showed
only regions-mfe was reclassified. research-map-plus-grid was still bare: it
composes doxa-research-map (74 engine refs) but its OWN bundle has 0, so keying
on the own-bundle signal alone missed it.
builtBundleLoadsEngine now also scans the bundles a leaf `composes`, resolving a
composes entry that names its child by element TAG (stack-demo composes
"research-dashboard-map", bundle "research-dashboard") through an
element→bundle map built from the scanned bundles. So a composite is hinted
when its own bundle OR any composed child's bundle loads an engine; big-picture
(composes only non-maps) stays out.
Result: both production composites hinted (regions-mfe via own bundle,
research-map-plus-grid via its child), and stack-demo too (it composes a map).
check:leaf-hints mirrors the same tag→bundle resolution from the manifest, so
gate and generator can't drift: PASS 41 hinted / 23 bare. Poison-tested the
composes-child case (stripped → fails) and the pure-non-map case (big-picture
given a hint → fails). Also carries the comment reword from the token-ladder
correction across every hinted leaf.
A cold map ran serially: leaf HTML, then the bundle (250-470 KiB gz, parsed),
then only the engine (from cdn.jsdelivr.net or api.mapbox.com), then the style
host, tiles, and data. Four origins discovered one after another, none
pre-connected. That waterfall is the shape behind A9's 3-5 s cold map.
generate-tree now emits, in each MAP leaf's <head>, a preconnect for the
engine origin, the style host and the data origin, and -- only on the 'auto'
leaf, which carries no engine <script> today -- a preload of the engine, so
DNS/TLS and the engine download start alongside the bundle instead of after
it. A non-map leaf (grid/card/chart-table/app-shell/composite) gets nothing.
The engine is decided at build time from the SAME inputs the runtime ladder
reads (profile-config.provider, then a baked token or a token endpoint; 'auto'
with no token path is MapLibre keyless), so the hint and the ladder cannot
disagree. Every URL, integrity and crossorigin comes from
library/constants/cdn.js, so a preload cannot drift from ensureEngineScript's
tag. The one case a static hint cannot foresee -- an explicit ?provider= or
window.MAP_PROVIDER overriding the build default at runtime -- costs one unused
preconnect.
New gate check:leaf-hints (gates:post): a map leaf without hints fails, a
non-map leaf carrying a map-engine hint fails, and a hint origin must be one
the code uses. PASS: 36 map leaves carry hints, 28 non-map leaves carry none.
Poison-tested both sides.
Unlanded (dx-base/a9-leaf-hints); the bundled-vs-shared-vs-today trade-off
report and any landing wait on rega's timing and regions' tiles.
Regenerated on this base rather than carried over: BUNDLE=<name> bun x vite
build for each, then bun run tree and fix:sri.
Three integrity hashes move, one per bundle. The MapLibre and Mapbox CDN pins
are byte-identical on both sides, and the only bundle paths in any changed
manifest line are ./cities-internet/, ./gospel-internet/ and ./gospel-resources/.
Verified in the BUILT output, not only in source: the shipped
cities-internet.js carries position:relative on :host, which is the declaration
the partner-page overlap depends on.
check:composite-freshness found stale on main: none. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
check:composite-freshness found stale on main: template-bundle. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
Since 2026-09-28 resolveMapProvider returns MapLibre for 'auto' whether or not a token is present;
only an explicit provider selects Mapbox. Four comments still said "Mapbox when a token is
available": useMapProvider.js's own header (and its note on the `token` argument),
useMapInstance.js at the provider option, check-provider-switch.mjs's contract note, and the
PROVIDER note that generate-tree writes into every leaf page.
The leaf page's note now says what the page does: it finds a token first only when one is on offer,
because place search uses one on either engine, and the element decides the engine. The 64 leaf
pages are regenerated and differ only in that note. The three JS files change in comments only
(compared minified, without renaming).
check:composite-freshness found stale on main: doxa-maps-spa
plugin-studio
prayer-walk-planner
template-bundle. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
GiCombos built its facets object inside provide() at setup, so T() ran once and
the result was handed to the consumer as a literal. After a live switch to Arabic
every facet name stayed in English — the labels were keyed, the keys resolved,
and the reader still saw the wrong language, because what was wrong was WHEN they
were read rather than whether they were translated.
check:frozen-labels cannot see this: every call site passes a real key and every
key exists in all eleven locales. The defect is a lifetime, not a string.
The facets are a computed now, provided through a getter so a consumer reading
.facets re-reads it rather than taking a snapshot. Demonstrated rather than
asserted: with a locale ref driven en -> ar, the old shape keeps returning
"Access" and the new one returns "الوصول".
Audited all 179 t() call sites across the three plugins by enclosing scope, not
by grep. This was the only frozen one; the six GiDrawer hits my first pass
flagged are inside a computed 60 lines up, which is why a lookback window is the
wrong tool for a lifetime question.
check:composite-freshness found stale on main: template-bundle. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
check:composite-freshness found stale on main: template-bundle. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
A map says how it behaves on a narrow screen once, in its <profile>.meta.json:
"mobile": "desktop-only" (blocked on a phone) or "larger-screens" (opens,
under a dismissible notice). Absent means phone-ready. Until now the rule
lived only in the Research Gallery, as two hard-coded id sets, so a map
opened standalone on its own leaf page on a phone got neither the block nor
the notice.
- profile-meta.mjs knows the vocabulary; generate-tree and the dev manifest
carry the flag into each profile's manifest entry, and generate-tree into
the leaf page's BASE_CONFIG (with the map's name for the desktop-only
sentence).
- ProfileLoader mounts library/components/LargerScreenNotice.vue on a screen
under 640px: for desktop-only the profile is never mounted and a centred
message says why; for larger-screens a slim in-flow bar sits above the map
(it cannot cover the map's controls), dismissible per profile for the
session, in the element's own locale and direction. Inside the Gallery it
stays quiet: every Gallery pane now carries data-doxa-gallery.
- One text: the Gallery's two sentences moved into the library catalogue as
messages.largerScreenNotice / desktopOnlyNotice (+ noticeDismiss), all 11
locales moved as they were, and the Gallery reads them from there.
- The Gallery derives its rules from the manifest's flags. On a phone it
mounts nothing until the manifest has landed: its baked first tab (Big
Picture) would otherwise mount there before the flags say it is
desktop-only.
- dashboard-plus-grid is desktop-only and gospel-internet/board is
larger-screens, the two sets the Gallery held; nothing changes for either.
- check:mobile-gating now asserts the vocabulary, that each flagged leaf page
carries its flag, the Gallery's derivation and its closed-before-manifest
rule, that Big Picture stays desktop-only, the 11 locales, and the
notice's mounting. Its self-test plants one failure per rule.
check:composite-freshness found stale on main: template-bundle. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
The collapsed-legend default and the removal of the SVG download both reach the
bundle. Verified in the artefact rather than the source: the download filename
and the posterSvg key are gone, the print path remains.
check:composite-freshness found stale on main: none. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.
The caption and its eleven locale keys reach the bundle, so this is a real
rebuild rather than a docs-only change. fix:sri reports 127 hashes already
agreed, 0 rewritten; manifest churn is this bundle and the spa manifest's own
self-reference.
check:composite-freshness found stale on main: none. Rebuilt, tree + SRI
regenerated; the landing precondition (fresh, one folder, SRI) passed in main-capture scan.