Purpose: a gate: 'binding' clean pass (real vision comparison, --judge live) is the ONLY result that may drop a surface off the verifier's Step 9 human-verification list; a real defect lands as a gaps: entry with screenshot evidence regardless of gate. The default gate: 'advisory' path (offline label-echo, no network) is a labels lookup for dogfooding and fast iteration — it surfaces defects it can detect from the label, but a clean advisory pass NEVER clears human verification (aodex#485: an unjudged/label-only pass must not be mistaken for a machine-verified one). Standalone-invocable for dogfooding a single surface.
Output: per-state *.judge.json + ui-eval-report.json under .planning/objectives/<obj>/evidence/ui_eval/, plus a verdict rollup.
The scoring engine is already shipped (plugins/devflow/devflow/bin/lib/flutter-ui-eval.cjs) with the
df-ui-evaluator model profile and the df-tools arms
verify flutter-ui-eval <manifest> [--raw] [--judge live|labels] / flutter-ui eval <manifest> [--raw] [--judge live|labels].
Both emit a scoreRun rollup
{ verdict: 'pass'|'pass-with-reviews'|'fail', gate: 'binding'|'advisory', counts, reviews[], fails[], unjudged[], states[] }.
gate is the run's STANDING, not its outcome: 'binding' ONLY when invoked with --judge live
(a real Anthropic vision comparison per state); 'advisory' on the default (no --judge, or
--judge labels) offline label-echo path (network:false) — a labels lookup, never a visual gate,
regardless of how clean its verdict is. An unrecognised --judge value is rejected with a usage
error rather than silently falling through to the offline path. This skill consumes that engine;
it does not re-implement scoring and does not pick a vision model id.
@.planning/STATE.md @.planning/ROADMAP.md
For deep judgement (capture + score + evidence write + ≤300-token rollup), spawn the ui-evaluator
agent via the Task tool with the resolved manifest path; otherwise run the workflow steps inline for a
quick single-surface dogfood.