| name | ui-verify |
| description | Use when ship-flow needs UI verify coverage for render fidelity, selectors, design tokens, computed CSS, dimensions, or handoff targets. |
UI Verify
Ship-flow built-in utility for fragment-level UI parity. It compares known DOM
selectors against exact getComputedStyle() values in a live browser and writes
a machine-readable report for ship-verify.
Scope
Use this for:
render_fidelity_targets[] generated by ship-design and
generate-ui-verify-spec.sh.
- Static CSS, design-token, pseudo-element, spacing, and dimension checks.
- Regression checks where the selector and expected value are already known.
design-system-parity runtime evidence when the selector and CSS property
are known; ship-verify populates its actual_computed_value evidence field
from the runner report's per-property Actual browser-returned
getComputedStyle() value.
Do not use this as whole-page approval. Fragment-level checks can pass while the
page composition still diverges from design. Whole-page parity is handled by
ship-verify Step 3.6.1 via whole_page_visual_targets[], full-page screenshot
capture, and reference-artifact comparison.
mockup-parity is outside fixed selector/value checks: it compares live DOM
structure against an HTML mockup or design artifact. Ship-verify owns that Done
Criterion judgment; use a DOM structure comparator, e2e/browser report, or
normalized digest rather than this computed-style utility.
Inputs
Run the built-in runner from a project root:
node plugins/ship-flow/skills/ui-verify/bin/run.js <yaml-path> [--no-screenshot] [--bail-on-first-fail]
YAML schema:
version: 1
mapping: spacebridge
auth_account: tenant_admin
title: "War room density tokens"
readiness:
timeout_ms: 10000
poll_ms: 100
setup:
- action: goto
url: "/"
- action: click
selector: ".open-density-panel"
ensure: open
postcondition: ".density-panel"
checks:
- name: "D1 row padding"
selector: ".entity-row"
expect:
paddingTop: "4px"
pseudo:
"::before":
backgroundColor: "rgb(178, 105, 255)"
readiness is optional. The defaults shown above apply when it is omitted, so
existing version 1 YAML remains compatible. A setup click polls its target
within the bounded readiness window instead of racing a cold page, then clicks
exactly once. CSS, XPath, @ref, and text= click locators remain accepted. A
click may override timeout_ms or poll_ms on that step.
Use ensure: open with a CSS postcondition when clicking a toggle should
open a surface idempotently. If the postcondition already exists, the runner
skips the click; otherwise it waits for a successful click and then for the
postcondition. ensure: open without postcondition is a runner error.
Before any computed-style probe, the runner polls the union of all declared
checks[].selector values until every selector exists in the same current
document. goto, login, redirect, and legacy wait: { for: networkidle }
setup declarations use timeout-bounded document or URL state rather than an
unbounded network-idle verdict. Explicit millisecond sleeps remain accepted for
backward compatibility, but the selector-union barrier is the readiness
verdict for checks.
The runner resolves .claude/e2e/mappings/<mapping>.yaml for base_url and
optional auth. It drives agent-browser, probes getComputedStyle(), and
writes .claude/e2e/reports/verify-<yaml-stem>-<timestamp>.md.
Output
Exit codes:
0 — all properties pass.
1 — at least one selector/property check fails.
2 — YAML, mapping, auth, setup, or runner error.
Report rows include selector, expected value, actual value, and pass/fail per
property. A selector not found is a failed check, not a skip.
A readiness timeout prints diagnostic evidence: current URL, missing selectors,
navigation timing/type, and available console and page-error context. Setup,
login, and navigation timeouts are runner errors and exit 2. A check-selector
timeout still writes a failed-check report and exits 1, preserving version 1
missing-selector behavior. Diagnostic collection is best-effort and reports
unavailable browser channels without masking the original timeout.
Boundaries
| Need | Use |
|---|
| Fixed selector × exact computed value | ship-flow:ui-verify |
design-system-parity computed-style evidence | ship-flow:ui-verify when selector/property are known |
mockup-parity DOM structure comparison | ship-verify with a live DOM structure comparator; outside fixed selector/value checks |
| Navigation, state transitions, user actions | e2e-pipeline:e2e-test or Playwright |
| Whole-page visual/design reference parity | ship-verify Step 3.6.1 |
| Unknown selector, CSS forensics, dynamic element discovery | agent-browser directly |
Common Mistakes
- Treating ui-verify PASS as visual approval for the whole page. It is only
fragment-level evidence.
- Using vague expected values such as "purple" or "close to design"; expected
values must match browser-returned strings like
rgb(250, 250, 248).
- Writing exploratory selectors into YAML. Resolve selectors first, then encode
stable checks.