Skip to content

Session handover — 2026-07-13 pt2

Two handover priorities closed (fcr.business.imageUrl, header-CTA reproducibility). Both turned out to be the opposite of their filed diagnosis, and the same instrument caught both: check the artifact, not the story.

What shipped

1. fcr.business.imageUrl — the asset was never missing

Filed as "upload the local logo to R2". It was already in R2, under the exact key fcr.header.logoUrl uses — the transformer hashed the local file straight onto the existing object (0 uploads). The field was simply never walked, and never resolved:

  • transform-seed-images.mjs's FIELD_MIGRATIONS had no fcr.business rule — the table was enumerated from fields that render, and this one renders nothing (it is og:image + LocalBusiness JSON-LD).
  • Base.astro fed the field into new URL(...) with no getImageSrc — the one CMS image consumer resolving nothing, so even a correct r2: ref would have emitted garbage.

Both fixed at the pipeline level; the next site inherits them. referenced-but-missing 1 → 0. See ADR-0005 followup and known-patterns "An image field that never renders on-page is still a shipped image field".

2. Header CTA — the detector was fine; the capture artifact was stale

pt4 shipped the pinned-outside-<header> CTA detector and recorded the CTA as "reproducible-from-capture, not manual". It wasn't. The detector had only ever run against a live browser session; the persisted section-backgrounds.json was captured mid-pt4 and carried no ctaCandidates on any of its 24 pages. So classifyHeaderCta was doing its job and returning null from an input with no candidates in it, and a reseed would have reverted the live CTA (which is exactly what the pt6 graft check refused to let happen).

Re-captured WCP live → ctaCandidates + headerCta on 24/24 pages → the regen now produces SERVICE AREAS → /service-areas from measurement. The live-D1 stamp came back a no-op — live and the regen independently agree, and that no-op is the proof. Committed seed corrected (it still held ctaText: ""). The 8 carousel slides survived the re-capture; only 3 other derived values moved (2 are the known harmless non-grid columns over-fire, 1 a new FAQ align).

3. Found en route: WCP's live topbar had zero social icons

The graft check surfaced fcr.topbar.socials with url: "" on live — and the TopBar adapter filters empty urls, so the deployed topbar rendered no social links while the live Wix site shows Facebook + YouTube. pt2's urlhref fix had landed in the code and the committed seed, but was never pushed to the deployed D1. Patched; both links now render.

4. sync-globals-to-d1.mjs promoted

Globals writes had accreted four throwaway .tmp/*.sql files — the same rot the wiki recorded when sync-style-to-d1.mjs was promoted for page blocks. Committed as its globals sibling: read-mutate-write by slug (never the ULID), merges by _type, writes the row back whole, --dry, warns-never-fabricates.

Wiki changes

  • ADR-0005 — followup: the migration walker must cover invisible image fields; enumerate from the schema, not from what a page renders.
  • ADR-0009 Slice 3 — header-CTA reproducibility closed; pt4's premature claim corrected in place.
  • ADR-0010 Slice C — scoping fact: a logo carries a name, not a media id, so it is in the Wix pool but invisible to the by-id join. Slice C needs a name-based fallback join.
  • known-patterns — three new + one correction: "A capture-plane detector is not shipped until the CAPTURE has been RE-RUN and PERSISTED"; "The graft check is a TWO-WAY diff — live can be STALE, not just surplus"; "An image field that never renders on-page is still a shipped image field"; and a correction to "logos are local-only" (false — the logo IS in the client's Wix library).
  • known-issuesreferenced-but-missing closed; header fast-follow #2's claim corrected; new entry: "WCP globals still not fully re-seedable — 3 residual divergences" with a reopen trigger.
  • session-end protocol — two conventions this session had to invent, now written down: "Correcting a claim a previous session got WRONG" (date it, keep the false claim visible — it is what cost the session, and both of today's had the same shape: a correct observation with a wrong inference drawn from it), and verify the publish on the production domain (wrangler's success message cannot distinguish Production from Preview; expect a few seconds' propagation lag before the new page 200s — don't re-deploy).

State

Live: WCP worker 8137320c, garvanbay worker 579877dd. Both HTTP 200, zero loud-fail placeholders (pt7's result held). WCP: og:image resolves, header CTA renders, topbar socials render. D1 writes were surgical globals stamps only — no reseed, no page writes. garvanbay regression-checked on the shared Base.astro change (og:image byte-identical before/after).

Next session (priority order)

  1. WCP is still NOT re-seedable end-to-end. Three globals divergences remain (known-issues): fcr.floating-cta (live WhatsApp deep-link vs regen's generic ENQUIRE → /contact-us), fcr.floating-social (live facebook+youtube vs regen's whatsapp-only), and an operator-authored native block. The first two smell like the same class as the header CTA — a matcher guessing where the capture plane should be measuring a Wix-pinned button. If that holds it is one new dimension, not three bug-fixes. Scope it before the next fleet-wide regen.
  2. Audit the fleet's capture artifacts for staleness — this is not a WCP quirk. Every capture-plane slice that adds a new in-page probe leaves every existing section-backgrounds.json one version behind, and the failure is silent: the classifier dutifully returns null from an input that lacks its field, and the regen writes an empty value over a good one. That is exactly how the header CTA sat broken for two sessions while the wiki recorded it as shipped. garvanbay's capture is the next one to check (it predates several probes). Cheap concrete move: assert each capture's schemaVersion + the presence of the fields the current classifiers read, and make a regen refuse to stamp from an artifact older than the probe that feeds it. See known-patterns "A capture-plane detector is not shipped until the CAPTURE has been RE-RUN and PERSISTED".
  3. ADR-0010 slice C — image provenance enrichment, now with the logo/name-join fact above.
  4. at-source-never-pulled: 298 — still unseparated from "used on live and our scrape missed it".
  5. Section-style density dimension + Slice 6 calibration.

The through-line of this run

pt7's lesson was check the producer before believing a capture gap. This run's is its sibling: check the artifact before believing a detector shipped. Both filed diagnoses were confidently wrong in the same direction — they assumed something was missing (an asset, a signal) when in fact it was present but unreachable (an R2 object nobody referenced; a classifier nobody re-ran the capture for). Neither survived one lookup at the stored JSON. A dimension that can only be demonstrated by pointing a browser at the live site is not in the pipeline yet.