code-verification
Post-implementation verification system that catches AI-introduced bugs. Covers 7 categories — TDZ errors, import mismatches, reference integrity, dead code, React state/effects, mock isolation, and CSS integrity. Run after every code change, after writing tests, or before markin
What it does
Code Verification Skill
A systematic post-implementation verification workflow that catches the bugs AI coding assistants most commonly introduce. This is NOT a code review for style or architecture — it is a mechanical correctness checklist that catches structural errors (TDZ, imports, dead code, mock leakage, CSS orphans, React anti-patterns) that humans and AI both miss during implementation.
When to Use
- After every code change (1-2 files changed -> run immediately)
- After a multi-file feature (run on all changed files in one pass)
- After writing/modifying tests (switch to Test Verification mode)
- Before marking any task complete (final gate)
- When a subagent completes work (verify their output)
- When user says: "verify", "check quality", "audit code", "run verification", "quality gate", "pre-commit check"
Quick Start
1. Identify changed files (git diff --name-only or manual list)
2. Run the 7-category checklist below on each file
3. Run automated checks (build, lint, tests)
4. Report findings as PASS / FAIL / WARNING
5. Fix all FAIL items before proceeding
The 7-Category Verification Checklist
Category 1: Variable Declaration Order (TDZ Prevention)
What to check: Variables, constants, and hooks used BEFORE their declaration in the same scope.
How it breaks: JavaScript const and let have a "temporal dead zone" — referencing them before their declaration line throws ReferenceError at runtime, but no build error.
React-specific: useMemo, useCallback, useEffect that reference state or derived values declared later in the component. This is the #1 AI-introduced bug.
Scan pattern:
- For every
useMemo,useCallback,useEffect: check that ALL variables in the dependency array AND the callback body are declared ABOVE that hook. - For every function that references a
const/let: check the declaration is above the function definition. - For every destructured import used in a module-level
const: check for circular dependencies.
Real examples caught:
activeQuestionsuseMemo referenced 150 lines before its declarationbaseDepsused in JSX but handler functions declared 100 lines laterDR_FIELDSreferenced inNFR_CATALOGbeforeexport const DR_FIELDSline
Fix: Move the declaration above all usages. If it's a React hook, reorder hooks so dependencies come first.
Category 2: Import/Export Integrity
What to check: Every import resolves to a real export. Named vs default matches.
How it breaks: Build may succeed (tree-shaking ignores dead imports in dev mode) but runtime throws undefined is not a function.
Scan pattern:
- For each
import { X } from './file': open./fileand confirmexport { X }orexport const Xorexport function Xexists. - For each
import X from './file': confirmexport default Xexists. - Flag:
import { X } from './file'when file only hasexport default X(or vice versa).
Real examples caught:
useResizeHandleimported as default when it's a named exportConfluencePagePickerimported as default when it's a named export- Removed component still imported in 3 files
Automated check:
npx eslint --rule '{"import/named": "error", "import/default": "error"}' src/
Category 3: Reference Integrity
What to check: After any rename/remove/move, ALL usages of the old name are updated.
Scan pattern:
- Search for ALL usages of the old name across the project
- Verify zero references remain to removed identifiers
- Check that moved code doesn't reference variables from its old scope
Real examples caught:
setPrdDocViewModewas removed butCmd+Ehandler still called it- Removed component still imported in 3 files
// BUG: setPrdDocViewMode was removed but Cmd+E handler still calls it
useEffect(() => {
const handler = (e) => {
if (e.metaKey && e.key === 'e') setPrdDocViewMode(prev => ...); // ReferenceError
};
}, []);
Category 4: Dead Code Detection
What to check: Unused imports, unreachable code, orphaned handlers.
Scan pattern:
- Unused imports: variable imported but never referenced in file body.
- Orphaned event handlers:
onClick={handleFoo}removed from JSX butconst handleFoo = ...still declared. - Unreachable code:
returnbefore a code block,if (false)guard, feature-flagged code where flag is always false. - State setters never called:
const [x, setX] = useState()wheresetXappears nowhere. - Functions defined but never called.
Automated check:
npx eslint --rule '{"no-unused-vars": "error", "no-unreachable": "error"}' src/file.jsx
Category 5: React State & Effects
What to check: State variables are used, effects clean up, no updates after unmount, correct dependencies.
5.1 Component Reuse Bugs
When the same component renders for multiple routes (e.g., OperationalDocEditor for DR/IRP/Recovery):
- Does it have a
key={uniqueId}to force remount on route change? - Does it reset internal state when props change?
5.2 Effect Dependencies
For every useEffect:
- Are all referenced variables in the dependency array?
- Are object/array deps stable (memoized) or will they trigger infinite re-renders?
- Does the cleanup function undo what the effect created?
5.3 Ref Safety
- Is
ref.currentused in the render return? (Should be state instead — ref changes don't trigger re-render) - Are refs initialized before first access? (Common with resize handles)
- Does
useRefget set in an effect that runs after the component mounts?
5.4 Async State Updates
- Does any async callback (fetch, setTimeout) update state after potential unmount?
- Is there a cleanup function that cancels pending operations?
- Every
useEffectthat calls an async function should have an abort/cancel mechanism.
Real examples caught:
initialLoadRefset totruebefore async data arrived, blocking subsequent updatesuseResizeHandleref null on mount because empty state rendered first (MutationObserver fix needed)- DR/IRP/Recovery shared
OperationalDocEditorreused state across route changes (fixed withkey={docType}) prdDocViewModestate removed butCmd+Ehandler still calledsetPrdDocViewMode
Common React Anti-Patterns
| Anti-Pattern | Why It Breaks | Fix |
|---|---|---|
Mutating state directly (state.push(x)) | React won't re-render | setState([...state, x]) |
Object/array in useEffect deps | New reference every render -> infinite loop | useMemo the dep, or use primitive |
ref.current in render return | Ref changes don't trigger re-render | Use state instead |
history.pushState with #fragment in hash router | Double-hash URL breaks navigation | Use state-based tracking |
Inline object as prop (style={{ color: 'red' }}) | New reference every render, breaks memo | Extract to useMemo or module-level const |
useEffect missing cleanup for async | State update on unmounted component | AbortController or mounted flag |
Category 6: Mock Isolation (Test Files Only)
What to check: Mocks don't leak between tests. Fake timers are restored. Tests are meaningful.
6.1 Mock Leakage
vi.mock()/jest.mock()at module level: OKmockImplementation()inside adescribewithoutafterEach(() => mock.mockReset()): LEAK RISKvi.useFakeTimers()without correspondingvi.useRealTimers()inafterEach: LEAKmockResolvedValueOncechains: fragile if test execution order changes. PrefermockImplementationthat inspects the call.- Multiple
describeblocks sharing the samefetch.mockwithout isolation: INTERFERENCE
6.2 Tautological Tests
Tests that can never fail:
- Asserting a mock's return value equals itself
expect(x).toBeDefined()where x is hardcoded in setupexpect(fn).toHaveBeenCalled()immediately after calling fn yourselfexpect(array.length).toBeGreaterThanOrEqual(0)(always true)
6.3 Query Specificity
getByText/getByRolethat matches multiple elements -> usegetAllBy*or scope withwithin()- Tests that pass because they find the wrong element (e.g., finding a button label that also appears in a tooltip)
6.4 Meaningful Assertions
- Every test should have at least one assertion
- Tests should assert behavior, not just "it renders"
- Snapshot tests should be small enough to review
Real examples caught:
- Jira test:
mockResolvedValueOncechain broke when test order changed; fixed with request-inspectingmockImplementation ConfluencePagePicker: fake timers from one test leaked into search filter testNFRTracker: missingSettingsContextmock caused cascading failures
Category 7: CSS Class Integrity
What to check: Every className in JSX has a corresponding CSS rule. No orphaned selectors.
7.1 Class Name Integrity
- Extract all
className="..."andclassName={...}values from the JSX file. - For each class, search the associated CSS file(s) for
.classname. - Flag: class used in JSX but not defined in CSS (will silently fail — no visual, no error).
- Flag: class defined in CSS but not used in any JSX (dead CSS — bloat).
Note: Dynamic classes like className={isActive ? 'active' : ''} need both branches checked.
7.2 CSS Variable Integrity
For every var(--token) in CSS:
- Is the variable defined in
:rootor a parent selector? - Is it defined for both light and dark themes?
Automated Verification Script
Run these commands after any code change:
# 1. Build check
npm run build
# 2. Lint check (catches unused vars, unreachable code)
npx eslint src/path/to/changed/file.jsx
# 3. Test check (run tests for changed file)
npx vitest run src/path/to/changed/file.test.jsx
# 4. Full suite (after a feature is complete)
npx vitest run
# 5. Circular dependency check (if available)
npx madge --circular src/
Report Template
Use this format when reporting verification results:
## Verification Report — [Project Name]
**Date:** [YYYY-MM-DD]
**Files checked:** [list]
**Tool:** code-verification skill
### PASS
- `path/to/file.jsx` — All 7 categories checked, no issues
### FAIL (must fix before proceeding)
- `path/to/file.jsx:142` — [CAT 1: TDZ] `activeQuestions` referenced before declaration
**Fix:** Move `const activeQuestions = useMemo(...)` to line 95 (before `showClarifyingQuestions`)
### WARNING (review, may be intentional)
- `path/to/file.jsx:88` — [CAT 4: DEAD CODE] `const [oldState, setOldState]` — setOldState never called
**Likely:** Leftover from removed feature. Remove if confirmed unused.
### Summary
| Category | Pass | Fail | Warn |
|----------|------|------|------|
| 1. TDZ | 4 | 1 | 0 |
| 2. Imports | 5 | 0 | 0 |
| 3. References | 5 | 0 | 0 |
| 4. Dead Code | 4 | 0 | 1 |
| 5. React State | 3 | 0 | 2 |
| 6. Mocks | 3 | 0 | 1 |
| 7. CSS | 5 | 0 | 0 |
Integration with Agents
This skill is the workflow. The agents are the executors:
| Agent | Role | When |
|---|---|---|
verification-agent | Runs Categories 1-5, 7 on product code | After implementation |
test-guardian | Runs Category 6 on test code | After writing tests |
code-reviewer | Broader quality review (SOLID, perf, security) | Before merge/deploy |
Integration with Rules
| Rule | Role | When |
|---|---|---|
quality-gate.mdc | Enforces 6 mandatory checks after every edit | Always (auto-applied) |
pre-implementation-checklist.mdc | Prevents bugs before they're written | Always (auto-applied) |
Quick Commands
# Run all tests for a specific file
npx vitest run path/to/file.test.jsx
# Run full test suite
npx vitest run
# Build check
npm run build
# Lint check
npx eslint src/path/to/changed/file.jsx
When to Skip Verification
- Editing only markdown, docs, or comments (no executable code)
- Adding a
TODOcomment - Changing only CSS values (not selectors or class names)
- Reverting a commit (restoring known-good state)
When Verification is MANDATORY (No Exceptions)
- Any
.jsx,.js,.ts,.tsxfile edit - Any file rename or move
- Any import/export change
- Any React hook addition, removal, or reordering
- Any state variable addition or removal
- Any test file modification
- After running
npm installor changingpackage.json - After merging branches or resolving conflicts
- After a subagent completes work in another window
Capabilities
Install
Quality
deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 7 github stars · SKILL.md body (12,566 chars)