Skip to content

Verify UI

Ali Sadeghi edited this page May 18, 2026 · 2 revisions

Verify UI Skill

Verify a feature's UI implementation matches the Stitch design at the token level. Produces a two-source token audit (HTML ↔ Code) overlaid with an X-component default-render trap checklist, plus an X-components compliance check.

Invocation:

/verify-ui myfeature

Prerequisites

  • Feature implemented and build passing.
  • .claude/docs/_project/stitch-project.json contains a features[{featurename}] entry.

If either prerequisite fails, the skill stops and tells you.

What It Checks

Source Purpose
HTML (Stitch download, persisted in extracted/) The design ground truth at audit time
Code (feature/{name}/src/commonMain/.../presentation/ui/) What's actually implemented
X-Components Catalog (.claude/skills/_shared/X_COMPONENTS_CATALOG.md) Default-render behavior overlay (min sizes, hardcoded paddings, default colors)

The audit is HTML ↔ Code, with the catalog as a third source for default-render checks. The implementation blueprint is not re-read as a token source — by the time verify-ui runs, the blueprint already drove the code. The single exception is the blueprint's Component Overrides table (Step 5.3.5), which captures per-feature overrides that would otherwise require a costly full sweep.

Workflow

Preflight → Acquire HTML (reuse or download) → Token Extraction → Catalog →
Token Audit → Trap Checklist → Component Overrides Check → X-Components Check →
Present Results → Handle Mismatches → Cleanup

1. Acquire HTML

Reuse extracted/stitch_{state}.html when present. Only download when missing or empty. Stitch URLs are single-use, so downloads happen sequentially (no parallel) to avoid racing the URL semantics.

2. Token Extraction

python3 .claude/skills/_shared/extract_tokens.py walks every DOM element and emits an inventory with deterministic Tailwind → dp/sp/color conversions plus tailwind-config overrides and global <style> rules. Reuse tokens_{state}.md when present.

3. Token Audit (mismatches only)

For every visual element in the inventory, convert each Tailwind class to its dp/sp/color/modifier value, find the matching code, and emit one block per mismatch using the effective rendered value rule:

effective rendered value = declared parameter, then overridden/constrained by X-component internals

For example, XIconButton without an explicit colors = parameter renders a visible surface-colored circle — so the Code column shows "visible surface background", not "no color declared".

4. Trap Checklist (seven catalog-driven traps)

# Trap Trigger
1 XIconButton default containerColor = surface call without explicit colors, HTML has no bg-*
2 XTextField defaultMinSize(280dp × 48dp) HTML container narrower / shorter
3 XTextField extra padding(top = 8.dp) when label != null label present
4 XTopAppBar always center-aligned title HTML title at ml-4 (left-aligned)
5 XDialog always 90% width HTML mockup uses different fraction
6 XPrimaryScrollableTabRow no divider by default HTML shows divider
7 XRadioButton unselected color = primary HTML shows outline-coloured ring

5. Component Overrides Check (5.3.5)

Reads only the ### Component Overrides table inside the blueprint's ## Pre-Implementation Contract. For each row (Component | Property | HTML Value | X-component Default | Override Required), checks the implementation and emits CRITICAL blocks for any missing override. Silent pass when the override is present. Silently skipped if the blueprint or table is missing.

6. X-Components Compliance

Forbidden imports flagged as CRITICAL:

import androidx.compose.material3.*   # any M3 component
import coil3.compose.AsyncImage       # use AsyncImage from :core:designsystem

MaterialTheme.colorScheme and MaterialTheme.typography are allowedXTheme wraps MaterialTheme. Only component imports are forbidden.

Severity

Severity Criteria
Critical Spacing ≥ 4dp off, wrong color role, missing component, wrong font size/weight, wrong corner radius, wrong icon size, wrong border, any trap caught (5.3), any missing override (5.3.5)
Minor Spacing 1–3dp off, shadow omitted, letter-spacing off, decorative detail, design-system-authoritative trap (centre-aligned title, 90% dialog width)
Data-only Different mock text/values — ignored

Output

File Content
.claude/docs/{featurename}/designs/{featurename}_audit.md Mismatch blocks only, no OK rows
stitch-project.jsonfeatures[{featurename}].verification { verified, verifiedAt, auditReport, extractedSources, xComponentsCompliant, criticalIssues, attempts }

Handling Mismatches

Critical issues: the skill tells you to run:

/modifying-kmp-feature {featurename} fix all UI audit issues based on @.claude/docs/{featurename}/designs/{featurename}_audit.md

verify-ui does not invoke /modifying-kmp-feature itself — you control the pipeline.

Only minor mismatches: offered as "Accept" (recommended) or "Fix all".

Why the Blueprint Isn't an Audit Source

The blueprint was previously a fourth source. It got dropped for three reasons:

  1. Duplicated the HTML — every token in the blueprint is derivable from the HTML.
  2. Defined verdicts that never firedBLUEPRINT MISMATCH always produced the same action as CODE MISMATCH.
  3. Expensive — ~5–7K tokens per run for no extra signal.

The Component Overrides table (5.3.5) is the one exception — a pre-curated catalog sweep that costs ~N rows of work (typically 0–5) instead of hundreds. See .claude/skills/verify-ui/RATIONALE.md for the full reasoning.

See Also

Back to Skills

Clone this wiki locally