Skip to content

The checks

A scan runs 38 checks across 7 weighted categories. Each check is scored 0–100 and weighted into a single composite score. The weights of the 37 checks that carry category metadata sum to 100; Pro/AI Analysis and platform-specific zero-weight checks are informational unless promoted into the scoring model. The CHECK_META table in the @vibecodeqa/schema package is the source of truth for the exact current check list and weights.

Last verified

Check list, categories, weights, and priorities on this page were verified against @vibecodeqa/cli 0.54.4 on 2026-08-08, by reading CHECK_META and running a real scan. The inventory below is complete; the detailed sections that follow cover the long-standing checks only.

Full check inventory

Every check a scan runs, in run order, with the category and weight it contributes.

Check Category Weight Priority
structure Foundations 6 high
lint Foundations 5 high
types Foundations 6 critical
type-safety Foundations 3 medium
standards Foundations 3 high
complexity Quality 5 high
duplication Quality 3 medium
error-handling Quality 3 high
react Quality 3 high
flutter Quality 0 high
accessibility Quality 4 high
docs Quality 3 low
best-practices Quality 3 medium
env-validation Quality 1 medium
git-hygiene Quality 1 medium
memory-safety Quality 1 high
testing Testing 13 critical
secrets Security 6 critical
security Security 5 critical
dependencies Security 5 high
architecture Architecture 5 high
performance Architecture 4 medium
dead-code — (synthetic) 0
container-health Quality 0 medium
cloudflare-workers Quality 0 high
sqlite-d1 Security 0 critical
confusion LLM Readiness 4 high
context LLM Readiness 5 high
doc-coherence AI Analysis 0 (Pro) high
code-coherence AI Analysis 0 (Pro) high
comment-staleness AI Analysis 0 (Pro) medium
html-quality Quality 0 medium
frontend-health Quality 2 high
styling Quality 1 medium
dead-patterns AI Analysis 0 (Pro) high
test-audit AI Analysis 0 (Pro) high
file-cohesion AI Analysis 0 (Pro) critical
design-consistency AI Analysis 0 (Pro) high

dead-code is a synthetic check: it is derived from the performance runner's findings, has no CHECK_META row, and is marked scoreImpact: false, so it appears in report.json and the HTML report but never moves the score.

Foundations (23% of score)

Project Structure

weight 6% · high priority

What it checks. Checks for standard project files: package.json, tsconfig.json, LICENSE, README, .gitignore, lockfile. Verifies test-to-source file ratio and that essential scripts (test, build) exist.

Why it matters

Missing config files cause build failures in CI. Missing LICENSE makes the project legally ambiguous. No lockfile means non-reproducible builds — a dependency update can break production silently.

How to fix

Ensure every project has package.json, tsconfig.json, LICENSE, .gitignore, and a lockfile. Add 'test' and 'build' scripts. Aim for at least one test file per source file.

Lint

weight 5% · high priority

What it checks. Runs the project's linter (Biome or ESLint, auto-detected) and counts errors and warnings. Lint rules catch bugs, enforce consistency, and prevent common mistakes before they reach production.

Why it matters

Unlinted code accumulates inconsistencies and latent bugs. Studies show that projects with active linting have 15-20% fewer production defects (Microsoft Research, 2019).

How to fix

Fix all lint errors. Warnings can be addressed incrementally. If no linter is configured, add Biome (@biomejs/biome) — it's the fastest linter for TypeScript with zero config needed.

Type Check

weight 6% · critical priority

What it checks. Runs tsc --noEmit to find TypeScript compilation errors. Type errors mean the code may crash at runtime in ways the compiler could have prevented.

Why it matters

Type errors are bugs. Every unresolved type error is a potential runtime crash. TypeScript's type system exists to prevent entire categories of bugs — ignoring it negates its value.

How to fix

Fix all type errors. If you're migrating from JavaScript, enable strict mode gradually — start with 'strict: true' and fix errors file by file.

Type Safety

weight 3% · medium priority

What it checks. Counts unsafe type patterns: 'as any' casts, explicit ': any' annotations, @ts-ignore directives, @ts-nocheck, and non-null assertions (!.). Each weakens the type system's protection.

Why it matters

'as any' silences the type checker at that point — any bug the types would have caught now slips through. @ts-ignore and @ts-nocheck disable type checking entirely for a line or file. Accumulated 'any' usage correlates with higher defect density.

