A point release, hours after 20260917, fixing one thing in the document check that release introduced.
The document check now reports an unfilled image slot. validate() reported an image frame
with no image, an image its document did not list, and an image that failed to load — and said
nothing about a picture that had arrived perfectly well and was a placeholder.
That was the gap that mattered most, because a placeholder passes every other test: it has a link, the link is in the document's image list, and it loads — it is a real picture from a real service. So a document whose every frame showed a grey box with a filename across it came back from the check with nothing to say.
It is reported as a warning, not an error, because an unfilled slot is the intended state of a template nobody has filled in yet. Whether it may be ordered is the host's decision, as it is for everything else the check reports.
⚠️ If you integrate POD documents, expect this. A POD document carries image keys and no URLs at all, so every photo block starts as a placeholder — this check will report each one until the customer uploads a picture, which is exactly what it is for.
The 20260917 notes are published, and amending a note that is already out is worse than a change arriving in the next one — a reader cannot tell which bundle they are looking at. A second note under the same version string would have the same problem in a worse way. So this is its own version, and the notes for 20260917 stand as they were.
The new check is image_is_placeholder, warning severity, with detail.placeholder_in naming
where the placeholder was found: element, element_print, manifest_editor, manifest_print
or manifest_thumbnail. The element's resolved asset and the manifest entry are both checked,
because they answer for different renderers and can disagree — the canvas draws the element's
asset, the PDF publisher resolves the manifest, and a placeholder in the manifest's print URL is
the one that reaches paper.
⚠️ The test is is_placeholder_url() in assetidtoasset.ts, beside DUMMY_IMAGE_SERVICE — the
single definition of where our placeholders come from. The validator asks it rather than keeping
its own copy of the host. A second copy of one string is how two readers drift apart, and the
failure mode here is silent: a check that no longer recognises our own placeholders passes a
document of grey boxes and reports nothing.
⚠️ The test requires the host and the separator. Written as a bare prefix it also matches a different host whose name merely starts with ours, whose pictures are not our placeholders. The headless harness caught that while the cases were being written out — it was recorded as an expected match, which it should never have been.
Three producers make placeholders and all of them land on that one host: the InDesign converter
(a link broken before the package was made — TYP-724 — and the whole images-off path), the
pod-converter (every POD photo block, plus IMAGE_NONE for a block with no key at all), and the
canvas itself, which builds one when a manifest entry carries no URLs.
The three image checks that pass for a placeholder still pass, and the browser suite asserts it: a finding repeated under two names is a finding the host has to de-duplicate.