All 20 checks with why-it-matters prose, severity, and cross-references to related audits.
Two ORMs pointed at the same database produce split-brain writes: Prisma and Drizzle cache query results differently, generate non-equivalent SQL for identical model intent, and maintain independent connection pools that break transaction isolation. Concurrent writes through both clients can bypass each other's query-level constraints and leave rows in states neither ORM expected, corrupting production data and making debugging nearly impossible because neither stack trace sees the whole picture.
Why this severity: Critical because split-brain data layers silently corrupt production rows and create debugging dead ends that cost days to untangle.
ai-slop-code-drift.data-auth-drift.dual-ormSee full patternTwo active auth libraries means two independent systems of record for who a user is. Password reset may work in NextAuth but silently fail for Clerk-authenticated users. Session revocation on logout may only fire in one library, leaving valid sessions alive in the other. OWASP A07 (Identification & Authentication Failures) and CWE-287 both flag fragmented identity systems as a direct path to authentication bypass — attackers can exploit the gap between which library enforces your authorization checks and which issued the session token they forged. Every route that trusts the wrong library is unprotected.
Why this severity: Critical because split auth systems produce routes that enforce access control against a session they didn't issue, creating authentication bypass vulnerabilities exploitable without credentials.
ai-slop-code-drift.data-auth-drift.dual-authSee full patternTwo actively-used primary database drivers almost always means two separate databases, and every query that spans them is an application-side join with no transaction guarantee. A user update that writes to Postgres and then fails before writing to MongoDB leaves your data permanently inconsistent — there is no rollback across drivers. ISO 25010 functional-suitability degrades when the same logical entity is split across databases: foreign key relationships disappear, referential integrity becomes manual, and migrations must coordinate across two systems. AI-generated code is especially prone to this because each new session starts from scratch and reaches for whatever driver was convenient.
Why this severity: Critical because cross-driver data splits eliminate transactional consistency, making partial writes and permanently inconsistent records routine rather than exceptional.
ai-slop-code-drift.data-auth-drift.dual-database-driverSee full patternTwo form libraries mean two validation APIs, two error-display conventions, and two mental models for managing touched/dirty/submitting state. Developers copy-paste the wrong pattern, accessibility attributes drift between screens, and form-level test helpers multiply. Users experience inconsistent error messaging and focus behavior across forms, and your bundle ships both runtimes to every page even when only one is used on that route.
Why this severity: High because inconsistent form behavior directly erodes accessibility compliance and user trust during critical conversion flows.
ai-slop-code-drift.ui-stack-drift.dual-form-librarySee full patternFragmenting global state across Zustand and Jotai (or any two stores) means some components subscribe to one source of truth while others subscribe to another, and no selector sees the complete application state. Cross-store updates require manual synchronization that inevitably drifts, causing UI components to render stale data, race conditions on login/logout flows, and bugs that only reproduce when state transitions span both stores in a specific order.
Why this severity: High because state fragmentation produces race conditions and stale renders that are expensive to reproduce and debug.
ai-slop-code-drift.ui-stack-drift.dual-state-managerSee full patternRunning MUI alongside Chakra ships two theme providers, two sets of primitives, two typography scales, and often two CSS-in-JS runtimes to every page. Bundle size roughly doubles for the styled-component portion of your app, Core Web Vitals degrade on mobile, and designers cannot produce a coherent visual system because every component comes from a different opinionated foundation. Dark mode toggles typically work in one library and break in the other.
Why this severity: Medium because the impact is bundle bloat and visual drift rather than correctness or data loss, though both affect production quality.
ai-slop-code-drift.ui-stack-drift.dual-component-librarySee full patternWhen no single CSS approach covers at least 70 percent of styled files, every contributor must learn Tailwind utility conventions, CSS Module naming rules, and styled-components template syntax to navigate the codebase. Design tokens live in three places, dark mode implementations diverge, and specificity conflicts between global CSS and scoped modules cause cascade bugs that only appear in production builds after PurgeCSS runs.
Why this severity: Medium because the risk is developer velocity and visual inconsistency rather than functional bugs, though cascade conflicts can break UI at build time.
ai-slop-code-drift.ui-stack-drift.dual-css-approachSee full patternTwo icon libraries ship two SVG sprite sheets, two sets of stroke-width defaults, and two sizing APIs. Users see icons at different visual weights depending on which component rendered them — Lucide's 2px strokes next to React Icons' Font Awesome 1px strokes look mismatched at the same pixel size. Bundle size also grows unnecessarily since tree-shaking rarely eliminates a full icon package, and screen readers receive inconsistent aria-hidden and role attributes.
Why this severity: Low because icon drift is cosmetic and bundle-weight, not functional, but it still shows on every page load.
ai-slop-code-drift.ui-stack-drift.dual-icon-librarySee full patternTwo HTTP clients create two error-handling conventions, two interceptor pipelines, two retry policies, and two authentication header-injection paths. A token refresh that works in your axios interceptor silently skips every ky call, producing inconsistent 401 behavior that depends on which file made the request. Request/response logging captures only half your traffic, and timeout defaults differ (axios has no default timeout, ky defaults to 10 seconds) creating unpredictable production behavior.
Why this severity: High because inconsistent auth-header injection and timeout behavior produce hard-to-reproduce production incidents.
ai-slop-code-drift.tooling-stack-drift.dual-http-clientSee full patternTwo validation libraries produce two schema syntaxes, two inferred-type systems, two error-object shapes, and two ways to compose refinements. A backend route validated with Zod cannot share its schema with a frontend form validated by Yup, so every endpoint has its contract defined twice and they drift the moment someone adds a field to only one side. Error rendering components branch on library-specific shapes, and TypeScript type narrowing works on one side but not the other.
Why this severity: High because schema drift between frontend and backend causes silent validation gaps where invalid data passes one check and fails the other.
ai-slop-code-drift.tooling-stack-drift.dual-validation-librarySee full patternRunning `react-router-dom` inside a Next.js app creates two URL-state systems that fight each other: Next.js's file-based router owns actual page transitions while react-router's `BrowserRouter` intercepts client-side navigation within its subtree. Back-button behavior becomes unpredictable, `useRouter` and `useNavigate` report different current paths, and server-rendered pages hydrate with mismatched route state. Shared links often render the wrong page on cold load.
Why this severity: High because hydration mismatches and conflicting route state break deep-linking and SEO on framework apps.
ai-slop-code-drift.tooling-stack-drift.dual-routerSee full patternRunning Jest and Vitest in the same repo doubles CI runtime because every pipeline executes both runners to cover both test sets. Coverage reports fragment across two tools and merge incorrectly, snapshot formats differ enough to produce false diffs when someone runs the wrong runner, and global setup files (mocks, polyfills, fetch shims) must be duplicated in two configs. Test authors pick whichever syntax they remember, and the suite's actual coverage is impossible to measure accurately.
Why this severity: Medium because the primary impact is CI time and coverage-report unreliability rather than production correctness.
ai-slop-code-drift.tooling-stack-drift.dual-test-frameworkSee full patternTwo date libraries mean two timezone-handling strategies, two parsing APIs, and two bundle payloads. date-fns treats dates as immutable UTC-first while dayjs mirrors Moment's mutable-looking API — code that mixes both produces DST-transition bugs that only fire twice a year. Formatting output drifts between components (one says "Jan 5" the other says "1/5"), and locale handling requires loading the right locale pack into the right library or date strings silently fall back to English.
Why this severity: Medium because DST and timezone bugs are real correctness issues, but they're bounded to date-display and scheduling features.
ai-slop-code-drift.tooling-stack-drift.dual-date-librarySee full patternTwo toast libraries produce two stacking contexts, two animation timings, and two position anchors. A success toast from sonner might render top-right while an error toast from react-hot-toast renders bottom-center, making notifications feel accidental rather than intentional. Users lose trust in the feedback system, and accessibility is also inconsistent: one library might set `role="status"` while the other uses `role="alert"`, changing how screen readers announce messages.
Why this severity: Low because toast drift is a UX polish issue, not a correctness or security concern.
ai-slop-code-drift.tooling-stack-drift.dual-toast-librarySee full patternNext.js routing resolution between `app/` and `pages/` follows non-obvious precedence rules: App Router wins for matching segments, but Pages Router catches everything App Router does not claim. Deploying a half-migrated app can change which route renders simply because someone added or removed a file, with no local indication. SEO metadata, layouts, and data-fetching conventions differ completely between the two routers, producing broken canonical URLs and duplicated or missing OG tags.
Why this severity: Medium because resolution ambiguity can swap which page renders at a given URL without any code change to that page.
ai-slop-code-drift.convention-drift.routing-pattern-consistencySee full patternTwo active payment processors means two webhook handlers, two subscription state machines, two refund flows, and two customer records — and they will diverge. Stripe webhooks fire for events that PayPal never sees; subscription cancellations processed in one system leave active billing in the other. ISO 25010 functional-suitability is directly violated when billing logic is split: a customer who cancels via the Stripe portal remains billed through the PayPal path. In a regulated context, split billing records also complicate revenue recognition and refund auditing. This drift pattern almost always originates from AI sessions adding a "quick PayPal option" without reviewing the existing Stripe integration.
Why this severity: Medium because split payment processors fragment billing state and refund logic, but the failure mode is financial inconsistency rather than immediate security compromise.
ai-slop-code-drift.convention-drift.dual-payment-processorSee full patternInconsistent file naming is a reliable signal of multi-session AI drift: each coding session inherits different conventions from different examples in context. A codebase split between `UserCard.tsx`, `user-card.tsx`, and `userCard.tsx` makes IDE autocomplete unreliable, grep patterns ambiguous, and code review cognitively expensive. ISO 25010 maintainability specifically covers naming consistency as a factor in modifiability — a 50/50 split means every developer mentally translates style before navigating. At scale, this compounds: a new engineer writes to the wrong convention, the next AI session reinforces whichever style it sees first, and the drift widens.
Why this severity: Low because inconsistent naming degrades maintainability and developer velocity without introducing runtime failures or security exposure.
ai-slop-code-drift.convention-drift.file-naming-consistencySee full patternMixed import styles — some files using `@/components/ui/button`, others using `../../../components/ui/button` — are a direct maintainability tax. Relative imports break silently when a file moves; alias imports are path-independent and survive directory reorganization. ISO 25010 maintainability flags this as a modifiability defect: every refactor that moves a file must also audit every relative import pointing at it. AI-generated code produces this drift because each session tends to copy the import style from whatever file it last read, producing a codebase where convention depends on which file the AI happened to open first.
Why this severity: Low because mixed import styles increase refactoring cost and error surface without causing runtime failures or security exposure in correctly-compiled code.
ai-slop-code-drift.convention-drift.import-alias-consistencySee full patternTwo i18n libraries fragment translation keys across two message-catalog formats, double the translation-team workflow, and produce two pluralization strategies that disagree on edge cases (zero counts, languages with dual/trial grammatical number). Translators receive exports from both systems and inevitably miss keys, so some UI strings render in the user's language while others fall back to the source locale. Build output ships both runtimes to every locale bundle.
Why this severity: Info because the impact is translation-workflow drag and partial-translation bugs, not functional or security failures.
ai-slop-code-drift.convention-drift.dual-i18n-librarySee full patternTwo charting libraries means two SVG-rendering approaches, two theming systems, and two tooltip conventions. Recharts' composable React pattern sits next to Chart.js's imperative canvas API and the resulting charts look and behave like they came from different products. Bundle size grows by 50 to 200 KB for the redundant library, which matters on mobile and on dashboard-heavy pages where Core Web Vitals already hover near Lighthouse thresholds.
Why this severity: Info because charting drift is bundle weight and visual inconsistency, not correctness or security.
ai-slop-code-drift.convention-drift.dual-charting-librarySee full patternRun this audit in your AI coding tool (Claude Code, Cursor, Bolt, etc.) and submit results here for scoring and benchmarks.
Open Multi-Session Drift Audit