-
Notifications
You must be signed in to change notification settings - Fork 0
Verify UI
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- Feature implemented and build passing.
-
.claude/docs/_project/stitch-project.jsoncontains afeatures[{featurename}]entry.
If either prerequisite fails, the skill stops and tells you.
| 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.
Preflight → Acquire HTML (reuse or download) → Token Extraction → Catalog →
Token Audit → Trap Checklist → Component Overrides Check → X-Components Check →
Present Results → Handle Mismatches → Cleanup
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.
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.
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".
| # | 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 |
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.
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 allowed — XTheme wraps MaterialTheme. Only component imports are forbidden.
| 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 |
| File | Content |
|---|---|
.claude/docs/{featurename}/designs/{featurename}_audit.md |
Mismatch blocks only, no OK rows |
stitch-project.json → features[{featurename}].verification
|
{ verified, verifiedAt, auditReport, extractedSources, xComponentsCompliant, criticalIssues, attempts } |
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".
The blueprint was previously a fourth source. It got dropped for three reasons:
- Duplicated the HTML — every token in the blueprint is derivable from the HTML.
-
Defined verdicts that never fired —
BLUEPRINT MISMATCHalways produced the same action asCODE MISMATCH. - 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.
- UI-Designer — where the HTML and blueprint come from
- Design-Pipeline — full pipeline overview
- Using-Design-System — the X-components rules verify-ui enforces
Back to Skills