Skip to content

Verify UI

Ali Sadeghi edited this page May 28, 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

  • Python 3 on PATH (preflight runs python3 --version; used by extract_tokens.py). Missing → the skill stops with install instructions.
  • Feature implemented and build passing.
  • .claude/docs/_project/stitch-project.json contains a features[{featurename}] entry.

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

Which states get audited

The audit always covers success. Loading / Failed / Empty are audited only when features[{featurename}].states.{state} == true — i.e. only the states selected during design. Skipped states are not downloaded, extracted, or audited. (For legacy entries without a states field, it's derived from observable state: loading/failed true, empty true only if an emptyScreenId exists.)

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.4), 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 →
Icons Manifest Audit → Images Manifest Audit → 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.4)

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. Icons Manifest Audit (5.7)

Runs only when icons.json exists and blueprintConsumed == true (design-aware feature). For each entry in the icons manifest it checks:

Check Severity
XML file exists at entry.drawable_path CRITICAL if missing
Code references entry.res_reference (painterResource(...)) MINOR if absent
Chrome-scope icons use DesignSystemResources.drawable.* (not feature-local Res.drawable.*) CRITICAL on wrong scope
No deprecated import androidx.compose.material.icons.* (use XIcon(painter = …)) CRITICAL
Orphan XMLs not in any manifest and not referenced by any .kt MINOR

7. Images Manifest Audit (5.8)

Same structure as the icons audit, for raster assets in images.json: file presence (CRITICAL), code reference (MINOR), wrong scope (CRITICAL), and one extra check — Stitch CDN URL used with AsyncImage (model = "https://lh3.googleusercontent.com/aida-public/…") is CRITICAL: bundled design assets must be Image(painter = painterResource(...)). Runtime-data AsyncImage(model = uiModel.field) is not flagged. Orphan images → MINOR.

8. 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.4), any manifest CRITICAL (missing asset, wrong scope, deprecated material-icons import, Stitch-CDN AsyncImage)
Minor Spacing 1–3dp off, shadow omitted, letter-spacing off, decorative detail, design-system-authoritative trap (centre-aligned title, 90% dialog width), manifest MINORs (declared-but-unreferenced asset, orphan XML/image)
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.4) 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