A device whose fonts lack U+0671 printed it as a box. Only those 13 code points change (0671: 13 -> 0, 0627:
+13); the bold verse is still a substring of the passage. check:packet-strings-parity fails on any U+0671 in
an ar value (it fails on the previous file). The Arabic scripture blocks also name Arabic faces before serif.
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.
Opt-in per series (series.json poster.headColumns, on for upg100 only), so every other series' sheet is
unchanged. The band is laid out by ONE function that both measureHeader() and the renderer call, so the
predicted header height is the drawn one. Each block is centred in an equal column between short rules,
with the inset the first column lacked. The footer's three blocks are drawn at the 13.5px they are wrapped
and spaced for (they were drawn at 12px), so the text grows with no change to the lines or the band's
height, and they are centred for that size.
SOURCE ONLY: the served copies, the integrity pin and its bundles are regenerated at landing.
loadPlaces memoised an empty table on ANY failure, so one network error meant no
city dots for the rest of the session, while the other pinned loaders retry. A
table that is not served (or a reader offline) is now forgotten, so a later print
tries again; wrong bytes, refused after the fresh refetch, stay refused for the
session.
The print-time files are pinned (poster-render.js and its classic copy,
packet-strings.json, ne-places.json, india-states.json) and were fetched with
cache: 'force-cache', which returns any cached copy, however old. After a
re-pin, a reader who had printed before kept the previous copy: it failed its
pin on every print and the print fell back without a word. Page 1 became the
stored poster, a non-English packet would print in English, and India's state
cards would be lost.
sha384.js fetchPinned fetches force-cache first (fast, and offline once
cached) and, when the copy is not served or fails its pin, once more with
cache: 'reload', which skips and refreshes the HTTP cache; only that answer
decides. posterSheets (the generator and the places table), packetStrings and
indiaStates all fetch through it. The classic-script path refreshes the cache
the same way and retries a refused tag once.
check:pinned-fetch-fresh models the HTTP cache with stale copies: page 1 still
draws, the packet keeps every language, India keeps its 36 states; a matching
cached copy is used with one request; wrong bytes are refused. The previous
loaders fail it. Self-test poisons: no fresh refetch, never the cache, a
mismatch accepted, a loader fetching its pinned file directly.
What the three columns ask; the blessing to pray over each group, Numbers 6:24-26 in full with its credit
(the public-domain text per language, compared verse by verse with its source; ro and hi print the English,
as the packet's other scripture does); one line of further blessing references (the Synodal's own Psalm
numbers in Russian); the prayer wheel at the end; and a pace table, daily (strongest) to every three months
(slower), weekly marked as the healthiest, each pace's daily load computed from the list's size.
The first page holds 11 rows (16 before); later pages keep 18. Measured with a 100-group list in all 11
languages: the longest first pages (ru, hi) keep 77px under their last row, the references fit one line.
check:packet-variants asserts the description, once, before the first row, and the computed pace; the
render gate follows the new pagination.
The tick boxes become tally cells, on the lightweight worksheet and on the full packet's profile rows, so a
list prayed through again and again counts every time. The headings are the questions themselves, broken
into balanced lines; the worksheet's tally columns widen to 160px so English heads take two lines. The
worksheet's note no longer says there is no pace to keep. Measured in all 11 languages: every worksheet
sheet and every profile row still fits (16 + 18 rows a sheet unchanged).
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.
A second read measured a hole in the phone print keep: a touch after print()
started the grace, and if the print UI then opened (the page hidden, or the
window blurred), nothing cancelled it, so the document could go while the
reader was still choosing Save as PDF. Now:
- going away again during the grace cancels the pending drop, and the next
"back" counts;
- BACK_GRACE_MS is 60 s (was 5 s): a slow phone can still be writing an
11-page packet after its dialog closes, and the kept document is invisible
on screen and replaced by the next print;
- a touch in the first TOUCH_SETTLE_MS (2 s) after print() is not "back" (a
double tap while the preview builds).
check:phone-print-keep gains arm H (a touch, then the print UI, by hiding and
by blur: still mounted past the grace, released after the next back) and arm I
(a touch in the settle window), with the poisons "no cancel when away again"
and "no touch settle window"; arm C now taps Print a few seconds after the
document is ready and stays in the dialog past the grace. The first cut fails
H and I; the pilot's file fails A to H. Desktop stays byte-identical.
On a phone, printDocument mounts the document into the page (#dxm-print-root and
a print-only style) and calls window.print(). It dropped both at afterprint. But
Android Chrome's print() does not block: afterprint fires once the preview is
built, and the file "Save as PDF" writes is rendered later, after the reader
taps Save, from the page as it is then. The preview showed a packet's 11 pages
and the saved PDF was the bare host page.
The document now stays until the reader is back on the page: shown again after
being hidden, focused again after losing focus, or touched after print(), then
BACK_GRACE_MS more for a job still rendering. A new print replaces it, a
cancelled one drops it, and the ten-minute ceiling stays. Listening starts at
print(), so the Print tap of a late print does not count. printImageBlob's
object URL now follows the document (onRelease) instead of afterprint. On
screen the document is display:none, as before. Desktop prints through the
frame exactly as before.
check:phone-print-keep runs the phone timeline on fake timers and a stub DOM
with an Android user agent; the previous file fails it (gone after afterprint,
image revoked). Its self-test poisons the old drop at afterprint, no release
when back, listeners armed at mount, no grace, printImageBlob revoking at
afterprint, and no ceiling.
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>.
Switch forkRoute/placePinsInState to static imports from their sibling
library modules (now on development) and delete the vendored forkRoute
fallback; opts may still override for a Worker. Re-register
check:circular-layout (script + gates:pre + description) after the merge
took development's package.json.
P2: test fourSides numbering against GEOMETRY per side (L cy↓, R y↑,
T x↑, B x↓) with a de-overlap drift tolerance, not label-emission order
(which numbering walks, so it could never fail). P3: assert every
pairedRows leader carries polys.length===2. Both mutation-tested: a
reversed side sort and a dropped polys each make the gate FAIL.
Clear check:no-fleet-names (neutral wording for the classic4 reference,
the vendored-fork note, the browser-budget comment, the gate's format
comment and the package.json description). Fix pairedRows leaders[].polys
(was null on every leader — store fork.polys; drop dead polysForCount).
Tie-break ids by code unit (cmpId), not localeCompare, for byte-identity
across runtimes/locales. Harden the gate: assert the fourSides side
sequence L<T<R<B and monotone numbering within each side (by label
emission order), and recount pins-outside-state and pairedRows crossings
from the OUTPUT, not from stats.
New library/packet/circularLayout.js: ring order, leader routing,
numbered four-sides and paired-row forks as a single pure, Worker-safe
module (geometry in, geometry out; no SVG, no DOM, deterministic). Modes
sideLanes (today's L/R), fourSides (numbered, no leaders) and pairedRows
(two leaders per row). measure/slotOf and placePinsInState/forkRoute are
injected; forkRoute falls back to a vendored copy until fork-leaders is
on this tree. Adds check:circular-layout (frozen 855-pin 60x96 fixture:
ring order, 0 dupes, 0 pins-outside-state, 0 crossings on paired rows,
determinism, a poison, and a node time/heap budget).
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.