code-verification · git:20260914.e75f220 · 2026-09-14 · sha256 97248759f3d148aa
code-verification git:20260914.e75f220A
Immutable. This exact content is served forever at /api/v1/blob/97248759f3d148aa.
---
name: code-verification
description: "Use after every code change, after writing tests, or before marking a task complete, and when the user says verify, quality gate, or audit code. Runs a 7-category mechanical check for TDZ, import, dead code, and mock leakage bugs."
domain: engineering
---
# 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:**
- `activeQuestions` useMemo referenced 150 lines before its declaration
- `baseDeps` used in JSX but handler functions declared 100 lines later
- `DR_FIELDS` referenced in `NFR_CATALOG` before `export const DR_FIELDS` line
**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 `./file` and confirm `export { X }` or `export const X` or `export function X` exists.
- For each `import X from './file'`: confirm `export default X` exists.
- Flag: `import { X } from './file'` when file only has `export default X` (or vice versa).
**Real examples caught:**
- `useResizeHandle` imported as default when it's a named export
- `ConfluencePagePicker` imported as default when it's a named export
- Removed component still imported in 3 files
**Automated check:**
```bash
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:**
- `setPrdDocViewMode` was removed but `Cmd+E` handler still called it
- Removed component still imported in 3 files
```javascript
// 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 but `const handleFoo = ...` still declared.
- Unreachable code: `return` before a code block, `if (false)` guard, feature-flagged code where flag is always false.
- State setters never called: `const [x, setX] = useState()` where `setX` appears nowhere.
- Functions defined but never called.
**Automated check:**
```bash
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.current` used 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 `useRef` get 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 `useEffect` that calls an async function should have an abort/cancel mechanism.
**Real examples caught:**
- `initialLoadRef` set to `true` before async data arrived, blocking subsequent updates
- `useResizeHandle` ref null on mount because empty state rendered first (MutationObserver fix needed)
- DR/IRP/Recovery shared `OperationalDocEditor` reused state across route changes (fixed with `key={docType}`)
- `prdDocViewMode` state removed but `Cmd+E` handler still called `setPrdDocViewMode`
#### 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: OK
- `mockImplementation()` inside a `describe` without `afterEach(() => mock.mockReset())`: LEAK RISK
- `vi.useFakeTimers()` without corresponding `vi.useRealTimers()` in `afterEach`: LEAK
- `mockResolvedValueOnce` chains: fragile if test execution order changes. Prefer `mockImplementation` that inspects the call.
- Multiple `describe` blocks sharing the same `fetch.mock` without 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 setup
- `expect(fn).toHaveBeenCalled()` immediately after calling fn yourself
- `expect(array.length).toBeGreaterThanOrEqual(0)` (always true)
#### 6.3 Query Specificity
- `getByText` / `getByRole` that matches multiple elements -> use `getAllBy*` or scope with `within()`
- 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: `mockResolvedValueOnce` chain broke when test order changed; fixed with request-inspecting `mockImplementation`
- `ConfluencePagePicker`: fake timers from one test leaked into search filter test
- `NFRTracker`: missing `SettingsContext` mock 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="..."` and `className={`...`}` 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 `:root` or a parent selector?
- Is it defined for both light and dark themes?
---
## Automated Verification Script
Run these commands after any code change:
```bash
# 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:
```markdown
## 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 |
|-------|------|------|
| Inline (main 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 |
|------|------|------|
| `verification-workflow.mdc` | Merged quality gate + pre-implementation checklist, enforced after every change | Always (auto-applied) |
| `code-quality.mdc` | Documentation, error handling, and logging standards | When editing JS/TS/JSX/PY |
## Quick Commands
```bash
# 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 `TODO` comment
- 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`, `.tsx` file 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 install` or changing `package.json`
- After merging branches or resolving conflicts
- After a subagent completes work in another window