How to fix

Replace 'as any' with proper types or type guards. Use 'unknown' instead of 'any' when the type is genuinely unknown. Remove @ts-ignore comments by fixing the underlying type issue.

Code Standards

weight 3% · high priority

What it checks. Checks coding conventions: file naming (PascalCase for components, kebab-case for modules), file size limits (>300 lines flagged), code smells (console.log, var, ==, eval, innerHTML, TODO/FIXME), config hygiene (strict mode), and framework best practices (Tailwind vs inline styles).

Why it matters

Large files are hard to review and test. console.log in production leaks internal data. var causes hoisting bugs. == causes type coercion surprises. eval/innerHTML are security vulnerabilities. Inconsistent naming makes the codebase harder to navigate.

How to fix

Split files over 300 lines. Replace console.log with a proper logger or remove it. Use const/let, ===, and safe DOM APIs. Enable TypeScript strict mode.

Quality (30% of score)

Error Handling

weight 3% · high priority

What it checks. Detects poor error handling: empty catch blocks, throw string literals, swallowed .catch(), floating promises, JSON.parse without try-catch, infinite loops, process.exit() in library code, and missing unhandledRejection handlers.

Why it matters

Empty catch blocks silently swallow errors. throw 'string' loses stack traces. Unhandled JSON.parse crashes on malformed input. Missing Error Boundaries in React cause the entire app to crash on render errors. Unhandled promise rejections crash Node.js 15+.

How to fix

Handle or log every catch. Use throw new Error() for stack traces. Wrap JSON.parse in try-catch. Add Error Boundaries in React. Add process.on('unhandledRejection') in server entry points.

Complexity

weight 5% · high priority

What it checks. Measures cognitive complexity of each function: how many branches (if/else/switch/for/while/ternary/&&/||) and how many lines. Functions over 60 lines or with complexity over 15 are flagged.

Why it matters

Complex functions are the #1 source of bugs. Research shows defect density increases exponentially with cyclomatic complexity above 10 (McCabe, 1976). Complex code is also harder to review, test, and modify safely.

How to fix

Extract complex functions into smaller ones. Use early returns to reduce nesting. Replace conditional chains with lookup tables or strategy patterns. Aim for functions under 30 lines with complexity under 10.

Duplication

weight 3% · medium priority

What it checks. Detects copy-pasted code blocks of 6+ lines across source files. Duplication is measured as a percentage of total source lines involved in duplicate blocks.

Why it matters

