The first-paint write is skipped when the address names a tab the shell
doesn't know yet (a row that only resolves once the manifest is in). Writing
tab 0 there would replace the link before applyManifest could honour it;
applyManifest's own first-paint replace writes the honoured tab.
Plugin Studio read its tab from #<bundle/profile> or from localStorage, and
never wrote it, so a reload worked for one reader but a sent link did not. It
now writes the view address through useViewAddress: ?tab=<bundle>__<profile>
(a row key's "/" is not a plain id; the double underscore keeps a sent link
meaning one row even if another bundle later adopts the profile's name). A
reader's tab click is a push, the first paint a replace, and Back/Forward
re-open the named tab without writing. route() reads ?tab= first (or a bare
profile name while it names exactly one row), then the old #bundle/profile
(rewritten to ?tab= on first paint, its hash dropped), then the remembered
tab, then the first row. The listener is removed before the hot-update return.
generate-tree bakes urlOwner 'app' into our own leaf pages only (never into an
embed snippet), and a framed leaf drops it at runtime, so a page embedded in a
partner's iframe reads its address but never adds entries to the partner's
Back button.
When the shell owns the address, a reload or a shared ?tab= now wins over a
profile-config tab, so the first-paint replace can never overwrite a sent link
with the default. Elsewhere the order is unchanged (attribute, config, URL).
A reader's pick in the rail writes ?tab= through useViewAddress as a push,
so a reload keeps the tab, a sent link opens it, and Back returns to the
previous tab. Only the address owner writes: urlOwner 'app' writes history,
'host' gets a dxm-address event for its router, and a partner's page is
never written. Programmatic switches (the manifest's re-select, the device
fallback, a host's tab attribute, Back/Forward) write nothing, and there is
no first-paint write. Back/Forward re-open the tab the address names on a
page that owns its address. ?tab= is read through readViewKeys.
The shell reads ?tab= through the shared view-address helper and writes the
open tab back through it: a reader's choice is a push, first paint a replace,
and Back / Forward re-apply the tab without writing. Only the address owner
writes (urlOwner 'app' on our own pages, 'host' hands the change to a host's
router, absent on a partner's page = read only), so a reload keeps the tab
and a sent link opens it.
Every verse now comes from one translation, the WEB British Edition (public domain), which reads "the LORD"
(the WEB reads "Yahweh"). Every text was re-checked verbatim against it (bible.helloao.org eng_webpb), 31 of
31 matching; the check found three mid-sentence names written with the sentence-start placeholder ("says the
LORD of Armies", "Now the LORD said", "as the LORD had told him") and the British spellings (towards, honour,
offence, amongst, marvellous). The credit line names the one translation.
The four Wall sources both sides changed (blessPoster.js, wall.css, wallCanvas.js, check-wall-no-bg-photos.mjs)
merged without conflict: the pilot's side is the comment-only privacy rewording of those files (c1a2f3698); both
sides are kept (no agent names; every branch change present). The generated files (the wall bundle, its leaf page
and the two manifests) were taken from the pilot and rebuilt from the merged source, then fix:sri and the tree.
The Bless poster follows the UPG 100 List posters' structure:
- the header and the prayer-themes chart close on dividers that run the page's width (to a quarter of the
border from the sheet's edge), while the text stays in the content column;
- at the foot: the call to action in a band ruled across the page ("Jesus Christ is the cornerstone, and we
are living stones. ... bless them in his name, and join the global family in prayer.", moved down from the
header), then the journey's table, a page-wide rule, and the footer: the whole priestly blessing,
Numbers 6:24-26 (World English Bible British Edition, public domain, verbatim), in two lines that fill
the width, with its reference and the credit line.
Measured on the print at 3 x 4, 2 x 3 and 5 x 8 ft, en and ar: the blessing fills 99.2% of the text width
(49 pt at 3 x 4, 74 pt at 5 x 8); the call to action is one line, 97.6% of its band in English; no text
overflows (the only overflow is the dividers' intended reach past the column). Both em constants come from
those measurements. Cards: 3 x 4 0.49 in, 2 x 3 0.35 in, 5 x 8 0.92 in (one verse per row).
bun run posters (SPARSE 3x3, POSTER_DATE 2026-10-02, the offline records cache), posters:shoot, posters:previews,
publish-html. 'List of 100 UPG' left in the zone sources: 0; 'UPG100 List' in all 28.
The tab label in both shells (doxa-maps-spa, posterverse) x11 in each language's own grammar (de 'UPG100-Poster',
es 'Carteles UPG100', zh 'UPG100 海报', …), upgMap displayName and wallHeading x11, the three meta labels, the
nav item and the dev title; the spa's default tab label, the posterverse description, the UPG-100 legend's
count column and the poster-sections noun. Values only: ids, keys, paths and file names stay.
Values only: keys, ids, paths and file names stay (my-upg-100-list, tab.upg-100). Catalogues legend, mapStrategy,
messages, search, tabs and upgMap in all 11 languages (13 keys); the shells' tab label in doxa-maps-spa and
posterverse x11 (German 'Poster der UPG100-Liste'); the three meta labels, the dev page title and the nav
label. poster-render's last-resort literals (used only by a series with no name of its own) follow:
'UPG100 List', 'What is a UPG100 List?'.
generateSheet gains `sparse` (default: every format but 'packet', so every existing caller is unchanged);
the UPG-100 zone sheet answers the packet's 'packet' request with the full letter poster, the same
1500x1941 page. check:poster-browser-equiv compares that sheet with Node's letter format without SPARSE.
The rail row now uses the plugin's own title in all 11 locales, copied from its
catalogue (blessIndiaPosters.title), so the rail and the plugin name it the same
way. Copied rather than read at runtime: naming that catalogue area from the
shell would ship the plugin's whole catalogue inside posterverse.js.
check:posterverse-shelf arm F asserts the two stay equal in every locale; its
self-test plants a drifted label.
The Experimental row showed the titleized id ("Gospel Internet") in every
language: tabLabel() translates a discovered tab only when strings.js has
'tab.<id>', and the manifest carries no title. Add 'tab.gospel-internet'
after 'tab.bless-india-posters' in each locale, with the plugin's own
strings. Rebuilt the gallery bundle; it differs from the pilot's only by
these 11 strings.
The poster sheet's own header 'Bless India in Jesus' name' printed in
English for every reader. It's a phrase, so add a posterHeader key x11
and pass the reader's-locale header to the generator. The footer verse
stays the English PD blessing until the strict-PD per-locale sourcing
lands. Verified: ar poster header = باركوا الهند باسم يسوع.
The plugin's own page chrome (title, intro, buttons, stats, notes) was
English in every locale, and in RTL shells its full stops jumped to the
start. Add the page strings to blessIndiaPosters.json x11, look them up
from the reader's locale (profile-config from the shells; ?lang / <html
lang> on the standalone leaf), set dir=rtl for ar/he/fa/ur, and format
counts via the locale. Verified: ar leaf draws dir=rtl with the Arabic
title; en draws dir=ltr.
deriveTreeBase() called inside build() returned '' (document.currentScript is
null by then), so the India boundaries loaded from /assets (the host's HTML
page) and the poster failed with 'Unexpected token <'. Use the house helper
resolveAssetsBase(profileConfig): the shells pass an absolute assetsBase, and
the standalone leaf falls back to the bundle's own tree root (import.meta.url,
captured at load). Verified: the leaf draws the 3-sheet poster, 0 errors.
The Experimental folder gains a bless-india-posters row, provisional until
its bundle is in the tree (a missing bundle prunes the row, so nothing shows
before it lands), with its label in all 11 locales. Its root is a
natural-height page of poster cards, so a row may set scroll: the element is
then mounted unpinned at its natural height and the pane scrolls it, instead
of being pinned to the pane, which would trap the page's own content.
check:posterverse-shelf expects the row and the scroll set by name; its
self-test drops the row and drops the flag.
A public preview plugin for the whole-India poster: every India people
group on one printable sheet, generated live from the current data
(nothing stored) and shown as its printable sheets with the glue strips.
Each poster carries the blessing — header "Bless India in Jesus' name"
and the Aaronic blessing (Numbers 6:24-26), switchable.
Generates with the plugin's own copy of the renderer; shows the sheets
via the shared PanelSheets and prints as a document at true size.
Public and experimental; a phone sees the preview but Print is blocked
(desktop only) until a design is proven phone-safe. Registers the
blessIndia poster type for the catalogue; label translated in 11
locales. Replaces the earlier India Posters review draft (not landed).
Element <bless-india-posters>.
Closed, the folder sat mid-drawer under the one short Posters section with
empty space below, so it read as a caption with nothing under it and was easy
to miss on a phone. Open, its plugins show like any section's rows; a reader
can still collapse it. check:posterverse-shelf asserts the open default, and
its self-test plants a closed folder.
The samples arm is now a function the self-test can poison: with withholding
switched off, India (no sheet tier, no outlines) must fail as a sample that
cannot be drawn. Closes the branch the arm had no poison for.
India, the one large-sheet country, now prints at 5 x 8 ft only, so the
5.5 x 5.5 ft and 3 x 5 ft side-lane cards would have drawn India's 60x96 sheet
under their own label. They now sample the largest drawable countries (China
at 66x66, Sudan at 36x60) through the same shared sheet path, and their
details say that no country prints at this size today
(posterDesign.missing.noCountryAtSize, 11 locales). The 60x96 card keeps
India and stays withheld. check:poster-design-catalogue now checks every
sample: drawable, or withheld by countrySheet.js.