Commit graph

987 commits

Author SHA1 Message Date
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
Doxa Maps
336a1e0a18 Merge branch 'bundler-2/script-registry' into bundler-2/handoff
# Conflicts:
#	internal/check-legend-data-contract.mjs
#	internal/check-map-control-overlap.mjs
#	library/composables/poster/useMapPoster.js
#	library/composables/useMapInstance.js
#	package.json
#	plugin-designs/doxa-research-map/research-map.vue
#	plugin-designs/research-dashboard/src/components/dashboards/DashboardMapPanel.vue
2026-09-29 14:50:42 +00:00
Doxa Maps
71050cbc8d Merge branch 'bundler-2/pair1' into bundler-2/handoff 2026-09-29 14:50:16 +00:00
Doxa Maps
2e72d59f35 Keep the reasons, drop the speaker, in the two merged branches
The consolidation brought back two Driver citations from older branches that
the reference sweep had already cleared from development. Both keep their
engineering reason and lose the speaker: a gate's rationale for existing, and
the mechanism of the print collapse.

Caught by check:no-new-driver-references, which is the point of running the
full chain rather than the seven gates the merged package.json had left.
2026-09-29 14:46:07 +00:00
doxa-maps
3ea2e3ce69 A9 leaf hints: cover a composite whose engine is in a composed child bundle
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.
2026-09-29 14:40:28 +00:00
doxa-maps
778e990ca4 A9 leaf hints: a token no longer selects Mapbox — engine = provider or MapLibre default
Correction (dx-shepherd 2026-09-29, from regions executing the shipping
resolver, confirmed by rega's A9NET on the wire): useMapProvider's default is
MapLibre unless provider is EXPLICITLY 'mapbox'; a baked token or a tokenUrl
does NOT select Mapbox any more. rega measured all 8 auto leaves — which carry
a pray.doxa.life data base — loading MapLibre from jsdelivr cold.

engineFor now returns 'mapbox' only for provider:'mapbox', else 'maplibre',
ignoring bakedToken/tokenUrl. And the engine preload is emitted unless the leaf
already has a static engine <script> — which only a provider:'maplibre' leaf
does; a provider:'mapbox' leaf emits no static tag (the Mapbox static tags were
removed 2026-09-25), so it now correctly gets a preload too.

No tree change: every production leaf is 'auto', and the old code also resolved
those to MapLibre (tokenUrl is empty, so hasEndpoint was false), so the built
hints were already jsdelivr+openfreemap. This makes the logic correct by reason
rather than by the config happening to be empty. check:leaf-hints PASS 37/27.
2026-09-29 14:40:27 +00:00
doxa-maps
71f36b5079 A9 leaf hints: key on the bundle's engine, not the leaf's isMap flag
rega's A9NET run found two production composite tabs — regions-dashboard/
regions-mfe and research-map-plus-grid — getting NO hints, because my first
cut gated on the leaf's isMap flag and both are isMap:false composites that
mount a map child and load the engine at runtime. Same trap the
check:leaf-engine-per-provider isMap gate fell into.

The gate now keys on whether the leaf's OWN page loads a map engine: a real
map leaf (isMap), OR a cap-4 nested-elements-mfe composite whose BUILT bundle
references an engine (builtBundleLoadsEngine). It excludes a cap-5
nested-mfe-spa shell (maps are iframe children), a genuinely map-less
composite (big-picture, stack-demo: 0 engine refs), and a plain non-map leaf
sharing a bundle with a map (connectivity-list). regions-mfe (33 engine refs)
is now hinted; research-map-plus-grid is not — its own bundle has 0 refs, the
engine loads in a lazily-fetched child (recorded gap; the deeper cause is the
upstream isMap classifier mislabelling these composites, which composes-by-tag
where the child .vue filename differs).

check:leaf-hints rebuilt to the same rule, read from the manifest (profile
type + isMap) and the built bundle, so gate and generator cannot drift. PASS
37 hinted / 27 bare; both new poisons bite (composite stripped of hints;
non-map leaf in a map bundle given a hint).
2026-09-29 14:40:27 +00:00
doxa-maps
fcebf2c589 A9 lever 1: engine-aware resource hints on map leaves
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.
2026-09-29 14:40:27 +00:00
Doxa Maps
4571596cf1 Merge branch 'bundler-2/grid-lazy-images' into bundler-2/handoff 2026-09-29 14:39:13 +00:00
Doxa Maps
af5060dc27 Register the control-inset gate, now that it has been run and proven
verify-browser-all's rule is that every gate listed there was run before it was
listed, so this waited for a real run rather than being registered on the
strength of the code reading correctly.

Measured, on the browser seat: the positive arm PASSES 9/9, and the mutation arm
-- the maplibre selector inside bottomControlInset broken to a name that matches
nothing -- FAILS on cases 1 and 5, the two whose pages carry only a maplibre
attribution. Cases 2, 3, 6 and 7 pass under the mutation by design: they assert
the inset is 0, so a selector that stops matching cannot make them fail. They
guard the opposite error, reserving space that is not there.

Registered in all three places: the script, its //scripts description, and
verify-browser-all's list. Deliberately NOT in gates:pre -- every assertion rests
on getBoundingClientRect, so it needs a browser and exits 75 NOT MEASURED
without a slot, which is never a pass.
2026-09-29 14:38:56 +00:00
Doxa Maps
9cdb59c1f1 A gate that the band the pan reserves is the band the controls occupy
check:popup-pan-controls proves the ARITHMETIC: given a band height, the pan
clears it. Nothing proves the band height is real. If bottomControlInset returns
0 -- a selector typo, an engine renaming its control classes, a control moving
outside the container -- then panPlanFor is handed bottomInset 0, behaves exactly
as it did before the fix, and check:popup-pan-controls still passes every case
because its arithmetic is still correct. The bug would be back with both gates
green. That is the failure this guards.

Seven cases against a real DOM, running the SHIPPED bottomControlInset read out
of the SFC (it is not exported), never a re-typed copy: a visible attribution
reserves a band EQUAL to what the DOM independently says, not merely non-zero,
which a stub returning 1 would satisfy; no controls reserves exactly 0; a
zero-sized control reserves nothing, since counting it would reserve the whole
map and refuse every popup; the taller of two corners wins, because the pin hint
is bottom-left while the attribution is bottom-right; a wrapped attribution
reserves more than one line, which is what a hard-coded constant gets wrong at
390; a control outside the container is ignored; a null container returns 0
rather than throwing.

It needs a real browser: every assertion rests on getBoundingClientRect, and no
DOM library here computes layout, so a headless stand-in would return zeros and
pass vacuously.

NOT REGISTERED. Browsers are rega's seat, so this has not been run, and
verify-browser-all's rule is that every gate listed there was run before it was
listed. It is registered only after rega's PASS.
2026-09-29 14:38:56 +00:00
Doxa Maps
1b19b7478a Register the control-inset gate, now that it has been run and proven
verify-browser-all's rule is that every gate listed there was run before it was
listed, so this waited for a real run rather than being registered on the
strength of the code reading correctly.

Measured, on the browser seat: the positive arm PASSES 9/9, and the mutation arm
-- the maplibre selector inside bottomControlInset broken to a name that matches
nothing -- FAILS on cases 1 and 5, the two whose pages carry only a maplibre
attribution. Cases 2, 3, 6 and 7 pass under the mutation by design: they assert
the inset is 0, so a selector that stops matching cannot make them fail. They
guard the opposite error, reserving space that is not there.

Registered in all three places: the script, its //scripts description, and
verify-browser-all's list. Deliberately NOT in gates:pre -- every assertion rests
on getBoundingClientRect, so it needs a browser and exits 75 NOT MEASURED
without a slot, which is never a pass.
2026-09-29 14:35:29 +00:00
Doxa Maps
315dd78520 A gate that the band the pan reserves is the band the controls occupy
check:popup-pan-controls proves the ARITHMETIC: given a band height, the pan
clears it. Nothing proves the band height is real. If bottomControlInset returns
0 -- a selector typo, an engine renaming its control classes, a control moving
outside the container -- then panPlanFor is handed bottomInset 0, behaves exactly
as it did before the fix, and check:popup-pan-controls still passes every case
because its arithmetic is still correct. The bug would be back with both gates
green. That is the failure this guards.

Seven cases against a real DOM, running the SHIPPED bottomControlInset read out
of the SFC (it is not exported), never a re-typed copy: a visible attribution
reserves a band EQUAL to what the DOM independently says, not merely non-zero,
which a stub returning 1 would satisfy; no controls reserves exactly 0; a
zero-sized control reserves nothing, since counting it would reserve the whole
map and refuse every popup; the taller of two corners wins, because the pin hint
is bottom-left while the attribution is bottom-right; a wrapped attribution
reserves more than one line, which is what a hard-coded constant gets wrong at
390; a control outside the container is ignored; a null container returns 0
rather than throwing.

It needs a real browser: every assertion rests on getBoundingClientRect, and no
DOM library here computes layout, so a headless stand-in would return zeros and
pass vacuously.

NOT REGISTERED. Browsers are rega's seat, so this has not been run, and
verify-browser-all's rule is that every gate listed there was run before it was
listed. It is registered only after rega's PASS.
2026-09-29 14:35:29 +00:00
Doxa Maps
7636404523 check:universal-props measures every bundle the tree has, and fails loud where it used to narrow silently
Its population was a hand list of 19 names, and it had drifted: the PRODUCTION country-map was never on
it, so its LIST-FETCH (the header's list prop never applied) passed unseen, and big-picture fetched the
list correctly with nothing to catch a regression. The population is now every plugin-designs/<b>/
with an index.js, minus an EXCLUDED map with a reason per entry (empty today), so a new bundle is
measured the day it lands: 28 bundles instead of 19.

Two fail-open paths now fail. `--only <name>` naming no measured bundle printed "PASS: 0 bundles"; it
exits 2 and lists what is measured. A listed bundle whose folder moved was skipped by an existsSync;
the population is derived from the folders, and an EXCLUDED entry naming no bundle is a stale decision
and also exits 2.

Measured over the whole tree, only two bypasses surfaced. country-map's LIST-FETCH is fixed by regions'
commit just before this one (same round, as it must be: this alone goes red). demo-map's LIST-DSM gets a
narrow ALLOW with its reason: it is scaffolding that demonstrates the raw DataSourceManager path, off
both reader shelves, and its other props are still measured. PASS: 28 bundles, 9 self-tested rules.
2026-09-29 14:35:28 +00:00
Doxa Maps
12078103d1 check:no-orphan-gates sees gate FILES outside internal/: a plugin's own gate that nothing runs fails
The file walk read internal/ only, and the chain arm counts package.json NAMES, so a plugin-local
check-*.mjs that nobody registered was invisible to both: on 2026-09-29 six were run by nothing
(dx-shepherd's census; exp's four have since been registered). Every tracked gate-shaped file under
plugin-designs/ or library/ must now be run by PATH from a script or another file's code, carry
@one-shot, or sit in the shrink-only `files` baseline for its owner.

Two rules keep it honest. Comments are stripped before searching, since a file mentioned in prose is
not run by it. And a basename counts only where no other gate file shares it:
library/scripts/research/verify-map-paint.mjs (199 lines, run by nothing) shares its name with
internal/verify-map-paint.mjs (342 lines, what verify:map-paint runs), so a name match let one file's
registration vouch for the other. Self-tested on planted cases (unregistered, comment-only, shared
basename). On the real tree it finds 4, now baselined for their owners:
  library/scripts/research/verify-map-paint.mjs            likely a stale copy
  plugin-designs/doxa-research-map/scripts/check-reduced-motion-jumps.mjs
  plugin-designs/gospel-resources/scripts/verify-translator-org-links.mjs   a data tool? @one-shot or register
  plugin-designs/research-map-plus-grid/scripts/check-ui-strings-have-keys.mjs
The chain arm's writer now keeps every key of the shared baseline file.
2026-09-29 14:35:28 +00:00
Doxa Maps
f96576fdf7 check:optional-t-equivalence registers ApproxPinNote on the {t, te, locale} form
ApproxPinNote moved from useOptionalT to useOptionalI18n (which wraps it) so its formatList names follow the sentence's own locale. The per-site register still asserted the old helper and failed. The row now names useOptionalI18n, as SemanticTreeLegend, PosterWall and all-people-groups already do, and still asserts the site passes its own APPROX_FALLBACK.
2026-09-29 13:34:37 +00:00
Doxa Maps
5a73e4d37d Guard the pan's control clearance, which a cut-height check cannot see
The popup auto-pan had no gate. Its founding bug was invisible to the obvious
one: measured at 390 on a 366x732 map, the pan fitted the popup inside the
container, the cut really was zero, and a real click on Full Profile still did
nothing, because the top element at the button's centre was
div.maplibregl-ctrl-attrib-inner on one pin and span.pin-hint-pill on the other.
Two pins that looked fixed and were not.

So this asserts the property that matters -- where the popup ENDS UP relative to
the band that takes the click -- rather than whether it was clipped.

It runs the SHIPPED panPlanFor, read out of the SFC with new Function because it
is not exported, the same way check:optional-t-equivalence reaches useOptionalT.
A re-typed copy of the arithmetic would pass forever while the component drifted,
which is the one failure a geometry gate must not have. POPUP_OFFSET is read from
the source too rather than assumed.

Each case states the resulting geometry independently instead of re-deriving the
expected number from the same formula: a self-consistent oracle cannot see an
error that shifts both sides, which is how a 12px offset hid here once already.

The band is measured at runtime, never hard-coded, so the rule is swept across
0-120px rather than pinned to one number -- 120 is far beyond anything observed
and is there to prove the rule, not the value. Also swept across every width the
component renders at, since below 768px the container is 2x width.

Mutation-tested three ways, each failing the case written for it: ignoring
bottomInset (the pre-fix behaviour) fails 15 cases; reserving only half the band
fails; dropping the Math.max clamp fails exactly the negative-inset case.
24 cases, registered in all three places, verified by re-reading the parsed file.
2026-09-29 13:31:24 +00:00
Doxa Maps
62c8a2120c The first-run superuser URL itself reaches the terminal, not only the lines around it
PocketBase's link is /_/#/pbinstall/<token> (two l's). The forward rule matched \bpbinstal\b, which cannot match 'pbinstall', so the terminal showed 'Launch the URL below' with no URL below it (repo, testing live with PocketBase 0.40.4). The rule is now pbinstall?, tested on the line as PocketBase prints it rather than on a guessed spelling: the instruction, the URL and the CLI alternative are shown, the banner and dashboard URL stay quiet.
2026-09-29 13:29:19 +00:00
Doxa Maps
c5723f2b15 The shared-point list follows its sentence's locale, and formatList never throws outside a browser
check:approx-pin-note server-renders ApproxPinNote in Node, and it crashed: with no locale argument
and no runtime locale, formatList fell through to detectLocale(), which reads `document`. The page
lookup is now a guarded last resort. ApproxPinNote also passes its sentence's own locale (the
host's vue-i18n when installed, else '' so the runtime/page chain applies), so a host with its own
i18n can never get an Arabic sentence with a list in another language.

The gate now expects the new English ("Koraga and Maila", the list grammar this change exists for)
and adds the Arabic case: two names joined with و, never an English comma inside Arabic prose.
Poisoned by putting join(', ') back, both of those cases fail; restored, it passes.
2026-09-29 13:29:18 +00:00
Doxa Maps
57e3a11e68 The first-run superuser link still reaches the terminal
With the backend's output going to .pb/logs, PocketBase's one-time 'create your first superuser' link and its command-line alternative went only to the log, so the HOWTO's admin screen at /api/pb/_/ was unusable on a fresh .pb without knowing to look there (repo found it testing the change live). Those lines are a step a person must take, so they are forwarded like errors and 'address already in use'. The banner and URLs stay quiet. Tested against the regex read from the source.
2026-09-29 13:29:18 +00:00