Skip to content

fix(design-system): let the visual baseline binding accept a refresh, not only the first adoption - #1742

Merged
BigSimmo merged 3 commits into
mainfrom
claude/ds-baseline-refresh-binding
Aug 8, 2026
Merged

fix(design-system): let the visual baseline binding accept a refresh, not only the first adoption#1742
BigSimmo merged 3 commits into
mainfrom
claude/ds-baseline-refresh-binding

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • validateCandidateSourceBinding required candidateSourceHead to name a commit whose AWAITING_BASELINE still declared the canonical six, and the current tree to declare none. That models the first adoption and nothing else. After test(visual): adopt the six linux visual baselines and satisfy their provenance contract #1729 landed, no commit on main declares the six again, so no future capture head can satisfy it — the binding was satisfiable exactly once, and that once has passed.
  • The binding now accepts either shape: first adoption (candidate declares six, current declares none) or refresh (both ends empty, suite byte-identical).

Stated plainly: the consequence is latent today, not live. validateLinuxVisualBaselineSet short-circuits on declaredPaths.length === 0 and no surface declares baseline.status: "committed", so the contract is dormant and refreshing a golden is currently ungated. This is insurance, not a rescue. The defect bites the moment those surfaces are declared (#242) — at which point the first intentional design change would leave the goldens red with no supported way to re-adopt them, which is precisely backwards for a gate meant to make design changes provable.

A refresh is the ordinary case once baselines exist: a surface is deliberately re-shot and its goldens replaced while the suite itself does not change. Normalisation already blanks the AWAITING_BASELINE values on both sides, so the "suite changed beyond the AWAITING declaration" check stays exact for both shapes.

Nothing is loosened beyond that. A candidate head with five ids, seven ids, a dynamic set, a spread or a duplicate still fails, as do a non-empty current list, a non-ancestor head, a SHA-256 mismatch, a wrong platform and an unreviewed set. The one previously-untested shape — a refresh — now has its own case, which is why the gap was invisible: nothing exercised it.

Verification

  • tests/design-system-adoption.test.tsTests 51 passed (51), including the new refresh case.
  • npm run check:design-system-adoption — exit 0, design-system adoption checked: 53 components, 55 roots.
  • npm run check:design-system-contract — exit 0.
  • npm run format:checkAll matched files use Prettier code style!

Risk and rollout

  • Risk: Low, and currently inert — the validator it changes is dormant while zero surfaces declare baseline files.
  • Rollback: git revert.
  • Provider or production effects: None.

Refs #242, #118.

Summary by CodeRabbit

  • Bug Fixes

    • Improved visual baseline adoption validation to support both initial adoption and unchanged baseline refreshes.
    • Refreshes now remain valid when no pending baseline items are present.
    • Updated validation feedback for invalid baseline states.
  • Tests

    • Expanded coverage for initial adoption, refreshes, and invalid-state scenarios.

… not only the first adoption

`validateCandidateSourceBinding` required `candidateSourceHead` to name a commit
whose `AWAITING_BASELINE` still declared the canonical six, and the current tree to
declare none. That models the FIRST adoption and nothing else. After #1729 landed,
no commit on main declares the six again, so no future capture head could ever
satisfy it -- the binding was satisfiable exactly once, and that once has passed.

The consequence is only latent today, and this commit does not pretend otherwise:
`validateLinuxVisualBaselineSet` short-circuits on `declaredPaths.length === 0` and
no surface yet declares `baseline.status: "committed"`, so the whole contract is
dormant and refreshing a golden is currently ungated. The defect bites the moment
those surfaces are declared (#242) -- at which point the first intentional design
change would leave the goldens red with no supported way to re-adopt them, which is
precisely backwards for a gate meant to make design changes provable.

So the binding now accepts either shape:

  FIRST ADOPTION  candidate head declares the six, current declares none.
  REFRESH         both ends empty, suite byte-identical.

A refresh is the ordinary case once baselines exist: a surface is deliberately
re-shot and its goldens replaced while the suite itself does not change at all.
Normalisation already blanks the AWAITING values on both sides, so the
"suite changed beyond the AWAITING declaration" check stays exact for both.

Nothing is loosened beyond that. A candidate head with five ids, seven ids, a
dynamic set, a spread or a duplicate still fails, as do a non-empty current list, a
non-ancestor head, a hash mismatch, a wrong platform and an unreviewed set. The one
previously-untested shape -- a refresh -- now has its own case, because the gap was
invisible precisely because nothing exercised it.

Verified: tests/design-system-adoption.test.ts 51 passed (51), including the new
refresh case; check:design-system-adoption and check:design-system-contract exit 0;
format:check clean.

Refs #242, #118
@supabase

supabase Bot commented Aug 8, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 68d182d2-5b3c-413c-9c95-145859207340

📥 Commits

Reviewing files that changed from the base of the PR and between fc399e2 and 6e71d69.

📒 Files selected for processing (2)
  • scripts/generate-design-system-adoption.mjs
  • tests/design-system-adoption.test.ts

📝 Walkthrough

Walkthrough

The visual baseline adoption script now accepts canonical six-ID states for first adoption and empty states for refreshes. Tests cover empty-to-empty refreshes and updated invalid-state messages.

Changes

Visual baseline adoption

Layer / File(s) Summary
Candidate baseline state validation
scripts/generate-design-system-adoption.mjs
Validation accepts canonical or empty AWAITING_BASELINE sets. Suite comparison normalizes both states.
First adoption and refresh coverage
tests/design-system-adoption.test.ts
Tests cover first adoption, empty-to-empty refreshes, and invalid candidate states.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main change: allowing visual baseline binding during refreshes.
Description check ✅ Passed The description covers the change, verification results, risk, rollback, and production effects; the relevant template sections are substantially complete.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/ds-baseline-refresh-binding

Comment @coderabbitai help to get the list of available commands.

@BigSimmo
BigSimmo enabled auto-merge (squash) August 8, 2026 16:10
@BigSimmo
BigSimmo disabled auto-merge August 8, 2026 16:13
@BigSimmo
BigSimmo merged commit 30dc42d into main Aug 8, 2026
24 checks passed
@BigSimmo
BigSimmo deleted the claude/ds-baseline-refresh-binding branch August 8, 2026 16:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant