{"id":"a8ecfb3b-6e93-48cc-89a2-8113a4352070","shortId":"JQvQh5","kind":"skill","title":"qa","tagline":"Systematically QA test a web application and fix bugs found. Runs QA testing,\nthen iteratively fixes bugs in source code, committing each fix atomically and\nre-verifying. Use when asked to \"qa\", \"QA\", \"test this site\", \"find bugs\",\n\"test and fix\", or \"fix what's broken\".\nProactiv","description":"## Preamble\n\n```bash\neval \"$(~/.vibestack/bin/vibe-slug 2>/dev/null)\" 2>/dev/null || SLUG=\"unknown\"\n_LEARN_FILE=\"${VIBESTACK_HOME:-$HOME/.vibestack}/projects/${SLUG:-unknown}/learnings.jsonl\"\nif [ -f \"$_LEARN_FILE\" ]; then\n  _LEARN_COUNT=$(wc -l < \"$_LEARN_FILE\" 2>/dev/null | tr -d ' ')\n  echo \"LEARNINGS: $_LEARN_COUNT entries loaded\"\n  if [ \"$_LEARN_COUNT\" -gt 5 ] 2>/dev/null; then\n    ~/.vibestack/bin/vibe-learnings-search --limit 5 2>/dev/null || true\n  fi\nelse\n  echo \"LEARNINGS: none yet\"\nfi\n```\n\n## Step 0: Detect platform and base branch\n\nFirst, detect the git hosting platform from the remote URL:\n\n```bash\ngit remote get-url origin 2>/dev/null\n```\n\n- If the URL contains \"github.com\" → platform is **GitHub**\n- If the URL contains \"gitlab\" → platform is **GitLab**\n- Otherwise, check CLI availability:\n  - `gh auth status 2>/dev/null` succeeds → platform is **GitHub** (covers GitHub Enterprise)\n  - `glab auth status 2>/dev/null` succeeds → platform is **GitLab** (covers self-hosted)\n  - Neither → **unknown** (use git-native commands only)\n\nDetermine which branch this PR/MR targets, or the repo's default branch if no\nPR/MR exists. Use the result as \"the base branch\" in all subsequent steps.\n\n**If GitHub:**\n1. `gh pr view --json baseRefName -q .baseRefName` — if succeeds, use it\n2. `gh repo view --json defaultBranchRef -q .defaultBranchRef.name` — if succeeds, use it\n\n**If GitLab:**\n1. `glab mr view -F json 2>/dev/null` and extract the `target_branch` field — if succeeds, use it\n2. `glab repo view -F json 2>/dev/null` and extract the `default_branch` field — if succeeds, use it\n\n**Git-native fallback (if unknown platform, or CLI commands fail):**\n1. `git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||'`\n2. If that fails: `git rev-parse --verify origin/main 2>/dev/null` → use `main`\n3. If that fails: `git rev-parse --verify origin/master 2>/dev/null` → use `master`\n\nIf all fail, fall back to `main`.\n\nPrint the detected base branch name. In every subsequent `git diff`, `git log`,\n`git fetch`, `git merge`, and PR/MR creation command, substitute the detected\nbranch name wherever the instructions say \"the base branch\" or `<default>`.\n\n---\n\n\n\n# /qa: Test → Fix → Verify\n\nYou are a QA engineer AND a bug-fix engineer. Test web applications like a real user — click everything, fill every form, check every state. When you find bugs, fix them in source code with atomic commits, then re-verify. Produce a structured report with before/after evidence.\n\n## Setup\n\n**Parse the user's request for these parameters:**\n\n| Parameter | Default | Override example |\n|-----------|---------|-----------------:|\n| Target URL | (auto-detect or required) | `https://myapp.com`, `http://localhost:3000` |\n| Tier | Standard | `--quick`, `--exhaustive` |\n| Mode | full | `--regression .vibestack/qa-reports/baseline.json` |\n| Output dir | `.vibestack/qa-reports/` | `Output to /tmp/qa` |\n| Scope | Full app (or diff-scoped) | `Focus on the billing page` |\n| Auth | None | `Sign in to user@example.com`, `Import cookies from cookies.json` |\n\n**Tiers determine which issues get fixed:**\n- **Quick:** Fix critical + high severity only\n- **Standard:** + medium severity (default)\n- **Exhaustive:** + low/cosmetic severity\n\n**If no URL is given and you're on a feature branch:** Automatically enter **diff-aware mode** (see Modes below). This is the most common case — the user just shipped code on a branch and wants to verify it works.\n\n**CDP mode detection:** Before starting, check if the browse server is connected to the user's real browser:\n```bash\n$B status 2>/dev/null | grep -q \"Mode: cdp\" && echo \"CDP_MODE=true\" || echo \"CDP_MODE=false\"\n```\nIf `CDP_MODE=true`: skip cookie import prompts (the real browser already has cookies), skip user-agent overrides (real browser has real user-agent), and skip headless detection workarounds. The user's real auth sessions are already available.\n\n**Check for clean working tree:**\n\n```bash\ngit status --porcelain\n```\n\nIf the output is non-empty (working tree is dirty), **STOP** and use AskUserQuestion:\n\n\"Your working tree has uncommitted changes. /qa needs a clean tree so each bug fix gets its own atomic commit.\"\n\n- A) Commit my changes — commit all current changes with a descriptive message, then start QA\n- B) Stash my changes — stash, run QA, pop the stash after\n- C) Abort — I'll clean up manually\n\nRECOMMENDATION: Choose A because uncommitted work should be preserved as a commit before QA adds its own fix commits.\n\nAfter the user chooses, execute their choice (commit or stash), then continue with setup.\n\n**Find the browse binary:**\n\n## SETUP\n\n```bash\n# vibestack does not include a browse daemon.\necho \"BROWSE_NOT_AVAILABLE\"\n```\n\nIf `BROWSE_NOT_AVAILABLE`: skip all `$B` commands and use text-only fallbacks (curl, open, direct HTTP checks).\n\n## Test Framework Bootstrap\n\n**Detect existing test framework and project runtime:**\n\n```bash\nsetopt +o nomatch 2>/dev/null || true  # zsh compat\n# Detect project runtime\n[ -f Gemfile ] && echo \"RUNTIME:ruby\"\n[ -f package.json ] && echo \"RUNTIME:node\"\n[ -f requirements.txt ] || [ -f pyproject.toml ] && echo \"RUNTIME:python\"\n[ -f go.mod ] && echo \"RUNTIME:go\"\n[ -f Cargo.toml ] && echo \"RUNTIME:rust\"\n[ -f composer.json ] && echo \"RUNTIME:php\"\n[ -f mix.exs ] && echo \"RUNTIME:elixir\"\n# Detect sub-frameworks\n[ -f Gemfile ] && grep -q \"rails\" Gemfile 2>/dev/null && echo \"FRAMEWORK:rails\"\n[ -f package.json ] && grep -q '\"next\"' package.json 2>/dev/null && echo \"FRAMEWORK:nextjs\"\n# Check for existing test infrastructure\nls jest.config.* vitest.config.* playwright.config.* .rspec pytest.ini pyproject.toml phpunit.xml 2>/dev/null\nls -d test/ tests/ spec/ __tests__/ cypress/ e2e/ 2>/dev/null\n# Check opt-out marker\n[ -f .vibestack/no-test-bootstrap ] && echo \"BOOTSTRAP_DECLINED\"\n```\n\n**If test framework detected** (config files or test directories found):\nPrint \"Test framework detected: {name} ({N} existing tests). Skipping bootstrap.\"\nRead 2-3 existing test files to learn conventions (naming, imports, assertion style, setup patterns).\nStore conventions as prose context for use in Phase 8e.5 or Step 7. **Skip the rest of bootstrap.**\n\n**If BOOTSTRAP_DECLINED** appears: Print \"Test bootstrap previously declined — skipping.\" **Skip the rest of bootstrap.**\n\n**If NO runtime detected** (no config files found): Use AskUserQuestion:\n\"I couldn't detect your project's language. What runtime are you using?\"\nOptions: A) Node.js/TypeScript B) Ruby/Rails C) Python D) Go E) Rust F) PHP G) Elixir H) This project doesn't need tests.\nIf user picks H → write `.vibestack/no-test-bootstrap` and continue without tests.\n\n**If runtime detected but no test framework — bootstrap:**\n\n### B2. Research best practices\n\nUse WebSearch to find current best practices for the detected runtime:\n- `\"[runtime] best test framework 2025 2026\"`\n- `\"[framework A] vs [framework B] comparison\"`\n\nIf WebSearch is unavailable, use this built-in knowledge table:\n\n| Runtime | Primary recommendation | Alternative |\n|---------|----------------------|-------------|\n| Ruby/Rails | minitest + fixtures + capybara | rspec + factory_bot + shoulda-matchers |\n| Node.js | vitest + @testing-library | jest + @testing-library |\n| Next.js | vitest + @testing-library/react + playwright | jest + cypress |\n| Python | pytest + pytest-cov | unittest |\n| Go | stdlib testing + testify | stdlib only |\n| Rust | cargo test (built-in) + mockall | — |\n| PHP | phpunit + mockery | pest |\n| Elixir | ExUnit (built-in) + ex_machina | — |\n\n### B3. Framework selection\n\nUse AskUserQuestion:\n\"I detected this is a [Runtime/Framework] project with no test framework. I researched current best practices. Here are the options:\nA) [Primary] — [rationale]. Includes: [packages]. Supports: unit, integration, smoke, e2e\nB) [Alternative] — [rationale]. Includes: [packages]\nC) Skip — don't set up testing right now\nRECOMMENDATION: Choose A because [reason based on project context]\"\n\nIf user picks C → write `.vibestack/no-test-bootstrap`. Tell user: \"If you change your mind later, delete `.vibestack/no-test-bootstrap` and re-run.\" Continue without tests.\n\nIf multiple runtimes detected (monorepo) → ask which runtime to set up first, with option to do both sequentially.\n\n### B4. Install and configure\n\n1. Install the chosen packages (npm/bun/gem/pip/etc.)\n2. Create minimal config file\n3. Create directory structure (test/, spec/, etc.)\n4. Create one example test matching the project's code to verify setup works\n\nIf package installation fails → debug once. If still failing → revert with `git checkout -- package.json package-lock.json` (or equivalent for the runtime). Warn user and continue without tests.\n\n### B4.5. First real tests\n\nGenerate 3-5 real tests for existing code:\n\n1. **Find recently changed files:** `git log --since=30.days --name-only --format=\"\" | sort | uniq -c | sort -rn | head -10`\n2. **Prioritize by risk:** Error handlers > business logic with conditionals > API endpoints > pure functions\n3. **For each file:** Write one test that tests real behavior with meaningful assertions. Never `expect(x).toBeDefined()` — test what the code DOES.\n4. Run each test. Passes → keep. Fails → fix once. Still fails → delete silently.\n5. Generate at least 1 test, cap at 5.\n\nNever import secrets, API keys, or credentials in test files. Use environment variables or test fixtures.\n\n### B5. Verify\n\n```bash\n# Run the full test suite to confirm everything works\n{detected test command}\n```\n\nIf tests fail → debug once. If still failing → revert all bootstrap changes and warn user.\n\n### B5.5. CI/CD pipeline\n\n```bash\n# Check CI provider\nls -d .github/ 2>/dev/null && echo \"CI:github\"\nls .gitlab-ci.yml .circleci/ bitrise.yml 2>/dev/null\n```\n\nIf `.github/` exists (or no CI detected — default to GitHub Actions):\nCreate `.github/workflows/test.yml` with:\n- `runs-on: ubuntu-latest`\n- Appropriate setup action for the runtime (setup-node, setup-ruby, setup-python, etc.)\n- The same test command verified in B5\n- Trigger: push + pull_request\n\nIf non-GitHub CI detected → skip CI generation with note: \"Detected {provider} — CI pipeline generation supports GitHub Actions only. Add test step to your existing pipeline manually.\"\n\n### B6. Create TESTING.md\n\nFirst check: If TESTING.md already exists → read it and update/append rather than overwriting. Never destroy existing content.\n\nWrite TESTING.md with:\n- Philosophy: \"100% test coverage is the key to great vibe coding. Tests let you move fast, trust your instincts, and ship with confidence — without them, vibe coding is just yolo coding. With tests, it's a superpower.\"\n- Framework name and version\n- How to run tests (the verified command from B5)\n- Test layers: Unit tests (what, where, when), Integration tests, Smoke tests, E2E tests\n- Conventions: file naming, assertion style, setup/teardown patterns\n\n### B7. Update CLAUDE.md\n\nFirst check: If CLAUDE.md already has a `## Testing` section → skip. Don't duplicate.\n\nAppend a `## Testing` section:\n- Run command and test directory\n- Reference to TESTING.md\n- Test expectations:\n  - 100% test coverage is the goal — tests make vibe coding safe\n  - When writing new functions, write a corresponding test\n  - When fixing a bug, write a regression test\n  - When adding error handling, write a test that triggers the error\n  - When adding a conditional (if/else, switch), write tests for BOTH paths\n  - Never commit code that makes existing tests fail\n\n### B8. Commit\n\n```bash\ngit status --porcelain\n```\n\nOnly commit if there are changes. Stage all bootstrap files (config, test directory, TESTING.md, CLAUDE.md, .github/workflows/test.yml if created):\n`git commit -m \"chore: bootstrap test framework ({framework name})\"`\n\n---\n\n**Create output directories:**\n\n```bash\nmkdir -p .vibestack/qa-reports/screenshots\n```\n\n---\n\n{{include lib/snippets/prior-learnings.md}}\n## Test Plan Context\n\nBefore falling back to git diff heuristics, check for richer test plan sources:\n\n1. **Project-scoped test plans:** Check `~/.vibestack/projects/` for recent `*-test-plan-*.md` files for this repo\n   ```bash\n   setopt +o nomatch 2>/dev/null || true  # zsh compat\n   eval \"$(~/.vibestack/bin/vibe-slug 2>/dev/null)\"\n   ls -t ~/.vibestack/projects/$SLUG/*-test-plan-*.md 2>/dev/null | head -1\n   ```\n2. **Conversation context:** Check if a prior `/plan-eng-review` or `/plan-ceo-review` produced test plan output in this conversation\n3. **Use whichever source is richer.** Fall back to git diff analysis only if neither is available.\n\n---\n\n## Phases 1-6: QA Baseline\n\n## Modes\n\n### Diff-aware (automatic when on a feature branch with no URL)\n\nThis is the **primary mode** for developers verifying their work. When the user says `/qa` without a URL and the repo is on a feature branch, automatically:\n\n1. **Analyze the branch diff** to understand what changed:\n   ```bash\n   git diff main...HEAD --name-only\n   git log main..HEAD --oneline\n   ```\n\n2. **Identify affected pages/routes** from the changed files:\n   - Controller/route files → which URL paths they serve\n   - View/template/component files → which pages render them\n   - Model/service files → which pages use those models (check controllers that reference them)\n   - CSS/style files → which pages include those stylesheets\n   - API endpoints → test them directly with `$B js \"await fetch('/api/...')\"`\n   - Static pages (markdown, HTML) → navigate to them directly\n\n   **If no obvious pages/routes are identified from the diff:** Do not skip browser testing. The user invoked /qa because they want browser-based verification. Fall back to Quick mode — navigate to the homepage, follow the top 5 navigation targets, check console for errors, and test any interactive elements found. Backend, config, and infrastructure changes affect app behavior — always verify the app still works.\n\n3. **Detect the running app** — check common local dev ports:\n   ```bash\n   $B goto http://localhost:3000 2>/dev/null && echo \"Found app on :3000\" || \\\n   $B goto http://localhost:4000 2>/dev/null && echo \"Found app on :4000\" || \\\n   $B goto http://localhost:8080 2>/dev/null && echo \"Found app on :8080\"\n   ```\n   If no local app is found, check for a staging/preview URL in the PR or environment. If nothing works, ask the user for the URL.\n\n4. **Test each affected page/route:**\n   - Navigate to the page\n   - Take a screenshot\n   - Check console for errors\n   - If the change was interactive (forms, buttons, flows), test the interaction end-to-end\n   - Use `snapshot -D` before and after actions to verify the change had the expected effect\n\n5. **Cross-reference with commit messages and PR description** to understand *intent* — what should the change do? Verify it actually does that.\n\n6. **Check TODOS.md** (if it exists) for known bugs or issues related to the changed files. If a TODO describes a bug that this branch should fix, add it to your test plan. If you find a new bug during QA that isn't in TODOS.md, note it in the report.\n\n7. **Report findings** scoped to the branch changes:\n   - \"Changes tested: N pages/routes affected by this branch\"\n   - For each: does it work? Screenshot evidence.\n   - Any regressions on adjacent pages?\n\n**If the user provides a URL with diff-aware mode:** Use that URL as the base but still scope testing to the changed files.\n\n### Full (default when URL is provided)\nSystematic exploration. Visit every reachable page. Document 5-10 well-evidenced issues. Produce health score. Takes 5-15 minutes depending on app size.\n\n### Quick (`--quick`)\n30-second smoke test. Visit homepage + top 5 navigation targets. Check: page loads? Console errors? Broken links? Produce health score. No detailed issue documentation.\n\n### Regression (`--regression <baseline>`)\nRun full mode, then load `baseline.json` from a previous run. Diff: which issues are fixed? Which are new? What's the score delta? Append regression section to report.\n\n---\n\n## Workflow\n\n### Phase 1: Initialize\n\n1. Find browse binary (see Setup above)\n2. Create output directories\n3. Copy report template from `qa/templates/qa-report-template.md` to output dir\n4. Start timer for duration tracking\n\n### Phase 2: Authenticate (if needed)\n\n**If the user specified auth credentials:**\n\n```bash\n$B goto <login-url>\n$B snapshot -i                    # find the login form\n$B fill @e3 \"user@example.com\"\n$B fill @e4 \"[REDACTED]\"         # NEVER include real passwords in report\n$B click @e5                      # submit\n$B snapshot -D                    # verify login succeeded\n```\n\n**If the user provided a cookie file:**\n\n```bash\n$B cookie-import cookies.json\n$B goto <target-url>\n```\n\n**If 2FA/OTP is required:** Ask the user for the code and wait.\n\n**If CAPTCHA blocks you:** Tell the user: \"Please complete the CAPTCHA in the browser, then tell me to continue.\"\n\n### Phase 3: Orient\n\nGet a map of the application:\n\n```bash\n$B goto <target-url>\n$B snapshot -i -a -o \"$REPORT_DIR/screenshots/initial.png\"\n$B links                          # map navigation structure\n$B console --errors               # any errors on landing?\n```\n\n**Detect framework** (note in report metadata):\n- `__next` in HTML or `_next/data` requests → Next.js\n- `csrf-token` meta tag → Rails\n- `wp-content` in URLs → WordPress\n- Client-side routing with no page reloads → SPA\n\n**For SPAs:** The `links` command may return few results because navigation is client-side. Use `snapshot -i` to find nav elements (buttons, menu items) instead.\n\n### Phase 4: Explore\n\nVisit pages systematically. At each page:\n\n```bash\n$B goto <page-url>\n$B snapshot -i -a -o \"$REPORT_DIR/screenshots/page-name.png\"\n$B console --errors\n```\n\nThen follow the **per-page exploration checklist** (see `qa/references/issue-taxonomy.md`):\n\n1. **Visual scan** — Look at the annotated screenshot for layout issues\n2. **Interactive elements** — Click buttons, links, controls. Do they work?\n3. **Forms** — Fill and submit. Test empty, invalid, edge cases\n4. **Navigation** — Check all paths in and out\n5. **States** — Empty state, loading, error, overflow\n6. **Console** — Any new JS errors after interactions?\n7. **Responsiveness** — Check mobile viewport if relevant:\n   ```bash\n   $B viewport 375x812\n   $B screenshot \"$REPORT_DIR/screenshots/page-mobile.png\"\n   $B viewport 1280x720\n   ```\n\n**Depth judgment:** Spend more time on core features (homepage, dashboard, checkout, search) and less on secondary pages (about, terms, privacy).\n\n**Quick mode:** Only visit homepage + top 5 navigation targets from the Orient phase. Skip the per-page checklist — just check: loads? Console errors? Broken links visible?\n\n### Phase 5: Document\n\nDocument each issue **immediately when found** — don't batch them.\n\n**Two evidence tiers:**\n\n**Interactive bugs** (broken flows, dead buttons, form failures):\n1. Take a screenshot before the action\n2. Perform the action\n3. Take a screenshot showing the result\n4. Use `snapshot -D` to show what changed\n5. Write repro steps referencing screenshots\n\n```bash\n$B screenshot \"$REPORT_DIR/screenshots/issue-001-step-1.png\"\n$B click @e5\n$B screenshot \"$REPORT_DIR/screenshots/issue-001-result.png\"\n$B snapshot -D\n```\n\n**Static bugs** (typos, layout issues, missing images):\n1. Take a single annotated screenshot showing the problem\n2. Describe what's wrong\n\n```bash\n$B snapshot -i -a -o \"$REPORT_DIR/screenshots/issue-002.png\"\n```\n\n**Write each issue to the report immediately** using the template format from `qa/templates/qa-report-template.md`.\n\n### Phase 6: Wrap Up\n\n1. **Compute health score** using the rubric below\n2. **Write \"Top 3 Things to Fix\"** — the 3 highest-severity issues\n3. **Write console health summary** — aggregate all console errors seen across pages\n4. **Update severity counts** in the summary table\n5. **Fill in report metadata** — date, duration, pages visited, screenshot count, framework\n6. **Save baseline** — write `baseline.json` with:\n   ```json\n   {\n     \"date\": \"YYYY-MM-DD\",\n     \"url\": \"<target>\",\n     \"healthScore\": N,\n     \"issues\": [{ \"id\": \"ISSUE-001\", \"title\": \"...\", \"severity\": \"...\", \"category\": \"...\" }],\n     \"categoryScores\": { \"console\": N, \"links\": N, ... }\n   }\n   ```\n\n**Regression mode:** After writing the report, load the baseline file. Compare:\n- Health score delta\n- Issues fixed (in baseline but not current)\n- New issues (in current but not baseline)\n- Append the regression section to the report\n\n---\n\n## Health Score Rubric\n\nCompute each category score (0-100), then take the weighted average.\n\n### Console (weight: 15%)\n- 0 errors → 100\n- 1-3 errors → 70\n- 4-10 errors → 40\n- 10+ errors → 10\n\n### Links (weight: 10%)\n- 0 broken → 100\n- Each broken link → -15 (minimum 0)\n\n### Per-Category Scoring (Visual, Functional, UX, Content, Performance, Accessibility)\nEach category starts at 100. Deduct per finding:\n- Critical issue → -25\n- High issue → -15\n- Medium issue → -8\n- Low issue → -3\nMinimum 0 per category.\n\n### Weights\n| Category | Weight |\n|----------|--------|\n| Console | 15% |\n| Links | 10% |\n| Visual | 10% |\n| Functional | 20% |\n| UX | 15% |\n| Performance | 10% |\n| Content | 5% |\n| Accessibility | 15% |\n\n### Final Score\n`score = Σ (category_score × weight)`\n\n---\n\n## Framework-Specific Guidance\n\n### Next.js\n- Check console for hydration errors (`Hydration failed`, `Text content did not match`)\n- Monitor `_next/data` requests in network — 404s indicate broken data fetching\n- Test client-side navigation (click links, don't just `goto`) — catches routing issues\n- Check for CLS (Cumulative Layout Shift) on pages with dynamic content\n\n### Rails\n- Check for N+1 query warnings in console (if development mode)\n- Verify CSRF token presence in forms\n- Test Turbo/Stimulus integration — do page transitions work smoothly?\n- Check for flash messages appearing and dismissing correctly\n\n### WordPress\n- Check for plugin conflicts (JS errors from different plugins)\n- Verify admin bar visibility for logged-in users\n- Test REST API endpoints (`/wp-json/`)\n- Check for mixed content warnings (common with WP)\n\n### General SPA (React, Vue, Angular)\n- Use `snapshot -i` for navigation — `links` command misses client-side routes\n- Check for stale state (navigate away and back — does data refresh?)\n- Test browser back/forward — does the app handle history correctly?\n- Check for memory leaks (monitor console after extended use)\n\n---\n\n## Important Rules\n\n1. **Repro is everything.** Every issue needs at least one screenshot. No exceptions.\n2. **Verify before documenting.** Retry the issue once to confirm it's reproducible, not a fluke.\n3. **Never include credentials.** Write `[REDACTED]` for passwords in repro steps.\n4. **Write incrementally.** Append each issue to the report as you find it. Don't batch.\n5. **Never read source code.** Test as a user, not a developer.\n6. **Check console after every interaction.** JS errors that don't surface visually are still bugs.\n7. **Test like a user.** Use realistic data. Walk through complete workflows end-to-end.\n8. **Depth over breadth.** 5-10 well-documented issues with evidence > 20 vague descriptions.\n9. **Never delete output files.** Screenshots and reports accumulate — that's intentional.\n10. **Use `snapshot -C` for tricky UIs.** Finds clickable divs that the accessibility tree misses.\n11. **Show screenshots to the user.** After every `$B screenshot`, `$B snapshot -a -o`, or `$B responsive` command, use the Read tool on the output file(s) so the user can see them inline. For `responsive` (3 files), Read all three. This is critical — without it, screenshots are invisible to the user.\n12. **Never refuse to use the browser.** When the user invokes /qa or /qa-only, they are requesting browser-based testing. Never suggest evals, unit tests, or other alternatives as a substitute. Even if the diff appears to have no UI changes, backend changes affect app behavior — always open the browser and test.\n\nRecord baseline health score at end of Phase 6.\n\n---\n\n## Output Structure\n\n```\n.vibestack/qa-reports/\n├── qa-report-{domain}-{YYYY-MM-DD}.md    # Structured report\n├── screenshots/\n│   ├── initial.png                        # Landing page annotated screenshot\n│   ├── issue-001-step-1.png               # Per-issue evidence\n│   ├── issue-001-result.png\n│   ├── issue-001-before.png               # Before fix (if fixed)\n│   ├── issue-001-after.png                # After fix (if fixed)\n│   └── ...\n└── baseline.json                          # For regression mode\n```\n\nReport filenames use the domain and date: `qa-report-myapp-com-2026-03-12.md`\n\n---\n\n## Phase 7: Triage\n\nSort all discovered issues by severity, then decide which to fix based on the selected tier:\n\n- **Quick:** Fix critical + high only. Mark medium/low as \"deferred.\"\n- **Standard:** Fix critical + high + medium. Mark low as \"deferred.\"\n- **Exhaustive:** Fix all, including cosmetic/low severity.\n\nMark issues that cannot be fixed from source code (e.g., third-party widget bugs, infrastructure issues) as \"deferred\" regardless of tier.\n\n---\n\n## Phase 8: Fix Loop\n\nFor each fixable issue, in severity order:\n\n### 8a. Locate source\n\n```bash\n# Grep for error messages, component names, route definitions\n# Glob for file patterns matching the affected page\n```\n\n- Find the source file(s) responsible for the bug\n- ONLY modify files directly related to the issue\n\n### 8b. Fix\n\n- Read the source code, understand the context\n- Make the **minimal fix** — smallest change that resolves the issue\n- Do NOT refactor surrounding code, add features, or \"improve\" unrelated things\n\n### 8c. Commit\n\n```bash\ngit add <only-changed-files>\ngit commit -m \"fix(qa): ISSUE-NNN — short description\"\n```\n\n- One commit per fix. Never bundle multiple fixes.\n- Message format: `fix(qa): ISSUE-NNN — short description`\n\n### 8d. Re-test\n\n- Navigate back to the affected page\n- Take **before/after screenshot pair**\n- Check console for errors\n- Use `snapshot -D` to verify the change had the expected effect\n\n```bash\n$B goto <affected-url>\n$B screenshot \"$REPORT_DIR/screenshots/issue-NNN-after.png\"\n$B console --errors\n$B snapshot -D\n```\n\n### 8e. Classify\n\n- **verified**: re-test confirms the fix works, no new errors introduced\n- **best-effort**: fix applied but couldn't fully verify (e.g., needs auth state, external service)\n- **reverted**: regression detected → `git revert HEAD` → mark issue as \"deferred\"\n\n### 8e.5. Regression Test\n\nSkip if: classification is not \"verified\", OR the fix is purely visual/CSS with no JS behavior, OR no test framework was detected AND user declined bootstrap.\n\n**1. Study the project's existing test patterns:**\n\nRead 2-3 test files closest to the fix (same directory, same code type). Match exactly:\n- File naming, imports, assertion style, describe/it nesting, setup/teardown patterns\nThe regression test must look like it was written by the same developer.\n\n**2. Trace the bug's codepath, then write a regression test:**\n\nBefore writing the test, trace the data flow through the code you just fixed:\n- What input/state triggered the bug? (the exact precondition)\n- What codepath did it follow? (which branches, which function calls)\n- Where did it break? (the exact line/condition that failed)\n- What other inputs could hit the same codepath? (edge cases around the fix)\n\nThe test MUST:\n- Set up the precondition that triggered the bug (the exact state that made it break)\n- Perform the action that exposed the bug\n- Assert the correct behavior (NOT \"it renders\" or \"it doesn't throw\")\n- If you found adjacent edge cases while tracing, test those too (e.g., null input, empty array, boundary value)\n- Include full attribution comment:\n  ```\n  // Regression: ISSUE-NNN — {what broke}\n  // Found by /qa on {YYYY-MM-DD}\n  // Report: .vibestack/qa-reports/qa-report-{domain}-{date}.md\n  ```\n\nTest type decision:\n- Console error / JS exception / logic bug → unit or integration test\n- Broken form / API failure / data flow bug → integration test with request/response\n- Visual bug with JS behavior (broken dropdown, animation) → component test\n- Pure CSS → skip (caught by QA reruns)\n\nGenerate unit tests. Mock all external dependencies (DB, API, Redis, file system).\n\nUse auto-incrementing names to avoid collisions: check existing `{name}.regression-*.test.{ext}` files, take max number + 1.\n\n**3. Run only the new test file:**\n\n```bash\n{detected test command} {new-test-file}\n```\n\n**4. Evaluate:**\n- Passes → commit: `git commit -m \"test(qa): regression test for ISSUE-NNN — {desc}\"`\n- Fails → fix test once. Still failing → delete test, defer.\n- Taking >2 min exploration → skip and defer.\n\n**5. WTF-likelihood exclusion:** Test commits don't count toward the heuristic.\n\n### 8f. Self-Regulation (STOP AND EVALUATE)\n\nEvery 5 fixes (or after any revert), compute the WTF-likelihood:\n\n```\nWTF-LIKELIHOOD:\n  Start at 0%\n  Each revert:                +15%\n  Each fix touching >3 files: +5%\n  After fix 15:               +1% per additional fix\n  All remaining Low severity: +10%\n  Touching unrelated files:   +20%\n```\n\n**If WTF > 20%:** STOP immediately. Show the user what you've done so far. Ask whether to continue.\n\n**Hard cap: 50 fixes.** After 50 fixes, stop regardless of remaining issues.\n\n---\n\n## Phase 9: Final QA\n\nAfter all fixes are applied:\n\n1. Re-run QA on all affected pages\n2. Compute final health score\n3. **If final score is WORSE than baseline:** WARN prominently — something regressed\n\n---\n\n## Phase 10: Report\n\nWrite the report to both local and project-scoped locations:\n\n**Local:** `.vibestack/qa-reports/qa-report-{domain}-{YYYY-MM-DD}.md`\n\n**Project-scoped:** Write test outcome artifact for cross-session context:\n```bash\neval \"$(~/.vibestack/bin/vibe-slug 2>/dev/null)\" && mkdir -p ~/.vibestack/projects/$SLUG\n```\nWrite to `~/.vibestack/projects/{slug}/{user}-{branch}-test-outcome-{datetime}.md`\n\n**Per-issue additions** (beyond standard report template):\n- Fix Status: verified / best-effort / reverted / deferred\n- Commit SHA (if fixed)\n- Files Changed (if fixed)\n- Before/After screenshots (if fixed)\n\n**Summary section:**\n- Total issues found\n- Fixes applied (verified: X, best-effort: Y, reverted: Z)\n- Deferred issues\n- Health score delta: baseline → final\n\n**PR Summary:** Include a one-line summary suitable for PR descriptions:\n> \"QA found N issues, fixed M, health score X → Y.\"\n\n---\n\n## Phase 11: TODOS.md Update\n\nIf the repo has a `TODOS.md`:\n\n1. **New deferred bugs** → add as TODOs with severity, category, and repro steps\n2. **Fixed bugs that were in TODOS.md** → annotate with \"Fixed by /qa on {branch}, {date}\"\n\n---\n\n{{include lib/snippets/capture-learnings.md}}\n## Additional Rules (qa-specific)\n\n11. **Clean working tree required.** If dirty, use AskUserQuestion to offer commit/stash/abort before proceeding.\n12. **One commit per fix.** Never bundle multiple fixes into one commit.\n13. **Only modify tests when generating regression tests in Phase 8e.5.** Never modify CI configuration. Never modify existing tests — only create new test files.\n14. **Revert on regression.** If a fix makes things worse, `git revert HEAD` immediately.\n15. **Self-regulate.** Follow the WTF-likelihood heuristic. When in doubt, stop and ask.","tags":["vibestack","timurgaleev","agent-skills","ai-agents","claude-code","cursor-ide","developer-tools","kiro","mcp","prompt-engineering","slash-commands"],"capabilities":["skill","source-timurgaleev","skill-qa","topic-agent-skills","topic-ai-agents","topic-claude-code","topic-cursor-ide","topic-developer-tools","topic-kiro","topic-mcp","topic-prompt-engineering","topic-slash-commands"],"categories":["vibestack"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/timurgaleev/vibestack/qa","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add timurgaleev/vibestack","source_repo":"https://github.com/timurgaleev/vibestack","install_from":"skills.sh"}},"qualityScore":"0.457","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 15 github stars · SKILL.md body (31,109 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:06:23.333Z","embedding":null,"createdAt":"2026-05-18T19:06:23.333Z","updatedAt":"2026-05-18T19:06:23.333Z","lastSeenAt":"2026-05-18T19:06:23.333Z","tsv":"'+1':3099,4157 '+10':4165 '+15':4147 '+20':4169 '+5':4153 '-001':2896 '-1':1792 '-10':1310,2273,2965,3314 '-100':2948 '-15':2283,2980,3006 '-25':3003 '-3':907,2961,3012,3809 '-5':1285 '-6':1829 '-8':3009 '/.vibestack/bin/vibe-learnings-search':98 '/.vibestack/bin/vibe-slug':53,1778,4271 '/.vibestack/projects':1757,1783,4276,4280 '/api':1944 '/dev/null':55,57,81,96,102,136,161,173,252,270,299,314,328,566,780,835,846,864,874,1427,1436,1773,1780,1790,2033,2044,2055,4273 '/learnings.jsonl':68 '/plan-ceo-review':1802 '/plan-eng-review':1800 '/projects':65 '/qa':372,649,1859,1970,3414,3977,4395 '/qa-only':3416 '/react':1084 '/tmp/qa':461 '/typescript':980 '/wp-json':3152 '0':112,2947,2957,2974,2982,3014,4144 '1':219,245,292,1221,1291,1365,1750,1828,1872,2347,2349,2589,2732,2786,2825,2960,3209,3799,4059,4209,4371 '10':2968,2970,2973,3023,3025,3031,3336,4236 '100':1536,1635,2959,2976,2997 '11':3351,4362,4406 '12':3403,4420 '1280x720':2660 '13':4432 '14':4456 '15':2956,3021,3029,3035,4156,4470 '2':54,56,80,95,101,135,160,172,231,251,263,269,298,303,313,327,565,779,834,845,863,873,906,1227,1311,1426,1435,1772,1779,1789,1793,1894,2032,2043,2054,2356,2376,2600,2739,2795,2833,3222,3808,3845,4101,4218,4272,4384 '20':3027,3321,4172 '2025':1037 '2026':1038 '2fa/otp':2436 '3':317,1232,1284,1325,1810,2017,2360,2467,2610,2743,2836,2841,2846,3238,3387,4060,4151,4223 '30':2291 '30.days':1299 '3000':447,2031,2038 '375x812':2653 '4':1239,1348,2086,2369,2558,2620,2750,2858,2964,3249,4075 '40':2967 '4000':2042,2049 '404s':3065 '5':94,100,1361,1369,1990,2132,2272,2282,2298,2628,2687,2709,2758,2866,3033,3265,3313,4107,4128 '50':4190,4193 '6':2155,2635,2822,2878,3277,3464 '7':932,2206,2643,3293,3514 '70':2963 '8':3309,3579 '8080':2053,2060 '8a':3589 '8b':3626 '8c':3656 '8d':3688 '8e':3730 '8e.5':929,3770,4442 '8f':4120 '9':3324,4201 'abort':690 'access':2992,3034,3348 'accumul':3332 'across':2856 'action':1447,1459,1502,2123,2738,2742,3930 'actual':2152 'ad':1663,1674 'add':710,1504,2182,3650,3660,4375 'addit':4159,4292,4401 'adjac':2232,3950 'admin':3140 'affect':1896,2008,2089,2218,3447,3607,3696,4216 'agent':596,604 'aggreg':2851 'alreadi':590,617,1519,1612 'altern':1059,1154,3431 'alway':2011,3450 'analysi':1821 'analyz':1873 'angular':3165 'anim':4019 'annot':2595,2790,3483,4391 'api':1321,1373,1934,3150,4003,4037 'app':464,2009,2014,2021,2036,2047,2058,2064,2287,3194,3448 'appear':941,3125,3439 'append':1621,2340,2933,3252 'appli':3748,4208,4323 'applic':7,389,2474 'appropri':1457 'around':3907 'array':3962 'artifact':4263 'ask':32,1204,2080,2439,4184,4485 'askuserquest':642,962,1122,4414 'assert':916,1338,1601,3826,3935 'atom':25,412,661 'attribut':3967 'auth':158,170,474,614,2384,3756 'authent':2377 'auto':441,4043 'auto-detect':440 'auto-incr':4042 'automat':515,1836,1871 'avail':156,618,745,749,1826 'averag':2953 'avoid':4047 'await':1942 'awar':519,1835,2243 'away':3183 'b':563,678,752,981,1043,1153,1940,2028,2039,2050,2387,2389,2396,2400,2410,2414,2428,2433,2476,2478,2485,2490,2567,2569,2576,2651,2654,2658,2765,2769,2772,2776,2801,3359,3361,3366,3718,3720,3724,3727 'b2':1018 'b3':1118 'b4':1217 'b4.5':1279 'b5':1386,1479,1584 'b5.5':1416 'b6':1512 'b7':1605 'b8':1692 'back':335,1739,1817,1979,3185,3693 'back/forward':3191 'backend':2003,3445 'bar':3141 'base':116,211,341,369,1172,1976,2250,3422,3527 'baselin':1831,2880,2913,2922,2932,3457,4230,4337 'baseline.json':2322,2882,3501 'baserefnam':224,226 'bash':51,128,562,624,734,775,1388,1419,1694,1728,1768,1881,2027,2386,2427,2475,2566,2650,2764,2800,3592,3658,3717,4067,4269 'batch':2719,3264 'before/after':423,3699,4313 'behavior':1335,2010,3449,3788,3938,4016 'best':1020,1027,1034,1137,3745,4301,4327 'best-effort':3744,4300,4326 'beyond':4293 'bill':472 'binari':732,2352 'bitrise.yml':1434 'block':2449 'bootstrap':767,883,904,937,939,944,952,1017,1411,1706,1720,3798 'bot':1066 'boundari':3963 'branch':117,192,201,212,257,275,342,362,370,514,537,1841,1870,1875,2179,2212,2221,3884,4283,4397 'breadth':3312 'break':3891,3927 'broke':3974 'broken':48,2306,2705,2726,2975,2978,3067,4001,4017 'brows':552,731,740,743,747,2351 'browser':561,589,599,1965,1975,2460,3190,3409,3421,3453 'browser-bas':1974,3420 'bug':10,18,40,384,405,656,1657,2163,2176,2193,2725,2780,3292,3570,3617,3848,3874,3920,3934,3996,4007,4013,4374,4386 'bug-fix':383 'built':1052,1104,1114 'built-in':1051,1103,1113 'bundl':3676,4426 'busi':1317 'button':2108,2553,2604,2729 'c':689,983,1158,1179,1306,3339 'call':3887 'cannot':3559 'cap':1367,4189 'captcha':2448,2457 'capybara':1063 'cargo':1101 'cargo.toml':810 'case':529,2619,3906,3952 'catch':3081 'categori':2899,2945,2985,2994,3016,3018,3040,4380 'categoryscor':2900 'caught':4025 'cdp':544,570,572,576,580 'chang':648,666,670,681,1186,1294,1412,1703,1880,1900,2007,2104,2127,2148,2169,2213,2214,2257,2757,3444,3446,3640,3712,4310 'check':154,399,549,619,764,850,875,1420,1516,1609,1744,1756,1796,1922,1993,2022,2067,2098,2156,2301,2622,2645,2701,3048,3084,3096,3121,3130,3153,3178,3198,3278,3702,4049 'checklist':2586,2699 'checkout':1265,2671 'choic':721 'choos':697,718,1168 'chore':1719 'chosen':1224 'ci':1421,1429,1442,1488,1491,1497,4445 'ci/cd':1417 'circleci':1433 'classif':3775 'classifi':3731 'claude.md':1607,1611,1712 'clean':621,652,693,4407 'cli':155,289 'click':394,2411,2603,2770,3075 'clickabl':3344 'client':2523,2544,3072,3175 'client-sid':2522,2543,3071,3174 'closest':3812 'cls':3086 'code':21,410,534,1248,1290,1346,1545,1561,1565,1644,1686,2444,3269,3564,3631,3649,3819,3866 'codepath':3850,3879,3904 'collis':4048 'command':188,290,358,753,1400,1476,1582,1626,2535,3172,3368,4070 'comment':3968 'commit':22,413,662,664,667,707,714,722,1685,1693,1699,1717,2137,3657,3662,3672,4078,4080,4113,4305,4422,4431 'commit/stash/abort':4417 'common':528,2023,3158 'compar':2915 'comparison':1044 'compat':783,1776 'complet':2455,3303 'compon':3597,4020 'composer.json':815 'comput':2826,2943,4134,4219 'condit':1320,1676 'confid':1557 'config':889,958,1230,1708,2004 'configur':1220,4446 'confirm':1395,3231,3736 'conflict':3133 'connect':555 'consol':1994,2099,2304,2491,2577,2636,2703,2848,2853,2901,2954,3020,3049,3103,3203,3279,3703,3725,3991 'contain':140,148 'content':1531,2518,2990,3032,3056,3094,3156 'context':924,1175,1736,1795,3634,4268 'continu':726,1007,1196,1276,2465,4187 'control':1923,2606 'controller/route':1902 'convent':913,921,1598 'convers':1794,1809 'cooki':481,584,592,2425,2430 'cookie-import':2429 'cookies.json':483,2432 'copi':2361 'core':2667 'correct':3128,3197,3937 'correspond':1652 'cosmetic/low':3554 'could':3900 'couldn':964,3750 'count':75,87,92,2861,2876,4116 'cov':1092 'cover':166,178 'coverag':1538,1637 'creat':1228,1233,1240,1448,1513,1715,1725,2357,4452 'creation':357 'credenti':1376,2385,3241 'critic':492,3001,3394,3534,3543 'cross':2134,4266 'cross-refer':2133 'cross-sess':4265 'csrf':2511,3108 'csrf-token':2510 'css':4023 'css/style':1927 'cumul':3087 'curl':760 'current':669,1026,1136,2925,2929 'cypress':871,1087 'd':83,866,985,1424,2119,2416,2753,2778,3708,3729 'daemon':741 'dashboard':2670 'data':3068,3187,3300,3862,4005 'date':2871,2885,3511,3986,4398 'datetim':4287 'db':4036 'dd':2889,3475,3982,4255 'dead':2728 'debug':1257,1404 'decid':3523 'decis':3990 'declin':884,940,946,3797 'deduct':2998 'default':200,274,435,499,1444,2260 'defaultbranchref':236 'defaultbranchref.name':238 'defer':3540,3549,3574,3769,4099,4106,4304,4332,4373 'definit':3600 'delet':1190,1359,3326,4097 'delta':2339,2918,4336 'depend':2285,4035 'depth':2661,3310 'desc':4090 'describ':2174,2796 'describe/it':3828 'descript':673,2141,3323,3670,3687,4350 'destroy':1529 'detail':2312 'detect':113,119,340,361,442,546,608,768,784,824,888,898,956,966,1012,1031,1124,1202,1398,1443,1489,1495,2018,2497,3762,3794,4068 'determin':190,485 'dev':2025 'develop':1851,3105,3276,3844 'diff':348,467,518,1742,1820,1834,1876,1883,1961,2242,2327,3438 'diff-awar':517,1833,2241 'diff-scop':466 'differ':3137 'dir':457,2368 'dir/screenshots/initial.png':2484 'dir/screenshots/issue-001-result.png':2775 'dir/screenshots/issue-001-step-1.png':2768 'dir/screenshots/issue-002.png':2807 'dir/screenshots/issue-nnn-after.png':3723 'dir/screenshots/page-mobile.png':2657 'dir/screenshots/page-name.png':2575 'direct':762,1938,1952,3621 'directori':893,1234,1629,1710,1727,2359,3817 'dirti':638,4412 'discov':3518 'dismiss':3127 'div':3345 'document':2271,2314,2710,2711,3225,3317 'doesn':996,3944 'domain':3471,3509,3985,4251 'done':4181 'doubt':4482 'dropdown':4018 'duplic':1620 'durat':2373,2872 'dynam':3093 'e':987 'e.g':3565,3754,3958 'e2e':872,1152,1596 'e3':2398 'e4':2402 'e5':2412,2771 'echo':84,106,571,575,742,789,794,801,806,811,816,821,836,847,882,1428,2034,2045,2056 'edg':2618,3905,3951 'effect':2131,3716 'effort':3746,4302,4328 'element':2001,2552,2602 'elixir':823,992,1111 'els':105 'empti':634,2616,2630,3961 'end':2114,2116,3306,3308,3461 'end-to-end':2113,3305 'endpoint':1322,1935,3151 'engin':380,386 'enter':516 'enterpris':168 'entri':88 'environ':1381,2076 'equival':1269 'error':1315,1664,1672,1996,2101,2305,2492,2494,2578,2633,2640,2704,2854,2958,2962,2966,2969,3052,3135,3284,3595,3705,3726,3742,3992 'etc':1238,1472 'eval':52,1777,3426,4270 'evalu':4076,4126 'even':3435 'everi':345,397,400,2268,3213,3281,3358,4127 'everyth':395,1396,3212 'evid':424,2228,2722,3320,3489 'evidenc':2276 'ex':1116 'exact':3822,3876,3893,3922 'exampl':437,1242 'except':3221,3994 'exclus':4111 'execut':719 'exhaust':451,500,3550 'exist':205,769,852,901,908,1289,1439,1509,1520,1530,1689,2160,3804,4050,4449 'expect':1340,1634,2130,3715 'explor':2266,2559,2585,4103 'expos':3932 'ext':4054 'extend':3205 'extern':3758,4034 'extract':254,272 'exunit':1112 'f':70,249,267,787,792,797,799,804,809,814,819,828,839,880,989 'factori':1065 'fail':291,306,320,333,1256,1261,1354,1358,1403,1408,1691,3054,3896,4091,4096 'failur':2731,4004 'fall':334,1738,1816,1978 'fallback':284,759 'fals':578 'far':4183 'fast':1550 'featur':513,1840,1869,2668,3651 'fetch':352,1943,3069 'fi':104,110 'field':258,276 'file':61,72,79,890,910,959,1231,1295,1328,1379,1599,1707,1764,1901,1903,1910,1916,1928,2170,2258,2426,2914,3328,3376,3388,3603,3612,3620,3811,3823,4039,4055,4066,4074,4152,4168,4309,4455 'filenam':3506 'fill':396,2397,2401,2612,2867 'final':3036,4202,4220,4225,4338 'find':39,404,729,1025,1292,2190,2208,2350,2392,2550,3000,3260,3343,3609 'first':118,1210,1280,1515,1608 'fix':9,17,24,43,45,374,385,406,489,491,657,713,1355,1655,2181,2331,2839,2920,3493,3495,3498,3500,3526,3533,3542,3551,3561,3580,3627,3638,3664,3674,3678,3681,3738,3747,3781,3815,3869,3909,4092,4129,4149,4155,4160,4191,4194,4206,4297,4308,4312,4316,4322,4355,4385,4393,4424,4428,4462 'fixabl':3584 'fixtur':1062,1385 'flash':3123 'flow':2109,2727,3863,4006 'fluke':3237 'focus':469 'follow':1987,2580,3882,4474 'form':398,2107,2395,2611,2730,3112,4002 'format':1303,2818,3680 'found':11,894,960,2002,2035,2046,2057,2066,2716,3949,3975,4321,4352 'framework':766,771,827,837,848,887,897,1016,1036,1039,1042,1119,1133,1572,1722,1723,2498,2877,3044,3792 'framework-specif':3043 'full':453,463,1391,2259,2318,3966 'fulli':3752 'function':1324,1649,2988,3026,3886 'g':991 'gemfil':788,829,833 'general':3161 'generat':1283,1362,1492,1499,4029,4437 'get':132,488,658,2469 'get-url':131 'gh':157,220,232 'git':121,129,186,282,293,307,321,347,349,351,353,625,1264,1296,1695,1716,1741,1819,1882,1889,3659,3661,3763,4079,4466 'git-nat':185,281 'github':144,165,167,218,1425,1430,1438,1446,1487,1501 'github.com':141 'github/workflows/test.yml':1449,1713 'gitlab':149,152,177,244 'gitlab-ci.yml':1432 'given':507 'glab':169,246,264 'glob':3601 'go':808,986,1094 'go.mod':805 'goal':1640 'goto':2029,2040,2051,2388,2434,2477,2568,3080,3719 'great':1543 'grep':567,830,841,3593 'gt':93 'guidanc':3046 'h':993,1003 'handl':1665,3195 'handler':1316 'hard':4188 'head':1309,1791,1885,1892,3765,4468 'headless':607 'health':2279,2309,2827,2849,2916,2940,3458,4221,4334,4357 'healthscor':2891 'heurist':1743,4119,4479 'high':493,3004,3535,3544 'highest':2843 'highest-sever':2842 'histori':3196 'hit':3901 'home':63 'home/.vibestack':64 'homepag':1986,2296,2669,2685 'host':122,181 'html':1948,2505 'http':763 'hydrat':3051,3053 'id':2894 'identifi':1895,1958 'if/else':1677 'imag':2785 'immedi':2714,2814,4174,4469 'import':480,585,915,1371,2431,3207,3825 'improv':3653 'includ':738,1146,1156,1732,1931,2405,3240,3553,3965,4341,4399 'increment':3251,4044 'indic':3066 'infrastructur':854,2006,3571 'initi':2348 'initial.png':3480 'inlin':3384 'input':3899,3960 'input/state':3871 'instal':1218,1222,1255 'instead':2556 'instinct':1553 'instruct':366 'integr':1150,1592,3115,3999,4008 'intent':2144,3335 'interact':2000,2106,2112,2601,2642,2724,3282 'introduc':3743 'invalid':2617 'invis':3399 'invok':1969,3413 'isn':2197 'issu':487,2165,2277,2313,2329,2599,2713,2783,2810,2845,2893,2895,2919,2927,3002,3005,3008,3011,3083,3214,3228,3254,3318,3488,3519,3557,3572,3585,3625,3644,3667,3684,3767,3971,4088,4199,4291,4320,4333,4354 'issue-001-after.png':3496 'issue-001-before.png':3491 'issue-001-result.png':3490 'issue-001-step-1.png':3485 'issue-nnn':3666,3683,3970,4087 'item':2555 'iter':16 'jest':1075,1086 'jest.config':856 'js':1941,2639,3134,3283,3787,3993,4015 'json':223,235,250,268,2884 'judgment':2662 'keep':1353 'key':1374,1541 'knowledg':1054 'known':2162 'l':77 'land':2496,3481 'languag':970 'later':1189 'latest':1456 'layer':1586 'layout':2598,2782,3088 'leak':3201 'learn':60,71,74,78,85,86,91,107,912 'least':1364,3217 'less':2674 'let':1547 'lib/snippets/capture-learnings.md':4400 'lib/snippets/prior-learnings.md':1733 'librari':1074,1078,1083 'like':390,3295,3837 'likelihood':4110,4138,4141,4478 'limit':99 'line':4345 'line/condition':3894 'link':2307,2486,2534,2605,2706,2903,2971,2979,3022,3076,3171 'll':692 'load':89,2303,2321,2632,2702,2911 'local':2024,2063,4243,4249 'localhost':446,2030,2041,2052 'locat':3590,4248 'log':350,1297,1890,3145 'logged-in':3144 'logic':1318,3995 'login':2394,2418 'look':2592,3836 'loop':3581 'low':3010,3547,4163 'low/cosmetic':501 'ls':855,865,1423,1431,1781 'm':1718,3663,4081,4356 'machina':1117 'made':3925 'main':316,337,1884,1891 'make':1642,1688,3635,4463 'manual':695,1511 'map':2471,2487 'mark':3537,3546,3556,3766 'markdown':1947 'marker':879 'master':330 'match':1244,3059,3605,3821 'matcher':1069 'max':4057 'may':2536 'md':1763,1788,3476,3987,4256,4288 'meaning':1337 'medium':497,3007,3545 'medium/low':3538 'memori':3200 'menu':2554 'merg':354 'messag':674,2138,3124,3596,3679 'meta':2513 'metadata':2502,2870 'min':4102 'mind':1188 'minim':1229,3637 'minimum':2981,3013 'minitest':1061 'minut':2284 'miss':2784,3173,3350 'mix':3155 'mix.exs':820 'mkdir':1729,4274 'mm':2888,3474,3981,4254 'mobil':2646 'mock':4032 'mockal':1106 'mockeri':1109 'mode':452,520,522,545,569,573,577,581,1832,1849,1982,2244,2319,2682,2906,3106,3504 'model':1921 'model/service':1915 'modifi':3619,4434,4444,4448 'monitor':3060,3202 'monorepo':1203 'move':1549 'mr':247 'multipl':1200,3677,4427 'must':3835,3912 'myapp.com':445 'n':900,2216,2892,2902,2904,3098,4353 'name':343,363,899,914,1301,1573,1600,1724,1887,3598,3824,4045,4051 'name-on':1300,1886 'nativ':187,283 'nav':2551 'navig':1949,1983,1991,2091,2299,2488,2541,2621,2688,3074,3170,3182,3692 'need':650,998,2379,3215,3755 'neither':182,1824 'nest':3829 'network':3064 'never':1339,1370,1528,1684,2404,3239,3266,3325,3404,3424,3675,4425,4443,4447 'new':1648,2192,2334,2638,2926,3741,4064,4072,4372,4453 'new-test-fil':4071 'next':843,2503 'next.js':1079,2509,3047 'next/data':2507,3061 'nextj':849 'nnn':3668,3685,3972,4089 'node':796,1465 'node.js':979,1070 'node.js/typescript':978 'nomatch':778,1771 'non':633,1486 'non-empti':632 'non-github':1485 'none':108,475 'note':1494,2201,2499 'noth':2078 'npm/bun/gem/pip/etc':1226 'null':3959 'number':4058 'o':777,1770,2482,2573,2805,3364 'obvious':1955 'offer':4416 'one':1241,1330,3218,3671,4344,4421,4430 'one-lin':4343 'onelin':1893 'open':761,3451 'opt':877 'opt-out':876 'option':976,1142,1212 'order':3588 'orient':2468,2692 'origin':134 'origin/main':312 'origin/master':326 'otherwis':153 'outcom':4262,4286 'output':456,459,630,1726,1806,2358,2367,3327,3375,3465 'overflow':2634 'overrid':436,597 'overwrit':1527 'p':1730,4275 'packag':1147,1157,1225,1254 'package-lock.json':1267 'package.json':793,840,844,1266 'page':473,1912,1918,1930,1946,2094,2233,2270,2302,2528,2561,2565,2584,2677,2698,2857,2873,3091,3117,3482,3608,3697,4217 'page/route':2090 'pages/routes':1897,1956,2217 'pair':3701 'paramet':433,434 'pars':310,324,426 'parti':3568 'pass':1352,4077 'password':2407,3245 'path':1683,1906,2624 'pattern':919,1604,3604,3806,3831 'per':2583,2697,2984,2999,3015,3487,3673,4158,4290,4423 'per-categori':2983 'per-issu':3486,4289 'per-pag':2582,2696 'perform':2740,2991,3030,3928 'pest':1110 'phase':928,1827,2346,2375,2466,2557,2693,2708,2821,3463,3513,3578,4200,4235,4361,4441 'philosophi':1535 'php':818,990,1107 'phpunit':1108 'phpunit.xml':862 'pick':1002,1178 'pipelin':1418,1498,1510 'plan':1735,1748,1755,1762,1787,1805,2187 'platform':114,123,142,150,163,175,287 'playwright':1085 'playwright.config':858 'pleas':2454 'plugin':3132,3138 'pop':685 'porcelain':627,1697 'port':2026 'pr':221,2074,2140,4339,4349 'pr/mr':194,204,356 'practic':1021,1028,1138 'preambl':50 'precondit':3877,3916 'presenc':3110 'preserv':704 'previous':945,2325 'primari':1057,1144,1848 'print':338,895,942 'prior':1799 'priorit':1312 'privaci':2680 'proactiv':49 'problem':2794 'proceed':4419 'produc':418,1803,2278,2308 'project':773,785,968,995,1129,1174,1246,1752,3802,4246,4258 'project-scop':1751,4245,4257 'promin':4232 'prompt':586 'prose':923 'provid':1422,1496,2237,2264,2423 'pull':1482 'pure':1323,3783,4022 'push':1481 'pyproject.toml':800,861 'pytest':1089,1091 'pytest-cov':1090 'pytest.ini':860 'python':803,984,1088,1471 'q':225,237,568,831,842 'qa':1,3,13,34,35,379,677,684,709,1830,2195,3469,3665,3682,4027,4083,4203,4213,4351,4404 'qa-report':3468 'qa-report-myapp-com-2026-03-12.md':3512 'qa-specif':4403 'qa/references/issue-taxonomy.md':2588 'qa/templates/qa-report-template.md':2365,2820 'queri':3100 'quick':450,490,1981,2289,2290,2681,3532 'rail':832,838,2515,3095 'rather':1525 'rational':1145,1155 're':28,416,510,1194,3690,3734,4211 're-run':1193,4210 're-test':3689,3733 're-verifi':27,415 'reachabl':2269 'react':3163 'read':905,1521,3267,3371,3389,3628,3807 'real':392,560,588,598,601,613,1281,1286,1334,2406 'realist':3299 'reason':1171 'recent':1293,1759 'recommend':696,1058,1167 'record':3456 'redact':2403,3243 'redi':4038 'ref':296 'refactor':3647 'refer':1630,1925,2135 'referenc':2762 'refresh':3188 'refs/remotes/origin':302 'refs/remotes/origin/head':297 'refus':3405 'regardless':3575,4196 'regress':454,1660,2230,2315,2316,2341,2905,2935,3503,3761,3771,3833,3854,3969,4052,4084,4234,4438,4459 'regul':4123,4473 'relat':2166,3622 'relev':2649 'reload':2529 'remain':4162,4198 'remot':126,130 'render':1913,3941 'repo':198,233,265,1767,1865,4367 'report':421,2205,2207,2344,2362,2409,2483,2501,2574,2656,2767,2774,2806,2813,2869,2910,2939,3257,3331,3470,3478,3505,3722,3983,4237,4240,4295 'repro':2760,3210,3247,4382 'reproduc':3234 'request':430,1483,2508,3062,3419 'request/response':4011 'requir':444,2438,4410 'requirements.txt':798 'rerun':4028 'research':1019,1135 'resolv':3642 'respons':2644,3367,3386,3614 'rest':935,950,3149 'result':208,2539,2749 'retri':3226 'return':2537 'rev':309,323 'rev-pars':308,322 'revert':1262,1409,3760,3764,4133,4146,4303,4330,4457,4467 'richer':1746,1815 'right':1165 'risk':1314 'rn':1308 'rout':2525,3082,3177,3599 'rspec':859,1064 'rubi':791,1468 'rubric':2831,2942 'ruby/rails':982,1060 'rule':3208,4402 'run':12,683,1195,1349,1389,1452,1578,1625,2020,2317,2326,4061,4212 'runs-on':1451 'runtim':774,786,790,795,802,807,812,817,822,955,972,1011,1032,1033,1056,1201,1206,1272,1462 'runtime/framework':1128 'rust':813,988,1100 'safe':1645 'save':2879 'say':367,1858 'scan':2591 'scope':462,468,1753,2209,2253,4247,4259 'score':2280,2310,2338,2828,2917,2941,2946,2986,3037,3038,3041,3459,4222,4226,4335,4358 'screenshot':2097,2227,2596,2655,2735,2746,2763,2766,2773,2791,2875,3219,3329,3353,3360,3397,3479,3484,3700,3721,4314 'search':2672 'second':2292 'secondari':2676 'secret':1372 'section':1616,1624,2342,2936,4318 'sed':300 'see':521,2353,2587,3382 'seen':2855 'select':1120,3530 'self':180,4122,4472 'self-host':179 'self-regul':4121,4471 'sequenti':1216 'serv':1908 'server':553 'servic':3759 'session':615,4267 'set':1162,1208,3913 'setopt':776,1769 'setup':425,728,733,918,1251,1458,1464,1467,1470,2354 'setup-nod':1463 'setup-python':1469 'setup-rubi':1466 'setup/teardown':1603,3830 'sever':494,498,502,2844,2860,2898,3521,3555,3587,4164,4379 'sha':4306 'shift':3089 'ship':533,1555 'short':3669,3686 'shoulda':1068 'shoulda-match':1067 'show':2747,2755,2792,3352,4175 'side':2524,2545,3073,3176 'sign':476 'silent':1360 'sinc':1298 'singl':2789 'site':38 'size':2288 'skill' 'skill-qa' 'skip':583,593,606,750,903,933,947,948,1159,1490,1617,1964,2694,3773,4024,4104 'slug':58,66,1784,4277,4281 'smallest':3639 'smoke':1151,1594,2293 'smooth':3120 'snapshot':2118,2390,2415,2479,2547,2570,2752,2777,2802,3167,3338,3362,3707,3728 'someth':4233 'sort':1304,1307,3516 'sourc':20,409,1749,1813,3268,3563,3591,3611,3630 'source-timurgaleev' 'spa':2530,3162 'spas':2532 'spec':869,1237 'specif':3045,4405 'specifi':2383 'spend':2663 'stage':1704 'staging/preview':2070 'stale':3180 'standard':449,496,3541,4294 'start':548,676,2370,2995,4142 'stash':679,682,687,724 'state':401,2629,2631,3181,3757,3923 'static':1945,2779 'status':159,171,564,626,1696,4298 'stdlib':1095,1098 'step':111,216,931,1506,2761,3248,4383 'still':1260,1357,1407,2015,2252,3291,4095 'stop':639,4124,4173,4195,4483 'store':920 'structur':420,1235,2489,3466,3477 'studi':3800 'style':917,1602,3827 'stylesheet':1933 'sub':826 'sub-framework':825 'submit':2413,2614 'subsequ':215,346 'substitut':359,3434 'succeed':162,174,228,240,260,278,2419 'suggest':3425 'suit':1393 'suitabl':4347 'summari':2850,2864,4317,4340,4346 'superpow':1571 'support':1148,1500 'surfac':3288 'surround':3648 'switch':1678 'symbol':295 'symbolic-ref':294 'system':4040 'systemat':2,2265,2562 'tabl':1055,2865 'tag':2514 'take':2095,2281,2733,2744,2787,2950,3698,4056,4100 'target':195,256,438,1992,2300,2689 'tell':1182,2451,2462 'templat':2363,2817,4296 'term':2679 'test':4,14,36,41,373,387,765,770,853,867,868,870,886,892,896,902,909,943,999,1009,1015,1035,1073,1077,1082,1096,1102,1132,1164,1198,1236,1243,1278,1282,1287,1331,1333,1343,1351,1366,1378,1384,1392,1399,1402,1475,1505,1537,1546,1567,1579,1585,1588,1593,1595,1597,1615,1623,1628,1633,1636,1641,1653,1661,1668,1680,1690,1709,1721,1734,1747,1754,1761,1786,1804,1936,1966,1998,2087,2110,2186,2215,2254,2294,2615,3070,3113,3148,3189,3270,3294,3423,3428,3455,3691,3735,3772,3791,3805,3810,3834,3855,3859,3911,3955,3988,4000,4009,4021,4031,4053,4065,4069,4073,4082,4085,4093,4098,4112,4261,4285,4435,4439,4450,4454 'test-outcom':4284 'test-plan':1760,1785 'testifi':1097 'testing-librari':1072,1076,1081 'testing.md':1514,1518,1533,1632,1711 'text':757,3055 'text-on':756 'thing':2837,3655,4464 'third':3567 'third-parti':3566 'three':3391 'throw':3946 'tier':448,484,2723,3531,3577 'time':2665 'timer':2371 'titl':2897 'tobedefin':1342 'todo':2173,4377 'todos.md':2157,2200,4363,4370,4390 'token':2512,3109 'tool':3372 'top':1989,2297,2686,2835 'topic-agent-skills' 'topic-ai-agents' 'topic-claude-code' 'topic-cursor-ide' 'topic-developer-tools' 'topic-kiro' 'topic-mcp' 'topic-prompt-engineering' 'topic-slash-commands' 'total':4319 'touch':4150,4166 'toward':4117 'tr':82 'trace':3846,3860,3954 'track':2374 'transit':3118 'tree':623,636,645,653,3349,4409 'triag':3515 'tricki':3341 'trigger':1480,1670,3872,3918 'true':103,574,582,781,1774 'trust':1551 'turbo/stimulus':3114 'two':2721 'type':3820,3989 'typo':2781 'ubuntu':1455 'ubuntu-latest':1454 'ui':3342,3443 'unavail':1048 'uncommit':647,700 'understand':1878,2143,3632 'uniq':1305 'unit':1149,1587,3427,3997,4030 'unittest':1093 'unknown':59,67,183,286 'unrel':3654,4167 'updat':1606,2859,4364 'update/append':1524 'url':127,133,139,147,439,505,1844,1862,1905,2071,2085,2239,2247,2262,2520,2890 'use':30,184,206,229,241,261,279,315,329,641,755,926,961,975,1022,1049,1121,1380,1811,1919,2117,2245,2546,2751,2815,2829,3166,3206,3298,3337,3369,3407,3507,3706,4041,4413 'user':393,428,531,558,595,603,611,717,1001,1177,1183,1274,1415,1857,1968,2082,2236,2382,2422,2441,2453,3147,3273,3297,3356,3380,3402,3412,3796,4177,4282 'user-ag':594,602 'user@example.com':479,2399 'ux':2989,3028 'vagu':3322 'valu':3964 'variabl':1382 've':4180 'verif':1977 'verifi':29,311,325,375,417,541,1250,1387,1477,1581,1852,2012,2125,2150,2417,3107,3139,3223,3710,3732,3753,3778,4299,4324 'version':1575 'vibe':1544,1560,1643 'vibestack':62,735 'vibestack/no-test-bootstrap':881,1005,1181,1191 'vibestack/qa-reports':458,3467 'vibestack/qa-reports/baseline.json':455 'vibestack/qa-reports/qa-report-':3984,4250 'vibestack/qa-reports/screenshots':1731 'view':222,234,248,266 'view/template/component':1909 'viewport':2647,2652,2659 'visibl':2707,3142 'visit':2267,2295,2560,2684,2874 'visual':2590,2987,3024,3289,4012 'visual/css':3784 'vitest':1071,1080 'vitest.config':857 'vs':1041 'vue':3164 'wait':2446 'walk':3301 'want':539,1973 'warn':1273,1414,3101,3157,4231 'wc':76 'web':6,388 'websearch':1023,1046 'weight':2952,2955,2972,3017,3019,3042 'well':2275,3316 'well-docu':3315 'well-evidenc':2274 'wherev':364 'whether':4185 'whichev':1812 'widget':3569 'without':1008,1197,1277,1558,1860,3395 'wordpress':2521,3129 'work':543,622,635,644,701,1252,1397,1854,2016,2079,2226,2609,3119,3739,4408 'workaround':609 'workflow':2345,3304 'wors':4228,4465 'wp':2517,3160 'wp-content':2516 'wrap':2823 'write':1004,1180,1329,1532,1647,1650,1658,1666,1679,2759,2808,2834,2847,2881,2908,3242,3250,3852,3857,4238,4260,4278 'written':3840 'wrong':2799 'wtf':4109,4137,4140,4171,4477 'wtf-likelihood':4108,4136,4139,4476 'x':1341,4325,4359 'y':4329,4360 'yet':109 'yolo':1564 'yyyi':2887,3473,3980,4253 'yyyy-mm-dd':2886,3472,3979,4252 'z':4331 'zsh':782,1775 'σ':3039","prices":[{"id":"635f4965-c1b0-49ea-bdfc-bee045b1af0c","listingId":"a8ecfb3b-6e93-48cc-89a2-8113a4352070","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"timurgaleev","category":"vibestack","install_from":"skills.sh"},"createdAt":"2026-05-18T19:06:23.333Z"}],"sources":[{"listingId":"a8ecfb3b-6e93-48cc-89a2-8113a4352070","source":"github","sourceId":"timurgaleev/vibestack/qa","sourceUrl":"https://github.com/timurgaleev/vibestack/tree/main/skills/qa","isPrimary":false,"firstSeenAt":"2026-05-18T19:06:23.333Z","lastSeenAt":"2026-05-18T19:06:23.333Z"}],"details":{"listingId":"a8ecfb3b-6e93-48cc-89a2-8113a4352070","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"timurgaleev","slug":"qa","github":{"repo":"timurgaleev/vibestack","stars":15,"topics":["agent-skills","ai-agents","claude-code","cursor-ide","developer-tools","kiro","mcp","prompt-engineering","slash-commands"],"license":"mit","html_url":"https://github.com/timurgaleev/vibestack","pushed_at":"2026-05-18T18:19:05Z","description":"vibestack is a portable skill pack for AI coding agents. Slash commands like /office-hours, /ship, /investigate, /tdd, /review install once and work across every agent that supports the Agent Skills open standard — Claude Code, Cursor, Kiro, and a growing list of others. ","skill_md_sha":"24bf098dc3ba62ae89a6fd4462457d3923657f12","skill_md_path":"skills/qa/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/timurgaleev/vibestack/tree/main/skills/qa"},"layout":"multi","source":"github","category":"vibestack","frontmatter":{"name":"qa","description":"Systematically QA test a web application and fix bugs found. Runs QA testing,\nthen iteratively fixes bugs in source code, committing each fix atomically and\nre-verifying. Use when asked to \"qa\", \"QA\", \"test this site\", \"find bugs\",\n\"test and fix\", or \"fix what's broken\".\nProactively suggest when the user says a feature is ready for testing\nor asks \"does this work?\". Three tiers: Quick (critical/high only),\nStandard (+ medium), Exhaustive (+ cosmetic). Produces before/after health scores,\nfix evidence, and a ship-readiness summary. For report-only mode, use /qa-only.\nVoice triggers (speech-to-text aliases): \"quality check\", \"test the app\", \"run QA\"."},"skills_sh_url":"https://skills.sh/timurgaleev/vibestack/qa"},"updatedAt":"2026-05-18T19:06:23.333Z"}}