Session handover — 2026-07-13¶
WCP now renders ZERO loud-fail placeholders on all 24 pages (276 → 39 → 0). This closes the last of the asset debt the pt5 reconciliation surfaced.
What shipped¶
The residual 39 img? placeholders (/service-areas 27, /accessibility-statement
12) were not a capture gap — the third time that instinct was wrong this run, and
the third time checking the PRODUCER first settled it in one
lookup:
/service-areas"CLICK AN AREA" is a link grid on live — 9 items of title + href, zero images./accessibility-statementis anInfoCardsblock of text cards (title + description).
Our extraction was faithful and the CMS adapter already passed image: undefined.
The bug was in the shared canonical block: services-1.astro rendered <TileMedia>
unconditionally, so every legitimately image-less card tripped the Image
primitive's loud-fail.
Fix: a block-level hasMedia guard — a grid where no item carries an image
renders no media slot; a grid where some do keeps it, so an item genuinely missing
an image still loud-fails. That signal is load-bearing (a service teaser that lost its
photo must be visible), so it was proven still live: blanking one image in a
3-image home grid fired the placeholder; reverted clean.
WCP worker 4f11c3c2. garvanbay unaffected (its grids carry images → hasMedia true
→ byte-identical markup; verified 0 placeholders, images intact).
Wiki changes¶
- ADR-0004 — followup (append-mostly): loud-fail scoping — structural absence is judged at the BLOCK, not the item. ADR-0004 is the loud-fail contract, and both of this run's placeholder bugs were failures of where the guard sits, so the rule belongs there: an item missing a field is loud when its siblings have it; structural when no item in the block has it.
- known-patterns.md — new entry "A grid with NO imagery is a TEXT grid" (decide media presence per BLOCK, not per item; the scope of "structural absence" is the container, which is the easy thing to get wrong).
- known-issues.md — the WCP placeholder issue closed;
empty-image-slots: 13explicitly recorded as benign (those are the legitimately image-less items) so nobody chases it to zero —rendered-placeholdersis the defect signal. asset-reconcile.mjs— bucket labels corrected to say so.
State¶
Committed to master: packages/components-v3/…/blocks/services-1.astro
(hasMedia guard), apps/cms/scripts/asset-reconcile.mjs (labels), wiki + this
handover. Live: WCP worker 4f11c3c2; no D1 writes (the fix is render-only —
the data was already correct). No garvanbay change.
Next session (priority order)¶
fcr.business.imageUrl—/assets/logos/…never migrated → dead on the worker, soog:image+ JSON-LD imagery are broken. Logos are FCR build assets (no wixstatic source): upload the local file to R2. One-liner, and it clears the lastreferenced-but-missingentry.- Header CTA is not reproducible from a regen (pt6 graft check) — pt4's detector doesn't fire on the stored capture, so WCP still isn't safely re-seedable end-to-end. Close before any fleet-wide regen.
- ADR-0010 slice C — image provenance enrichment (API filenames/dimensions/alt),
now that
searchFilesgives the true 392-file pool. at-source-never-pulled: 298— now worth a second read: with the placeholders at zero and the logo/ribbon questions settled, a residual here is a genuine capture-coverage signal rather than noise.- Section-style density dimension + Slice 6 calibration.
The through-line of this run¶
Three consecutive "the capture must have missed it" hypotheses; three times the real
cause was downstream of a correct capture (a transformer misroute, an emitter
shape coercion, an unconditional media slot). The build's section-matchers.json
sidecar — which matcher produced this block? — settled each one immediately. Reach
for it before theorising about a missing asset.