SuperAPI AI Directory

verify-fix-loop

Testing & quality

View repository

Updated 10-15 19:58

About this skill

/verify-fix-loop — Verify-Fix iterative loop (Local Playwright MCP, Headed)

Run a "verify → diagnose → fix → re-verify" loop via local Playwright MCP (headed mode), using snapshot + console + network as evidence each round; on FAIL, fix the code and verify again in the next round. For the Hard cap and HITL trigger timing, see Step 0b (the sole authoritative source in this document; all other places only reference it without restating)。

Differences from existing skills

Skill Purpose When to use
playwright-human-in-the-loop Operational: confirm before each major browser operation Execute one-off flows in an admin interface
verify-fix-loop Repair: loop verification and code fixing UI bug fixing, E2E behavior alignment
verify-evidence-loop Evidence: 4-dimension literature verification of technical claims Evidence checks before high-risk decisions
design Planning: architecture decisions and plan outputs (non-execution) When the problem exceeds the fix scope and needs re-planning, hand off

This skill does not reinvent: bring-your-own-MCP (local Playwright headed), reuse playwright-human-in-the-loop 's checklist-driven verification mode, reuse verify-evidence-loop 's iteration + HITL gate mode. When beyond the fix scope, delegate via HITL option 4 to /design(requires Agent tool)。

Step 0: Pre-checks

0a. Playwright MCP Headed mode confirmation

Headed mode is determined by the Playwright MCP server startup parameter (--headed flag), not a per-call switch.

How to check:

  1. Try calling mcp__playwright__browser_snapshot — if the tool does not exist or returns an error, treat MCP as not started
  2. Ask the user whether the current Playwright MCP server is started in headed mode

If headed is not enabled, prompt to add in ~/.claude.json or the project's .mcp.json :

{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["-y", "@playwright/mcp@latest", "--headed"]
    }
  }
}

After adjusting, you mustrestart Claude Code to let MCP reconnect. Necessity of Headed mode: the user can observe the browser in sync, visually confirm during HITL, and the debug experience is far better than headless.

If MCP is unavailable → stop the flow, ask the user to start it and retry,do not attempt to substitute with Bash。

0b. Scope confirmation (mandatory HITL) — the sole source for hard cap / HITL trigger timing

Use AskUserQuestion to collect four required pieces of information (none may be missing):

About to start the verify-fix iterative loop:

  • Goal: [$ARGUMENTS summary]
  • Estimate: ~5-10k tokens per round,hard cap = 5 rounds(agents drift easily over multiple rounds, hence this cap)
  • After 2 rounds (from Round 3) ask each round whether to continue

