Skip to content

Session handover — 2026-07-13 pt3

The floating dimension shipped. But the headline is what it found on the way: the wiki's own account of the bug was inverted, and a whole slice had been scoped against it. The instrument that caught it was the same one as the last two runs — look at the artifact — pointed at a new place: production data.

What happened

1. The filed diagnosis was backwards

known-issues carried a table of WCP's "3 residual globals divergences" with the columns headed live (faithful) and regen (would overwrite). The pt2 handover reasoned forward from it: the matcher guesses a generic default where the capture plane should be measuring WCP's WhatsApp floating button — probably one dimension, not three bug-fixes.

One Playwright probe of the live Wix DOM (before writing any code) killed it. Live WCP carries three floating widgets, and our deployed site matched none of them:

live Wix DOM (measured) what live D1 was serving
ENQUIRE/contact-us, mid-right pill (179×45) nothing — slot held a WhatsApp button
WhatsApp button, bottom-right (55×55) mislabelled as the CTA
Up scroll-to-top (47×47) no CMS home
(no floating social rail exists on live) facebook + youtube rail (phantom)

The regen was the faithful side. FloatingCTA.js had ENQUIRE → /contact-us right all along. Of the six fields across the two blocks, exactly one was genuinely unmeasured: FloatingSocial.js's hardcoded position: 'right' (live measures bottom-right).

2. Where live's values came from

apps/cms/scripts/.tmp/wcp-add-floating-globals.sqluntracked, hand-written, no git history. The 2026-07-11 session needed values to deploy these globals, nothing measured them, so it typed them in. It invented the WhatsApp CTA, copy-pasted the topbar's socials into a floating rail live doesn't have, and wrote the socials: url: "" that pt2 later spent time diagnosing as a threading bug. Three bad values, one file.

Then it compounded: the values reached live D1 → the graft check saw regen ≠ live with nothing to arbitrate → recorded live as "faithful" → known-issues published it → a follow-on session scoped a capture dimension to reproduce it. A fabricated value in production is worse than a missing one: missing is loud (ADR-0004), fabricated is indistinguishable from a measurement, and it accretes authority every time a doc cites it. New pattern: A hand-written D1 patch is a FABRICATION with a production address.

Decision (Cathal): correct live toward measurement. The hand-patch is fabrication, not operator surplus.

3. The dimension, built anyway — and it earns its place

Without measurement we'd have no way to know the matcher was right, and position was still a guess. Shipped (CMS lane, ADR-0009 Slice 3):

  • Capture — a floatingGeometry walker (chrome.floatingRaw, raw geometry only) that partitions Wix's pinned layer with the header probe, at the header band: header CTA above, floating below. Two mirror-image guards that must stay in step.
  • Classifiers — pure classifyFloatingCta / classifyFloatingSocial (lib/section-style.js), partitioning the floating set by href class: a social platform is never the CTA (the exact conflation the hand-patch made); a bare / href is a scroll-to-top, recognised and deliberately dropped. position from measured corner distances, clamped to each block's own enum (they differ), omitted entirely when unmappable.
  • Result — live WCP measures ENQUIRE@right + whatsapp@bottom-right on 24/24 pages, read back from the persisted artifact. garvanbay measures 0 candidates → null on both (faithful).

