All 24 checks with why-it-matters prose, severity, and cross-references to related audits.
Misorganized directory structure forces every contributor to build a mental map from scratch. When components live in the root, API logic lives inside component files, and the `src/` wrapper is applied inconsistently, adding a feature means hunting across the entire tree. ISO 25010 maintainability.analysability degrades directly: the time to locate where a change belongs rises sharply. New contributors — or future you — lose hours before writing a single line. Framework conventions exist precisely to make projects predictable.
Why this severity: Critical because a fractured directory structure makes every subsequent change slower and riskier, compounding across the entire development lifecycle.
code-maintainability.code-organization.file-folder-structureSee full patternCircular dependencies cause modules to receive `undefined` at initialization time because JavaScript resolves the cycle by partially evaluating one module before the other is ready. This produces runtime bugs that are invisible to the type system and nearly impossible to reproduce reliably. CWE-1120 (Excessive Complexity) applies: circular graphs make the build tool's evaluation order non-deterministic and prevent tree-shaking, silently bloating your bundle. AI-generated codebases are especially prone to cycles because utility files get written to "reach back up" into components they originally served.
Why this severity: Critical because circular imports can produce silent `undefined` values at runtime that bypass type checking and are extremely difficult to trace back to their root cause.
code-maintainability.code-organization.no-circular-depsSee full patternA component that fetches data, transforms it, manages multiple unrelated state slices, and renders three distinct UI panels cannot be tested in isolation, reused elsewhere, or modified safely. ISO 25010 maintainability.modularity and reusability both degrade: a change to the API call shape ripples into the rendering logic and breaks tests that only intended to cover the UI. AI-generated "God components" in `app/page.tsx` are a common failure mode — the model writes one large coherent component because it never has to maintain it.
Why this severity: Medium because mixed-concern components increase bug surface and slow down every future change, but they do not immediately break production behavior.
code-maintainability.code-organization.single-responsibilitySee full patternDuplicated logic is a maintenance trap: every bug fix, every business rule change, and every refactor must happen in N places simultaneously. Miss one copy and you ship an inconsistency. ISO 25010 maintainability.reusability directly penalizes this pattern. AI-generated codebases accumulate duplicate logic across sessions because the model rewrites familiar patterns rather than importing the utility it generated three sessions ago. Date formatting, currency conversion, and API error handling are the most common duplicated patterns.
Why this severity: Medium because duplicated logic creates divergence risk on every future change, but individual copies typically function correctly in isolation until they get out of sync.
code-maintainability.code-organization.shared-logic-extractedSee full patternInconsistent import ordering is a low-stakes signal with a real cost: it generates unnecessary merge conflicts when two developers touch the same file, and it slows down code review because readers must mentally parse which dependencies are third-party versus internal. ISO 25010 maintainability.analysability degrades when every file has a different ordering convention. Projects assembled across multiple AI sessions are especially prone to this because each session may apply a different implicit convention.
Why this severity: Low because inconsistent imports cause friction and merge conflicts but do not break functionality or introduce security risk.
code-maintainability.code-organization.import-organizationSee full patternTypeScript without `strict: true` is a false sense of safety. With `strictNullChecks` disabled, the compiler allows `null` and `undefined` to be passed anywhere — silently — meaning null pointer exceptions lurk undetected until runtime. With `noImplicitAny` disabled, entire code paths go untyped. CWE-704 (Incorrect Type Conversion or Cast) applies: the type system fails to catch conversions that will break at runtime. ISO 25010 maintainability.analysability and modifiability both degrade when developers cannot trust the type system to catch refactoring errors.
Why this severity: Critical because disabling strict mode allows null pointer bugs and implicit `any` types to pass compilation silently, making the type system fail at its primary job.
code-maintainability.naming-conventions.typescript-strictSee full patternMixed naming conventions — camelCase functions next to snake_case utilities, PascalCase components alongside kebab-case file names — slow down code review, create false matches during search, and generate typo-based import errors that TypeScript only catches if the module resolution fails. ISO 25010 maintainability.analysability degrades because developers cannot predict where code lives or what it's called. AI-generated projects are especially prone to this: convention drift accumulates across sessions as the model applies whatever convention seems locally natural.
Why this severity: Medium because naming inconsistencies slow every code review and search task, but they do not break runtime behavior unless they cause import resolution failures.
code-maintainability.naming-conventions.consistent-namingSee full patternMagic numbers and strings scattered across logic files make the codebase unreadable and misconfiguration-prone. When the same timeout value appears as `3000` in five places, changing the business rule requires a grep hunt across the codebase — and missing one copy silently introduces inconsistency. ISO 25010 maintainability.analysability degrades because developers cannot distinguish a meaningful business threshold from an arbitrary implementation detail. Magic values in business rule logic are particularly dangerous because they look identical to arbitrary constants.
Why this severity: Low because magic values obscure intent and make configuration changes error-prone, but they do not typically cause correctness failures unless multiple copies get out of sync.
code-maintainability.naming-conventions.no-magic-valuesSee full patternWithout ESLint and Prettier, code style diverges with every commit. Reviewers spend time on formatting comments instead of logic. Style inconsistencies accumulate until they generate real merge conflicts. ISO 25010 maintainability.analysability and modifiability both degrade as the codebase becomes harder to read and predict. Projects bootstrapped with `create-next-app` get a default ESLint config that is never customized — it provides minimal coverage and gives a false impression that linting is configured.
Why this severity: Medium because absent linting and formatting tools allow consistent, preventable code quality issues to accumulate that slow every code review and future refactoring.
code-maintainability.naming-conventions.eslint-prettierSee full patternA missing or boilerplate README means the first developer to clone your project — or you on a new machine six months from now — must read source code to discover how to install dependencies, configure environment variables, and start the server. ISO 25010 maintainability.analysability fails at the project entry point. An unmodified `create-next-app` README is indistinguishable from a project with no documentation at all: it describes Next.js, not your project. Every undocumented setup step is a blocker for every future contributor.
Why this severity: High because a missing or boilerplate README blocks every new contributor from setting up and running the project without direct help from the original author.
code-maintainability.documentation.readme-existsSee full patternUndocumented complex logic — scoring algorithms, multi-step data transformations, non-obvious conditionals — forces every developer who touches that code to reverse-engineer it from the implementation. ISO 25010 maintainability.analysability and reusability both degrade: exported functions without JSDoc cannot be safely consumed by callers who don't understand the contract. AI-generated business logic is especially prone to undocumented complexity because the model writes correct-but-opaque implementations that prioritize functionality over legibility.
Why this severity: Medium because undocumented complex logic multiplies the time required to safely modify or reuse it, but the immediate runtime behavior is unaffected.
code-maintainability.documentation.function-commentsSee full patternWithout `.env.example`, every new developer must read source code to discover which environment variables the project requires — and they will invariably miss some. The result is a broken local setup, a support request to the original author, or — worse — a developer who hard-codes credentials to get unstuck. ISO 25010 maintainability.analysability fails at the setup boundary. SSDF PW.4 requires documenting configuration requirements; an absent `.env.example` is a direct gap. Projects with Supabase, Stripe, and auth libraries typically have 8–15 required variables.
Why this severity: High because a missing `.env.example` makes the project impossible to set up without direct help, blocking every new contributor and deployment to a new environment.
code-maintainability.documentation.env-exampleSee full patternUndocumented API routes are a maintenance hazard: a developer adding a new caller must read the full implementation to understand the expected request shape, authentication requirements, and error responses. At scale, this creates integration bugs and prevents safe independent development. ISO 25010 maintainability.analysability and reusability both degrade. Projects with 10+ API routes and zero documentation force every integration point to be reverse-engineered from implementation details — the kind of friction that produces subtle API misuse bugs.
Why this severity: Medium because undocumented API routes force callers to infer contracts from implementations, increasing integration error risk on every change without breaking existing behavior.
code-maintainability.documentation.api-documentedSee full patternUnused production dependencies add bundle weight, extend install time, and expand your attack surface — every extra package is a potential supply chain compromise vector. CWE-1357 (Reliance on Insufficiently Trustworthy Component) applies: dependencies you didn't intend to ship still ship. AI-generated codebases accumulate unused packages frequently: the model installs `axios` and `moment` in one session, then the next session uses native `fetch` and inline date formatting without removing the earlier additions.
Why this severity: Medium because unused dependencies bloat the bundle and attack surface without delivering functionality, but they do not immediately break application behavior.
code-maintainability.dependency-management.no-unused-depsSee full patternProduction dependencies two or more major versions behind stable miss security patches, performance improvements, and API reliability fixes that maintainers actively backport to current releases. CWE-1104 (Use of Unmaintained Third Party Components) applies directly. SSDF PS.3 requires tracking dependency freshness as a security control. Using React 17 when React 19 is stable, or Next.js 12 when Next.js 15 is stable, means operating on code whose known vulnerabilities have been fixed — just not for you.
Why this severity: Medium because significantly outdated production dependencies accumulate known security vulnerabilities and miss critical patches, but do not immediately break functionality.
code-maintainability.dependency-management.deps-currentSee full patternDuplicate versions of shared packages in the lock file trigger the infamous "Invalid hook call" error for React and produce silent type mismatches, doubled bundle size, and non-deterministic runtime behavior when two copies of the same module hold separate module-level state. When `react`, `react-dom`, `graphql`, or `@types/*` resolve to multiple versions, instanceof checks fail across module boundaries, context providers stop propagating to consumers imported from the other copy, and production bugs surface only on specific code paths. This directly undermines dependency-coherence hygiene and turns routine upgrades into days-long debugging sessions.
Why this severity: Low because most duplicate sub-dependencies are harmless, but conflicts on framework packages like React escalate quickly to production breakage.
code-maintainability.dependency-management.no-duplicate-depsSee full patternA `package.json` with `"some-library": "latest"` or `"another-lib": "*"` means a fresh `npm install` six months from now could pull a breaking major version — silently. CWE-1357 applies: the project depends on whatever happens to be newest, not on a version it was tested against. SSDF PS.3 requires version-pinning as a supply chain control. This failure mode is especially dangerous in CI/CD pipelines that run `npm install` without a lockfile — a new release of a dependency can break production deployments without any code change.
Why this severity: Medium because wildcard or unbounded version specifiers allow untested breaking changes to be silently installed on any fresh `npm install`, turning a routine deploy into a potential breakage.
code-maintainability.dependency-management.version-specifiersSee full patternEvery `@ts-ignore` comment suppresses a real type error — it does not fix the underlying type mismatch, it hides it. The bug still exists at runtime; TypeScript just stops warning about it. Three or more suppressions signal a pattern of bypassing the type system rather than fixing it, which compounds: developers learn that `@ts-ignore` is an acceptable solution, and the count grows. ISO 25010 maintainability.modifiability degrades because refactoring becomes unpredictable — suppressions hide which code actually works.
Why this severity: Critical because TypeScript suppression comments allow real type errors to reach production silently, bypassing the primary safety mechanism TypeScript provides.
code-maintainability.code-hygiene.typescript-compilesSee full patternDead code — unused components, unexported utility modules, unreachable API routes — imposes a cognitive tax on every developer who reads the codebase. Is this file used? Was it intentionally removed? Should I modify it or ignore it? ISO 25010 maintainability.analysability degrades as dead code accumulates. It also creates false positives in security reviews: an unused API route with no authentication looks like a security gap even if nothing calls it. AI-generated codebases accumulate dead code across sessions as earlier implementations get replaced without cleanup.
Why this severity: Medium because substantial dead code increases cognitive overhead and misleads security reviews, but does not break runtime behavior until a dead module is incorrectly believed to be unreachable and then unexpectedly invoked.
code-maintainability.code-hygiene.no-dead-codeSee full patternCommented-out code blocks leave the reader uncertain about whether the code represents a previous implementation, a planned alternative, or a debugging remnant. That uncertainty slows every code review. ISO 25010 maintainability.analysability degrades: developers must read and evaluate code that does nothing. Files with large blocks of commented code are harder to grep and diff, and they create review fatigue that causes reviewers to miss real issues. If the code is needed, it belongs in a branch. If it is not needed, git history already preserves it.
Why this severity: Low because commented-out code creates cognitive overhead and clutters diffs, but does not affect runtime behavior or security directly.
code-maintainability.code-hygiene.no-commented-codeSee full patternUnguarded `console.log` calls in production code expose internal data structures — user objects, API responses, internal state — to browser consoles and server logs. CWE-532 (Insertion of Sensitive Information into Log File) applies when logged objects include user data, tokens, or application secrets. Beyond the data exposure risk, `console.log` in server-side code that runs on every request floods logs with noise, making real errors and security incidents harder to detect. AI-generated codebases accumulate debug logs that were never removed before shipping.
Why this severity: Low because `console.log` in production primarily causes data leakage and log noise rather than direct security exploitation, though CWE-532 applies when logged objects contain sensitive data.
code-maintainability.code-hygiene.no-console-logsSee full patternA `TODO: add auth check here` comment in authentication code means the auth check is absent — not planned, not partially implemented, but missing. This is a shipped security gap with a note attached. In payment processing code, `FIXME: validate webhook signature` means webhook validation is not happening. ISO 25010 maintainability.analysability penalizes TODOs that represent real functionality gaps, not just cleanup debt. At 10+ total TODOs, the project signals that a substantial portion of intended functionality was deferred without resolution.
Why this severity: Medium because TODOs in critical code paths — auth, payments, validation — represent absent security controls, not future cleanup work, making them functionally equivalent to known vulnerabilities.
code-maintainability.code-hygiene.no-critical-todosSee full patternAI-built projects that ship without tests accumulate risk with every change. There is no safety net when modifying working code — a refactor that breaks authentication or payment processing goes undetected until a user reports it. ISO 25010 maintainability.testability directly measures this gap. SSDF PW.8 requires testing as a software assurance control. The absence of tests is especially costly in AI-assisted development where the model makes structural changes across sessions that can silently break previously working behavior.
Why this severity: High because untested critical paths — authentication, payments, data validation — have no automated regression detection, making every future change a gamble against undetected breakage.
code-maintainability.code-hygiene.tests-existSee full patternPre-commit hooks catch linting and formatting violations at commit time — seconds after the code is written — rather than in CI (minutes later) or code review (hours or days later). Without hooks, malformatted code enters the repository freely, and style violations accumulate until code review becomes dominated by formatting comments instead of logic review. ISO 25010 maintainability.modifiability degrades as the codebase becomes harder to read. SSDF PW.7 recognizes automated code review tooling as a software assurance control.
Why this severity: Low because absent git hooks allow preventable style and lint violations to enter the codebase, increasing review burden, but CI and code review provide a slower fallback.
code-maintainability.code-hygiene.git-hooksSee full patternRun this audit in your AI coding tool (Claude Code, Cursor, Bolt, etc.) and submit results here for scoring and benchmarks.
Open Code Maintainability Audit