Skip to content

Session handover — 2026-07-06 pt3

Continues from session-2026-07-06-pt2-handover.md (WCP content fix + ADR-0009 accepted + Slice 1). This half: executed ADR-0009 Slice 2a — the emit/consume half of Capture v2. One commit on master, pushed: dec213b.

What changed — where to look

  • ADR-0009 Slice 2a (dec213b) — site-level design tokens now flow design.json → emitSiteCss → per-site CSS override, wired into both lanes. Network-free; zero visual change until a design.json exists (Slice 2b's extended capture populates it). New: lib/design-derive.js (pure deriver, _raw → bounded buckets), lib/design-derive.validate.mjs (27 checks), scripts/emit-design-json.js (derive design.json from stored theme.json _raw, no re-crawl). theme.js gains emitSiteCss + tokenizes the brand CTA corner as --btn-radius. Callers: emit.js#emitProject, emit-theme-css.mjs (+ designPathFor). Slice tracker split into 2a (done) / 2b (planned) in decisions/0009-target-output-architecture.md; the token table + cascade note landed in aesthetic-token-contract.md.

  • Scope finding that sharpened the 2a/2b boundary. The hoped-for "derive real tokens from the existing theme.json" didn't pan out: the stored _raw samples carry no borderRadius/boxShadow (capture never grabbed them) and Wix <section> padding is 0 (rhythm lives on inner spacers). So the capture work moved wholly to Slice 2b; 2a is purely the emit/consume plumbing (mirrors Slice 1: ship the consumer with safe defaults, capture feeds it later). No contract change — the confirmed done-criteria already used a hand-authored design.json as the shift demo.

  • New known-patternknown-patterns.md "A per-site CSS override must be UNLAYERED to beat an unlayered :root default — @layer loses". The load-bearing implementation call: an @layer site override would silently lose to emitGlobalCss's unlayered :root defaults, so emitSiteCss appends an unlayered :root and wins by source order.

Verified

  • Zero-regression: emitGlobalCss diff (HEAD vs current, no design.json) is only the --btn-radius default + two 4pxvar(--btn-radius) swaps; computed values identical (Slice-1's declaration-level bar). emitSiteCss(null) === ''.
  • Shift demo: a bounded design.json (pill / lg / airy / flat) emits the correct unlayered :root override block.
  • Both lanes (Phase 3 regression check on shared emitGlobalCss): real CMS emit-theme-css.mjs output diffs against HEAD by exactly the three expected lines and nothing else; per-site emit.js loads clean. Validate script: 27/27.

Next priority

ADR-0009 Slice 2b — Capture v2 (the capture half). Extend the Playwright capture() (lib/theme-extractor.js) to record real borderRadius + boxShadow on button/card and the effective section-band rhythm (not the 0-padding <section> element — measure the inner spacer / band), then re-crawl garvanbay + WCP so design.json carries real bounded tokens (today emit-design-json.js yields empty tokens → no override, correctly). Then the per-section style records + classifiers (alignment, image side, columns, density, header/topbar) into capture-section-backgrounds.js, riding the existing section-tone join rails. Slice 3 threads those section props into blocks.

Carried/open (unchanged from pt2, see known-issues): 3 WCP logo-strip placeholders; cross-account sharding unproven; non-fatal Map/Prose/Features build errors; per-site static-build @source gap; per-site static noindex,nofollow launch blocker.