Duplicated code means bugs must be fixed in multiple places. Miss one copy and the bug persists. DRY (Don't Repeat Yourself) violations increase maintenance cost linearly with each copy.

How to fix

Extract duplicated logic into shared functions or modules. If two files share the same pattern, create a helper. If the duplication is across repos, consider vendoring a shared module.

Documentation

weight 3% · low priority

What it checks. Checks README quality (existence, length, sections) and JSDoc coverage (what percentage of exported functions/classes have documentation comments).

Why it matters

Undocumented code is hard to onboard to and easy to misuse. Missing README means new contributors can't get started. Undocumented exports become tribal knowledge that leaves when people leave.

How to fix

Write a README with: what it does, how to install, how to run, how to develop. Add JSDoc comments to all public exports — even a one-line description helps.

React Patterns

weight 3% · high priority

What it checks. Checks React-specific patterns. Configured React ESLint plugins are the primary source for React diagnostics: eslint-plugin-react-hooks, eslint-plugin-react, eslint-plugin-react-refresh, eslint-plugin-jsx-a11y, and the newer React ESLint plugin families. VCQA heuristics fill gaps when those tools are absent or do not cover a visualized metric, including conditional hook calls, missing key props in .map(), index keys, prop spreading on DOM elements, useEffect dependency hazards, direct DOM queries, inline style pressure when Tailwind is present, and missing Error Boundaries. Monitor reports group findings into React Health categories: hooks, effects, rendering, component structure, error boundaries, compiler readiness, Fast Refresh, and accessibility.

Why it matters

Conditional hooks cause React to crash at runtime. Missing keys cause incorrect reconciliation — items can swap, duplicate, or lose state. Index keys break when lists are reordered or filtered.

How to fix

Never call hooks inside conditions, loops, or nested functions. Always provide a unique, stable key in .map(). Avoid spreading unknown props onto DOM elements. Install and enable eslint-plugin-react-hooks for the official Rules of React and React Compiler diagnostics.

Flutter Health

advisory · high priority

What it checks. Checks Flutter-specific project health across single-package and multi-package roots: package discovery, analysis_options.yaml coverage, flutter_lints, flutter_test, widget tests, integration_test, generated Dart files, and pubspec hygiene.

Why it matters

Flutter repos often contain several packages. If app, admin, and shared packages drift on analysis rules, test layout, or generated-file handling, CI can miss broken widgets and noisy generated files can dominate quality maps.

How to fix

Give each Flutter package analysis options or inherit a root config. Enable flutter_lints or a stronger lint pack. Keep widget and integration tests near each Flutter app, and treat *.g.dart / *.freezed.dart files as generated or visual-neutral.

Accessibility

weight 4% · high priority

What it checks. Runs standard static accessibility tools first, then applies VibeCode QA fallback heuristics for gaps.

  • JSX/TSX is checked with eslint-plugin-jsx-a11y through ESLint's programmatic Linter API.
  • Static HTML is checked with html-validate:standard and html-validate:a11y.
  • Built-in heuristics cover Vue/Svelte templates, missing accessible names, heading-order skips, missing landmarks, static color contrast, hidden focus indicators, click-only controls, autoFocus usage, positive tabIndex, dialog focus basics, and missing html lang.
  • Issues include file, line, rule, selector, WCAG category, severity, and a suggested fix when known.

Why it matters

Missing alt text makes images invisible to screen readers. Icon-only buttons and unlabeled inputs are unusable with assistive technology. Click-only controls, broken focus indicators, bad tab order, and weak dialog focus handling exclude keyboard users. Low contrast makes text unreadable for many users.

Static vs runtime

The built-in accessibility check is static: it reads source files and HTML without building the app. That keeps VCQA fast and zero-config. Runtime DOM auditing with axe-core / @axe-core/playwright is the next layer when a project can be built, served, and routed reliably.

Best Practices

weight 3% · medium priority

What it checks. Advisory check for industry-standard CI/CD, supply chain, and repo hygiene practices. Checks: GitHub Actions with explicit permissions, OIDC instead of long-lived tokens, pinned action SHAs, frozen lockfile in CI, committed lockfile, engine constraints, SECURITY.md, CODEOWNERS, CONTRIBUTING.md, .env.example, pre-commit hooks, automated dependency updates (Dependabot/Renovate).

Why it matters

Missing CI/CD practices lead to supply chain attacks (tj-actions breach affected 23,000 repos in 2025). Long-lived tokens can be stolen from CI logs. Unpinned actions allow tag-poisoning. No lockfile means non-reproducible builds. No SECURITY.md means vulnerabilities go unreported.

How to fix

Pin third-party actions to SHA. Use OIDC trusted publishing instead of tokens. Set explicit permissions in workflows. Add SECURITY.md, CODEOWNERS, and CONTRIBUTING.md. Configure Dependabot or Renovate for automated dependency updates. Add pre-commit hooks.

Testing (13% of score)

Testing

weight 13% · critical priority

What it checks. Deep assessment of test quality across 6 dimensions: pyramid presence (unit/integration/component/E2E layers), test execution (pass/fail), coverage (statement/branch/line/function), file pairing (test file per source file), test quality (assertion density, mock ratio, snapshot ratio), and E2E tool detection (Playwright/Cypress).

Why it matters

Code without tests is code you can't safely change. Missing test layers mean entire categories of bugs go undetected: unit tests catch logic bugs, integration tests catch API contract breaks, E2E tests catch user-visible regressions. Low coverage means large portions of code are never exercised.

How to fix

Follow the testing pyramid: many unit tests, some integration tests, fewer E2E tests. Aim for >80% branch coverage. Every source file should have a corresponding test file. Use Playwright for E2E if you have a web frontend.

Architecture (9% of score)

Architecture

weight 5% · high priority

What it checks. Analyzes the import graph to detect structural problems: circular dependencies, god modules (imported by >50% of files), orphan modules (dead code), high fan-out (importing too many modules), and connector modules (high coupling). Generates an SVG architecture diagram.

Why it matters

Circular dependencies create build order issues and make refactoring impossible without breaking changes. God modules become bottlenecks — any change ripples through the entire codebase. High coupling means you can't change one module without testing everything it touches.

How to fix

Break circular deps by extracting shared types to a separate file. Split god modules by concern. Reduce fan-out by co-locating related code. Use dependency injection for loose coupling.

Performance

weight 4% · medium priority

What it checks. Detects barrel imports that defeat tree-shaking, heavy dependencies with lighter alternatives, static imports of large libraries that could be lazy-loaded, and runtime CSS-in-JS overhead.

Why it matters

Barrel files (index.ts re-exports) prevent bundlers from tree-shaking unused code, bloating bundles by 2-10x. Heavy dependencies like moment.js add 300KB when date-fns does the same in 7KB. Static imports of visualization libraries delay initial page load.

How to fix

Replace barrel re-exports with direct imports. Swap heavy deps for lighter alternatives. Use dynamic import() for large libraries only needed on interaction. Prefer zero-runtime CSS (Tailwind, CSS Modules) over styled-components.

Security (16% of score)

Secrets

weight 6% · critical priority

What it checks. Scans source files for hardcoded secrets: AWS keys, GitHub tokens, Stripe keys, OpenAI/Anthropic API keys, Google API keys, private keys, and generic secret patterns. Checks 14 regex patterns against every non-test source file. Delegates to gitleaks when installed.

Why it matters

Hardcoded secrets in source code are the #1 cause of credential leaks. Once pushed to Git, secrets are in the history forever — even if deleted in a later commit. Leaked API keys can be exploited within minutes by automated scanners.

How to fix

Never hardcode secrets. Use environment variables or a secret manager (Bitwarden, AWS Secrets Manager, Cloudflare Secrets). If a secret was committed, rotate it immediately — deleting the file is not enough.

Security Patterns

weight 5% · critical priority

What it checks. Static analysis for 31 vulnerability patterns mapped to CWE IDs. Covers: XSS, injection, weak crypto, prototype pollution, path traversal, SSRF, credential storage (localStorage/sessionStorage/cookies/connection strings/hardcoded passwords), and missing security headers. Delegates to eslint-plugin-security when installed (adds ReDoS, timing attacks, non-literal require/fs).

Why it matters

These patterns represent the most commonly exploited vulnerabilities in web applications (OWASP Top 10). A single XSS or injection vulnerability can lead to account takeover, data theft, or complete system compromise.

How to fix

Replace innerHTML with textContent or DOM APIs. Never use eval(). Use parameterized queries for SQL. Use crypto.randomUUID() instead of Math.random() for tokens. Validate all user input before use in file paths or URLs.

Dependencies

weight 5% · high priority

What it checks. Runs npm/pnpm audit to find known vulnerabilities (CVEs) in dependencies. Also checks for outdated packages — major version gaps indicate potential security debt and breaking API changes.

Why it matters

Vulnerable dependencies are the most common attack vector for supply chain attacks. 84% of codebases contain at least one known vulnerability in their dependencies (Synopsys OSSRA 2024). Outdated major versions often have unpatched security issues.

How to fix

Run 'pnpm audit' regularly and fix critical/high vulnerabilities immediately. Keep dependencies updated — use Dependabot or Renovate for automated PRs. Pin versions with a lockfile.

LLM Readiness (9% of score)

Confusion Index

weight 4% · high priority

What it checks. Measures naming ambiguity that causes LLMs to misunderstand or edit the wrong code. Checks: file name confusability (Levenshtein distance + synonym detection), generic function/variable names, export name collisions across files, and ambiguous abbreviations.

Why it matters

GPT-4o drops 28.6 percentage points on code summarization when names are ambiguous (arXiv:2510.03178). LLMs editing similar-named files is the #1 reported failure mode in AI-assisted development. Generic names like process(), handle(), data cause models to misinterpret intent.

How to fix

Use descriptive, unique names. Avoid synonym files (utils.ts + helpers.ts — pick one). Avoid generic exports. Disambiguate abbreviations (use 'authentication' not 'auth' if both auth meanings exist in the codebase).

Context Locality

weight 5% · high priority

What it checks. Measures how self-contained code is for LLM consumption. Checks: token density per file, import count, circular dependencies, and context sinks (files that import many modules but export little). Based on the finding that LLMs lose 30%+ accuracy for information in the middle of long contexts.

Why it matters

Files over ~4000 tokens exceed the 'sweet spot' for LLM attention (Liu et al. 2023 'Lost in the Middle'). Circular dependencies create infinite loops in LLM code navigation. Heavy import chains force LLMs to load many files, burning context window budget (Chroma 'Context Rot' 2025).

How to fix

Keep files under 400 lines / 4000 tokens. Limit imports to <15 per file. Break circular dependencies. Co-locate related code to reduce cross-file jumps.

AI Analysis (Pro · informational)

These checks need a VCQA_PRO_KEY in the environment. Without it they report status unavailable and are excluded from the score. There are seven of them; file-cohesion and design-consistency do not yet have a detailed section below.

Doc Coherence

weight Pro · high priority

What it checks. LLM-powered analysis that detects contradictions between documentation and code. Finds stale README claims, incorrect JSDoc parameters, outdated CHANGELOG references, and comments that no longer match the implementation.

Why it matters

Stale documentation is worse than no documentation — it actively misleads developers and LLMs. When README says 'supports X' but the feature was removed, new contributors waste time. When JSDoc says a param is required but code treats it as optional, callers crash.

How to fix

Enable doc-coherence with a VibeCode QA Pro subscription. The LLM scans all documentation against the actual code and surfaces contradictions with specific file references.

Code Coherence

weight Pro · high priority

What it checks. LLM-powered analysis that detects internal contradictions within the codebase itself. Finds inconsistent validation logic, conflicting defaults across modules, naming convention drift, dead config flags, and behavioral mismatches.

Why it matters

Incoherent codebases are the #1 source of 'it works on my machine' bugs. When module A validates email with regex and module B uses a different regex, some emails pass one and fail the other. When timeouts differ across modules, race conditions emerge under load.

How to fix

Enable code-coherence with a VibeCode QA Pro subscription. The LLM analyzes cross-module patterns and surfaces behavioral contradictions that static analysis cannot detect.

Comment Staleness

weight Pro · medium priority

What it checks. Detects stale comments: TODOs older than 6 months, numeric claims that don't match code ("handles 3 cases" but switch has 5), commented-out code blocks, and @deprecated without replacement. LLM-powered semantic mismatch detection with Pro.

Why it matters

Stale comments mislead developers and AI agents. A TODO from 2024 wastes attention. A comment saying '3 cases' when there are 5 causes readers to miss branches. Commented-out code blocks signal incomplete refactoring and confuse LLM context windows.

How to fix

Delete TODOs that won't be done — create issues instead. Delete commented-out code (it's in git history). Update numeric claims when adding branches. Add replacement info to @deprecated.

