Skip to content

Session handover — 2026-07-07 pt4

Continues from session-2026-07-07-pt3-handover.md (ADR-0009 columns). This session shifted from fanning out dimensions to validation: designed and began building the ADR-0009 §6 near-match scorecard — the ship/hold metric that was the last-session recommendation and the unblocker for Slices 4 & 6. One code+docs commit + this wiki commit.

What changed — where to look

  • New contract: docs/pipeline/near-match-scorecard-contract.md — the metric design, synthesised from two blind parallel studies (deep-reasoner + Codex, briefed identically). The crux calls: a measured-feature scorecard (not a literal pixel diff — fonts are substituted, decoration stripped); three deterministic axes (S structural / T theme / G_det masked-perceptual) under a hurdle+veto gate with thresholds fit on a batch; LLM triage-only, never the gate. Load-bearing insight: fidelity = re-measuring the deployed OUTPUT, not comparing to what we stamped (an identity). Build tracker (Steps 0–5) inside.
  • ADR-0009 (decisions/0009-…md) — §6 rewritten to reference the contract; Slice 4 tracker row now logs scorecard Steps 0/1/2 shipped with numbers; Slice 6 row references the calibration method.
  • Code — 3 axes + emitter, all deterministic, builds/* gitignored:
  • lib/structural-diff.js (S, Step 0) — junk-filter → canonicalise Wix dup-pairs → heading-anchored NW alignment → omit-aware per-dim agreement → role-weighted S.
  • lib/theme-fidelity.js (T, Step 1) — wraps fidelity-harness.js typography+palette into a 0–100 axis + veto flags (fallbackNavy, …).
  • lib/perceptual-diff.js (G_det, Step 2) — section-crop coarse colour+luma grid over full-page shots; reuses structural-diff#alignPage.
  • lib/scorecard.js — combined fidelity-scorecard.json emitter (3 axes + weight-re-normalised partial composite, not yet a verdict).
  • lib/capture-section-backgrounds.js — additive --base/--out (symmetric re-capture of the deployed output) + --shots + rect.y (default crawl unchanged).
  • known-patterns: one durable entry — measuring fidelity means re-measuring the deployed output; comparing a capture to what we stamped is an identity (+ canonicalise/junk-filter corollary).
  • known-issues: scorecard-in-progress (Steps 3–5 pending) + the deployed-site fidelity gaps the scorecard surfaced (garvanbay muted bands not painting; WCP service-grid columns 4-vs-3 + align/imageSide) + metric-side follow-ups.

Verified

  • All 5 lib/*.js pass node -c. Default probe crawl path unchanged (both new flags fall back to prior hardcoded values).
  • Three-axis scorecard run live against both deployed CMS workers: garvanbay (emdash.dcathal.org) S=96 / T=100 / G_det=80.8 (composite 93.2); WCP (wcp.dcathal.org) S=59.9 / T=100 / G_det=70.9 (72.7). The known-good site ranks near the top (the sanity anchor), WCP lands "needs-polish" — a sensible spread where every deduction traces to a real gap or defensible structural difference.
  • G_det adds orthogonal signal (flags garvanbay hero + WCP FAQ as top visual divergences, invisible to S). Junk-filter + canonicalise validated on real data (WCP: 6/31/9 junk sections filtered per page; garvanbay: 6 dup-pairs collapsed).

Next priority — Step 3 (the GATE), then Slices 4 & 6

Step 3 is the next build: the full composite + the hurdle/veto gate (verdict: ship|manual-polish|hold) in lib/scorecard.js, enforcing the veto flags T already collects. That turns the three axes into an actual decision. Then Slice 4 (GenericSection + matcher-gap into S) and Slice 6 (calibrate thresholds on a 30–50-site batch — the point where the measured pass rate, not these two anchor points, sets ship/hold). Before G_det can gate, triage the low-sim outliers (real vs crop artifact) — see the contract follow-ups.

Second track still open (unblocked by the metric now existing): bring more already-deployed sites through capture→scorecard to grow the labelled sample.

Carried / open (see known-issues)

Scorecard Steps 3–5 pending; deployed-site gaps the scorecard surfaced (garvanbay muted-tone, WCP columns/align/imageSide) unfixed by design (metric ≠ fixes this session); G_det real-vs-artifact triage; no .validate.mjs yet for the new pure modules; T re-measures emission not the deployed DOM; per-site static lane still consumes no capture; plus all prior carried items (cross-account sharding, brand-detection nondeterminism, noindex launch blocker, …).