| name | verification-loop |
| description | Run a structured pre-PR verification sweep across build, types, lint, tests, security, and diff review. Always activate this skill when the user says things like "verify my changes", "run checks", "is this ready for PR?", "check my code", "run the verification loop", or after completing a feature, refactor, or significant change. Also activate proactively before any PR creation — even if not explicitly asked. Works for TypeScript, JavaScript, and Python projects. |
Verification Loop
A structured, phased quality gate for code changes — designed to catch issues before they reach a PR or production.
Workflow
When this skill activates:
- Detect the project type from context (package.json → JS/TS, pyproject.toml / setup.py → Python, or ask if ambiguous).
- Run phases in order. Each phase gates the next — if Phase 1 (build) fails, skip phases 2–4 since their output is unreliable on a broken build. Always run Phase 5 (security) and Phase 6 (diff) regardless.
- Collect results as you go — don't wait until the end to report failures.
- Produce the verification report after all phases complete.
- If issues are found, list them prioritized by severity and offer to fix them.
Phase 1: Build
A broken build means nothing else is trustworthy. Fix this before anything else.
npm run build 2>&1 | tail -30
pnpm build 2>&1 | tail -30
pip install -e . 2>&1 | tail -20
python -m build 2>&1 | tail -20
Gate: If build fails → skip Phases 2, 3, 4. Report the failure immediately. Still run Phases 5 and 6.
Phase 2: Type Check
Type errors are silent runtime bugs. Treat errors as blockers; warnings as informational.
npx tsc --noEmit 2>&1 | head -50
pyright . 2>&1 | head -50
mypy . 2>&1 | head -50
Report the count of errors vs. warnings. Fix all errors before marking types as PASS.
Phase 3: Lint
Lint failures indicate code style violations or real logic issues (unused vars, unreachable code, etc.).
npm run lint 2>&1 | head -50
npx eslint src/ 2>&1 | head -50
ruff check . 2>&1 | head -50
Distinguish between errors (must fix) and warnings (should fix). Auto-fixable issues can be resolved with:
npx eslint src/ --fix
ruff check . --fix
Phase 4: Test Suite
Tests verify behavior hasn't regressed. Coverage below 80% is a flag worth surfacing to the user.
npm run test -- --coverage 2>&1 | tail -60
npx vitest run --coverage 2>&1 | tail -60
pytest --cov=. --cov-report=term-missing 2>&1 | tail -60
Report:
- Total tests, passed, failed, skipped
- Overall coverage %
- Any newly failing tests (compare against known baseline if available)
If tests fail, identify whether it's a pre-existing failure or something introduced by the current change.
Phase 5: Security Scan
Always run this, even if the build failed. Secrets in code are an immediate risk regardless of build state.
Prefer a dedicated tool if available:
trufflehog filesystem . 2>&1 | head -30
detect-secrets scan 2>&1 | head -30
If no dedicated tool is installed, run a targeted grep as a fallback — but note it's a spot-check, not a full scan:
grep -rn --include="*.ts" --include="*.tsx" --include="*.js" --include="*.py" \
-E "(sk-|api_key|API_KEY|secret_key|SECRET_KEY|private_key|PRIVATE_KEY|password\s*=|bearer\s)" \
. 2>/dev/null | grep -v "node_modules" | grep -v ".git" | head -20
grep -rn "console\.log\|debugger\|breakpoint()" --include="*.ts" --include="*.tsx" src/ 2>/dev/null | head -10
Flag any hits for manual review — false positives are expected with grep; use judgment.
Phase 6: Diff Review
Review what actually changed before declaring the work done. Surprises here are common after a long session.
git diff --stat HEAD
git diff --name-only HEAD
git diff HEAD -- path/to/file
For each changed file, check:
- Unintended changes — files touched that shouldn't have been
- Missing error handling — new code paths without try/catch or error returns
- Edge cases — null inputs, empty arrays, concurrent access, boundary values
- TODOs / FIXMEs left in — intentional or forgotten?
- Commented-out code — should it be deleted or is it temporary?
Verification Report
After all phases, always produce this report:
VERIFICATION REPORT
===================
Project: [name and type — JS/TS/Python]
Scope: [feature / refactor / bugfix — inferred from diff]
Phase 1 — Build: [PASS / FAIL]
Phase 2 — Types: [PASS / FAIL] (X errors, Y warnings)
Phase 3 — Lint: [PASS / FAIL] (X errors, Y warnings)
Phase 4 — Tests: [PASS / FAIL] (X/Y passed, Z% coverage)
Phase 5 — Security: [PASS / WARN / FAIL] (X issues found)
Phase 6 — Diff: [CLEAN / REVIEW NEEDED] (X files changed)
Overall: [✅ READY / ⚠️ READY WITH NOTES / ❌ NOT READY] for PR
Issues (prioritized):
1. [BLOCKER] ...
2. [SHOULD FIX] ...
3. [OPTIONAL] ...
Use BLOCKER for anything that must be fixed before merging, SHOULD FIX for things that will cause problems soon, and OPTIONAL for style or polish items.
Continuous Mode
For long sessions, run the verification loop at natural breakpoints rather than on a timer — the right cadence is task-driven, not clock-driven:
- After completing a discrete unit of work (function, component, endpoint)
- Before switching context to a different part of the codebase
- When something "feels off" after a complex change
- Always before opening a PR
To invoke, just say "run verification", "check my changes", or "are we good?".