Delivered by surgical sync-globals-to-d1.mjs stamp (2 blocks patched, 7 preserved — the operator's native block and the migrated r2: logo refs survive a reseed would have destroyed). No worker redeploy — data-only; the render path was already in the bundle.

The proof is a no-op. An independent re-measurement of our deployed chrome now agrees with live on both floating dims (globals-diff floating peer: agree: true, disagreements 0). Run before today's fix, that instrument would have flagged both — the blind spot that let the hand-patch pass as ground truth is closed.

4. The staleness guard (pt2's priority 2, closed)

schemaVersion had been written into every capture artifact since v2 and no consumer had ever read it. Now seed-from-build.js#CAPTURE_REQUIREMENTS has each capture-fed dimension declare the version that introduced its probe and the chrome key that probe always emits — even when it finds nothing, because a null can't distinguish "ran, found nothing" (garvanbay) from "never ran" (stale). Missing input → skipped with a loud warning, never stamped from a fabricated null, never fatal.

Proven against the pre-slice v3 artifact: it refused the floating dimension by name while still stamping header/topbar (which v3 satisfies) — surgical, not a blanket refusal.

Verification

  • Zero-regression, A/B (regen with the change stashed vs applied): garvanbay byte-identical on pages and globals; WCP byte-identical on pages, globals changed only in the floating dimension.
  • Validators: 143 checks (was 103); globals-diff / structural-diff / scorecard-gate all green.
  • Both workers HTTP 200, 0 loud-fail placeholders. WCP renders the ENQUIRE pill + WhatsApp rail; the phantom facebook/youtube rail is gone.
  • Carousel slideUrls (8 frames) survived the re-capture — --slides was passed deliberately; without it the regen would have blanked the hero.

Wiki changes

  • ADR-0009 Slice 3 — floating dimension + the capture-staleness guard; records that the slice corrected the wiki.
  • known-issues — "WCP globals not re-seedable" CLOSED (the false table kept visible, dated); new entry for the two render-lane follow-ups.
  • known-patterns — two new (a hand-written D1 patch is a fabrication; a new in-page probe makes every capture artifact stale), one new technical (Wix's pinned layer holds several unrelated widgets), and a correction in place to "The graft check is a TWO-WAY diff" — which had itself encoded the false claim, having warned against assuming a direction and then assumed one.
  • section-style-contract — floating as the 6th dim.

Second half — a fidelity review turned into a direction change

Cathal reviewed the deployed WCP and listed real gaps (a video we don't render, missing "why choose us" overlays, dropped icons on the trust ribbon, hero text layout, "and many more"), and proposed clearing both sites and rebuilding from inception to see what the pipeline actually produces. Checking the artifacts first (again) sorted his list into three different classes:

gap class what the artifact said
the 2nd video (VID-20251217-WA0003), in the "Waterford County Painters" section and again in the FAQ asset drop pool has 46 videos; we migrated 1
icons on "7-Year Guarantee / Fully insured" matcher drop fcr.usp-bar items carry icon: ""
"Why choose us" overlays (VAT Registered…) matcher/section drop unconfirmed — needs enumeration
hero text layout render only the hero data is correct: 8 slides + video, right R2 URLs

The hero one matters: the content was right and the render was wrong, so "the site looks wrong" and "the pipeline lost data" are not the same problem and we had been conflating them. That is the argument for measuring before fixing.

Direction taken (Cathal): rebuild both sites from inception, instrumented; assets reconcile + report only (bulk-migrating the 45 videos without segmentation would be motion without progress). Scoped and locked at scope-2026-07-13-clean-room-rebuild — that document is where the next session starts.

Preconditions landed (commit 555968d) — including one that nearly poisoned the report

  • garvanbay is on the Wix API. wix_site_id committed, verified against the API rather than trusted (41 files, 0 videos — so the video debt is WCP-specific: 45 files, not portfolio-wide).
  • The media-pool instrument was broken and is fixed. Plugging garvanbay in, searchFiles returned 0 files — no error, a clean confident empty pool. ADR-0010 had locked "the POOL is searchFiles" on the strength of WCP alone; garvanbay is simply absent from Wix's media search index. Run as scoped, the reconciliation would have reported garvanbay has zero asset debt — and we would have believed it, because that was the answer we wanted. The pool is now the union (mediaPool), warning loudly when the enumerations disagree. WCP unchanged at 393; garvanbay 0 → 41. See ADR-0010 second amendment.

Next session

Execute scope-2026-07-13-clean-room-rebuild. Preconditions are green; the destructive step (clearing both live D1s) wants a fresh context. Baselines to beat/report against are in that doc.

Deferred, in priority order behind the rebuild (all now tracked in known-issues):

  1. The baked seed carries the wrong site's identity — WCP's admin says "garvanbay". Not cosmetic: provisioning a fresh tenant against that stale file seeds the wrong client's content. It is a precondition inside the rebuild scope, and a hard blocker on ADR-0008 Slice 3 fleet provisioning.
  2. fcr.floating-cta's render treatment — measured right is correct, but the block styles it as a rotated vertical tab while live's ENQUIRE is a horizontal pill.
  3. originalNameOf returns a folder name (Misc) for 19 of WCP's 46 videos — a hard precondition of any video migration (ADR-0010 slice C's family).
  4. Audit the fleet for other fabrications. One hand-written .tmp/*.sql file produced three bad values and misdirected two sessions. It is unlikely to be the only one.
  5. Section-style density dimension + Slice 6 calibration.

The through-line

pt7: check the producer before believing a capture gap. pt2: check the artifact before believing a detector shipped. This run began as check the artifact before believing LIVE is the truth — and then said it three more times, because the session found four authoritative-looking artifacts that were wrong:

  1. a stale capture (no floatingRaw) that would have stamped empties over good values;
  2. a hand-written SQL patch that put fabricated values in production and got promoted to ground truth by the wiki;
  3. a stale baked seed silently giving WCP another client's identity;
  4. a one-site API contract (searchFiles is the pool) that returns a confident, flattering zero on the second site.

The common shape is not "we made mistakes" — it is that every one of them looked like success. A missing value is loud by design (ADR-0004). A fabricated value, a stale artifact, an empty enumeration: these are indistinguishable from the real thing until you open them. The four are why the next session rebuilds from inception instead of patching: an artifact you regenerate cannot lie to you about its provenance.