| name | jat-verify |
| description | Escalatory browser verification - open the app in a real browser and test it. Two modes - builder-verify (test the feature you just built) and cold-review (fresh-eyes reviewer pass over a whole surface or site). Use after "READY FOR REVIEW", before shipping a preview/demo to a human, or when asked to "actually test this" / "review this like a stranger". |
| metadata | {"author":"jat","version":"2.0"} |
/skill:jat-verify - Browser Verification
Test work in a real browser. Two modes:
| Mode | When | Output |
|---|
| builder-verify | You just built a feature; prove it works end-to-end | pass/fail checklist + screenshots |
| cold-review | A surface/site is about to be shown to a human (customer preview, demo, contest, launch) | severity-ranked findings report |
/skill:jat-verify # builder-verify, auto-detect what to test
/skill:jat-verify /tasks # builder-verify a specific path
/skill:jat-verify --cold https://site.tld # cold-review an entire experience
NOT for static checks (tests, lint, types) — those live in /skill:jat-complete.
Browser Tooling (both modes)
Attach, don't relaunch. A persistent browser runs on CDP port 9222. NEVER run browser-start.js --port 9222 (it kills the persistent browser). Preferred, in order:
- chrome-devtools MCP tools (
mcp__chrome-devtools__*) — available in most sessions; use new_page, navigate_page, take_screenshot, take_snapshot, evaluate_script, list_console_messages, emulate.
browser-*.js CLI tools (~/.local/bin/) — they attach to :9222 by default. Only use browser-start.js (no --port) for a throwaway instance.
Key techniques:
- Fresh state:
new_page with isolatedContext: "review-<id>" gives clean cookies/storage — mandatory for cold-review, useful for auth flows.
- Console errors:
list_console_messages with types: ["error","warn"] (+ includePreservedMessages: true after multi-page flows). Do NOT monkeypatch console.error.
- Mobile:
emulate with viewport: "390x844x2,mobile,touch" (window resize fails on maximized windows). Clear with empty viewport string.
- Timing: wrap actions in
evaluate_script polling loops and record elapsed ms — "felt slow" needs a number.
Mode 1: builder-verify
- Determine target — URL, feature, success criteria from your recent work. Ask only if genuinely ambiguous.
- Navigate + screenshot the initial state.
- Operate the feature — click/fill/submit the real UI (snapshot → click by uid, or
evaluate_script). Screenshot after each significant action.
- Check console (
list_console_messages, errors + warnings). Note pre-existing vs new.
- Report pass/fail checklist + screenshot paths. Failed → fix, re-verify, then return to 🔍 READY FOR REVIEW.
Mode 2: cold-review (fresh-eyes reviewer pass)
Role-play the coldest plausible visitor (a customer prospect, a contest judge, a new hire). You are NOT the builder — be a skeptic, try to break it. The value is what a stranger trips on that the builders can no longer see.
Rules of engagement:
- Blank slate: isolated browser context, no reading the code first. Discover the experience the way a visitor does.
- The three questions, at every surface: (a) What am I looking at? (b) What am I supposed to do here? (c) After I do it, what happens and where do I go next? Any surface that fails one of these is a finding.
- Operate everything. Every primary CTA gets clicked, every flow completed for real. If it generates, generate. If it uploads, upload. A button that appears to do nothing is a finding even if code says it works.
- Follow every outbound link and promised artifact (docs, GitHub, "read more", download). A 404 on a link the experience depends on is a blocker. (Real case: a contest demo's README link — the judged criterion — 404'd for signed-out visitors.)
- Hunt the promised moments. Anything the copy promises ("watch it refuse", "see X happen") must be reachable by following the on-screen guidance alone. If you need expert knowledge or N extra steps to trigger it, the demo's money moment is buried — major finding.
- Adversarial inputs: bare domains, garbage input, nonexistent resources, double-clicks, back-button. Clean failure = pass; dead spinner/blank = finding.
- Time everything that runs async. Report dead spinners, hangs, and anything > a few seconds with no progress feedback.
- Mobile pass (~390px emulation) over each major surface: horizontal overflow, tap targets, legibility.
- Console sweep on every page visited.
- Screenshot the notably good AND the notably broken.
Report format:
COLD REVIEW: <target>
1. First impression — honest 5-second and 30-second reactions
2. Walk-through, surface by surface — three questions answered; what worked; what confused
3. Findings ranked: BLOCKERS (visitor bounces) → MAJOR (money moment lost) → PAPERCUTS
4. Strengths — what specifically lands (so fixes don't break it)
5. Screenshot index
Be blunt; flattery is useless. If it's great, say what specifically lands.
The loop — cold-review is step 1 of 3:
cold-review (reviewer) → fix wave (builder) → RE-VERIFY (same reviewer)
The re-verify is not optional: run the same E2E path again and hunt second-order leaks — the layer below the fixes. (Real cases: after a theming fix, outtake rows still carried the old vertical; a {{first_name}} fallback rendered a literal "there"; stale cache entries from before the fix silently bypassed it.) Fixes introduce their own disconnects; only the same cold path finds them.
Signals: in a JAT task session, emit jat-signal review with findings (ranked) before presenting; blockers/major items go in doNow/suggestedTasks.
After Verification
- builder-verify passed → 🔍 READY FOR REVIEW; user can
/jat:complete.
- builder-verify failed → fix, re-verify, then review state.
- cold-review → deliver the report; do NOT fix unless asked (the deliverable is the reviewer's perspective, and the builder may be mid-flight on the same files).