# Design audit fix plan — all — 2026-08-10

Report: [`2026-08-10-all.report.md`](./2026-08-10-all.report.md)

Only `kit-defect` findings are here. There is **no token item** — all 72 ramp
steps match the live variable table, so `/figma-sync` has nothing to do this
round. The two `design-defect` findings (BTN-01, BTN-02) and the five
`deliberate` ones produce no code change by design; BTN-01/BTN-02 go to the
showcase Findings tab instead, which is item 5.

Ordered by blast radius. Items 1–3 are registry/showcase only and land in any
order; item 4 changes rendered output; item 5 is documentation. **Item 6 is the
only consumer-visible one** and is deliberately last, because item 2 is what
makes it visible in the first place.

---

## 1. Map CBAR's avatar `neutral` onto the kit's `black` palette · fixes AVT-01 · S

**Files** `showcase/src/registry/avatar.tsx:23`

**Change** in `figma.valueMap.colorPalette`, add `black: 'neutral'` beside the
existing `tertiary: 'third'`:

```ts
valueMap: { shape: { circle: 'shape' }, colorPalette: { tertiary: 'third', black: 'neutral' } },
```

**Watch out** the map is keyed **kit value → Figma value**, not the other way
round — `compare()` reads `alias[kitValue]`. Getting it backwards produces no
error, just an unchanged `diff` row. The claim rests on `.palette-black` binding
`--ui-color-neutral-*` (`src/styles/theme.css:193`); it is a mapping fix only, so
no component, prop or token moves.

**Done when** `/parity` shows Avatar's `colorPalette` row as `diff` with
`kit-only: red|green|yellow` and **no** `figma-only` values — `neutral` and
`black` have paired up.

## 2. Disambiguate the two `RadioMark` sets · fixes REG-02 · M

**Files** `showcase/src/figma/spec.ts:66` (`findSet`),
`showcase/src/registry/types.ts` (`Entry['figma']`),
`showcase/src/registry/form-controls.tsx:172`

**Change** add an optional `id?: string` to `Entry['figma']`; when present,
`findSet` matches on node id and ignores the name. Point `radio-group` at
`2451:5841` (the 576-variant set). When `id` is absent and the name matches more
than one set, surface it — a `dup` row on `/parity` or a console warning, not a
silent first-match.

**Watch out** this is the item that *creates* work rather than closing it: once
`radio-group` resolves to the real set, its `variant` axis becomes a visible
`no-prop` row, which is item 6. Land this knowing the parity numbers get worse
before they get better. Also `pin: { state: 'default' }` on that entry refers to
the **old** set's axis — `2451:5841` has no `state` axis, it has `.isChecked?`,
`.isDisabled?` and `.focusVisible?`, all already covered by `STATE_AXES`. Drop
the stale pin in the same edit.

**Done when** `/parity` lists RadioMark `2451:5841` as the linked set for
`radio-group`, and a deliberate duplicate name in a scratch edit produces a
visible warning rather than a silent pick.

## 3. Let one entry cover several Figma sets · fixes REG-01 · M

**Files** `showcase/src/registry/types.ts`, `showcase/src/pages/parity.tsx`,
`showcase/src/registry/forms.tsx:347` (select),
`showcase/src/registry/navigation.tsx:117` (pagination),
`showcase/src/registry/navigation.tsx:190` (tabs)

**Change** add `alsoCovers?: string[]` to `Entry['figma']`. Sets named there are
**listed as covered and never axis-diffed** — the same treatment slots already
get. Then: `select` covers `Select.Content`; `pagination` covers `Pagination
left` and `Pagination right`; `tabs` covers the `tabs` set (`TabsTrigger`).
Update the "sets with no kit counterpart" count to exclude them.

**Watch out** do not diff the secondary sets. `Select.Content` has its own `size`
axis that would collide with the trigger's, and `tabs` (the trigger) carries a
`state` axis plus icon slots — diffing either produces noise, not findings. The
genuinely uncovered three (`IconButton`, `search` ×2) must still read as
uncovered; the goal is an honest number, not a smaller one.

**Done when** `/parity` reports **3** sets with no kit counterpart instead of 7,
and Select/Pagination/Tabs each name their secondary sets in the page's own
listing.