Dead Patterns

weight Pro · high priority

What it checks. Detects leftover code from incomplete refactors — the signature debt of AI-assisted development. Finds fallback code paths to old implementations, parallel systems doing the same thing, dead defensive guards, hardcoded feature flags with unreachable branches, orphaned abstractions, and redundant wrappers.

Why it matters

Vibe-coded projects accumulate dead patterns fast. When AI refactors code, it creates fallbacks to the old way 'just in case' — but those fallbacks never get cleaned up. Over time, you end up with two implementations of everything, config flags that are always true, and catch blocks that fall back to code that should have been deleted months ago. This doubles the surface area for bugs and confuses both humans and AI tools navigating the codebase.

How to fix

Enable dead-patterns with a VibeCode QA Pro subscription. The LLM analyzes code clusters to find refactor leftovers that static analysis cannot detect — parallel implementations, dead fallbacks, and orphaned abstractions.

Test Audit

weight Pro · high priority

What it checks. Detects fake, shallow, and misleading tests — the 'test theater' that inflates coverage without verifying behavior. Finds empty test bodies, trivial assertions (expect(true).toBe(true)), weak-only checks (.toBeDefined), mock-heavy tests, skipped tests, and tests whose names don't match what they actually verify.

Why it matters

AI-generated tests often look real but test nothing. An empty test body always passes. expect(true).toBe(true) is a tautology. Tests with more mocks than assertions test the mock setup, not your code. This creates a false sense of safety — your coverage number goes up while your actual protection stays zero. Refactors break real behavior but all tests still pass because they never tested real behavior.

How to fix

Enable test-audit with a VibeCode QA Pro subscription. The LLM analyzes each test to determine if its assertions actually verify the behavior described in its name.