MapInfo (library/components/info) answers "what can this map do for
you?" with real output the map makes, pre-generated so it opens at once.
The examples are an ordered list of kinds rather than a fixed set,
because maps make different things: an image (a poster), pages (a packet
that shows its first page and expands to every page), a deck (cards that
expand from a stack to a grid) and a table (a real excerpt of the
spreadsheet a map exports, with translatable headers). An example whose
image is missing drops out quietly: no broken-image icon, no empty frame.
The pointer at the button goes for good once that map's popup has been
opened and closed; a checkbox in the popup turns it off on every map.
Both are kept in localStorage behind a guard, so private browsing cannot
break the page. On a phone the popup takes the whole screen; Escape
closes it and focus returns to the button. The pointer's motion stops
under prefers-reduced-motion.
All of its text is one new catalogue area, 'mapInfo', in all eleven
locales: the component's own words, and each map's lead, takeaway and
note as mapInfo.tab.<tabId>.<field>. One area because a bundle ships only
the areas its source names, and the gallery that mounts a popup per map
names none of the maps' own areas. This commit carries the UPG-100
map's two sentences; the other maps' follow.
resources-map.meta.json carried NO stage, so the manifest defaulted it to
experimental — while doxa-maps-spa, the gallery that becomes Deep Research,
mounts it: doxa-maps-spa.meta.json composes "gospel-resources/resources-map"
and TAB_DEFS names it as the Gospel Resources tab. The record disagreed with
what ships, and the record was the part that was wrong.
WHAT THIS CHANGES: the manifest stage, and nothing a reader sees. Verified —
the diff moves one "experimental" to one "production" and ZERO sha384 hashes.
No bundle is rebuilt and no byte of any map changes.
The stricter production gates now apply to this profile and it passes them:
gates:pre 103 PASS / 0 FAIL / 1 NOT MEASURED of 104. That is the part worth
having, because marking something production is only honest if it then has to
meet the production bar.
NOT a decision about which profile the Deep Research page SHOULD show.
gospel-dashboard is the production composite and remains the better end state;
it is not switched to today because its .gd-map is sized 80svh — a viewport
unit inside a pane that is not the viewport — which against rega's measured
panes gives the map 91% of the pane at 1440x900 and 95% at 390x844, and
because it has never been shot inside the gallery. That fix is written and
held local for after the deadline.
- 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.
For vibe coders: run the Plugin Studio, build one map or all of them (and the automatic copy into a sibling
DX Life site), and embed a map: every map's own embed.script in manifest.json, loaded from DX Life's
public/dx-maps. For agents: the repo builds mobilization maps, and each goal (reach a city, mobilize for
people groups, plan outreach, prayer packets and resources) is mapped to the production maps that serve
it, with the skill, the plugin rules, the landing rules and the freeze on experimental maps.
`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.
- 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.
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.
Each of these pushed branches reads unmerged on the Forgejo list because no
merge commit names it, while its patches are already on development under other
shas: git cherry reports 0 unlanded patches for every one of the nine.
origin/regions/land-rg5 7e99159cb
origin/regions/leaf-print fc93c97e4
origin/regions/legend-aria b35559495
origin/regions/legend-caret 28789b2c9
origin/regions/manifest-visibility 674121df5
origin/regions/print-busy 09adc903f
origin/regions/print-chrome a86b3d7be
origin/regions/vtl-context-lost cbb6f0040
origin/regions/zone-region-namespace f3c050aed
Checked by SUBSTANCE rather than by diffing the files, because the files differ
from these tips wherever they were edited again afterwards -- a byte comparison
reads that as missing work and is the wrong instrument. Spot-checked
legend-aria: LegendMobile.vue differs from the branch, and development carries
six aria-state attributes, so the toggles do announce their state.
The tree is unchanged by this commit: -s ours takes nothing.
The regions list's scroll failure was a style-label collision: the region
card and the list shared one stylesheet key, and the card overwrote the
list's rules. fe054b2c7 gives the card its own key, landed with the rebuild
in 3302f424c. The pane-mount scroller on this branch was never applied;
this merge records it and keeps the tree unchanged.
origin/regions/country-packet (f33b5b73c): superseded. Its one unlanded patch
removes four Driver citations from region-dashboards.vue,
check-regions-uses-library.mjs and src/UupgsList.vue. That work reached
development through the later version of the same commit, and the proof is the
gate rather than a file comparison: check:no-new-driver-references PASSES on
development with 0 references. The files differ from this tip only because they
were edited again afterwards.
origin/regions/perrow-boot (b97c3512e): superseded, and its target no longer
exists. Its one unlanded patch edits
plugin-designs/regions-dashboard/src/RegionCountryMap.vue, a path DELETED from
development when the component moved to library/components/maps/. Taking it
would resurrect a dead file.
These are PUSHED tips, which differ from the local branches of the same name
(88312a24b and f1a198522). The Forgejo branch list reads the pushed refs, so
they showed unmerged while the local ones were already ancestors -- a population
difference, not lost work. The tree is unchanged by this commit.
check:composite over EVERY bundle (this landing changes vite.config.js) found it: its committed
bytes are not what its source builds (committed ef13ff5d4adf, rebuilt e9b269ca6ffa). Every
other bundle on development rebuilt to its committed bytes. Tree and SRI regenerated.
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 merge took development's side on the generated files, as the rule requires,
so the bundle is rebuilt here from the merged source. Verified in the artifact:
the two shadow-style keys are distinct again -- ,"regions-list") once and
,"region-section-card") once -- so the card no longer overwrites the list's
stylesheet.
RegionSectionCard passed THREE arguments to useShadowStyles(css, label): the CSS,
then 'regions-list', then 'region-section-card'. The signature takes two, so
'regions-list' was the key and its own name was silently ignored.
useShadowStyles keys its <style> tag by label and, on a collision, OVERWRITES
the existing tag's text instead of adding one (useShadowStyles.js:60-61). This
card is a CHILD of regions-list, so the two share one shadow root: the cards
render after the fetch, mount second, find the list's tag under the shared key
and replace every .rl-* rule with the card's CSS.
Measured in the running page: .rl-root became position:static and .rl-scroll
overflow-y:visible, the shadow root held 3 style tags where a working tree holds
4, and 'rl-root{' appeared nowhere in it. The list therefore had no scroller of
its own, a wheel moved the pane column instead, and every region below the fold
was unreachable -- at 1440 Middle East, North America and Oceania; at 390
everything except Africa.
It was latent until the label became real: before the cyrillicHeading fix, a
dangling comma concatenated 'regions-list' INTO regions-list's own CSS, so the
list keyed by a content hash and the two never met. Fixing that rule turned a
silent collision into a visible break, which is why the live site is unaffected
and every sha after it is not.
Verified in the artifact, not the source: ,"regions-list") appears once in the
rebuilt bundle where it appeared twice, ,"region-section-card") now appears once,
and the .rl-* rules are still present.
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.
The merge took development's side on eight generated files, which is the rule for
generated output -- it is regenerated, never hand-merged. Rebuilt here so the
artifact matches the merged source: the three corrected :host rules are present
in the built bundle.
country-map.vue's poster-wall wiring put the poster table, peopleGroupRecords
and the sheet code into the bundle of EVERY DX Life country page, for a wall
that is hidden by default. Measured: country-map.js 391,475 bytes on
development against 683,401 here -- +291,926, a 74% increase -- and with it
removed the bundle is 391,625, back within 150 bytes of development.
Making the three imports lazy does not help, and I measured that rather than
assuming it: with all three behind await import() and the table fetched at
mount, the bundle grew to 684,700. vite.config.js:282 sets
inlineDynamicImports, so a dynamic import is flattened straight back in and only
the wrapper is added. Removing the weight needs the pinned-served-asset pattern
that poster-render.js already uses -- card
PERF-LOAD-THE-PRINTING-SUBSYSTEM-ON-DEMAND.
library/packet/countrySheet.js stays: it is unreached at runtime (0 hits in the
built bundle) so it adds nothing, and it is the library half this element will
use once the printing code loads on demand.
ProfileLoader's comment now names both populations -- 20 of the 25 bundles are
single-profile, 10 of the 17 that actually mount this loader, which are the only
ones the default affects.
The .pane clip (14096e19c) keeps a pane from painting outside its box,
but a profile with no scroller of its own then lost everything below the
pane's bottom: regions-mfe's regions list (rega RD3: last row at y1426 in
an 843 px pane; at 390 only Africa visible). Before the clip that content
spilled over the next pane instead. The pane mount now scrolls it at pane
height (overflow-y:auto), since a scroll container's scrollable area
includes its descendants' visible overflow; wheel and Tab reach it, and a
wheel at its end chains on to the column. Panes whose content fits (a
wall with its own scroller, a map) never scroll here.
BoundedSet.vue, CenteredSetTarget.vue and VisionFunnel.vue came back through the
handoff merges, byte-identical to what c5c01dead deleted on purpose on 09-28
("Delete 7 unreachable library components"). That commit also added
check:no-dead-library precisely so they could not return. Verified before
removing: 0 files import charts/BoundedSet.vue, charts/CenteredSetTarget.vue or
charts/VisionFunnel.vue, and packetCharts.js references none of them, so nothing
is left dangling. check:no-dead-library passes with them gone.
A first count said BoundedSet had 6 importers. It has none: those files import
layoutBoundedSet from charts/bounded-set.js, a different module, and the grep
matched the substring.
packetCharts.js: the doc block describing scatterCells sat above topCells' own
block, two functions away from what it documents. Moved to sit directly above
scatterCells. No code change.
Resolving package.json conflicts by unioning unique lines is right for a file
that holds one entry per line. Applied to ordinary source it duplicates
declarations, because both sides of a hunk keep their copy and nothing
de-duplicates across the join.
Eleven plugin entry points ended with the same import twice, and the poster
renderer with two identical `const sheet`. Each is a SyntaxError: every one of
those bundles would have failed to build, and the poster export would not run.
Found by parse-checking every changed .js against the merge base, not by the
gates -- gates:pre passed 101 of 102 with all twelve files broken, because its
parse gates do not cover plugin entry points.
One measurement trap worth recording. `node --check` on a .js file parses it as
CommonJS, so a bare `import` is a syntax error and ALL 28 entry points appear
broken, on development too. That reading says the tree is on fire and is simply
wrong. Copying each file to a .mjs and checking that parses it as a module,
which separates the eleven that are genuinely broken here from the rest that
are fine.
main-capture scan refused this branch with six bundles whose committed output is
not what their sources build on it: cities-internet, country-posters, demo-map,
doxa-research-map, doxa-simple-map and gospel-internet.
THE CAUSE IS THIS BRANCH, not development. It changes seven shared library
sources development does not have -- ProfileLoader.vue, the BoundedSet,
CenteredSetTarget, LifeCalendar and VisionFunnel chart components, packetCharts.js
and packet/countrySheet.js -- and ProfileLoader alone reaches every element that
wraps one, six references deep in demo-map's bundle. So consumers this branch
never edited still build differently on it, and their committed bytes went stale
the moment the library changed. The composite-freshness rule, one level up: a
shared source has more consumers than the lander is looking at.
Proved by rebuilding the same six ON DEVELOPMENT, where all six reproduce their
committed bytes exactly and nothing changes. An earlier reading of mine compared
these bundles to development's and found them identical, and took that as
evidence development was stale. Identical committed bytes say nothing about
whether those bytes match what the SOURCE builds; on this branch the source had
moved underneath them. Rebuilding on development is the test that distinguishes
the two, and it clears development.
Each rebuilt one at a time (memory is the limit on this box), then the tree
regenerated and SRI refreshed once. Every one of the six changed, and each new
hash is the one the failing scan predicted for it, so this is the output those
sources produce rather than a rebuild that happens to differ.
No source file is touched by this commit.
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.