Please provide:

  1. Target URL to verify(e.g.:http://localhost:3000/login)
  2. PASS condition(specific, verifiable; e.g.: "after clicking Login, redirect to /dashboard and no error in console")
  3. Modifiable file scope(glob; e.g.:src/components/Login/**、src/api/auth.ts) — used to limit the editing boundary of the Fix phase
  4. Dev server status(already running / needs to be started first / not applicable, see 0c)

If any item is missing → must not enter Step 1.

PASS condition DSL (recommended format)

One criterion per line, type + parameters + expected value. Phase A performs direct mechanical comparison, avoiding the uncertainty of "free text → LLM interpretation."

Type Syntax Example
url url: <regex 或字串> url: /dashboard$
element element: <ref 或 selector> element: button[name="Sign out"]
text text: "<字串>" text: "Welcome, Alice"
not-element not-element: <selector> not-element: .login-form
console console: no-error or no-warning console: no-error
network network: no-4xx / no-5xx / no-failure network: no-failure
eval eval: <JS 表達式(須 truthy)> eval: window.localStorage.getItem('token') !== null

Example:

url: /dashboard$
element: nav [name="User menu"]
console: no-error
network: no-5xx

Free text input → automatically converted to DSL at the end of Step 0b, read back to the user for confirmation before starting.

0c. Dev Server Strategy

Based on the answer to item 4 of 0b:

Status Behavior
Already running Go directly to Step 1;browser_navigate when connection is refused, fall back to 0c HITL, do not auto-start
Needs to be started first AskUserQuestion Ask whether the skill should start it with Bash.Default is not to start, ask the user to open another terminal and run npm run dev then come back
Not applicable(static HTML / production URL) Skip server check

Why not auto-start by default: the dev server is a long-running process; auto-starting will consume token budget continuously tailing stdout; when the skill ends, the lingering process is hard to reclaim; connection retry / port conflict logic is complex and error-prone.

If the user insists on letting the skill start it → Bash(run_in_background=true) + health check after 5 seconds (browser_navigate whether 200). On failure, terminate the process and report. When the skill endsforce promptthe user to kill it manually.

0d. Persistent round log (automatically created)

Before starting Step 1, create the file:.claude/verify-fix-loop/<timestamp>-<slug>.md

  • <timestamp>:YYYYMMDD-HHMMSS
  • <slug>: the last path segment of the URL in kebab-case, truncated to 30 characters (pure query → verify-<random>)
  • At the end of each round, append one ## Round N block (diagnosis, files changed, verdict); modified files are not automatically reverted
  • HITL early exit / cap-exceeded / PASS all write the final report to the same file
  • Purpose: cross-session handoff (with /handoff), PR description citation, retrospective debug trail
  • Not committed to git: recommended .gitignore add .claude/verify-fix-loop/

Step 1: Verify-Fix Loop

Execute Phase A → B → C → D round by round until PASS or until the hard cap from Step 0b is reached; starting from round 3, pass through the HITL Gate of Step 2 before entering Phase A.

Phase A: Verify

Verify each PASS condition item by item (checklist-driven, better than free-text judgment):

  1. browser_navigate(target_url) — go to the target page
  2. browser_wait_for(...) — wait for the ready selector / text according to the PASS condition
  3. Perform operations according to the PASS condition (click / fill / select, etc.)
  4. browser_snapshot() — obtain the ARIA tree
  5. browser_console_messages() — collect all console messages
  6. browser_network_requests() — collect all network requests

Judge each PASS condition item by item (corresponding one-to-one with the Step 0b PASS condition DSL):

DSL type Verification item Source PASS condition
url: URL matches expectation snapshot.url String or regex match
element: Expected element appears snapshot ARIA Contains expected ref / selector
not-element: Expected element does not exist snapshot ARIA Does not contain specified selector
text: Expected text appears snapshot ARIA(accessible name / textContent) Contains specified string
console: No console error / warning browser_console_messages No level: error(or warning)
network: No failed network requests browser_network_requests No 4xx / 5xx / failed
eval: Custom condition (DOM / state) browser_evaluate Expression truthy

All PASS → exit success;Any FAIL → enter Phase B.

Phase B: Diagnose

Extract root cause from failure evidence, output fixed format:

Round {N} Diagnosis
- Failed criteria:
  - [criterion 1]
  - [criterion 2]
- Evidence:
  - snapshot excerpt: <關鍵節點>
  - console error: <stack trace 首行>
  - network failure: <method> <url> → <status>
- Suspected root cause: <一句話>
- Suspected files (within allowed_paths):
  - <path 1>
  - <path 2>

If suspected files exceed allowed_paths → mark [OUT-OF-SCOPE],do not edit directly, leave for HITL gate to remind user to expand scope.

Phase C: Fix

Edit according to diagnosisOnly within allowed_paths files:

  • Use Read → Edit / Write, minimal change principle
  • Record file diff summary in round_log before and after modification (+N -M lines)
  • Target only 1 root cause at a time; do not incidentally do unrelated cleanup

Hard prohibitions:

Prohibited behavior Reason
Modify tests / spec to make assert looser "Passing for the sake of passing" is not a real fix
Modify the PASS condition itself Same as above, pollutes the verification loop
Swallow error directly in catch Hides the problem, next round may still FAIL but console becomes clean
Cross-scope file deletion / architecture change Belongs to /design scope
Hardcode value to bypass Treats the symptom, not the root cause

Phase D: Wait for Reload

  • HMR scenario:browser_wait_for(time=2) → browser_navigate(target_url) Force reload
  • Requires build / restart: use AskUserQuestion to ask the user whether ready, do not automatically run build (to avoid long occupancy)
  • SSR / Next.js: follow project conventions (hot reload is usually sufficient; if server component changes are involved, restart is required)

Step 2: HITL Gate (trigger timing see Step 0b: every round starting from round 3)

Before entering Phase A use AskUserQuestion:

Still not passing verification after Round {N-1} ends.

Round Log:

# Verdict Diagnosis summary Files Changed
1 FAIL Login button onClick missing src/Login.tsx
2 FAIL Token header not sent on /api/me src/api/client.ts

Currently blocking PASS conditions:

  • {failed criterion 1}
  • {failed criterion 2}

Options:

  1. Continue — run 1 more round (maximum up to round 5 hard cap)
  2. Stop and report — output current state, hand over to human
  3. Change strategy — describe new direction then re-enter Step 0b
  4. Hand off to /design — problem exceeds fix scope, needs architecture replanning

When hard cap is reached, even if "Continue" is selected, force stop and output cap-exceeded report.

Handling when option 4 is selected: call /design and pass current round_log and failure evidence as context, to avoid /design starting from scratch.

Step 3: Final Report

Regardless of success / early exit / reaching cap, final output uses unified format:

## Verify-Fix Loop Report

**Status:** PASS | EARLY-EXIT | CAP-EXCEEDED
**Rounds:** N / 5
**Target:** {target_url}
**Allowed paths:** {glob list}

### PASS Criteria
- [x] 預期元素出現
- [x] URL 正確
- [ ] 無 console error  ← 仍 FAIL(早退或 cap-exceeded 時)

### Round Log
| # | Verdict | Diagnosis | Files Changed |
|---|---|---|---|
| 1 | FAIL | Login button missing onClick | src/Login.tsx (+5 -2) |
| 2 | FAIL | API returns 401, token header missing | src/api/client.ts (+3 -0) |
| 3 | PASS | — | — |

### Files Modified(累積)
- src/Login.tsx
- src/api/client.ts

### Next Steps
- {若 PASS:建議跑 lint / test / `/pr`}
- {若 EARLY-EXIT:列出選擇的選項與下一步}
- {若 CAP-EXCEEDED:強烈建議轉 /design 重新規劃,附 round_log}

See Also

  • /playwright-human-in-the-loop — single-operation browser automation (non-loop)
  • /design — architecture replanning when the problem exceeds fix scope
  • /verify-evidence-loop — Evidence verification of technical claims (not code fixes)
  • /pr — Commit + PR automation after successful loop