Commit graph

214 commits

Author SHA1 Message Date
Doxa Maps
fe43c966f3 Merge remote-tracking branch 'origin/development' into repo/merge-main-bless 2026-10-01 00:54:28 +00:00
Doxa Maps
6e766104ac Merge #8.6 (the Rudder screenshot) onto #8.5 + #8.7 2026-09-30 22:44:50 +00:00
Doxa Maps
daa3c28566 Rudder screenshot: blur the microphone field, whose clipped device name began to show
Only the field's box changes (x 90-287, y 268-309 of 435x941). The PNG still holds only
IHDR, IDAT and IEND.
2026-09-30 22:44:48 +00:00
Doxa Maps
39b8dd1d77 README: a new screenshot of Rudder, the offline voice-to-text desktop app, running
deploy5-desktop-rudder.png is replaced with a screenshot of Rudder running (Ready, with a
transcript). It carries no names, emails, paths, hostnames or tokens, and its metadata is
stripped: the PNG holds only IHDR, IDAT and IEND. The alt text says what it shows.
2026-09-30 22:42:59 +00:00
Doxa Maps
4129ad4bfd Build poster-design, regenerate the tree, SRI and the capability-exemplars table on the merged source
The composites both shells now name (doxa-maps-spa's Prayer Mobilization
row, posterverse's composes) resolve once poster-design exists, so the
tree is generated here, once, on the merged tree.
2026-09-30 22:42:56 +00:00
Doxa Maps
6deb2569be The agent-swarm diagram and its README section, redrawn to how changes land today
delegation-model.svg, re-rendered to delegation-model.png at 2x (only IHDR, IDAT, IEND):
- development, not main, is at the centre, behind a landing lock that takes one landing at a
  time; the plugin ring and the three outputs are kept (the desktop output working).
- A coordinator and a gate-keeper replace the single overseer; the legend gains them.
- "How a change lands" has four steps: own branch; a second reader; one at a time (in the
  lock: merge development, rebuild, run every check, push only if nothing fails); promote
  to main (only when the owner approves, after full checks on that version).
- The outputs band adds: the dev preview follows development, the published site follows
  main.
README, the same section, so the text matches the picture: the summary table row, the
section's intro, the image's alt text, the kitchen list (now five points) and the glossary
("landing lock" replaces "merge queue"). No tool or personal names.
2026-09-30 22:41:30 +00:00
Doxa Maps
703f3efbc6 README and docs: no private server address or platform name, and the desktop app works
- The clone examples in README.md and documentation/DEPLOY.md name a private server; they
  now read `git clone --depth 1 <your-repo-url>`.
- skills/plugin-designer/references/backend.md quoted a planning heading that names a
  platform; it now says the tiers are recorded "as an open, unproven assumption".
- The desktop app (Tauri; Rudder runs as one) works: the capability table's Desktop column
  is ✅, and the outputs table, the Output 3 heading and its screenshot's alt text say so.
  The WordPress column keeps 🧪, so the table's legend is unchanged.
- delegation-model.svg: the desktop output's label reads WORKING, in the green of the other
  two outputs. delegation-model.png is re-rendered from it at 2x in Chromium. Rendering the
  previous SVG the same way reproduced the committed PNG with 0 pixels different, and the
  new render differs only inside the desktop box. The PNG carries only IHDR, IDAT and IEND.
2026-09-30 22:36:29 +00:00
Doxa Maps
1d2b29d6b5 Merge origin/development into studio/land-pd-seam 2026-09-30 22:23:58 +00:00
Doxa Maps
85c435be06 PanelSheets: a plain style id, and the library index lists the new poster files
The shadow-styles id must be a plain lowercase identifier (check:shadow-css-parses
reads anything else as a CSS rule concatenated onto the id), so 'PanelSheets'
becomes 'panel-sheets'; nothing imports the component yet. The derived library
index gains panelSheets.js and PanelSheets.vue.
2026-09-30 22:18:46 +00:00
Doxa Maps
e4b2bbb47d Capability exemplars: list posterverse (26 bundles)
bun run capability-exemplars on the current tree. The posterverse bundle landed
without regenerating this table, so check:capability-exemplars (gates:post)
reported that the table disagrees with the manifest. Doc only; no bundle.
2026-09-30 22:11:45 +00:00
Doxa Maps
d23a161138 Rebuild regions-dashboard, doxa-research-map, doxa-maps-spa and doxa-simple-map from the merged source; the library index catalogues MapPrintProgress.vue and mapPrintTemplate.js 2026-09-30 11:06:44 +00:00
Doxa Maps
f3fdf4bf37 Mobile apps from plugins: a how-to, with Deep Research as the worked example
documentation/how-to-build-mobile-apps-from-plugins/README.md explains why Deep Research
(doxa-maps-spa, its app preset) is the plugin to wrap first: the seven production maps in one
phone-ready shell, token-free on MapLibre. It then walks the whole path: tools, the wiring check,
one command, what each step does, another plugin as the app, making it your own, and fixes.

The one command needed two small changes; the default app is unchanged:
- internal/set-app-start-page.mjs takes APP_START=<plugin>/<screen>[/<preset>] and opens that page
  instead of the UPG-100 list. Unset, it behaves and marks the page exactly as before. A malformed
  value, a page missing from the build, or links that would not resolve are refused, as before.
- package.json: phone:from-tree is sync, start page, verify, assemble, install from the committed
  tree, with no full rebuild (bun run build refuses without BUILD_ALLOW=1).
  phone:deep-research is phone:from-tree with Deep Research as the start page.

how-to.md links the guide, and two of its lines are corrected: webDir is public/dx-maps/, and
apk:debug's first step is the full build, which asks for BUILD_ALLOW=1.

Checked, with no Android tools: the start page written for doxa-maps-spa/doxa-maps-spa/app, then
the app root served and loaded in the shared browser at 390 and 1280. It showed the gallery
element, 15 tabs (the seven maps and the experimental ones) and a drawn map, with 0 console errors
and 0 failed requests. --check passed for APP_START and failed for the default until it was
restored; the default run still writes the UPG-100 page with its original marker. The Gradle and
adb steps are those bun run phone already uses; they were not run here.
2026-09-30 10:04:34 +00:00
Doxa Maps
b4664aa67e MapInfo can answer a map-control info button (MapInfoButton), fail-open
The "what can this map do for you?" button can now live IN a map's control
column instead of floating over it. This is the bridge only: nothing changes
until a map adds the control and its gallery tab sets trigger: 'control'.

- map-controls/MapInfoButton.vue (new): a MapControlButton with the info
  icon and the localized mapInfo.open label. Clicking it sends a bubbling,
  composed 'dxmaps:mapinfo-open' event out of the plugin's shadow root to
  the gallery pane. On mount it asks 'dxmaps:mapinfo-control' and shows
  ONLY if a MapInfo on the same pane answers (ack), so a standalone leaf or
  a partner page never shows a button that opens nothing. A MapInfo that
  mounts later broadcasts 'dxmaps:mapinfo-host' and the button asks again.
- info/MapInfo.vue: new prop trigger, 'floating' (default, unchanged) |
  'control'. In control mode it listens on its own pane: it acts only on
  events whose composedPath contains the pane, and stops them there. Its own
  floating button and pointer hide ONLY while the announced control is
  MEASURED usable: connected, a non-zero on-screen rect, and in no
  inert/aria-hidden subtree. It is re-measured by IntersectionObserver and
  ResizeObserver plus a 1.5 s fallback timer, never inferred from an unmount
  event. Escape and close return focus to the control when it is on screen,
  else to the floating button. aria-expanded is kept on the control.

Proved on a UPG-100 pilot served locally (gallery page, 1440, MapLibre and
Mapbox, en and ar), exactly one info button on screen at every step:
wall 1 floating; Map 1 control (it wins its hit test and sits inside the
toolbar column); opened from the control, Escape closes it with focus back
on the control; toolbar hidden 1 floating, shown again 1 control; tab away
and back 1; back to the wall 1 floating. 0 page errors. That pilot's wiring
is not in this commit.
2026-09-30 03:11:40 +00:00
Doxa Maps
c00bf1034f Regenerate the library index for usePaneConfig, which landed without it (check:library-index) 2026-09-29 20:10:25 +00:00
Doxa Maps
93f809ebcd A map explains itself: an info button, a one-time pointer and an example popup
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.
2026-09-29 19:08:02 +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
506b42fc31 Merge repo/readme-rudder-shot: the Driver's Rudder desktop screenshot in the README (HELD since 01:32Z for his cut-off condition "before you add it to the readme you nee"; merged on the merge-all order) 2026-09-29 14:50:44 +00:00
Doxa Maps
ef89113877 README, HOWTO and .env.example: a changed port takes effect when bun run dev restarts (V8, third fresh reader)
A fresh reader given only the README and the HOWTO reached the Studio and a plugin's /__leaf page with
nothing else needed, but one step. After "port 8090 is already in use ... set DX_PB_PORT", neither
doc said the setting is read when bun run dev starts, so the new port only applies after a restart.
The README copies .env.example before starting the server, and the port message appears only once it
runs, so the steps looped with no stated way out. All three places that mention DX_PB_PORT now say to
pick a free port and restart.
2026-09-29 11:56:47 +00:00
Doxa Maps
c92e857e01 README and docs: a plugin's own page is /__leaf/<plugin>/<profile>, and auto is MapLibre
A fresh reader given only the README and HOWTO-join-the-table got through install, bun run dev and
the Studio. One gap: no address for a single plugin's page. The Capability 1 fold says each plugin's
folder holds "an index.html for previewing it", which reads as /plugin-designs/<plugin>/index.html,
and that 404s under bun run dev. The page is /__leaf/<plugin>/<profile>, and the Studio's list is
/__plugin-gallery/manifest.json. Both are now named.
Three smaller notes from the same reader:
- the README copied .env.example to .env while the HOWTO uses .env.local. Both work and .env.local
  wins; the README now uses .env.local too, which also keeps .env free for compose.yaml;
- the Mapbox token read as required; it is one of two ways to get a background;
- the 8090 port hint (DX_PB_PORT) was only in the HOWTO; it is now named where the README first
  mentions PocketBase.

Also, the engine rule (was a follow-up commit, f0e965e4d):
Since 2026-09-28 useMapProvider.js resolves `auto` to MapLibre, and Mapbox is an explicit choice:
"provider": "mapbox" plus a token. The docs still said "Mapbox when a token is available":
- README's map-engines row;
- how-to.md's provider section;
- the plugin-designer skill's props table, which even says to confirm in useMapProvider.js.
All three now state the current rule. So do four lines that told readers to set provider maplibre to
avoid needing a key: README's Get it running and its "No token" fold, .env.example's token comment,
and reference.md's no-key row.
Case-insensitive git grep "Mapbox when a token" over README.md, documentation/ and skills/: 3 before, 0 after.
2026-09-29 11:04:22 +00:00
Doxa Maps
92c5422d1c Docs and the plugin-designer skill: keep the reason, drop the speaker (6 lines)
THIRD-PARTY.md's two open licensing items "need an owner's decision" instead of going to a named person.
needs-eyes describes the browser policy and a maintainer's laptop as the second pair of eyes. The
skill and its glossary say the Experimental section was replaced by capability tiers, with the same
pointers into plugin-studio.vue. grep -w Driver over documentation/ and skills/ is now 0;
check:no-new-driver-references passes.
2026-09-29 09:48:51 +00:00
Doxa Maps
f96fb4290f A desktop-only composite blocks on a phone too: the phone rule is a composable its root can call
rega measured dashboard-plus-grid's own leaf at 390px: the page carried
"mobile": "desktop-only" in its profile-config, and the dashboard, the grid
and a MapLibre canvas mounted anyway. The rule lived in ProfileLoader, and
this composite defines its element without ProfileLoader (it bakes its
children in), so nothing on that page read the flag.

- library/composables/useScreenGate.js holds the rule (narrow screen, not
  inside the Gallery, dismissed for the session); ProfileLoader uses it,
  unchanged in behaviour.
- dashboard-plus-grid calls it: on a narrow screen the desktop-only message
  replaces the element, and the dashboard and grid never mount.
- check:mobile-gating (g): every flagged profile's element must mount
  through ProfileLoader (an import in its index.js, not a mention in a
  comment) or call useScreenGate itself. The pre-fix composite fails it.
2026-09-29 09:18:55 +00:00
Doxa Maps
69c0966117 Regenerate the library index for this round's library changes 2026-09-29 07:31:17 +00:00
Doxa Maps
51ef6f7ec4 One phone flag per map, and the leaf page follows it as well as the Gallery
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.
2026-09-29 07:31:16 +00:00
Doxa Maps
898f804570 Regenerate the library index for the helpers this landing adds 2026-09-29 05:26:26 +00:00
Doxa Maps
05d7724bfe README + DEPLOY: no links into private repos; the web folder's size is measured by a gate
dx-base measured two defects in the A8 draft for text that goes public:
- Links into the private DX Life repo answer 404 to anyone without an account. The live
  example is now plain words (README, DEPLOY), and the clone line points at the public repo
  (doxa-open/doxa-maps, as DEPLOY already did). DEPLOY's "three ways" becomes the two routes;
  the CDN route is retired.
- The web folder row said 536 files, 76 MiB. The folder is 855 files, 119.2 MiB. New
  check:readme-size re-measures public/dx-maps and fails when the row is more than 10% off,
  printing the line to paste. It passes at 855/119; the old numbers fail.
2026-09-29 05:26:25 +00:00
Doxa Maps
867c559095 One server for a site and its maps: bun run dropin, and the drop-in goes straight into the site's public/
The drop-in was proven on a laptop with one server: the three DX Life branches rendered their maps,
7 of 7 checks passed, with internal/sync-dropin.mjs --from-config --dest <doxa-life>/public. This
makes that the default path:

- dropin.dest is ../doxa-life/public. The old ../doxa-life/public/embed/doxa-maps-build was stale.
- bun run dropin = sync-dropin --from-config; deploy:dev (build + drop-in) now uses it.
- The README gains "The easiest path": the studio for the work, dropin.dest at your site's public/,
  then build and drop in.

One hazard came with the new destination, and it is closed here. --prune deletes every file in the
destination outside the drop-in's allowlist, which was right while that was a folder of its own. Into
a site's public/, it would delete the site. deploy:dev passed --prune, so it no longer does, and
sync-dropin refuses --prune into any folder named public/. Measured in a scratch site: --prune into
site/public exits 1 with the reason; a plain drop-in copies dx-maps/ and leaves the site's own
file in place.
2026-09-29 03:03:51 +00:00
Doxa Maps
7dc634275e Put the cloud Dockerfile at the repo root, so a platform pointed at the repo finds it
Railway, DigitalOcean and `docker build` use a root Dockerfile with no setting, and it is
Coolify's and Dokploy's default path. The file moves; nothing is copied.

- VOLUME /data is gone. Railway rejects the line, and a named volume is needed anyway
  (VOLUME alone gives each new container a fresh anonymous one). The platforms mount /data.
- The baked PocketBase gate's comment named the old path. It now says the repo-root
  Dockerfile, and the gate's SHA-256 pin moves with it (2987055b... -> 2eceef03...). The
  hook's code is unchanged: the exact RUN passes `sha256sum -c`, and the old block still
  passes its old pin.
- .dockerignore excludes everything: the Dockerfile copies nothing from the build context,
  so no platform sends the whole repository to the builder.
- compose.yaml: the same image with its /data volume and memory limit; settings from .env.
- deployment/cloud/README.md gains "Where it runs": Coolify, Dokploy, Railway, a server with
  Docker, Kubernetes, and why not DigitalOcean App Platform (no persistent volumes).
  DEPLOY.md and two comments follow the move.
2026-09-29 02:35:36 +00:00
Doxa Maps
9b4db40443 Three post-landing gates green again: the library index, the capability table, Path2D
gates:post had gone red on development in three places that no landing runs, because landings run
gates:pre. The library index and the capability-exemplars table are derived documents: regenerated,
they now list the country-map bundle, BackToTopButton and useHostedHelp. check:no-free-identifiers
flagged the Wall's new Path2D (a canvas built-in every browser has) as never bound; it knows the
canvas built-ins now. No code changes.
2026-09-29 02:35:35 +00:00
Doxa Maps
7058e868eb README: show Rudder running as a desktop app
Output 3 showed only the map app as a desktop app. Rudder is the desktop
example the README describes, and it has now been built with
`bun run desktop:build rudder-voice` and run on Linux: a screenshot of the
running app goes under the map app's, with one line on how to build it.

The PNG carries no text chunks (the original recorded its creation time
and timezone); the pixels are unchanged.
2026-09-29 01:32:16 +00:00
Doxa Maps
1ca78d6d5d A laptop that follows the table says when it needs credentials, and the last main defaults say development
The joining page, DEPLOY and the laptop sync default moved to development in the
commit before this one. This finishes the move and closes what a fresh clone's
friend test found.

- landing-preconditions diffs against origin/development when no landing branch
  is exported, instead of main.
- CLOUD-DEVELOPMENT-ENVIRONMENT, the plugin-designer skill (SKILL.md, workflow,
  glossary) and the shared dev server's notes land on and follow development;
  the skill says never to push to main.
- The sync fetches with the laptop's own credentials. git runs with prompts off,
  so on a clone with no credential helper it failed every interval with a bare
  "fetch-failed / remote: Unauthorized", which read as a broken server. That case
  is now its own state, needs-credentials: the log (once, not every tick) and
  /api/dev-sync say "dev-sync needs git credentials for <remote>". The joining
  page and .env.example say so, and that a fresh clone starts on main and must
  switch to development before the sync can fast-forward it.

Measured in scratch repos: the private remote with no helper gives
needs-credentials and one warning over two ticks; a local remote with no
DX_SYNC_BRANCH follows development and fast-forwards; a missing remote stays
fetch-failed.
2026-09-29 00:59:14 +00:00
Doxa Maps
490dfd1f8c The table is development and main is production: the joining page, DEPLOY and the laptop sync follow it
The joining page now teaches laptop (the workshop), development (the table everyone lands on, followed by the
shared dev server) and main (production: /cdn, the websites and every partner snippet load it; never pushed to
directly). Its commands pull and push development. Schema is made on a laptop, never in the shared server's
PocketBase screen, whose automatic migration files are lost at the next restart.

DEPLOY: the cloud server follows development and publishes main at /cdn (PRODUCTION_BRANCH=main); publishing
merges development into main; EMBED_BASE_URL makes snippets absolute; /cdn revalidates within 5 minutes. The
drop-in example pointed at a deleted branch and now names research-gallery-drop-in, with a link to running all
three DX-life ways on a laptop.

Laptop sync (DX_SYNC_REMOTE) follows development by default, so teammates' landings arrive before they are
published.
2026-09-29 00:59:13 +00:00
Doxa Maps
0bf8b88ff0 Regenerate the library index: the three packet charts and the items that landed uncatalogued 2026-09-28 15:01:26 +00:00
Doxa Maps
04bb5b264c Regenerate the library index and the capability exemplars
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Both are derived files that had drifted: an import count for utils/html.js, and
regions-dashboard's exemplar is region-dashboards now, not regions-list.
2026-09-28 14:53:59 +00:00
Doxa Maps
43130aa40e CONTRIBUTING: source and build output as two commits in one push (not two pushes), with the two exemptions
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
2026-09-28 13:05:56 +00:00
Doxa Maps
f2e2509167 documentation: the browser guard, and ask the repo rather than grepping
Follow-up to the doc landing in 49, which was written before the guard existed.

Adds the guard: every browser gate reaches Playwright through
internal/lib/playwright-guarded.mjs and refuses unless browser-slot.sh exported
DOXA_BROWSER_SLOT; an unslotted run exits 75 with the command to use, quoted
verbatim. And says the slot is a COUNTING SEMAPHORE, not a mutex, with the reason
from its own header -- a single lock queued 10-19 deep for hours because the real
constraint is memory, ~300-500MB per chrome, not exclusivity.

Replaces the grep advice with `bun run browser-gates`. The grep still works and
is fine for a quick look, but it is a heuristic over file text: my own count from
grepping internal/check-*.mjs said 87 browser gates; the repo's own detector says
97, because browser gates also live in plugin-designs/*/scripts/. Corrected. The
authoritative list cannot drift from what is enforced, because
check:browser-gates-guarded uses the same detector.

One line the guard's header earns and this doc had not stated: being able to
launch is not the same as it being yours to launch. The guard stops the accident;
it does not hand a newcomer the seat. Testing whether the guard refuses is itself
a browser launch.

Does NOT claim path-into-node_modules detection: studio has that in landing 50,
and it is not in this tree, so the doc does not describe it yet.
2026-09-28 09:07:30 +00:00
Doxa Maps
a02458a171 documentation: which gates need a browser, and what exit 75 means
238 checks; 148 run anywhere, 87 need a real browser, 3 shell out. A newcomer
cannot tell from the name -- check:packet-render sounds like a file check and
drives a browser; check:composites-mount sounds like it needs one and does not.
The test is one grep for playwright/chromium, and the doc says so.

The part worth writing down is exit 75. run-parallel.mjs:262 defines three
outcomes, not two: 75 (EX_TEMPFAIL) is NOT MEASURED -- the gate could not look --
and a gate that exits 0 while announcing SKIP is also NOT MEASURED. Only another
non-zero is a FAIL. Two traps follow: exit 0 alone does not mean a gate looked at
anything, and your own `timeout` produces 124, which says you stopped it, not
that the code failed.

Also states the rule the split exists for -- one machine, one browser seat, so
one person runs them -- and why it is not just logistics: a source read and a
render are different measurements. Four catalogue gates can pass while a page
still paints English; and of 16 cards parked as "needs a browser", 7 were about
markup, a path, a manifest field or a gate, and settled headlessly.

Every number measured on main d8baaefd2 rather than estimated, including
correcting gates:pre from 13 to 15 after re-running it.
2026-09-28 08:31:18 +00:00
Doxa Maps
c73d713b43 Delete useMapPacket.js: nothing imports it since both packets print through the shared HTML renderer
research-map and countries-map moved to the shared printer, leaving the
composable with no importer on main. jsPDF stays: useMapPoster.toPdf,
posterSizes and my-upg-100-list still reach it. The file map row goes and the
library index is regenerated.
2026-09-28 06:44:14 +00:00
Doxa Maps
6451a2b158 bun run desktop:build <plugin> packages a desktop plugin as an app; check:targets keeps non-web plugins out of the web build
A plugin's <profile>.meta.json targets (web, mobile, desktop, widget; absent = web)
now decide where it is built. internal/plugin-targets.mjs is the one reading.
desktop:build builds a desktop plugin into .desktop/<plugin>/ with a page that
names its engine, builds its backend as a Tauri sidecar for this machine, and runs
tauri build with a --config override; tauri.conf.json and public/ are untouched.
The shell starts the bundled rudder-engine (RUDDER_AUDIO=browser, RUDDER_HOME in the
app data folder) and stops it on exit. A plugin whose targets leave out web
(Rudder: desktop + widget) is no longer built for the web tree: run-parallel,
generate-tree and check-composite-freshness skip it, and its public/ folder is
removed; the dev server still gives the Studio its corner. check:targets
(gates:pre, with a self-test of five planted violations) validates the values,
widget corners and backend folders and fails if a non-web plugin reaches the built
tree. Measured: desktop:build rudder-voice on Linux produced Rudder_0.1.0_amd64.deb
(8.8 MB) with the app and the engine side by side; the app has not been launched.
2026-09-28 06:44:14 +00:00
Doxa Maps
7077c55502 Remove a kill switch the code does not have
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
file-map.md documented `SOW_EXPORT_BUTTON=false` as a hidden global switch that "hides the
fully-wired Export menu across ALL bundles". SOW_ appears nowhere in this repo, so anyone setting
it would get silence and conclude the Export menu was broken. Docs describe the code as it is, so
the claim is gone.

The per-component prop it mentioned is real and untouched: LegendMobile.vue passes
:export-enabled. Only the global env override was fictional. MAX_LIVE went with the staging.js row
it lived in, and neither name appears in README.md or documentation/ now.

If a global export switch is wanted, that is a card, not a doc edit.
2026-09-28 03:40:55 +00:00
Doxa Maps
9b6bcaa0fa Doc audit: five stale claims a newcomer would have acted on
Audited README.md and all 35 documentation/*.md against main. Script names and markdown links
were already clean — 59 documented scripts all exist in package.json, 0 broken links. What was
wrong was file-map.md describing files that no longer exist, and three paths that had moved.

REMOVED, all archived in afb998f17 or earlier and still documented as current:
  internal/staging.js — the repo-root staging page; the plugin studio is the only entry now
  index.html — the same page's HTML
  library/composables/useDoxaSearch.js — deleted in ea0c47b27, and dropped from a prose list too
REPOINTED: the three colour strategies documented under plugin-designs/doxa-research-map/src/colors/
live in library/colors/. THIRD-PARTY.md's two vendored files live under data/vendor/.
embeddability.md's reference to the staging script now says it was archived and where the entry is.

WHAT I DID NOT "FIX", because it was not broken: ~20 relative shorthand paths in the architecture
docs (`composables/useMapData.js` inside a document about library/) read correctly in context, and
three paths name things that are not repo files at all — a runtime endpoint (public/api/maps/token.json),
a generated artifact (out/_records.json) and a placeholder (./bundle/bundle.js). Reporting those as
defects would have buried the five real ones in 23 false positives.

TWO MEASUREMENT TRAPS I fell into on the way, both corrected before reporting: my first env-var scan
grepped only internal/, plugin-designs/ and library/ and declared 13 documented env vars unread —
11 of them are read in internal/build-lock.sh, .env.example, deployment/cloud/Dockerfile and the Go
backend. And an earlier sweep of my own data files reported six "rega" hits that were all the word
"aggregates".
2026-09-28 03:40:55 +00:00
Doxa Maps
febeff4990 Public build follows the production branch, and rebuilds itself when production moves
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
main is the shared sandbox the dev server follows; /cdn is built only from PRODUCTION_BRANCH (default
production), which moves when someone promotes: git push origin main:production. The container watches
that branch and rebuilds /cdn once it has held a new commit for CDN_AUTOBUILD_MINUTES (default 2; 0 = the
admin button only); a failed commit is not retried automatically. The build fetches the branch into its
own ref (never touching the dev server's FETCH_HEAD) and uses that commit's own exclusion list, so
loosening it takes a promotion too. DEPLOY.md documents the promote step.
2026-09-28 03:37:09 +00:00
Doxa Maps
2e92a05b30 A preset keeps its profile's defaults: instance props merge over the meta config instead of replacing it
A preset page baked only the instance's props, so every default in the profile's
.meta.json config that the instance did not repeat was lost (go-int: upg-neighbor's
five presets dropped pinHint:false). instanceHtml now takes the meta config first
and the props over it. check:preset-config-merge (gates:post) reads every built
preset page and fails on a lost default; the rule is written into
PRESET-PLUGIN-STANDARD.md. Affected before the fix: upg-neighbor only; no
production preset has profile defaults to lose.
2026-09-28 03:12:45 +00:00
Doxa Maps
b7333ef970 HOWTO: build the Rudder desktop app on macOS or Windows, and what is not proven yet 2026-09-28 02:38:49 +00:00
Doxa Maps
1bbfeae07c documentation/DEPLOY.md: the 4 ways dx-maps ships, linked from the README
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Laptop (bun run dev, zero config); a shared cloud dev server (Docker or Coolify, with a persistent /data);
public embeds from /cdn or any static host; the built folder inside a site's public/, as DX-life does.
Each with the command, what you get, and the detailed doc.
2026-09-28 02:27:12 +00:00
Doxa Maps
60b479d8e7 The register said "unestablished" after it was established
upg100-plugin caught it: my THIRD-PARTY.md row 17 stated their licences table
was EMPTY on the very commit where it held all 162. Our landings crossed and
neither of us could see the other's tree. Worse than they framed it -- my own
two files disagreed, since data/boundaries/ATTRIBUTION already carried the 162
and the three duty classes.

Row 17 now records what is true: 162 licences established, 32 duty-free, 65
attribution-only, 65 share-alike class (58 ODbL + 7 explicit ShareAlike), with
the ODbL "Derivative Database" question marked OPEN and legal rather than
measurable. The "unverified, someone should look" paragraph drops from four
rows to three, because world-adm0's provenance is answered.

★ AND THE STRUCTURAL FIX, WHICH MATTERS MORE THAN THE ROW. The counts are
asserted in two files, so that is the one place these records can silently
disagree. The register now names their PROVENANCE.json as the AUTHORITY and
says plainly that if the two disagree, it wins -- drift becomes resolvable
instead of invisible. Their phrase for the failure is the right one: a register
that still reads "unestablished" after the work is done is settled-by-omission
in reverse, the absence of an update reading as the absence of the work.
2026-09-28 02:03:22 +00:00
Doxa Maps
4244c9097a merge main before the licence landing
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
2026-09-28 01:57:25 +00:00
Doxa Maps
9cd99cba23 merge main before the licence landing 2026-09-28 01:57:11 +00:00
Doxa Maps
2a692021c0 Boundary attribution travels with the boundaries
The India ADM1 boundary is Creative Commons Attribution (CC BY 2.5 IN,
sourced from DataMeet and the Election Commission of India), so the credit
has to reach whoever receives the data. It did not: 6.1 MB of boundary
GeoJSON shipped with no human-readable attribution, and a sidecar for one
file of eight.

data/boundaries/ATTRIBUTION now ships beside the data. Every licence value in
it is verbatim from the geoBoundaries API, queried per boundary -- CC BY 2.5
IN for India, Public Domain for China. No licence wording is ours.

★ IT TOOK TWO ALLOWLIST EDITS, and the first one silently did nothing. The
boundary staging is TWO-STAGE: a pair list gathers into the build pool, and a
separate path list decides what reaches the tree. I added the file to the pair
list, rebuilt, and it still did not ship. An entry in one stage of a two-stage
pipeline is not an entry.

WORLD-ADM0 IS CORRECTED, not closed. This register first guessed Natural
Earth, public domain. It is geoBoundaries gbOpen assembled per country: its
features carry geoBoundaries' own iso3/shapeGroup/shapeName, and the plugin's
data/adm0/PROVENANCE.json names the source and endpoint. That file also states
the real problem -- gbOpen passes each country's UPSTREAM licence through, so
one file carries up to 162 licences and up to 162 attribution duties -- and
its licences table is EMPTY. Which of the 162 are CC BY is unestablished.
Stated in ATTRIBUTION as an undischarged duty rather than papered over.

pplr's row is exp-shepherd's evidence: the PPLR ArcGIS org aggregating IMB,
Joshua Project, ROP and WCD identifiers, publishing no licence at all, and
WCD is a proprietary Brill database.
2026-09-28 01:55:03 +00:00
Doxa Maps
308e1e82ab The joining page opens with the promise the setup actually keeps
repo's zero-config .env.example is on main (8c529c031), verified before writing about it: every DX_* and
VITE_* line is present and empty, empty meaning the local default. That is the follow-up patch I held back
rather than documenting a file whose contents had not landed.

"Every line in it is optional" is a better opening than the list I had, because it IS the zero-config
promise in five words — a reader who copies the file and fills in nothing has a working setup, which is
exactly what the Driver asked the default to be.

Also states what happens if the Mapbox token is left empty: the Mapbox-backed maps do not draw, and the
keyless MapLibre provider is the alternative. My previous wording implied the token was required to get
anywhere, which is not true and is discouraging at exactly the wrong moment.
2026-09-28 01:46:52 +00:00
Doxa Maps
e8ddfc34a6 Vue and Tabulator ship their MIT notices, and a third-party register
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Both are MIT, which asks for the permission notice to be included with the
software. Tabulator's minified .js carried only "(c) Oliver Folkerd 2025" and
its .css carried nothing; Vue's banner names @license MIT but omits the
permission text. Each now has its upstream LICENSE vendored verbatim beside
it -- fetched, not authored, with the URL and sha256 recorded.

★ AND THE ALLOWLIST IS WHY IT WOULD NOT HAVE WORKED. generate-tree stages
vendor/ by an explicit PATH LIST, so the licences sat in data/vendor and never
reached the tree: staged count 0. Vendoring a notice the staging step drops is
not compliance, it is paperwork. Both LICENSE paths are now listed.

documentation/THIRD-PARTY.md is the register the sweep produced: every
non-original thing dx-maps ships, its source, its licence, whether the licence
or attribution actually travels, and the gap. Compiled by inspecting the
SHIPPED tree rather than the source lists, because the question is what a
recipient receives.

Four rows are left OPEN and marked as such. Two are unverified and need a look
(world-adm0's provenance, the pplr upstream). Two need a decision, not a fetch:
people-groups and the 304 derived tables carry data whose redistribution terms
are not established, 36 MB of it. Attaching a licence I have not confirmed
would be worse than the gap, so those go to the Driver. geoBoundaries is
closable by work rather than judgment -- CC BY needs attribution, and the
.meta.json sidecar pattern already exists here for one file of eight.
2026-09-28 01:30:47 +00:00