## 4. Give icon-only buttons CBAR's 6px corner · fixes ICO-01 · S

**Files** `src/components/button/button.tsx` — the four `icon-*` rungs in the
`size` variant (the base string keeps `rounded-xs` for text buttons)

**Change** add `rounded-sm` to `icon-xs`, `icon-sm`, `icon`, `icon-lg`, so a
lone-icon button reads `--ui-radius-sm` (6px) where a text button keeps
`--ui-radius-xs` (4px). CBAR draws Button at 4px (`2446:7312`) and IconButton at
6px (`2406:2254`).

**Watch out** **confirm before landing** — this finding is `unconfirmed` in the
report, resolved from the cva rather than from `getComputedStyle`. Run `pnpm dev`,
open `/button`, switch the Figma panel on (`?figma=live`) and read the radius row.
Two constraints: the rung string must come *after* the base `rounded-xs` in the
composed class list for `cn` to resolve the conflict the right way, and this is a
visual change to every icon button in every consuming app — small, but it needs a
changeset (patch) even though no prop moves.

**Done when** the Figma panel's `border-radius` row reads match against
`2406:2254`, `pnpm test:run` is green, and `pnpm size` shows no budget moved.

## 5. Move BTN-01's new evidence into the Findings tab · fixes BTN-01, BTN-02 · S

**Files** `showcase/src/pages/parity-findings.tsx`

**Change** BTN-01 is already written up there; replace the hex-level argument
with the **variable-binding** one, which is materially stronger: Button's
`primary` variant is bound to `surface/colored/secondary` and its `secondary`
variant to `surface/colored/primary`, while IconButton and Alert bind both
correctly. Include the six-row evidence table from the report and the node ids.
Add BTN-02 as a new finding — the tertiary ramp is `third` on Button and
`turquoise` on IconButton, where IconButton also has a *different* `secondary`.

**Watch out** **no component or token changes** belong in this item. Do not swap
ramps to make Button agree; `tokens.css` is machine-owned and `/figma-sync` would
revert it anyway. The page is `.tsx` and its copy is subject to the showcase's
i18n rules — findings prose is English-only alongside the existing entries; do
not translate component or set names.

**Done when** `/parity?tab=findings` shows both findings with node ids, and
`pnpm typecheck` (both programs) is green.

## 6. Add a `variant` axis to `RadioGroupItem` · fixes RAD-01 · L

**Files** `src/components/radio-group/radio-group.tsx`,
`src/components/radio-group/radio-group.test.tsx`, `test/cases.tsx`,
`showcase/src/registry/form-controls.tsx:174`, `README.md` §9, `.changeset/`

**Change** add `variant` to `RadioGroupItem`'s cva, composing `controlVariants`
from `src/lib/cva-presets.ts` the way Checkbox and Switch do, defaulting to
`solid`. CBAR draws `solid | subtle | outline | inverted` across 576 variants
(`2451:5841`). Decide `inverted` explicitly: it has no counterpart in
`controlVariants`, so either it maps onto an existing treatment or it is recorded
as a deliberate omission — **do not** invent a sixth kit-wide treatment for one
component.

**Watch out** the full consumer-visible checklist applies and an item that stops
at the component is incomplete: registry entry updated, `pnpm props:gen`,
`pnpm consumer:gen`, a changeset, and a `### 9x.` subsection in `README.md`.
Beyond that: the treatment must read from the `--ctl-*` roles the palette class
sets, never a `--ui-*` primitive or a literal, or `pnpm lint` fails the build; a
new case belongs in `test/cases.tsx`, which feeds **both** the axe and the SSR
sweeps; and `size` budgets should be re-read since the component grows.

**Land this last.** Until item 2 lands, the gap this closes is not even visible
on `/parity`, and the axis values should be read off the set `2451:5841` rather
than off the capture's first-match.

**Done when** `/parity` shows RadioGroup's `variant` row as `match` (or as a
`diff` carrying only the recorded `inverted` decision), the full gate is green,
and `README.md` §9 documents the new axis.

---

## Full gate

```bash
pnpm lint && pnpm typecheck && pnpm test:run && pnpm build && pnpm verify && pnpm size
```

If something fails in a way that looks environmental rather than caused by the
change, `/kit-doctor` triages it. Do not bump the version or publish — that is
`/release-kit`.
